Wrong aspect ratio using WINDOW_KEEPRATIO in OpenCV

Viewed 28

I'm using OpenCV to display a sequence of images in a fixed size window maintaining the image's aspect ratio. At some point in the sequence, the image fills the whole window and the aspect ratio is no longer respected for any further images.

I have distilled the problem into this Python code (using OpenCV 4.5.5.64 with Python 3.8 on Ubuntu 20.04):

cv2.namedWindow("random", cv2.WINDOW_KEEPRATIO | cv2.WINDOW_GUI_NORMAL)
while True:
    img_h, img_w = np.random.randint(100, 300, 2)
    image = np.zeros((img_h, img_w))    # Black image of random size
    cv2.imshow("random", image)
    cv2.waitKey()

This image sequence illustrates the problem:

enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here ...

Digging into the problem, the following code displays a sequence of images of increasing aspect ratio and checks the displayed size, comparing the display aspect ratio against the original value:

name = "random"
cv2.namedWindow(name, cv2.WINDOW_KEEPRATIO | cv2.WINDOW_GUI_NORMAL)
img_h = 100
for img_w in range(100, 200):       # Increasing width
    image = np.zeros((img_h, img_w))
    cv2.imshow(name, image)
    cv2.waitKey(1)                  # Force display

    _, _, dsp_w, dsp_h = cv2.getWindowImageRect(name)
    dsp_aspect = dsp_w / dsp_h
    img_aspect = img_w / img_h
    print(f"Image: {img_w}/{img_h} = {img_aspect:.2f}  "
          f"Display: {dsp_w}/{dsp_h} = {dsp_aspect:.2f}")
    cv2.waitKey()

Both aspect ratios are (approximately) equal until the image fills the window. Then all further images fill the window with the wrong aspect ratio:

Image: 100/100 = 1.00  Display: 300/300 = 1.00
Image: 101/100 = 1.01  Display: 303/300 = 1.01
Image: 102/100 = 1.02  Display: 306/300 = 1.02
Image: 103/100 = 1.03  Display: 309/300 = 1.03
Image: 104/100 = 1.04  Display: 312/300 = 1.04
Image: 105/100 = 1.05  Display: 315/300 = 1.05
Image: 106/100 = 1.06  Display: 318/300 = 1.06
...
Image: 130/100 = 1.30  Display: 390/300 = 1.30
Image: 131/100 = 1.31  Display: 393/300 = 1.31
Image: 132/100 = 1.32  Display: 400/300 = 1.33   <<<=====
Image: 133/100 = 1.33  Display: 400/300 = 1.33   <<<=====
Image: 134/100 = 1.34  Display: 400/300 = 1.33   <<<=====
Image: 135/100 = 1.35  Display: 400/300 = 1.33   <<<=====
Image: 136/100 = 1.36  Display: 400/300 = 1.33   <<<=====
...

However, while waiting for a keystroke at waitKey() the window can be manually resized. Then the displayed image automagically recovers the proper aspect ratio. But the problem appears again later when another image fills the window.

So, programmatically resizing the window might do the trick:

name = "random"
cv2.namedWindow(name, cv2.WINDOW_KEEPRATIO | cv2.WINDOW_GUI_NORMAL)
img_h = 100
for img_w in range(100, 200):
    image = np.zeros((img_h, img_w))
    cv2.resizeWindow(name, 400, 300)    # Resize the window
    cv2.imshow(name, image)
    cv2.waitKey()

It doesn't. Calling resizeWindow() with the desired size is not enough. It's necessary to actually change it.

The following does work:

name = "random"
cv2.namedWindow(name, cv2.WINDOW_KEEPRATIO | cv2.WINDOW_GUI_NORMAL)
img_h = 100
for img_w in range(100, 200):
    image = np.zeros((img_h, img_w))
    cv2.resizeWindow(name, 401, 300)    # Force a change in window size
    cv2.resizeWindow(name, 400, 300)    # Recover the desired size
    cv2.imshow(name, image)
    cv2.waitKey()

Is losing the aspect ratio an OpenCV bug? Is there a better solution than the double resize?

0 Answers
Related