安卓自动化的主流做法是免 root,靠无障碍服务和 ADB,让程序去做重复操作。
读不到控件时用找图找色
脚本要操作界面,得先知道界面在哪里。常规做法是读控件树:安卓会给当前界面生成一棵节点树,无障碍服务可以读。每个按钮、输入框、图片都有 id、文本、描述和位置边界,脚本按这些属性找控件。游戏画面里 OpenGL / SurfaceView 渲染的内容没有标准控件节点。自绘控件在节点树里往往只剩一个空壳。图片按钮整张图就是一个按钮。这些界面读不到节点,只能截图找目标,找到再操作。
EasyClick 里,申请截图、抓屏、找图、找色、比色都在图色模块(image 系列 API,对象前缀是 image),走系统官方能力,免 root。
最早的自动化脚本是坐标脚本,录下屏幕上一个点的 (x, y),到点就点。分辨率一变、布局一调、弹窗一弹,这个坐标就废了。找图记的是目标长什么样,命中后再取出它在屏幕上的位置。按钮挪了位置、换了机型、改了字体,只要样子还在,同一套模板通常还能找到。没有控件节点的界面,只要屏幕上看得到,也能找。目标完全没有颜色和形状特征时,才退回坐标。成熟平台支持在一块坐标区域内随机点击,用来降低操作特征(功能特性文档)。
找图、找色怎么用
找图是目前用得最多的识别手段,做的是模板匹配。准备一张目标小图当模板,在屏幕大图上从上到下、从左到右滑动,每个位置算一次相似度,超过阈值就算命中。命中后返回位置区域(Rect),取中心点当点击坐标。模板从开发工具截下来,放进工程 res 文件夹,脚本里用 readResAutoImage() 读取。相似度由阈值参数控制:
| 参数 | 含义 | 默认值 |
|---|---|---|
threshold |
图片相似度,0~1 的浮点数,最终命中判定标准 | 0.9 |
weakThreshold |
弱阈值,用于每一轮匹配中检验是否继续匹配,相似度低于它则提前放弃该轮 | 0.7 |
匹配方法(method 参数)有 6 种可选,全部来自 OpenCV 的标准模板匹配方法:
| 取值 | 匹配方法 | 说明 |
|---|---|---|
| 0 | TM_SQDIFF | 平方差匹配法 |
| 1 | TM_SQDIFF_NORMED | 归一化平方差匹配法 |
| 2 | TM_CCORR | 相关匹配法 |
| 3 | TM_CCORR_NORMED | 归一化相关匹配法 |
| 4 | TM_CCOEFF | 系数匹配法 |
| 5 | TM_CCOEFF_NORMED | 归一化系数匹配法 |
官方文档写的图像识别率是 95% 以上,指常规、清晰、静态界面(功能特性文档)。实际效果看截图清不清楚、模板和画面是否一致、界面变了多少、阈值设得合不合理。后面是一个能跑的找图示例,函数名和参数顺序以文档为准:
image.initOpenCV(); // 找图前先初始化 OpenCV 类库(首次较慢,之后很快)
let template = readResAutoImage("sms.png"); // 从工程 res 文件夹读取模板小图
let aimage = image.captureFullScreen(); // 抓取当前屏幕
// 找图:弱阈值 0.7,相似度 0.9,最多找 21 个,method=5 归一化系数匹配法
let points = image.findImage(aimage, template, 0, 0, 0, 0, 0.7, 0.9, 21, 5);
if (points && points.length > 0) {
// 返回的是 Rect 区域,取中心点作为点击坐标
let x = parseInt((points[0].left + points[0].right) / 2);
let y = parseInt((points[0].top + points[0].bottom) / 2);
clickPoint(x, y);
}
image.recycle(aimage); // 图片用完要回收,防止内存暴涨
image.recycle(template);
找图还有几个变体。findImageEx 会自己截屏再找。findImage2 带缩放,目标被缩放渲染时比 findImage 更准,EC 9.41.0+。findImageByColor 做透明找图,模板可以带透明,也不用先初始化 OpenCV,EC 7.15.0+。截图本身要花时间。captureScreen 把截图转成 Bitmap,大约 0~20ms。大约 16ms 内连续调用,拿到的是同一张截图(图色函数文档)。模板匹配内部用图像金字塔加速,一般不用自己调。
找色不拿整张图去比,只在指定区域里找指定颜色的点,所以比找图轻。单点找色(findColor)在区域内找和给定值匹配的点,可以带偏色,返回坐标数组。固定色 UI、纯色按钮、状态指示灯常用它。颜色参数格式形如 0xCDD7E9-0x101010,前半是颜色值,后半是偏色容差。threshold 是 01 的颜色相似度,8 的查找方向。单点只核对一个点的颜色,大面积同色背景容易误报。多点找色(limit 限制返回个数,orz 是 1findMultiColor)用一个点做锚点,再核对周围若干点的相对位置和颜色,全部符合才算命中:
// 第一个点的颜色作为基准,再校验相对偏移点
// 格式:x 偏移|y 偏移|颜色[-偏色],多个点用逗号分隔
let firstColor = "0xDD7A5F-0x101010";
let points = "29|25|0xBB454B-0x101010,58|44|0xA6363A-0x101010";
// findMultiColorEx 自动截屏多点找色
let result = image.findMultiColorEx(firstColor, points, 0.9, 0, 0, 0, 0, 10, 1);
if (result && result.length > 0) {
clickPoint(result[0].x, result[0].y);
}
几个点的相对位置和颜色很难在屏幕别处同时对上,所以比单点不容易误报。图标角标、红点、带纹理的按钮常用这种写法。比色(cmpColor / cmpColorEx)检查某个位置上的几个点颜色是否都符合预期,全部符合才返回 true,用来看按钮状态有没有切换。cmpMultiColor / cmpMultiColorEx 可以依次试多组方案,命中返回该组索引,没命中返回 -1。色块查找用的是找色能返回区域内全部匹配点这一点,用来圈出连续色块、找到边界。血条、进度条通常先找两端的颜色边界,再按比例估算,不用准备整张模板图。开发工具可以在截图上取点、取色、生成配置文件。J 系列函数(findColorJ 等)直接从 JSON 读参数。
识别失败怎么调,API 与场景速查
界面会变,一次调好的阈值很难一直管用。找不到就把 threshold 从 0.9 降到 0.85、0.8;找错位置就调高。找色的 threshold 同样处理。阈值只管放多宽,模板本身还得新、还得清楚。全屏查找慢,也容易被别的元素干扰。找图和找色都有 x, y, ex, ey,把范围收在目标可能出现的那一块,同屏相似的元素也不容易认错。同一个目标可以准备几张模板轮流试。多组比色用 cmpMultiColor 一次比完。页面加载有延迟,循环识别,等到目标出现再操作,超时就退出。固定 sleep 经常要么等不够,要么空等。image.setInitParam 可以设置找图找色的最大时间(action_timeout),到点自动返回,免得一直卡住。
找图优先。找不到再找色,还不行就重试。后面是申请截图、找图、找色接在一起的写法:
function main() {
// 1. 申请截图权限,整个脚本执行一次即可(type 0 自动选择)
let request = image.requestScreenCapture(10000, 0);
if (!request) {
loge("申请截图权限失败");
exit();
}
// 申请完权限至少等 1 秒再截图,否则可能截不到图
sleep(1000);
// 2. 找图:在屏幕上找"开始任务"按钮模板(res 文件夹下的 start.png)
image.initOpenCV();
let template = readResAutoImage("start.png");
// findImageEx 自动截屏找图:弱阈值 0.7,相似度 0.9,只找 1 个
let points = image.findImageEx(template, 0, 0, 0, 0, 0.7, 0.9, 1, 5);
if (points && points.length > 0) {
// 返回 Rect 区域,取中心点点击
let x = parseInt((points[0].left + points[0].right) / 2);
let y = parseInt((points[0].top + points[0].bottom) / 2);
clickPoint(x, y);
} else {
// 3. 找图失败,退而求其次:找红色角标(颜色带偏色容差)
let redPoints = image.findColorEx("0xFF3B30-0x101010", 0.9, 0, 0, 0, 0, 10, 1);
if (redPoints && redPoints.length > 0) {
clickPoint(redPoints[0].x, redPoints[0].y);
} else {
loge("找图、找色都没有命中,等待后重试");
}
}
image.recycle(template);
}
main();
排查速查表:
| 现象 | 常见原因 | 对策 |
|---|---|---|
| 找不到图 | 目标还没出现 / 模板与画面不一致 / 阈值过高 | 等目标出现再识别;换新模板;降低 threshold |
| 找错位置 | 同屏相似元素多 / 阈值过低 | 提高 threshold;缩小搜索区域;改用多点找色 |
| 识别慢 | 全屏查找 / 频繁手动截图 | 限定 x,y,ex,ey;用 Ex 系列自动截屏函数 |
| 长时间运行内存涨 | 图片对象没回收 | 用完立即 image.recycle(img) |
无障碍模式下第一次调用 requestScreenCapture 会弹出系统授权,选总是允许。代理模式截图不用这个权限。长时间没人看着跑,用代理模式(图色函数文档)。权限申请之后至少等大约 1 秒再截图。每次都点同一个像素、间隔固定、顺序固定,批量跑的时候容易被当成机器操作。EasyClick 的点击可以落在一块坐标区域里的随机位置(功能特性文档)。找图返回的就是一块区域(Rect),在这块区域里随机取点再点:
// 在目标区域内随机取点再点击,避免每次点击位置完全一致
let x = parseInt(points[0].left + Math.random() * (points[0].right - points[0].left));
let y = parseInt(points[0].top + Math.random() * (points[0].bottom - points[0].top));
clickPoint(x, y);
这篇讲的所有识别与操作都建立在系统官方能力之上,本身合法合规。风险来自使用用途本身。
图像识别 API 速览表,以下函数均出自图色函数文档,名称与参数请以文档为准:
| 类别 | 函数 | 作用 |
|---|---|---|
| 截图权限 | image.requestScreenCapture(timeout, type) |
申请屏幕截图权限;type:0 自动 / 1 授权 / 2 无需权限(需代理模式) |
| 截图 | image.captureScreen / image.captureFullScreen / image.captureFullScreenEx |
截取屏幕 / 全屏 / 全屏扩展,返回图片对象 |
| 截图 | image.captureScreenshot / image.captureScreenSurface |
代理模式 SurfaceControl 截图(EC 安卓 12.4.0+) |
| 截图 | image.captureToFile |
截图保存为 PNG 文件 |
| 找图 | image.findImage(image, template, …) |
模板匹配找图,返回位置区域 |
| 找图 | image.findImageEx(template, …) |
自动截屏找图 |
| 找图 | image.findImage2(image, template, …) |
含缩放的找图,更精准(EC 9.41.0+) |
| 找图 | image.findImageByColor(image, template, …) |
透明找图,无需初始化 OpenCV |
| 找色 | image.findColor(image, color, threshold, …) |
单点找色,返回坐标数组 |
| 找色 | image.findColorEx(color, …) |
自动截屏单点找色 |
| 找色 | image.findMultiColor(image, firstColor, points, …) |
多点找色 |
| 找色 | image.findMultiColorEx(firstColor, points, …) |
自动截屏多点找色 |
| 比色 | image.cmpColor / image.cmpColorEx |
单点或多点比色,全部符合返回 true |
| 比色 | image.cmpMultiColor / image.cmpMultiColorEx |
多组比色,返回命中组索引(-1 为未找到) |
| 找非色 | image.findNotColor |
查找与指定颜色不相等的点 |
| OpenCV | image.initOpenCV() |
初始化 OpenCV 类库(找图前调用) |
| OpenCV | image.matchTemplate / image.matchTemplateEx |
模板匹配封装(弱/强双阈值) |
| OpenCV | image.useOpencvMat(1) |
切换 mat 存储格式,更快更省内存(EC 10.18.0+) |
| 资源管理 | image.recycle(img) / image.recycleAllImage() |
回收图片,防止内存暴涨 |
Ex 结尾的函数会自己截屏。J 结尾的函数从 JSON 读参数(findColorJ、findMultiColorJ 等,配置文件由开发工具生成)。
| 你的场景 | 推荐手段 | 理由 |
|---|---|---|
| 游戏画面 / 自绘界面(无控件) | 找图 findImageEx + 多点找色 |
模板匹配定位非标准控件 |
| 固定色按钮 / 状态点 | 单点找色 findColorEx |
颜色鲜明,执行最快 |
| 图标角标 / 红点 / 复杂图标 | 多点找色 findMultiColorEx |
组合特征抗干扰 |
| 判断按钮可点 / 不可点 | 比色 cmpColorEx |
一组点全部符合才命中 |
| 血条 / 进度条 | 找色定位颜色边界,按比例估算 | 无需完整模板图 |
| 目标可能被缩放渲染 | findImage2 缩放找图 |
比 findImage 更精准 |
| 需要读取屏幕文字 | OCR 识别(PPOCR-V4/V5/V6 全免费、本地离线) | 文字类内容用 OCR |
| 需要识别对象(怪物、物品、人物) | YOLO 目标检测(ncnn 手机优化,文档) | 神经网络定位非文字对象 |
| 长时间无人值守运行 | 代理模式 + 区域内随机点击 | 代理模式截图无需权限 |
更完整的识别栈(找图找色 / OCR / YOLO 三级)与运行模式选型看安卓自动化技术栈全景。
FAQ
Q1:找图和找色有什么区别,什么时候用哪个? A:找图基于 OpenCV 模板匹配,识别的是“整张图的样子”,适合特征复杂的目标(图片按钮、图标、游戏画面元素);找色识别的是“颜色特征”,适合颜色鲜明、结构简单的目标(纯色按钮、角标红点、血条端点),执行更快。复杂场景常组合使用。
Q2:OpenCV 图像识别率 95%+ 是什么意思? A:95%+ 是官方宣称的识别率,指常规、清晰、静态界面下的表现。实际效果取决于截图清晰度、模板质量、界面变化程度与阈值设置,识别失败可通过降低阈值、限定区域、多图备选、重试来改善。
Q3:找图的相似度阈值怎么调?
A:threshold 是 0~1 的浮点数,默认 0.9。找不到就适当调低(如 0.85、0.8),误识别就调高;weakThreshold(默认 0.7)控制每轮匹配是否继续,一般保持默认即可。
Q4:单点找色和多点找色怎么选? A:单点找色只验证一个点的颜色,遇到大面积同色背景容易误报;多点找色以第一个点颜色为基准,再校验周围若干点的相对位置与颜色,组合特征更唯一、抗干扰更强。图标角标、红点这类场景建议用多点找色。
Q5:图像识别需要 root 吗? A:不需要。截图、识别、点击都基于系统官方能力,在免 root 范围内完成,EasyClick 支持安卓 5.0 及以上的系统。
Q6:找到目标之后怎么点击? A:找图返回位置区域,取中心点或区域内随机点点击;找色返回坐标点数组,取对应 x/y 点击。为降低操作特征,建议点击位置在目标区域内随机化。
Q7:为什么有时候找不到图? A:常见原因:目标还没出现(加载延迟)、模板与实际画面不一致(版本更新、主题变化、缩放)、阈值过高、搜索范围不对。对策:等待目标出现、准备多套模板、降低阈值、限定搜索区域。
Q8:截图需要什么权限?
A:无障碍模式下首次调用 requestScreenCapture 会弹出系统授权,选择“总是允许”;代理模式下截图不需要权限,长时间无人值守运行建议用代理模式。申请权限后需等待约 1 秒再截图。
Q9:找图找色慢怎么办?
A:把搜索范围限定到目标可能出现的小区域,避免全屏查找;用 Ex 系列自动截屏函数减少重复截图;图片用完及时 recycle;找图前先 initOpenCV;需要极致性能时可用 useOpencvMat 切换 mat 存储格式,速度更快、内存占用更少。
Q10:截图图片为什么要回收?
A:截图返回的是内存中的图片对象,不回收会持续占用内存,长时间运行可能内存暴涨。每次用完调用 image.recycle(img) 及时回收即可。
关于 EasyClick:手机自动化脚本开发平台,覆盖安卓免 ROOT、iOS 免越狱、鸿蒙三大手机生态,还提供苹果脚本编写、苹果群控、安卓群控、远程云控、AI 群控手机等。→ 了解全部产品
想要真实跑起来?
本文介绍的方案均可基于 EasyClick 能力在 iEasyClick 落地。官网提供完整文档、开发工具与自动化产品,免费体验。