这是我的第一篇博客,记录的是之前匹配微信小程序按键的图像,代码的内容很多都是在各种地方攒的,反正最后的功能还是实现了的。
识别窗口
首先你得确定你要辨别的窗口
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) # 这个是点击