匹配窗口是否有特定图片-Python

这是我的第一篇博客,记录的是之前匹配微信小程序按键的图像,代码的内容很多都是在各种地方攒的,反正最后的功能还是实现了的。

识别窗口

首先你得确定你要辨别的窗口

import win32con
import win32ui
import win32gui
import win32api
hwnd = win32gui.FindWindow(None, "xxx")  # 父句柄,不懂的可以直接去网上搜索这行代码,会有详细的讲解
hwndChildList = []  # 创建子窗口列表
win32gui.EnumChildWindows(hwnd, lambda hwnd, param: param.append(hwnd), hwndChildList)
hwnd1 = win32gui.FindWindowEx(hwndChildList[0], 0, None, None)
# win32gui.SetForegroundWindow(hwnd)  # 指定句柄设置为前台,也就是激活
# win32gui.ShowWindow(hwnd, win32con.SW_NORMAL)  # 显示最前 从最小化模式显示为正常
windowRec = win32gui.GetWindowRect(hwnd1)  # 目标子句柄窗口的坐标 左上右下边到屏幕边的距离
# 获得窗口的坐标、宽高
left, top, right, bottom = windowRec[0], windowRec[1], windowRec[2], windowRec[3]
width, height = windowRec[2] - windowRec[0], windowRec[3] - windowRec[1]

窗口截图

获取到窗口句柄后就可以进行截图了,截图的目的是为了后面的图形匹配,我本来一直用的桌面截图,效率太低,后来发现可以窗口截图,速度提升了十倍

def capture(file_name, capture_width, capture_height):
    # 返回句柄窗口的设备环境,覆盖整个窗口,包括非客户区,标题栏,菜单,边框
    hWndDC = win32gui.GetWindowDC(hwnd1)
    # 创建设备描述表
    mfcDC = win32ui.CreateDCFromHandle(hWndDC)
    # 创建内存设备描述表
    saveDC = mfcDC.CreateCompatibleDC()
    # 创建位图对象准备保存图片
    saveBitMap = win32ui.CreateBitmap()
    # 为bitmap开辟存储空间
    saveBitMap.CreateCompatibleBitmap(mfcDC, capture_width, capture_height)
    # 将截图保存到saveBitMap中
    saveDC.SelectObject(saveBitMap)
    # 保存bitmap到内存设备描述表
    saveDC.BitBlt((0, 0), (capture_width, capture_height), mfcDC, (0, 0), win32con.SRCCOPY)
    saveBitMap.SaveBitmapFile(saveDC, file_name)
    # 内存释放
    saveDC.DeleteDC()
    win32gui.DeleteObject(saveBitMap.GetHandle())
    mfcDC.DeleteDC()
    win32gui.ReleaseDC(hwnd, hWndDC)
# capture("images/animal_screenshot.png", width, height)

这个代码是找的网上的,我也不懂原理好用就行,是我在所有代码里找的最好用而且最快的

最后一行是代码解释
第一个传入的参数是保存的文件路径,我写的是存入一个images的文件夹并保存成animal_screenshot的图片
第二个是窗口的宽,第三个就是窗口的高

匹配图形

实现图形匹配

