MaaEnd IconRecognition:基于C++与ONNX的物品图标识别实现原理
【免费下载链接】MaaEndMaaEnd 终末地小助手:基于视觉 AI 的「明日方舟:终末地」自动化工具项目地址: https://gitcode.com/gh_mirrors/maa/MaaEnd
MaaEnd 是一款基于视觉 AI 的《明日方舟:终末地》自动化工具,其中IconRecognition 物品图标识别组件负责在游戏中"看懂"背包、仓库、交易台等界面上的每一个物品:给定一块屏幕区域,它就能返回物品 ID、格子和置信度分数。本文带你拆解这个 C++ 核心模块的四步识别流水线、它如何与 ONNX 模型分工协作,以及从哪些文件开始阅读源码最合适。
IconRecognition 是什么:只做"认物品"一件事
IconRecognition是 MaaEnd 的 C++ Custom Recognition 组件,对外只暴露一个recognizeAPI。调用方做两件事:
- 告诉它当前是什么界面(
grid_type,如transfer背包/仓库、trade交易台、rewards奖励卡片等); - 给它一块 Maa ROI(1280x720 基准下的
[x, y, w, h]区域)。
它则返回每个命中格子的物品 ID、坐标和匹配分数。需要强调的是:它只负责定位与分类,不负责进入界面、点击物品或流程跳转——那些由 Pipeline 或业务 Service 控制。这种"识别与操作解耦"是整个 MaaEnd 自动化的架构前提,也让识别组件可以独立测试、独立迭代。
组件入口在 agent/cpp-algo/source/IconRecognition/,模块说明见 README.md。运行时它只读取三份公开资源:
- 物品目录:recognition_items.json,近 9000 行,记录每个
item_id的名称、分类、稀有度和图标资源; - 图标资源:
assets/resource/image/IconRecognition/<rarity>/*.png,按稀有度分组的物品图标; - 多语言文案:
assets/locales/interface/*.json。
识别流水线四步:找格子 → 校颜色 → 配图标 → 滤结果
抛开实现细节,IconRecognition只做四件事(详见 识别算法文档):
| 步骤 | 做什么 | 核心类 |
|---|---|---|
| 1. 格子定位 | 在 ROI 内找出全部物品格子 | GridDetector、GridProfiles、RegularLattice |
| 2. 颜色条校正 | 用稀有度颜色条修正格子相位 | RarityClassifier、TrustedRarity |
| 3. 图标匹配 | 逐格与候选模板做结构+颜色匹配 | CandidateSelector、IconMatcher、SubpixelMatcher |
| 4. 结果过滤 | 按阈值、纹理、排序去重后返回 | ForegroundTexture、ItemMatchLess |
第一步:如何在屏幕上找到物品网格
游戏界面里的物品是一格格排好的,但分辨率、缩放、界面元素都会变化,所以不能硬编码坐标。GridDetector的做法是:
- 结构候选:从格框边缘和明暗差中找出可能的网格区域(
GridFeatures、GridGeometry、GridAnchors协作); - 颜色条证据:背包类界面格子底部有一条代表稀有度的窄色条,只有同时满足宽度、厚度、连续性、背景对比和双边缘约束的窄条,才被视为可靠的位置证据(RarityClassifier.cpp);
- 规则网格拟合:把离散的横纵观测拟合成一套统一的"起点+间距"规则网格(RegularLattice.cpp),再由同一套浮点网格一次性投影出所有格子坐标,避免逐格累加把取整误差传播下去;
- 双路对比:颜色条候选与结构候选互相验证,证据不足时保留保守的结构候选回退路径。
此外,组件内置 Win32 与 ADB 两套 1280x720 控制器的网格 profile(见 grid-profiles.md):ADB 放大画面会先临时归一化到标准 720p 逻辑密度再运行同一套算法,最后把坐标映射回原图——调用方无需关心设备差异。
第二步:稀有度颜色条的"先验"价值
识别背包物品时,稀有度颜色条不只是装饰。在逐格匹配前,RarityCandidates会先用颜色条把候选模板缩小到同稀有度集合:首轮只比对同稀有度模板,没达标再扩大到全候选。候选集小了,匹配就更快、更稳——这是典型的"用廉价先验换昂贵计算"的工程取舍。
第三步:模板匹配 + Lab 颜色空间 + 亚像素细化
每个格子的图标匹配发生在输入原图上(IconMatcher.cpp),模板直接从 128px 原始图标资源缩放到当前格子尺寸,同时考虑两路信号:
- 结构相似:OpenCV 模板匹配得分;
- 颜色相似:在 Lab 色彩空间中比较亮度与颜色分量——Lab 把"明暗"和"颜色"拆开,比直接比 RGB 更能抵抗光照和背景差异。
两路分数合并后,若分数"值得再看但还没达标",SubpixelMatcher会在像素级再搜索更细的位置偏移(SubpixelMatcher.h)。还有两个很有工程味的细节:
- 低纹理拒绝:
ForegroundTexture会拒绝几乎空白、纹理方差不足的格子,防止把空格或纯色块硬认成某物品; - 遮挡恢复:当最高候选的残差集中在格子上下边缘时,
EdgeOcclusion判定图标被工具栏等元素遮挡,把实测遮挡带从匹配遮罩中清零后重新排名,且只有恢复结果保持原最高候选不变、达到阈值时才采纳。
第四步:阈值、排序与去重
只有最终分数达到请求阈值(默认 0.85)、且未被低纹理检查拒绝的结果才进入公开matches。结果先按分数降序,同分再按格子 y、x 和物品 ID 比较(ItemMatchLess);开启去重后每个item_id只保留得分最高的格子。值得注意的是:"识别完成但没有命中"对外返回no_match,是正常结果而非异常;只有网格定位完全失败才返回exception。请求与结果的完整类型定义见 IconRecognitionTypes.h。
ONNX 与模板匹配:MaaEnd 的"双引擎"分工
一个常见的疑问:MaaEnd 是"视觉 AI"工具,为什么 IconRecognition 不用神经网络?
答案在于分工。MaaEnd 的 ONNX 推理集中在 MapLocator 模块:YoloPredictor.h 和 CameraOrientationPredictor.h 引入onnxruntime_cxx_api.h,运行时加载cls.onnx、preprocess.onnx、polar_with_ref.onnx等模型(见 MapLocateAction.cpp),由 CMakeLists.txt 统一链接ONNXRuntime,用神经网络解决开放场景的地图定位这类"没有固定答案"的问题。
而 IconRecognition 面对的是闭集识别:物品图标是已知、可枚举的(目录里有多少物品就有多少模板),所以它选择了确定性视觉算法——模板匹配 + 颜色空间比较 + 几何拟合。这套方案的优势很直接:
- 无需训练数据:新物品只要把图标和资源目录同步进来就能识别;
- 分数可复现:同一张截图每次匹配结果一致,便于回归测试;
- 界面适配可控:每个
grid_type都有明确的 profile 和遮罩策略,行为边界清晰。
一句话总结:神经网络负责开放世界的"看懂",确定性算法负责已知物品集的"认准",两者通过同一个 C++ 算法核心协作,构成 MaaEnd 的视觉 AI 底座。
配套工具链与推荐阅读路径
图标识别能稳定工作,离不开一条"数据先行"的资源流水线:tools/icon_recognition/ 下的download.py、catalog.py、publish.py负责图标素材的下载、目录生成与发布校验,item_transfer/则处理同图标组物品的映射生成,确保recognition_items.json与游戏素材保持同步。
如果你想继续深入,建议按这条路径阅读:
- 外部契约(参数、参考 ROI、返回值):IconRecognition 开发者使用指南
- 模块职责与数据流:内部架构文档
- 算法细节(网格定位、匹配、遮挡恢复):识别算法文档
- 网格 profile 维护:网格配置维护
- 测试与人工审核图:测试文档,测试代码位于 test/
- 编排入口:IconRecognizer.cpp,MaaFramework 适配层见 IconRecognitionRecognition.cpp
从"一个格子如何被认出来"到"整个目录如何被维护",IconRecognition 展示了视觉自动化工具最务实的一面:不追求炫技的模型,而是把几何先验、颜色空间和确定性匹配用到极致。理解了这个模块,你就掌握了 MaaEnd 大部分业务任务(自动囤货、背包收纳、交易识别)背后共同的识别基础。
【免费下载链接】MaaEndMaaEnd 终末地小助手:基于视觉 AI 的「明日方舟:终末地」自动化工具项目地址: https://gitcode.com/gh_mirrors/maa/MaaEnd
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考