Python OpenCV鼠标回调进入无限循环

发布于 2025-01-10 14:15:55 字数 1929 浏览 0 评论 0原文

我有以下代码,应该让用户通过单击图像上的 4 个点来选择 4 边区域(不一定是矩形):

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()

我遇到的问题是:

  1. 此行执行: print(f'定义草图所在的 4 边多边形:')
  2. 我们进入循环,
  3. 使用调试器单步执行此行: print(f' Please click on point {i}: ', end=' ')
  4. 当我迈步时什么也没有发生越过第 3 点处的线路。控制台上没有任何文本,什么也没有。
  5. 我双击图像,回调工作正常,现在步骤 3 中的打印和回调中的打印都会立即执行。
  6. waitKey 似乎会永远运行。就像它进入了自己的 while True: waitKey() 循环一样,因为无论我点击多少次,我都不会进入 for 循环的第二次迭代。我在控制台上的输出如下所示:
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)

我试图简单地获取 4 个点的坐标。

我尝试查找 opencv 处理回调的方式是否有任何奇怪的地方,但文档在细节上非常模糊。另外,我尝试从回调中返回 True,因为某些库需要您明确表示该事件在被释放之前已被“消耗”。

我的问题是:

  1. 这里发生了什么?为什么 waitKey 在 for 循环中没有返回?
  2. 可以采取什么措施来获得所需的行为?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文