在 python openCV 中,我试图创建一个 GUI,用户必须在其中选择设置 y 坐标处的像素。我可以获得要将鼠标设置到的 openCV 像素位置,但我无法将其与 win32api.SetCursorPos() 所需的整个系统像素联系起来。我尝试使用 cv2.moveWindow('label', x, y) 移动图像窗口,然后通过 y+offset 偏移光标,但这是一个非常不精确的解决方案。 有什么办法可以找到图像原始像素所在的当前系统像素?
最佳答案
我不知道直接使用 OpenCV 执行此操作的方法(毕竟,它意味着方便原型(prototype)制作,而不是一个完整的 GUI 框架),但由于我们在 Windows 上,我们可以破解它使用直接使用 WinAPI。
注意有一点复杂——回调返回图像坐标,因此如果启用缩放,我们的精度将受到限制,我们必须做一些额外的工作来将坐标映射回客户端窗口坐标。
让我们首先研究 OpenCV 为图像显示窗口创建的窗口层次结构。我们可以调查源代码,但有一种更快的方法,即使用 MSVS 中的 Spy++ 工具。
我们可以为此编写一个简单的脚本来显示一些随机数据:
import cv2
import numpy as np
WINDOW_NAME = u'image'
img = np.zeros((512, 512), np.uint8)
cv2.randu(img, 0, 256)
cv2.namedWindow(WINDOW_NAME, cv2.WINDOW_NORMAL)
cv2.imshow(WINDOW_NAME, img)
cv2.waitKey()
当我们在 Spy++ 中找到这个窗口时,我们可以看到以下信息。
有一个顶层窗口,其标题等于我们指定的窗口名称,属于 Main HighGUI 类
。此窗口包含一个子窗口,没有标题,属于 HighGUI 类
。
想到以下算法:
使用
FindWindow
通过标题找到顶层窗口,并获取它的窗口句柄。使用
GetWindow
获取其子窗口的句柄。使用
GetClientRect
获取客户区(包含渲染图像)的宽度和高度。将
x
和y
图像相对坐标转换回客户区空间。 (我们需要知道当前图像的尺寸才能执行此操作,因此我们会将当前图像作为回调的用户参数传递。)使用
ClientToScreen
将坐标转换为屏幕空间
示例脚本:
import win32gui
from win32con import GW_CHILD
import cv2
import numpy as np
# ============================================================================
def on_mouse(event, x, y, flags, img):
if event != cv2.EVENT_LBUTTONDOWN:
return
window_handle = win32gui.FindWindow(None, WINDOW_NAME)
child_window_handle = win32gui.GetWindow(window_handle, GW_CHILD)
(_, _, client_w, client_h) = win32gui.GetClientRect(child_window_handle)
image_h, image_w = img.shape[:2]
real_x = int(round((float(x) / image_w) * client_w))
real_y = int(round((float(y) / image_h) * client_h))
print win32gui.ClientToScreen(child_window_handle, (real_x, real_y))
# ----------------------------------------------------------------------------
def show_with_callback(name, img):
cv2.namedWindow(name, cv2.WINDOW_NORMAL)
cv2.setMouseCallback(name, on_mouse, img)
cv2.imshow(name, img)
cv2.waitKey()
cv2.destroyWindow(name)
# ============================================================================
WINDOW_NAME = u'image'
# Make some test image
img = np.zeros((512, 512), np.uint8)
cv2.randu(img, 0, 256)
show_with_callback(WINDOW_NAME, img)
关于python - 在 OpenCV 中查找图像的原始像素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46838984/