Search code examples
pythonopencvtqdm

OpenCV - The text in cv2.putText is flickering in numpy ndarray with cv2.imshow


In the conversion I'm using I'm using cv2.imshow to display each frame and added tqdm to show progress of the conversion. My problem is the text is flickering in the window. I've played around with cv2.putText before and with an fps counter I got about 25 fps, about 4 milliseconds a frame, but with a timestamp - datetime.now().timestamp() returned about 0.001 per loop. No idea but I think cv2.putText might be in it's own thread for these to be off, that or cv2.imshow might be in it's own thread.

Anyway, I simplified this for posting it here, and left out the conversion of the video. The problem I'm having is that the text is flickering in cv2.imshow

import cv2 as cv
import numpy as np
from tqdm import tqdm
from datetime import datetime

image = np.full(shape = (100, 200, 3), fill_value = (100, 100, 100), dtype = np.uint8)
timestamp = datetime.now().timestamp()

start, stop, scale, font = 6, 0, 0.7, cv.FONT_HERSHEY_COMPLEX
for i in range(500):
    for thikness in range(start, stop, stop + 1 - start):
        color = (0, 0, 0) if thikness == start else (255, 255, 255)

        percent, time, iteration = tqdm.format_meter(
            n = i,
            total = 500,
            elapsed = datetime.now().timestamp() - timestamp,
            ascii = '  ■',
            bar_format = '{percentage:3.0f}% {bar};{remaining};{n_fmt} / {total_fmt}').split(';')

        cv.putText(
            img = image,
            text = percent,
            org = (10, 30),
            fontFace = font,
            fontScale = scale,
            color = color,
            thickness = thikness,
            lineType = cv.LINE_AA
        )
        cv.putText(
            img = image,
            text = time,
            org = (10, 60),
            fontFace = font,
            fontScale = scale,
            color = color,
            thickness = thikness,
            lineType = cv.LINE_AA
        )

        cv.putText(
            img = image,
            text = iteration,
            org = (10, 90),
            fontFace = font,
            fontScale = scale,
            color = color,
            thickness = thikness,
            lineType = cv.LINE_AA
        )

        cv.imshow(winname = 'Frame', mat = image)
        cv.waitKey(1)

Solution

  • I spotted it.

    It was the indent at the bottom with cv.imshow and cv.waitKey. I had the indent in the second for loop instead of the first for loop.

    There are two text images being place in the second for loop. One in each loop. It was showing the black text and then calling cv.imshow, and doing it again with the white text so it was flickering between white and black instead of putting the white text on top of the black which is what I was after.

    import cv2 as cv
    import numpy as np
    from tqdm import tqdm
    from datetime import datetime
    
    start, stop, scale, font, timestamp = 6, 0, 0.7, cv.FONT_HERSHEY_COMPLEX, datetime.now().timestamp()
    for i in range(500):
        image = np.full(shape = (100, 300, 3), fill_value = (100, 100, 100), dtype = np.uint8)
    
        percent, time, iteration = tqdm.format_meter(
            n = i,
            total = 500,
            elapsed = datetime.now().timestamp() - timestamp,
            ascii = ' ',
            bar_format = '{percentage:3.0f}% {bar};{remaining};{n_fmt} / {total_fmt}').split(';')
    
        for thickness in range(start, stop, stop + 1 - start):
            color = (0, 0, 0) if thickness == start else (255, 255, 255)
            cv.putText(
                img = image,
                text = percent,
                org = (10, 30),
                fontFace = font,
                fontScale = scale,
                color = color,
                thickness = thickness,
                lineType = cv.LINE_AA
            )
            cv.putText(
                img = image,
                text = time,
                org = (10, 60),
                fontFace = font,
                fontScale = scale,
                color = color,
                thickness = thickness,
                lineType = cv.LINE_AA
            )
    
            cv.putText(
                img = image,
                text = iteration,
                org = (10, 90),
                fontFace = font,
                fontScale = scale,
                color = color,
                thickness = thickness,
                lineType = cv.LINE_AA
            )
    
        cv.imshow(winname = 'Frame', mat = image)
        cv.waitKey(1)