def check_pic(img_name, a, click=False):
    # 屏幕缩放系数 mac缩放是2 windows一般是1
    screenScale = 1
    # 事先读取按钮截图
    img_path = 'images/{img}.png'.format(img=str(img_name))
    target = cv2.imread(r"%s" % img_path, cv2.IMREAD_GRAYSCALE)
    # 先截图
    capture("images/animal_screenshot.png", width, height)
    # 读取图片 灰色会快
    temp = cv2.imread(r'images/animal_screenshot.png', cv2.IMREAD_GRAYSCALE)
    tool_height, tool_width = target.shape[:2]
    back_height, back_width = temp.shape[:2]
    # 先缩放屏幕截图 INTER_LINEAR INTER_AREA
    scaleTemp = cv2.resize(temp, (int(back_width / screenScale), int(back_height / screenScale)))
    # 匹配图片
    res = cv2.matchTemplate(scaleTemp, target, cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    print(cv2.minMaxLoc(res))
    # max_val就是匹配度,
    if max_val >= a:
        print("Found it! %s" % img_name)
        if not click:
            return True
        else:
            top_left = max_loc
            bottom_right = (top_left[0] + tool_width, top_left[1] + tool_height)
            tagHalfW = int(tool_width / 4)
            tagHalfH = int(bottom_right[1] / 2)
            tagCenterX = top_left[0] + tool_width - tagHalfW
            tagCenterY = int(top_left[1] + 10)
            tmp = [int(tagCenterX), int(tagCenterY)]
            tmp = win32api.MAKELONG(tmp[0], tmp[1])
            win32gui.SendMessage(hwnd1, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, tmp)  # 鼠标左键按下
            win32gui.SendMessage(hwnd1, win32con.WM_LBUTTONUP, win32con.MK_LBUTTON, tmp)  # 鼠标左键抬起
            # ctypes.windll.user32.SetCursorPos(tagCenterX, tagCenterY)
            # ctypes.windll.user32.mouse_event(2, 0, 0, 0, 0)
            # ctypes.windll.user32.mouse_event(4, 0, 0, 0, 0)
            return True
    else:
        print("%s没找到" % img_name)
# 第一个参数是图片名,你在当前文件夹创建images,把要匹配的图片放在里面
# 第二个是匹配度,越高对识别的图的相似度要求越高
# 第三个是点击功能,如果写True就会识别图形并点击,默认False,即不点击
# check_pic("draw_treasure", 0.9, True)

获取图片数据并匹配

这一步就是运用opencv这个工具读取两个图片并进行匹配
这个是演示部分,这里有些东西实际匹配中可能写了多余但是为了让刚学的人明白,就写了也加了注释。还有这里是从原代码单独提出来的,所以有些函数是没有的,去下面的那段代码就可以找到,这段是讲解opencv的,别复制了,学过opencv的人可以跨过

img_path = 'images/{img}.png'.format(img=str(img_name))
# target 是图片里的素材,就是想按钮啊,特定图像的
# imread 的第二个参数就是读取的形式,这里是读取为灰色,详细的搜索opencv就能学会
target = cv2.imread(r"%s" % img_path, cv2.IMREAD_GRAYSCALE)
# 读取图片 灰色会快 temp是背景
temp = cv2.imread(r'images/animal_screenshot.png', cv2.IMREAD_GRAYSCALE)
tool_height, tool_width = target.shape[:2]
back_height, back_width = temp.shape[:2]
# 先缩放屏幕截图 INTER_LINEAR INTER_AREA
scaleTemp = cv2.resize(temp, (int(back_width / screenScale), int(back_height / screenScale)))
res = cv2.matchTemplate(scaleTemp, target, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
print(cv2.minMaxLoc(res))
# 把识别到的图片框出来
cv2.rectangle(temp, max_loc, (max_loc[0] + tool_width, max_loc[1] + tool_height), (0, 0, 225), 2)
# 显示图片
cv2.imshow("MatchResult----MatchingValue="+str(min_val), temp)
# 保存图片
cv2.imwrite('animal_win.png', temp, [int(cv2.IMWRITE_PNG_COMPRESSION), 9])
cv2.waitKey()
if max_val >= a:
    print("Found it! %s" % img_name)
else:
	print("%s没找到" % img_name)

点击功能

点击功能实现的也算是后台点击,这样子你的鼠标就可以做别的事情了,我觉的更方便,不喜欢后台点击可以用前台点击,就是我注释的部分,前台点击方法还有很多,pyautogui,win32api,等等,当然如果你点击发现没有效果也可以用前台点击试试看点击函数都干嘛了,
这里提个重点,后台点击和前台点击的相对坐标是不一样的,后台的相对坐标以窗口左上角为起点,前台以桌面(0,0),即左上角为起点

# 左上角
top_left = max_loc
tagHalfW = int(tool_width / 4)
tagCenterX = top_left[0] + tool_width - tagHalfW
tagCenterY = int(top_left[1] + 10)
tmp = [int(tagCenterX), int(tagCenterY)]
tmp = win32api.MAKELONG(tmp[0], tmp[1])
win32gui.SendMessage(hwnd1, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, tmp)  # 鼠标左键按下
win32gui.SendMessage(hwnd1, win32con.WM_LBUTTONUP, win32con.MK_LBUTTON, tmp)  # 鼠标左键抬起
# ctypes.windll.user32.SetCursorPos(tagCenterX, tagCenterY)
# ctypes.windll.user32.mouse_event(2, 0, 0, 0, 0)
# ctypes.windll.user32.mouse_event(4, 0, 0, 0, 0)

完整代码如下

import cv2
import win32con
import win32gui
import win32ui

hwnd = win32gui.FindWindow(None, "动物餐厅")  # 父句柄   窗口的类名可以用Visual Studio的SPY++工具获取
# print(hwnd)
hwndChildList = []
win32gui.EnumChildWindows(hwnd, lambda hwnd, param: param.append(hwnd), hwndChildList)
hwnd1 = win32gui.FindWindowEx(hwndChildList[0], 0, None, None)
# print(hwnd1)
# win32gui.SetForegroundWindow(hwnd)  # 指定句柄设置为前台,也就是激活
# win32gui.ShowWindow(hwnd, win32con.SW_NORMAL)  # 显示最前 从最小化模式显示为正常
windowRec = win32gui.GetWindowRect(hwnd1)  # 目标子句柄窗口的坐标 左上右下边到屏幕边的距离
# 获得窗口的坐标、宽高
left, top, right, bottom = windowRec[0], windowRec[1], windowRec[2], windowRec[3]
width, height = windowRec[2] - windowRec[0], windowRec[3] - windowRec[1]
# print(windowRec)


def capture(file_name, capture_width, capture_height):
    # 返回句柄窗口的设备环境,覆盖整个窗口,包括非客户区,标题栏,菜单,边框
    hWndDC = win32gui.GetWindowDC(hwnd1)
    # 创建设备描述表
    mfcDC = win32ui.CreateDCFromHandle(hWndDC)
    # 创建内存设备描述表
    saveDC = mfcDC.CreateCompatibleDC()
    # 创建位图对象准备保存图片
    saveBitMap = win32ui.CreateBitmap()
    # 为bitmap开辟存储空间
    saveBitMap.CreateCompatibleBitmap(mfcDC, capture_width, capture_height)
    # 将截图保存到saveBitMap中
    saveDC.SelectObject(saveBitMap)
    # 保存bitmap到内存设备描述表
    saveDC.BitBlt((0, 0), (capture_width, capture_height), mfcDC, (0, 0), win32con.SRCCOPY)
    saveBitMap.SaveBitmapFile(saveDC, file_name)
    # 内存释放
    saveDC.DeleteDC()
    win32gui.DeleteObject(saveBitMap.GetHandle())
    mfcDC.DeleteDC()
    win32gui.ReleaseDC(hwnd, hWndDC)
    
def check_pic(img_name, a, click=False):
    # 屏幕缩放系数 mac缩放是2 windows一般是1
    screenScale = 1
    # 事先读取按钮截图
    img_path = 'images/{img}.png'.format(img=str(img_name))
    target = cv2.imread(r"%s" % img_path, cv2.IMREAD_GRAYSCALE)
    # 先截图
    capture("images/animal_screenshot.png", width, height)
    # 读取图片 灰色会快
    temp = cv2.imread(r'images/animal_screenshot.png', cv2.IMREAD_GRAYSCALE)
    tool_height, tool_width = target.shape[:2]
    back_height, back_width = temp.shape[:2]
    # 先缩放屏幕截图 INTER_LINEAR INTER_AREA
    scaleTemp = cv2.resize(temp, (int(back_width / screenScale), int(back_height / screenScale)))
    # 匹配图片
    res = cv2.matchTemplate(scaleTemp, target, cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    print(cv2.minMaxLoc(res))
    cv2.rectangle(temp, max_loc, (max_loc[0] + tool_width, max_loc[1] + tool_height), (0, 0, 225), 2)
    cv2.imshow("MatchResult----MatchingValue="+str(min_val), temp)
    cv2.imwrite('animal_win.png', temp, [int(cv2.IMWRITE_PNG_COMPRESSION), 9])
    cv2.waitKey()
    if max_val >= a:
        print("Found it! %s" % img_name)
        if not click:
            return True
        else:
            top_left = max_loc
            tagHalfW = int(tool_width / 4)
            tagCenterX = top_left[0] + tool_width - tagHalfW
            tagCenterY = int(top_left[1] + 10)
            # 后台点击
            tmp = [int(tagCenterX), int(tagCenterY)]
            tmp = win32api.MAKELONG(tmp[0], tmp[1])
            win32gui.SendMessage(hwnd1, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, tmp)  # 鼠标左键按下
            win32gui.SendMessage(hwnd1, win32con.WM_LBUTTONUP, win32con.MK_LBUTTON, tmp)  # 鼠标左键抬起
            # 前台点击
            # ctypes.windll.user32.SetCursorPos(tagCenterX, tagCenterY)
            # ctypes.windll.user32.mouse_event(2, 0, 0, 0, 0)
            # ctypes.windll.user32.mouse_event(4, 0, 0, 0, 0)
            return True
    else:
        print("%s没找到" % img_name)
check_pic('anniu1', 0.8) # 这个是不点击的,匹配到返回True
check_pic('anniu1', 0.8, True) # 这个是点击
  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这个错误通常是因为 OpenCV 无法找到特定窗口或图像文件。可能有几个原因导致这个问题,比如: 1. 图像路径错误:请确保您提供的图像路径是正确的,并且图像文件确实存在。 2. 窗口名错误:如果您正在尝试访问一个不存在的窗口,请确保您输入的窗口名是正确的。 3. OpenCV 版本问题:某些版本的 OpenCV 可能会遇到此问题。尝试更新到最新版本或回退到较旧的版本。 4. 编译问题:如果您是自己编译的 OpenCV,那么可能会出现编译问题。请检查您的编译选项是否正确,并且您的代码与您所编译的版本兼容。 您可以尝试通过检查以上原因来解决这个问题。如果还有问题,您可以提供更多的错误信息和代码,以便更好地帮助您解决问题。 ### 回答2: cv2.error是OpenCV库的一个错误类型。该错误通常发生在使用opencv-python库时,具体位于highgui模块的window.cpp文件的第971行。 这个错误可能有多种原因。一种可能是在调用opencv-python库中的图形用户界面函数时出现了问题。这些函数负责创建和管理窗口,显示和处理图像等。可能是参数传递错误或者部分必需的库文件缺失导致的。 解决这个错误的方法有几种。首先,我们可以检查所使用的OpenCV版本是否与报错中的版本匹配。如果版本不一致,可以尝试升级或降级到与所安装的库匹配的版本。 其次,我们可以检查所使用的参数是否正确。确保正确设置窗口的相关属性和参数。 另外,还应该确保所使用的库文件完整且正确安装。有时候,缺少某些关键的库文件会导致该错误的发生。可以尝试重新安装opencv-python库,或者手动安装所需的库文件。 如果上述方法都不起作用,还可以尝试卸载并重新安装opencv-python库。这将清除可能存在的任何错误或冲突,并重新安装库文件,以便修复错误。 总之,cv2.error: OpenCV(4.7.0) D:\a\opencv-python\opencv-python\opencv\modules\highgui\src\window.cpp:971:... 是OpenCV库在窗口管理函数中的一个错误。通过检查版本、参数和库文件的完整性,可以解决这个问题。 ### 回答3: 这个错误提示显示了在使用OpenCV库的高级图形用户界面模块时发生了一个错误,程序找不到具体的窗口.cpp文件。通常,这种错误是由于以下几个原因之一: 1. OpenCV库版本不兼容:发生这个错误的可能性之一是您安装的OpenCV库版本与当前程序代码不兼容。解决这个问题的方法是确保OpenCV库的版本与您的程序代码所需的版本匹配。 2. 缺少依赖库:OpenCV库需要一些其他的依赖库来正常工作,如图形库、视频库等。这个错误有可能是由于缺少这些依赖库造成的。您可以通过检查您的系统环境和OpenCV库的依赖项来解决这个问题。 3. 文件路径错误:这个错误显示了cpp文件的具体路径,可能是由于您的程序代码中引用的OpenCV库文件的路径不正确导致的。您可以检查程序代码中的路径设置和文件引用,确保它们指向正确的文件路径。 解决这个问题的方法是首先确定OpenCV库的版本和您的代码要求的版本是否匹配。然后,您可以检查系统环境和库的依赖项,确认所有的依赖库都已正确安装。最后,您可以检查程序代码中的文件路径设置和文件引用,确保它们正确指向OpenCV库文件的路径。如果问题仍然存在,您可以查阅OpenCV的官方文档和社区,了解更多关于这个错误的详细信息和解决方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值