ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

游戏窗口自动化点击与防误点设计:模板匹配 + 区域限制 + 强制置顶

游戏窗口自动化点击与防误点设计:模板匹配 + 区域限制 + 强制置顶 游戏窗口自动化点击与防误点设计模板匹配 区域限制 强制置顶“游戏的 UI 按钮比识别模型本身难写——‘放弃奖励’ 和 ‘提前离开’ 之间就隔 200 像素脚本一不留神就退出牌局。”一、背景识别准了 ≠ 脚本能玩前三篇把看牌做完了第 56 篇JOKER 准确率 94%第 57 篇整链路通过率 93%第 58 篇牌面识别 98.7%但脚本跑起来后新的问题来了“怎么让脚本替我点屏幕”这一步看着简单实际是我踩坑最久的——下面这张截图就是经典现场注意看这一帧有多少可点击元素元素位置期望行为首充礼包右上(1100, 80)不点弹窗会盖住手牌带首充图标右下(1280, 690)不点金币底部(440, 700)不点会触发充值弹窗奖底部(1050, 700)不点过牌中右(1080, 320)按需点出牌提示气泡(650, 470)不点看完自己消聊天图标右下(1300, 670)不点挂小王右侧(1100, 410)不点如果脚本天真地用find_tpl全屏扫出牌模板找到的最高分位置 80% 在首充礼包上——因为那是个红底大按钮比对相似度比真正的出牌还高。二、find_tpl 多尺度模板匹配最底层的在屏幕里找按钮算法和第 56 篇牌面识别的多尺度匹配思路一致只是参数不同deffind_tpl(gray,tpl_name,threshold0.8,regionNone,scales(0.85,0.9,1.0,1.1,1.15)):多尺度模板匹配在 region 子图里找 tpl_name 模板。 返回 (cx, cy, score) 或 None。 tplTEMPLATES[tpl_name]# 灰度图ifregionisnotNone:x0,y0,x1,y1region subgray[y0:y1,x0:x1]off_x,off_yx0,y0else:subgray off_x,off_y0,0bestNoneforsinscales:new_wmax(4,int(tpl.shape[1]*s))new_hmax(4,int(tpl.shape[0]*s))tpl_scv2.resize(tpl,(new_w,new_h),interpolationcv2.INTER_AREA)iftpl_s.shape[0]sub.shape[0]ortpl_s.shape[1]sub.shape[1]:continuerescv2.matchTemplate(sub,tpl_s,cv2.TM_CCOEFF_NORMED)_,score,_,loccv2.minMaxLoc(res)ifscorethresholdand(bestisNoneorscorebest[2]):best(off_xloc[0]tpl_s.shape[1]//2,off_yloc[1]tpl_s.shape[0]//2,float(score))returnbest注意scales(0.85, 0.9, 1.0, 1.1, 1.15)和第 56 篇牌面识别的 0.5~1.5 不一样按钮通常不需要太大尺度变化——UI 元素固定大小缩放范围窄一些反而快。三、第一个原则每个按钮必须限定 region这是自动化点击最重要的一条规则。不限定 region等于裸奔。# 不同按钮的区域定义投屏画面分辨率 1376×768REGIONS{出牌:(100,600,1280,720),过牌:(900,280,1200,360),提示:(300,280,700,400),放弃奖励:(400,300,850,520),# 见踩坑第 6 节算贡:(200,400,1100,700),取消托管:(900,100,1200,200),进贡确认:(500,400,900,600),}为什么必须限定举几个反例不限定 region 的场景错误点击出牌模板全屏扫命中首充礼包红底按钮更红过牌模板全屏扫命中金币圆形按钮位置相近提示模板全屏扫命中挂小王提示框颜色相近实战所有出牌类按钮都限定在手牌带 y600~720误点率从 12% → 0.3%。四、第二个原则强制窗口置顶 真实坐标点击脚本点击必须在游戏窗口前台才有效。Windows 下用SetForegroundWindow 模拟鼠标事件importwin32gui,win32con,win32api,ctypesdefforce_foreground(hwnd):把窗口强制拉到前台。ifwin32gui.IsIconic(hwnd):win32gui.ShowWindow(hwnd,win32con.SW_RESTORE)win32gui.SetForegroundWindow(hwnd)# Windows 焦点切换有保护需要先按 Alt 解锁ctypes.windll.user32.keybd_event(0x12,0,0,0)# Alt downctypes.windll.user32.keybd_event(0x12,0,2,0)# Alt upwin32gui.SetForegroundWindow(hwnd)defclick_xy(hwnd,x,y):在窗口坐标 (x, y) 真实点击先置顶再点击。force_foreground(hwnd)# 把窗口客户区坐标转为屏幕坐标left,topwin32gui.ClientToScreen(hwnd,(0,0))sx,syleftx,topy win32api.SetCursorPos((sx,sy))win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,sx,sy,0,0)win32api.Sleep(50)win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,sx,sy,0,0)两个坑Windows 焦点保护直接SetForegroundWindow不一定生效需要先按一下 Alt 模拟切窗口动作客户区 vs 屏幕坐标截图是客户区坐标去掉标题栏点击要转成屏幕坐标加窗口位置五、第三个原则截图与点击必须同一坐标系defcapture_window(hwnd):截取窗口客户区转灰度。left,top,right,bottomwin32gui.GetClientRect(hwnd)w,hright-left,bottom-top hwnd_dcwin32gui.GetWindowDC(hwnd)mfc_dcwin32ui.CreateDCFromHandle(hwnd_dc)save_dcmfc_dc.CreateCompatibleDC()bmpwin32ui.CreateBitmap()bmp.CreateCompatibleBitmap(mfc_dc,w,h)save_dc.SelectObject(bmp)# PW_RENDERFULLCONTENT 2 让 DWM 截图包含图层窗口投屏画面需要ctypes.windll.user32.PrintWindow(hwnd,save_dc.GetSafeHdc(),2)bmpinfobmp.GetInfo()bmpstrbmp.GetBitmapBits(True)imgnp.frombuffer(bmpstr,dtypenp.uint8).reshape(bmpinfo[bmHeight],bmpinfo[bmWidth],4)imgimg[...,:3]# 去掉 alphareturncv2.cvtColor(img,cv2.COLOR_BGR2GRAY)关键参数PrintWindow的第三个参数2PW_RENDERFULLCONTENT。如果不传投屏画面是黑的Windows 8 的 DWM 合成层。六、重头戏防误点踩坑实录——提前离开按钮这是我自动化点击史上最深的一个坑。6.1 现象牌局结束弹出结算页。我设计的逻辑是看到放弃奖励按钮 → 点关闭结算页没有放弃奖励 → 不点等 30 秒自己消但脚本一上对局结束就立刻退出大厅回到登录页——明显是误点了**“提前离开”**按钮。6.2 排查元素y 坐标范围x 坐标范围活动广告皇冠宝贝y0~300x300~1000玩家头像/名字y300~450x200~1200放弃奖励按钮y400~500x500~800提前离开按钮y550~650x500~800两个按钮横向位置几乎一样放弃奖励在上、提前离开在下距离只有 80~150 像素。6.3 老代码的问题旧代码# popup_region 是手牌带裁剪时复用的区域很大popup_region(300,150,950,720)# y 范围到 720giveupfind_tpl(gray,放弃奖励,threshold0.60,regionpopup_region)问题分析问题后果popup_region y 上限 720把提前离开也包含进去find_tpl 在结算页里既找到了放弃奖励又找到了提前离开分数 0.78 vs 0.81——0.81 赢了点了提前离开threshold0.60 太低任何 0.6 的放弃奖励都触发包括 logo/广告里的放弃字样6.4 修复# 新版单独给 giveup 设区域 提高阈值giveup_region(400,300,850,520)# 收窄到只看放弃奖励那一行giveupfind_tpl(gray,放弃奖励,threshold0.80,regiongiveup_region)改动旧新region(300, 150, 950, 720)(400, 300, 850, 520)threshold0.600.80误点率18.7%0.3%踩坑经验auto_test_loop.py里早就留过一句注释——“桌面出现’提前离开’绝不点击等着就行”。但当时没意识到提前离开和放弃奖励在同一个find_tpl候选里互相干扰直到真挂了一次。6.5 防误点的通用设计总结三条防误点规则每个按钮独立 region——不让其他按钮的模板进入候选threshold ≥ 0.80——只信高置信度匹配宁可不点不误点多模板投票——放弃奖励和提前离开是反义按钮绝不在同一个 region 里同时找defsafe_click_button(hwnd,gray,name,region,threshold0.80):安全点击找不到高分按钮就不点。resultfind_tpl(gray,name,thresholdthreshold,regionregion)ifresultisNone:returnFalsecx,cy,scoreresult# 二次校验候选位置 50px 内不能出现互斥按钮foranti_name,anti_regioninANTI_BUTTONS.get(name,[]):iffind_tpl(gray,anti_name,threshold0.75,regionanti_region):log.warn(f互斥按钮{anti_name}同时出现放弃点击{name})returnFalseclick_xy(hwnd,cx,cy)returnTrue七、其他防误点设计7.1 取消托管按钮过滤玩家手动点过托管后结算页会多一个取消托管按钮。# 看到取消托管→ 跳过所有放弃奖励逻辑iffind_tpl(gray,取消托管,0.85,(900,100,1200,200)):return# 玩家在托管别动他7.2 算贡按钮 vs 出牌按钮进贡阶段会有进贡确认按钮位置和出牌按钮接近手牌带同一区域# 看到进贡确认→ 不要走出牌分支iffind_tpl(gray,进贡确认,0.85,(500,400,900,600)):handle_gong_phase()return7.3 广告弹窗首充礼包、皇冠宝贝、签到奖励这类弹窗强制关掉# 任何首充类弹窗出现30s 内直接关forad_namein[首充礼包,皇冠宝贝,签到]:iffind_tpl(gray,ad_name,0.80):find_and_click(hwnd,关闭X,0.80)time.sleep(1)八、算贡场景的 UI 复杂度算贡是够级最复杂的环节——4 个玩家同时交互UI 上同时存在这一帧同时有中间区3 家出的牌组合10 10 10 10、K K K 4 2 2 2 2 2 3 蓝色圆点1左侧玩家头像试用标签右侧玩家头像闪蓝色光圈顶部首充礼包持续干扰底部手牌带9 9 8 8 8 8 7 7 7 7 7 6 6 6 6 5 5 5 5 5 4 4 4 3底部右下奖按钮算贡算法 自动化点击必须保证在 30 秒内完成识别 4 家手牌 → 算出进贡关系 → 点对应牌 → 点进贡确认 → 等结算。任何误点都会导致整局重来。九、实测数据3 局全自动对局指标旧版本新版本误点提前离开18.7%0.3%误点首充礼包6.4%0.1%误点过牌实际为出牌4.2%0.5%单局自动对局成功率53%91%玩家接管次数/局2.70.4单局成功率从 53% → 91%主要靠的是 giveup 防误点-18.4pp和 region 限制-6.3pp。十、算法优缺点对比方案优点缺点模板匹配 region 限制本文快、可解释、好调试每个按钮要单独调 region全屏扫描不用维护 region 列表误点率 18%不可用YOLO UI 目标检测一遍扫出所有按钮训练集要求高、推理慢OCR识字 定位不依赖模板慢、对字体换皮敏感实战推荐先上模板匹配 手工 region能覆盖 80% 场景。难处理的几类活动弹窗、节日换皮走 OCR fallback。十一、踩坑清单写给未来自己现象原因修复脚本点完按钮没反应窗口没在前台SetForegroundWindow Alt 解锁投屏画面截出来是黑的DWM 合成层问题PrintWindow第三参数传 2找出牌找到首充礼包没限定 region每个按钮单独 region点了放弃奖励实际点了提前离开region 包含了下方的提前离开收窄到 (400, 300, 850, 520) 阈值 0.80托管玩家被反复点没检测取消托管检测到取消托管直接 return算贡时点了出牌没检测进贡确认检测到进贡确认走算贡分支十二、小结游戏窗口自动化点击本质是模板匹配 区域限制 强制置顶 互斥校验四件事多尺度模板匹配find_tplscale 0.85~1.15—— 跟得上 UI 微调每个按钮独立 region—— 杜绝误点强制窗口置顶SetForegroundWindow Alt 解锁—— 确保点击生效互斥按钮二次校验—— 防止放弃奖励 vs 提前离开这类陷阱整套链路让单局对局成功率从 53% → 91%记牌器终于能放心让它自己跑了。系列目录牌面角标识别与阈值校准JOKER 误识踩坑手牌带定位与行分割亮度 HSV 颜色双指标投影实战CNN 与模板匹配混合识别ONNX 推理实战游戏窗口自动化点击与防误点设计 ← 本文本机实测环境Windows 11 Python 3.11 OpenCV 4.8 pywin32 手机 1080×1920 投屏scrcpy 1.25。
返回列表