0

I have the following code that should let the user select a 4-sided area (not necessarily a rectangle) by clicking on 4 points on an image:

import os
import cv2



FILE_PATH = r'.\img.jpg'
IMAGE_RESIZE_FACTOR = 2

WINDOW_NAME = 'RemoveBG'


img = cv2.imread(FILE_PATH)

print(f'File: "{os.path.abspath(FILE_PATH)}"')

h, w, *_ = img.shape
cv2.imshow(WINDOW_NAME, cv2.resize(img, (w // IMAGE_RESIZE_FACTOR, h // IMAGE_RESIZE_FACTOR)))

print(f'Image size (h x w): {h} x {w}')


def mark_point(event, x, y, flags, param):
    global img
    global marked_points
    if event == cv2.EVENT_LBUTTONDBLCLK:
        x *= IMAGE_RESIZE_FACTOR
        y *= IMAGE_RESIZE_FACTOR

        print(f'({x}, {y})')

        img = cv2.circle(img, (x, y), 100, (0, 0, 0), -1)
        marked_points += [(x, y)]


marked_points = []

cv2.setMouseCallback(WINDOW_NAME, mark_point)


print(f'Define the 4-sided polygon where the sketch resides:')
for i in range(1, 4+1):
    print(f'  Please click on point {i}: ', end='')
    cv2.waitKey()
    cv2.imshow(WINDOW_NAME, cv2.resize(img, (w // IMAGE_RESIZE_FACTOR, h // IMAGE_RESIZE_FACTOR)))


print(marked_points)


cv2.waitKey()
cv2.destroyAllWindows()

The problem I am having is this:

  1. This line executes: print(f'Define the 4-sided polygon where the sketch resides:')
  2. We enter the loop
  3. I step over this line with the debugger: print(f' Please click on point {i}: ', end='')
  4. Nothing happens as I step over the line at point 3. No text on the console, nothing.
  5. I double click on the image, the callback works correctly, now both the print from step 3 and the print from the callback execute at once.
  6. waitKey seems to run forever. Like it enters its own loop of while True: waitKey(), because no matter how many times I click, I do not get to the 2nd iteration of the for loop. My output on the console looks like this:
Image size (h x w): 2048 x 1532
Define the 4-sided polygon where the sketch resides:
  Please click on point 1: (280, 598)
(544, 692)
(794, 902)
(916, 1052)
(1130, 1174)

I am trying to simply get the coordinates of 4 points.

I have tried looking up if there is anything weird in how opencv processes callbacks but the documentation is notoriously vague in details. Also I have tried returning True from the callback as some libraries need you to explicitly say that the event is "consumed" before it will be let go.

My questions are:

  1. What happens here? Why isn't waitKey returning in the for loop?
  2. What can be done to get the desired behaviour?
Rares Dima
  • 1,575
  • 1
  • 15
  • 38
  • you may want to take a look [here](https://stackoverflow.com/a/51143586/7540911) on how waitkey works – Nullman Feb 28 '22 at 11:47
  • also, `print(..., end='')` will not flush because there's no newline character. you should also pass `flush=True` to see that text immediately – Christoph Rackwitz Feb 28 '22 at 12:11
  • 1
    there is no "infinite loop". you simply don't satisfy the condition for waitKey to return. – Christoph Rackwitz Feb 28 '22 at 12:12
  • @ChristophRackwitz so a mouse click is not seen by waitkey as a key press? – Rares Dima Feb 28 '22 at 15:25
  • Yeah wait key doesn't recognize mouse clicks, there is a workaround here which counts mouse clicks with the param and uses that as the while loop. https://stackoverflow.com/questions/64807196/python-show-image-until-mouse-button-is-clicked – kpie Feb 28 '22 at 15:35
  • correct. you get mouse events in the mouse callback only, and keyboard key presses from waitKey only. the program has to be _in_ waitKey, or call it frequently, for GUI to work at all. even if you only care about mouse events, you need waitKey. – Christoph Rackwitz Feb 28 '22 at 15:44

0 Answers0