AutoJs6 中文文档 下载 App

图片找图 — match 模板匹配详解

什么是找图

找图(模板匹配)是在大图像(通常是当前屏幕截图)中查找是否存在一张小图像(模板)的操作。与找色的区别在于:找色只匹配颜色,找图匹配整块区域的像素特征。

截图 (screen)          模板 (icon)
┌──────────────┐       ┌─────┐
│              │       │ [🔍]│
│    [🔍]     │ ← 匹配 │     │
│              │       └─────┘
└──────────────┘

基本用法

准备模板图片

首先需要一张干净的模板图片——要找的目标区域的截图:

  1. 打开目标界面
  2. 用 AutoJs6 截图或系统截图
  3. 手动剪裁出目标区域(建议在电脑上用图片编辑器)
  4. 保存为 PNG(推荐,无损)或 JPG

加载模板

// 从文件加载模板图
let template = images.read("/sdcard/templates/login_btn.png");

// 或用网络图片(v6.7 新增异步加载)
// let template = await images.loadAsync("https://...");

执行匹配

let screen = images.captureScreen();
let template = images.read("/sdcard/templates/login_btn.png");

// 基本匹配
let result = images.match(screen, template);

console.log("匹配结果类型: " + typeof result);

// 单目标匹配 —— 返回最佳匹配点
if (result) {
    console.log("找到模板!位置: (" + result.x + ", " + result.y + ")");
    console.log("相似度: " + result.matches); // 0-100
    click(result.x + template.width / 2, result.y + template.height / 2); // 点击中心
}

screen.recycle();
template.recycle();

匹配阈值

相似度阈值(threshold)

// threshold 决定多大相似度才算"匹配"
// 默认 0.9(90% 相似度)
let result = images.match(screen, template, {
    threshold: 0.9  // 0-1,越接近 1 要求越高
});

// 更宽松(适配颜色略有差异的情况)
let result = images.match(screen, template, { threshold: 0.8 });

// 更严格(避免误匹配)
let result = images.match(screen, template, { threshold: 0.95 });

阈值选择建议

阈值范围适用场景风险
0.95 - 1.0静态界面、精确匹配可能找不到
0.85 - 0.95推荐平衡精度与召回
0.7 - 0.85有细微变化的界面可能误匹配
< 0.7模糊匹配误匹配概率高

多目标匹配

当屏幕上可能出现多个模板实例时:

// 找全部匹配点
let results = images.matchAll(screen, template, {
    threshold: 0.85
});

console.log("共找到 " + results.length + " 个匹配");
results.forEach(r => {
    console.log("位置: (" + r.x + ", " + r.y + ") 相似度: " + r.matches);
});

// 逐个点击
results.forEach(r => {
    click(r.x + template.width / 2, r.y + template.height / 2);
    sleep(300); // 间隔一下
});

去重匹配

matchAll 默认开启了非极大值抑制(NMS),避免同一个位置返回多个重叠结果。可以调整去重距离:

let results = images.matchAll(screen, template, {
    threshold: 0.85,
    region: [0, 0, 1080, 1920],  // 限定搜索区域
    max: 10,                     // 最多返回几个结果
    weak: true,                  // 是否包含弱匹配结果
    // 去重相关
    thresholdFirst: false,        // 先做阈值筛选再去重
    similarityThreshold: 0.9,     // 去重时的相似度阈值
    target: null                 // 自定义去重目标函数
});

区域限定匹配

// 只在屏幕下半部分搜索
let result = images.match(screen, template, {
    region: [0, 960, 1080, 960]  // x, y, width, height
});
// 性能提升明显!

多模板匹配

// 准备多个模板,分别匹配
let templates = [
    { name: "play", img: images.read("/sdcard/templates/play.png") },
    { name: "pause", img: images.read("/sdcard/templates/pause.png") },
    { name: "stop", img: images.read("/sdcard/templates/stop.png") }
];

function findBestMatch(screen, templates) {
    let best = null;
    templates.forEach(t => {
        let r = images.match(screen, t.img, { threshold: 0.8 });
        if (r && (!best || r.matches > best.matches)) {
            best = { name: t.name, x: r.x, y: r.y, similarity: r.matches };
        }
    });
    return best;
}

let screen = images.captureScreen();
let found = findBestMatch(screen, templates);
if (found) {
    console.log("匹配到: " + found.name + " 相似度: " + found.similarity);
}

// 清理
screen.recycle();
templates.forEach(t => t.img.recycle());

图像预处理

匹配前可以对图像做预处理,提高匹配成功率:

剪裁后匹配

let screen = images.captureScreen();
// 只在关键区域剪裁后匹配
let region = images.clip(screen, 0, 1000, 1080, 500);
let result = images.match(region, template, { threshold: 0.9 });
region.recycle();
screen.recycle();

灰度匹配

某些情况下灰度图比彩色更稳定:

// 预先把模板转为灰度
let template = images.read("/sdcard/templates/target.png");
let grayTemplate = images.grayscale(template);

// 灰度图做匹配
let result = images.match(screen, grayTemplate);
template.recycle();
grayTemplate.recycle();

二值化

let binary = images.binary(template, {
    threshold: 128    // 二值化阈值
});

常见问题

匹配返回 null

// 可能原因排查:
// 1. 模板图片太大 —— 推荐 < 200x200px
// 2. 阈值太高 —— 降低到 0.8 或 0.7
// 3. 模板不在截图中 —— 确保目标真的在屏幕上
// 4. 分辨率不同 —— 模板要在目标设备上截取

// 调试:逐步降低阈值
for (let t = 0.95; t >= 0.5; t -= 0.05) {
    let r = images.match(screen, template, { threshold: t });
    if (r) {
        console.log("阈值 " + t + " 时匹配成功,相似度 " + r.matches);
        break;
    }
}

匹配位置偏移

截图坐标系和点击坐标系可能存在差异:

// 点击时记得加模板宽高的一半(点中心)
click(result.x + template.width / 2, result.y + template.height / 2);

内存管理

// ❌ 错误:不释放图片
for (let i = 0; i < 100; i++) {
    let screen = images.captureScreen();
    // 使用 screen...
    // 忘了 recycle!循环 100 次 = 内存爆炸
}

// ✅ 正确:用完就释放
for (let i = 0; i < 100; i++) {
    let screen = images.captureScreen();
    // 使用 screen...
    screen.recycle(); // ✅ 及时释放
}

性能优化

优化方法效果
限定搜索区域region 参数搜索范围越小越快
小尺寸模板< 200x200px计算量减少
复用截图同一张图多次匹配避免重复截图开销
灰度匹配转灰度后匹配减少色彩干扰
合适阈值先 0.85 再微调避免反复尝试