在OpenCV中查找图像的原点像素

时间:2017-10-19 21:12:49

标签: python opencv mouse

在python openCV中我试图创建一个GUI,用户必须在set y坐标处选择像素。我可以获得我想要将鼠标设置为的openCV像素位置,但我无法将其绑定到win32api.SetCursorPos()所需的整个系统像素。我尝试使用cv2.moveWindow('标签',x,y)移动图像窗口,然后将光标偏移y + offset,但这是一个非常不精确的解决方案。 有没有办法找到图像原点像素所在的当前系统像素?

1 个答案:

答案 0 :(得分:0)

我不知道用OpenCV直接做到这一点的方法(毕竟,它意味着原型设计的便利性,而不是一个完整的GUI框架),但由于我们在Windows上,我们可以使用它来破解它WinAPI直接。

N.B。有一个轻微的复杂性 - 回调返回图像坐标,所以如果启用缩放,我们的精度将受到限制,我们必须做一些额外的工作来将坐标映射回客户端窗口坐标。

让我们首先研究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 ++中找到这个窗口时,我们可以看到以下信息。

Spy++ showing the OpenCV HighGUI window

有一个顶级窗口,其标题等于我们指定的类别Main HighGUI class的窗口名称。此窗口包含一个没有标题的子窗口,以及类HighGUI class

我想到了以下算法:

  1. 使用FindWindow按标题查找顶级窗口,并获取窗口句柄。

  2. 使用GetWindow获取其子窗口的句柄。

  3. 使用GetClientRect获取客户区的宽度和高度(包含渲染图像)。

  4. xy图像相对坐标转换回客户区空间。 (我们需要知道当前图像的尺寸,因此我们将当前图像作为回调的用户参数传递。)

  5. 使用ClientToScreen

  6. 将坐标转换为屏幕空间

    示例脚本:

    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)