欢迎来到 嗅灵易学

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

为什么你的大漠找图在别人电脑上全失效?聊聊特征匹配与颜色容差的门道

为什么你的大漠找图在别人电脑上全失效?聊聊特征匹配与颜色容差的门道

前阵子写了个自动登录的图色脚本,自己机器上跑得那叫一个丝滑,找图命中率 100%。美滋滋丢到群里让兄弟试,结果他那边一张都找不到,报的全是"未找到"。我一开始还嘴硬,说他分辨率没调对、DPI 没关。直到我远程看了他一眼屏幕——窗口一模一样,就是找不到。折腾一下午,根子出在俩地方:特征选得不对,和颜色容差没留余地。这俩坑,几乎每个写图色脚本的人都会踩至少一次。

一句话定性: 找图不是"截图比对"那么浪漫的事,它是个在噪声环境里做模糊匹配的活儿。你以为的"同一个红",在两块屏幕上早就不是同一个 RGB 了。

先说清一件事:找图到底在找什么

无论是大漠的 FindPic 还是自己用 OpenCV 写的模板匹配,本质都是同一件事:在大图里滑动一个小图,逐像素比较相似度,超过阈值就认为是命中。关键参数有两个——相似度阈值(sim)和颜色容差(tolerance)。新人最容易犯的错,是把 sim 拉到 0.95 以上,觉得自己严谨,结果环境一变就全盘皆输。

相似度不是越高越好

sim=1.0 意味着"每一个像素都必须严丝合缝"。但现实里,抗锯齿会让边缘差几个值,录制软件/显卡输出会整体漂移,甚至窗口失焦时界面会泛灰。把 sim 卡死,等于要求"连噪点都得一模一样",这是不可能的任务。

颜色容差:屏幕上的"同一个红"其实一直在变

同一处按钮,我机器上是 (220,80,80),兄弟机器上可能是 (212,88,75)。差了不到 10,肉眼根本看不出,但按"严格相等"比的算法直接判你没找到。容差就是给每个像素一个"允许偏差多少"的宽容度。

选特征,比调参数重要十倍

我后来才懂:特征图选错了,参数怎么调都救不回来。几条我现在的选取原则:

  • 选信息量大的区域:角标、图标、带纹理的按钮,比一整块纯色背景强太多。
  • 避开会动态变化的部分:按钮上的文字加载慢、红点提示时有时无,拿它当特征必翻车。
  • 避开阴影和高光边缘:不同 DPI、不同主题下,阴影的羽化算法不一样,边缘最不可靠。
  • 特征尽量小而唯一:太大搜索慢,太普通会误命中;一个不常见的图标刚刚好。

容差怎么取?我一般分三档

  1. 严(sim 0.9+,容差 5~10):纯色 UI、固定主题、本机专用。命中干净,但换环境就废。
  2. 中(sim 0.75~0.9,容差 20~40):日常通用档,我 80% 的脚本落在这。
  3. 松(sim 0.6~0.75,容差 50+):环境光波动大、有抗锯齿、跨机器分发。但太松会"张冠李戴",务必先在目标环境实测。

一段能直接跑的带容差匹配

不依赖大漠也能体会这套逻辑,下面用 PIL + numpy 手搓一个,单通道容差可控:

from PIL import Image
import numpy as np

def find_with_tolerance(hay, needle, tol=30, step=2):
    """在大图 hay 里找小图 needle,tol 为单通道允许偏差"""
    H = np.asarray(hay.convert("RGB")).astype(int)
    N = np.asarray(needle.convert("RGB")).astype(int)
    nh, nw = N.shape[:2]
    best = None
    for y in range(0, H.shape[0] - nh, step):
        for x in range(0, H.shape[1] - nw, step):
            patch = H[y:y+nh, x:x+nw]
            diff = np.abs(patch - N).max(axis=2)   # 每个像素最大通道差
            if diff.max() <= tol:                  # 全部像素都在容差内
                sim = 1 - diff.mean() / 255
                if best is None or sim > best[0]:
                    best = (sim, x, y)
    return best   # (相似度, x, y) 或 None

# 用法
hay = Image.open("screen.png")
needle = Image.open("btn_login.png")
hit = find_with_tolerance(hay, needle, tol=35)
print(hit)   # (0.91, 412, 308) 表示在 (412,308) 命中,相似度 0.91
我踩过的几个坑(都是学费):
  • 只截了按钮中间,结果按钮文字是异步加载的,慢半秒就找不到——后来改成截图标而非文字。
  • 用了带圆角阴影的图当特征,别人机器 DPI=125% 时阴影算法不同,边缘全偏。
  • 没考虑任务栏自动隐藏,窗口 Y 偏移了 40px,找图范围没覆盖到,死活找不到。

回过头看,找图这件事的精髓不是"算法多牛",而是你对人体工学和显示环境的理解——知道哪块屏幕区域稳定、哪种颜色会漂、哪个特征不随状态变。把特征选对、容差留口活气,你的脚本就能从"我机器能跑"进化到"发群里大家都能用"。这中间的差距,就是新手和老手的分水岭。

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

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

0 0 0 举报
复制成功