欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

为什么换了分辨率图色脚本就废了?用 OpenCV 模板匹配把"找图"做稳

为什么换了分辨率图色脚本就废了?用 OpenCV 模板匹配把"找图"做稳

做游戏图色脚本的人,几乎都踩过同一个坑:在 1920×1080 上写得好好的"找图",换台电脑、或窗口一缩放,整个脚本就找不着北了。传统做法(大漠插件 dm.FindPic、按键精灵的找图命令)本质是把一张固定尺寸的位图拿去逐像素比对,分辨率一变,图就对不上。

这一篇就讲:用 OpenCV 的模板匹配(cv2.matchTemplate)+ 多尺度,把"找图"做成能抗分辨率变化的能力。它依然是纯图色思路,但底层换成了更稳的算法。


一、传统找图为什么脆弱

大漠找图的原理可以简化成一句话:拿模板图在屏幕截图上滑动,每挪一个像素就比一遍,找差异最小的位置。问题在于:

  • 尺寸敏感:模板是 100×40 的按钮,游戏在 125% 缩放下实际显示 125×50,像素就不对齐了。
  • 抗干扰差:画面叠加了半透明提示、描边变化时,逐像素比对直接判"不匹配"。
  • 旋转/形变无能为力:图标只要转个角度,传统找图就失效。
核心思路:OpenCV 不依赖"像素级严丝合缝",而是用归一化相关系数衡量相似度,再配合多尺度缩放模板,让同一套脚本能适配不同分辨率。

二、核心函数:cv2.matchTemplate

函数签名:

result = cv2.matchTemplate(image, templ, method[, result])
参数含义
image待搜索的大图(截图),BGR 格式 ndarray
templ模板小图,尺寸必须 ≤ 大图
method匹配方法,图色脚本首选 cv2.TM_CCOEFF_NORMED

返回值:一个二维浮点数组 result,每个元素是该位置与模板的相似度。取值 -1~1,越接近 1 越像

新手必踩坑:TM_CCOEFF_NORMED / TM_CCORR_NORMED 等"归一化"方法时,相似度是越大越好,要用 minMaxLocmax;而 TM_SQDIFF 系列是越小越好,要取 min。方法选错、取值方向搞反,会整张图乱报匹配点。

三、单尺度匹配:先跑通最小可用版

import cv2

# 截图与大漠一样,OpenCV 读进来是 BGR 顺序
screen = cv2.imread('screen.png')   # 大图
templ  = cv2.imread('button.png')   # 模板小图

# 归一化相关系数匹配:越接近 1 越像
res = cv2.matchTemplate(screen, templ, cv2.TM_CCOEFF_NORMED)
_, max_val, _, max_loc = cv2.minMaxLoc(res)

print('最高相似度:', max_val)
if max_val >= 0.85:                # 阈值自定,0.8~0.9 常见
    x, y = max_loc               # 匹配到的左上角坐标
    print('按钮坐标:', x, y)

这段代码就能替代一次 dm.FindPic。但还没解决分辨率问题——模板尺寸固定的话,缩放后依然对不上。下面加多尺度。


四、多尺度匹配:抗分辨率变化的关键

场景:同一游戏在 100% / 125% / 150% 缩放下,按钮尺寸会变。做法是:把模板按多个比例缩放后分别去匹配,取全局最优。

import cv2
import numpy as np

def find_template(screen, templ, threshold=0.85, scales=(1.0, 0.9, 0.8, 1.1, 1.2)):
    h, w = templ.shape[:2]
    best = None
    for scale in scales:
        tw, th = int(w * scale), int(h * scale)
        # 跳过非法尺寸:模板不能大于大图、不能缩没了
        if tw < 1 or th < 1 or tw > screen.shape[1] or th > screen.shape[0]:
            continue
        t = cv2.resize(templ, (tw, th))
        res = cv2.matchTemplate(screen, t, cv2.TM_CCOEFF_NORMED)
        _, max_val, _, max_loc = cv2.minMaxLoc(res)
        if best is None or max_val > best[0]:
            best = (max_val, max_loc, scale, (tw, th))
    if best and best[0] >= threshold:
        x, y = best[1]
        return (x, y, best[2], best[3])   # 左上角、缩放比、模板尺寸
    return None

screen = cv2.imread('screen.png')
templ  = cv2.imread('button.png')
hit = find_template(screen, templ)
print('命中:', hit)   # 例如 (430, 120, 1.1, (88, 44))
为什么这样更稳:无论游戏是 125% 还是 150% 显示,只要真实按钮落在一个缩放比例附近,多尺度循环就能"对上号",一套脚本适配多种分辨率,这正是传统固定位图找图做不到的。

五、工程上还要补的两件事

  1. ROI 限定搜索区:别拿全屏去 matchTemplate,先把截图裁到按钮可能出现的区域(如底部技能栏),速度能快一个量级。
  2. 预处理提特征:匹配前对截图和模板做灰度化、二值化或边缘提取(见本专栏 L5/L7),能排除半透明描边、背景纹理的干扰,命中率更高。
性能提醒:多尺度 + 全屏匹配在 1080p 下可能跑几十毫秒。图色脚本若要逐帧实时,请配合 ROI 裁剪、降采样、或只匹配关键状态点,别无脑全屏扫。

本讲要点

  • cv2.matchTemplate 用归一化方法时取 maxTM_SQDIFFmin,方向别反。
  • 模板必须比大图小,否则直接报错。
  • 多尺度缩放模板是抗分辨率变化的核心技巧。
  • 配合 ROI 裁剪与预处理,速度、命中率才能兼顾。

下一篇我们聊另一个图色刚需——找色:为什么直接比 RGB 容易被亮度骗,以及用 HSV + cv2.inRange 让颜色识别更抗干扰。

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功