Skip to content

Merge:'feat/Agent-RedDot'| 专用红点识别器替代模板#294

Merged
sunyink merged 30 commits into
mainfrom
feat/Agent-RedDot
May 30, 2026
Merged

Merge:'feat/Agent-RedDot'| 专用红点识别器替代模板#294
sunyink merged 30 commits into
mainfrom
feat/Agent-RedDot

Conversation

@sunyink
Copy link
Copy Markdown
Owner

@sunyink sunyink commented May 29, 2026

Summary by Sourcery

引入专用的红点通知检测器并共享 HSV 工具,同时扩展用于新 UI 状态的 OCR/颜色匹配流水线节点。

新特性:

  • 添加 RedDotDetector 自定义识别模块,使用 HSV 与形状/拓扑分析检测带有内部感叹号的红色通知小圆点。
  • 暴露通用的 HSV 掩膜与连通域标记工具,以便在多个识别模块之间复用。
  • 扩展 Global 流水线定义,新增用于 OCR 按钮红色状态、奖励文本以及若干礼包/场景 UI 的颜色/OCR/模板节点。

增强:

  • 将 HSV 掩膜计算从 HSVShapeMatching 中重构为模块级辅助函数,以便其他检测器复用。
  • 明确现有 OCR 背景检测的描述,使其涵盖背景和文本两部分。
Original summary in English

Summary by Sourcery

Introduce a dedicated red-dot notification detector and share HSV utilities while expanding OCR/color-match pipeline nodes for new UI states.

New Features:

  • Add a RedDotDetector custom recognition module that detects red notification dots with internal exclamation marks using HSV and shape/topology analysis.
  • Expose shared HSV masking and blob-labelling utilities for use across multiple recognition modules.
  • Extend Global pipeline definitions with new color/OCR/template nodes for OCR button red state, reward text, and several pack/scene UIs.

Enhancements:

  • Refactor HSV mask computation from HSVShapeMatching into module-level helpers to be reused by other detectors.
  • Clarify existing OCR background detection description to include both background and text.

Summary by CodeRabbit

发布说明

  • 新功能

    • 新增红点检测器(RedDotDetector)及预设,支持预设模式与独立模式的可视化调试与识别输出
  • 功能优化

    • 大规模将界面识别从模板/颜色迁移为红点检测,覆盖抽卡、邮件、日常、公会、通行证、报酬等模块
    • 新增并统一红点预设与识别参数,提升识别稳定性与一致性
  • 功能调整

    • 重构多处流程节点判定与路由,调整 OCR/颜色组合判定与若干节点行为与延时配置

Review Change Stack

sunyink added 27 commits May 16, 2026 21:02
初步测试较为优秀。

HIGHLIGHT:红点特征识别,稳健性极高,且高度复用。
1280/1281:隐式Rec=SubName已被废止,声明子识别会被忽略。
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 29, 2026

📝 Walkthrough

Walkthrough

新增模块级 HSV 工具与连通域标注;在 agent/recognition/binarymatch.py 中实现 RedDotDetector 自定义识别器;在多个 pipeline JSON 中将模板/颜色识别替换为 RedDotDetector 或复合识别,并新增预设与全局识别节点。

走查

PR 实现了基于 HSV 的红点检测自定义识别器 RedDotDetector,通过模块级工具函数替换原有的 HSVShapeMatching 类方法,并将游戏全流程的红点识别方式从模板匹配统一迁移到该新识别器,同时大幅重构流程节点的识别条件与控制逻辑,采用复合识别(And/Or)和节点引用模式以降低配置重复性。

变更

红点检测器核心实现

图层 / 文件(s) 摘要
HSV 工具函数与连通域标注
agent/recognition/binarymatch.py
新增 deque 导入;模块级 HSV 映射、多阈值掩膜生成与 4-邻域 BFS 连通域标注函数;示例注释小幅调整。
HSVShapeMatching 重构
agent/recognition/binarymatch.py
HSVShapeMatching 改为调用模块级 _compute_hsv_mask;移除类内 _map_h_compute_hsv_mask 实现。
RedDotDetector 识别器实现
agent/recognition/binarymatch.py
新增 RedDotDetector(独立/预设模式、双段红色 HSV 掩膜、blob 标注与面积筛选、enclosed 过滤、内部亮色提取、逐行投影结构判定、调试可视化与日志)。

预设配置与全局识别节点

图层 / 文件(s) 摘要
全局工具识别节点
assets/resource/base/pipeline/Global.json
更新 Sub_Ocr_Enable_Clr 描述;新增 Sub_Ocr_Red_Clr 与 Rec_Reward_Ocr / Rec_Pack_* 节点。
预设配置节点定义
assets/resource/base/pipeline/Dummy.json, assets/resource/base/pipeline/Test.json
新增 Agt_RedDot_Preset / RedDot_Preset 预设与 CheckPanel_A 示例,定义 hsv_ranges、red_area、inner_v_min/inner_s_max、gap_ratio 与 debug 开关;并移除旧测试节点。

游戏流水线识别迁移(示例)

图层 / 文件(s) 摘要
抽卡 / Gacha 流程
assets/resource/base/pipeline/GACHA.json, assets/resource/base/pipeline/GACHA_ADV.json
多处抽卡页模板匹配替换为 RedDotDetector(含 preset 引用),调整 focus/only_rec,新增/禁用若干节点与 next 路径。
快速狩猎 / Battle 流程
assets/resource/base/pipeline/Battle.json
新增沙箱门控与红点校验;狩猎场、冒险航线、双倍/石洞等节点改为复合/分支识别并拆分细粒度分支;增强复位/replace 规则。
日常 / 公会流程
assets/resource/base/pipeline/Daily.json
Daily_EnterUnion 改用 RedDotDetector 并更新 ROI/post_delay;新增 Daily_UnionReward;Daily_UnionBack 改为 And 复合识别并移除分段回退节点。
邮件 / 任务 / 活动 / 通行证
assets/resource/base/pipeline/Mail.json, assets/resource/base/pipeline/QuestList.json, assets/resource/base/pipeline/Activities.json, assets/resource/base/pipeline/Pass.json
将多个模板/颜色识别替换为 RedDotDetector 或 And 复合识别,调整 ROI、子条件命名(sub_name)与 next 路由,删除/新增相关状态节点。
启动 / 地图 / 其它
assets/resource/base/pipeline/StartGame.json, assets/interface.json, 若干 pipeline
将部分单一 OCR/Template 判定替换为 And/Or 组合或引用新 Rec_* 节点;interface.json 中移除/改写若干选项与控制字段。

评估

🎯 4 (Complex) | ⏱️ ~60 分钟

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题清晰准确地反映了主要变更内容:添加专用红点识别器(RedDotDetector)来替代模板匹配方式,这是整个PR的核心目标。
Docstring Coverage ✅ Passed Docstring coverage is 92.31% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/Agent-RedDot

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 29, 2026

Reviewer's Guide

基于 HSV 颜色 + 拓扑分析,引入独立的 RedDotDetector 自定义识别器,将通用 HSV 工具函数从 HSVShapeMatching 中抽取为模块级辅助方法,并更新 pipeline JSON 定义以支持新的 OCR/场景识别以及红色检测。

RedDotDetector analyze 预设模式 vs 独立流水线的流程图

flowchart TD
    A[analyze] --> B{params contains preset}
    B -- yes --> C[_run_preset]
    C --> D[context.run_recognition preset_node]
    D --> E{detail and detail.hit}
    E -- yes --> F[adjust box with roi offset]
    F --> G[return AnalyzeResult]
    E -- no --> H[return None]

    B -- no --> I[_run_standalone]
    I --> J[read hsv_ranges, red_area, inner_v_min, inner_s_max, gap_ratio]
    J --> K[apply roi to argv.image]
    K --> L[convert work_bgr to HSV]
    L --> M[_compute_hsv_mask]
    M --> N[_label_blobs on red_mask]
    N --> O{for each blob in area range}
    O --> P[compute blob bbox]
    P --> Q[extract box_red, box_hsv]
    Q --> R[_label_blobs on non_red_crop]
    R --> S[compute enclosed & inner_bright]
    S --> T{any inner_bright pixels}
    T -- no --> O
    T -- yes --> U[_has_exclamation]
    U --> V{has exclamation}
    V -- no --> O
    V -- yes --> W[compose result_box with roi offset]
    W --> X[return AnalyzeResult]
    O -->|no more blobs| Y[return None]
Loading

File-Level Changes

Change Details Files
将 HSV 范围处理和连通域标记抽取为共享的模块级工具,并让 HSVShapeMatching 使用这些工具。
  • 添加 _map_h() 辅助函数,用于在处理下界/上界的情况下,将 OpenCV H(0-180)转换为 Pillow H(0-255)。
  • 添加 _compute_hsv_mask(),用于将多个 HSV 范围通过 OR 合并为一个布尔掩码,以便多个识别器复用。
  • 实现 _label_blobs(),基于 BFS 的 4-连通域标记,对前景 blob 使用从 1 开始的标签,对背景使用 0。
  • 将 HSVShapeMatching 中用于 HSV 掩码的实例方法替换为对新模块级辅助函数的调用,并移除原有的按类实现。
agent/recognition/binarymatch.py
添加健壮的 RedDotDetector 自定义识别器,利用 HSV 掩码、blob 分析和垂直投影检测带有感叹号的红色通知小红点,包括基于预设的配置和调试工具。
  • 通过 @AgentServer.custom_recognition 将 RedDotDetector 注册为 CustomRecognition,并实现 analyze(),在预设模式与独立模式之间进行分发,并带有健壮的异常日志记录。
  • 在预设模式下,根据 argv.roi 裁剪输入图像,通过 context.run_recognition 将识别委托给预设节点,并将返回的 box 转换回全局坐标。
  • 在独立模式下,对 HSV 红色范围、blob 面积限制、内部亮度/饱和度阈值和 gap_ratio 进行参数化;基于 roi 裁剪;将 BGR 转换为 HSV;通过 _compute_hsv_mask 计算 red_mask;并通过 _label_blobs 对红色 blob 进行标记。
  • 对于每个候选 blob,计算其边界框,在框内提取 HSV,通过对非红色像素进行连通域标记并过滤边界泄漏来计算封闭的非红区域,然后利用 V 和 S 阈值得到 inner_bright 像素。
  • 实现 _has_exclamation(),通过分析 inner_bright 的垂直投影,裁剪首尾的零值行,寻找最小“gap”行,应用深度比阈值(gap_ratio),并要求形成两段结构(上方至少 2 行非零、下方至少 1 行非零的竖直笔画)。
  • 添加调试辅助方法用于保存中间图像(ROI 裁剪、红色掩码、内部 blob 掩码),在启用 debug 时记录垂直投影和 gap 检查,同时提供基础的 bool-mask 到 BGR 的转换。
  • 当任一 blob 通过所有检测时,返回包含检测到的小红点框和元数据的 AnalyzeResult,否则返回 None。
agent/recognition/binarymatch.py
扩展 pipeline 配置以支持额外的颜色/OCR/模板识别,并明确描述。
  • 优化 Sub_Ocr_Enable_Clr 的描述,以明确其同时检查 OCR 按钮背景和文字亮度。
  • 新增 Sub_Ocr_Red_Clr ColorMatch 节点,通过 HSV 范围和连通区域要求(降低数量上限)检测红色 OCR 按钮背景/文字。
  • 新增 Rec_Reward_Ocr OCR 节点,在固定 ROI 中通过正则匹配预期字符串检测奖励界面底部文字。
  • 新增 Rec_Pack_FantasiaSquare TemplateMatch 节点,通过指定 ROI 内的 Mirror_FantasiaSquare_Ico.png 检测特定静态 UI 图标。
  • 新增 Rec_Pack_GoldenColosseum 和 Rec_Pack_GlupyDiner OCR 节点,使用特定 ROI 和预期中文文本来识别这些场景。
assets/resource/base/pipeline/Global.json

Tips and commands

Interacting with Sourcery

  • 触发新评审: 在 pull request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的评审评论。
  • 从评审评论生成 GitHub issue: 在评审评论下回复,请求 Sourcery 从该评论创建 issue。你也可以在评审评论下回复 @sourcery-ai issue 来创建 issue。
  • 生成 pull request 标题: 在 pull request 标题中任意位置写上 @sourcery-ai 即可随时生成标题。也可以在 pull request 中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成 pull request 摘要: 在 pull request 正文任意位置写上 @sourcery-ai summary,即可在对应位置生成 PR 摘要。也可以在 pull request 中评论 @sourcery-ai summary 来(重新)生成摘要。
  • 生成 reviewer's guide: 在 pull request 中评论 @sourcery-ai guide,即可(重新)生成 reviewer's guide。
  • 解决所有 Sourcery 评论: 在 pull request 中评论 @sourcery-ai resolve 来解决所有 Sourcery 评论。如果你已经处理完所有评论且不想再看到它们,这会非常有用。
  • 撤销所有 Sourcery 评审: 在 pull request 中评论 @sourcery-ai dismiss 来撤销所有现有的 Sourcery 评审。尤其适用于你想从零开始一次新评审的情况——别忘了再评论 @sourcery-ai review 来触发新评审!

Customizing Your Experience

访问你的 dashboard 以:

  • 启用或禁用诸如 Sourcery 生成的 pull request 摘要、reviewer's guide 等评审功能。
  • 修改评审语言。
  • 添加、移除或编辑自定义评审指令。
  • 调整其他评审设置。

Getting Help

Original review guide in English

Reviewer's Guide

Introduces a dedicated RedDotDetector custom recognizer based on HSV color + topology analysis, factors common HSV utilities out of HSVShapeMatching into module‑level helpers, and updates pipeline JSON definitions to support new OCR/scene recognition and red-color checks.

Flow diagram for RedDotDetector analyze preset vs standalone pipeline

flowchart TD
    A[analyze] --> B{params contains preset}
    B -- yes --> C[_run_preset]
    C --> D[context.run_recognition preset_node]
    D --> E{detail and detail.hit}
    E -- yes --> F[adjust box with roi offset]
    F --> G[return AnalyzeResult]
    E -- no --> H[return None]

    B -- no --> I[_run_standalone]
    I --> J[read hsv_ranges, red_area, inner_v_min, inner_s_max, gap_ratio]
    J --> K[apply roi to argv.image]
    K --> L[convert work_bgr to HSV]
    L --> M[_compute_hsv_mask]
    M --> N[_label_blobs on red_mask]
    N --> O{for each blob in area range}
    O --> P[compute blob bbox]
    P --> Q[extract box_red, box_hsv]
    Q --> R[_label_blobs on non_red_crop]
    R --> S[compute enclosed & inner_bright]
    S --> T{any inner_bright pixels}
    T -- no --> O
    T -- yes --> U[_has_exclamation]
    U --> V{has exclamation}
    V -- no --> O
    V -- yes --> W[compose result_box with roi offset]
    W --> X[return AnalyzeResult]
    O -->|no more blobs| Y[return None]
Loading

File-Level Changes

Change Details Files
Factor HSV range handling and connected-component labeling into shared module-level utilities and adapt HSVShapeMatching to use them.
  • Add _map_h() helper to convert OpenCV H (0-180) to Pillow H (0-255) with lower/upper handling.
  • Add _compute_hsv_mask() to OR-merge multiple HSV ranges into a boolean mask reused by multiple recognizers.
  • Implement _label_blobs() BFS-based 4-connected component labeling with 1-based labels for blobs and 0 for background.
  • Replace HSVShapeMatching’s instance methods for HSV masking with calls to the new module-level helpers and remove the old per-class implementations.
agent/recognition/binarymatch.py
Add a robust RedDotDetector custom recognizer that detects red notification dots with embedded exclamation marks using HSV masking, blob analysis, and vertical projection, including preset-based configuration and debugging utilities.
  • Register RedDotDetector as a CustomRecognition with @AgentServer.custom_recognition and implement analyze() to dispatch between preset and standalone modes with robust exception logging.
  • In preset mode, crop the input image by argv.roi, delegate recognition to a preset node via context.run_recognition, and translate the returned box back to global coordinates.
  • In standalone mode, parameterize HSV red ranges, blob area limits, inner brightness/saturation thresholds, and gap_ratio; crop by roi; convert BGR to HSV; compute red_mask via _compute_hsv_mask; and label red blobs via _label_blobs.
  • For each candidate blob, compute its bounding box, extract HSV within the box, compute enclosed non-red regions via connected-component labeling of non-red pixels with border-leak filtering, and then derive inner_bright pixels using V and S thresholds.
  • Implement _has_exclamation() to analyze the vertical projection of inner_bright, trimming leading/trailing zeros, finding a minimal “gap” row, enforcing a depth ratio threshold (gap_ratio), and requiring a two-part structure (vertical stroke with ≥2 non-zero rows above and ≥1 non-zero row below).
  • Add debugging helpers to save intermediate images (ROI crop, red mask, inner blob masks) and log vertical projection and gap checks when debug is enabled, along with basic bool-mask-to-BGR conversion.
  • Return AnalyzeResult with the detected red dot box and metadata when any blob passes all tests, otherwise None.
agent/recognition/binarymatch.py
Extend pipeline configuration to support additional color/OCR/template recognitions and clarify descriptions.
  • Refine Sub_Ocr_Enable_Clr description to clarify it checks both OCR button background and text brightness.
  • Add Sub_Ocr_Red_Clr ColorMatch node to detect red OCR button background/text using an HSV range and connected-region requirement with a reduced count limit.
  • Add Rec_Reward_Ocr OCR node to detect reward screen bottom text via regex-matched expected string in a fixed ROI.
  • Add Rec_Pack_FantasiaSquare TemplateMatch node for detecting a specific static UI icon via Mirror_FantasiaSquare_Ico.png in a given ROI.
  • Add Rec_Pack_GoldenColosseum and Rec_Pack_GlupyDiner OCR nodes with specific ROIs and expected Chinese text to recognize those scenes.
assets/resource/base/pipeline/Global.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了两个问题,并给出了一些整体反馈:

  • _label_blobs 中使用了 deque,但在当前 diff 中没有看到相应的导入;请确认在模块级别添加 from collections import deque(或等效导入),以避免运行时出现 NameError。
  • RedDotDetector._run_preset_run_standalone 中,你使用了裸 print 来输出命中日志;为了与模块其他部分保持一致并更好地控制日志输出,建议改用 mfaalog.debug/info 等日志函数。
给 AI Agent 的提示
Please address the comments from this code review:

## Overall Comments
- In `_label_blobs` you use `deque` but there is no corresponding import in the shown diff; ensure `from collections import deque` (or equivalent) is present at module level to avoid a runtime NameError.
- In `RedDotDetector._run_preset` and `_run_standalone` you use bare `print` for hit logs; for consistency with the rest of the module and better log control, consider replacing these with `mfaalog.debug/info` calls.

## Individual Comments

### Comment 1
<location path="agent/recognition/binarymatch.py" line_range="620-622" />
<code_context>
+            print(f"[RedDotDetector] [preset:{preset_node}] 命中 → {adjusted}")
</code_context>
<issue_to_address>
**suggestion:** 避免使用裸 `print` 进行日志输出,请改用已有的日志设施。

使用 `print` 会创建一个未配置的日志通道,绕过我们的日志配置,并可能在生产环境中过度输出到 stdout。请通过 `mfaalog`(例如 `mfaalog.info`/`debug`)来记录日志,以保持一致性并实现集中控制。

```suggestion
            adjusted = (bx + rx, by + ry, bw, bh)
            mfaalog.debug(f"[RedDotDetector] [preset:{preset_node}] 命中 → {adjusted}")
            return CustomRecognition.AnalyzeResult(box=adjusted, detail={"preset": preset_node})
```
</issue_to_address>

### Comment 2
<location path="agent/recognition/binarymatch.py" line_range="606-611" />
<code_context>
+        """
+        preset_node = params["preset"]
+        roi = argv.roi
+        if roi is not None:
+            rx, ry, rw, rh = roi.x, roi.y, roi.w, roi.h
+        else:
+            rx = ry = rw = rh = 0
+
+        if rw > 0 and rh > 0:
+            cropped = argv.image[ry:ry + rh, rx:rx + rw]
+        else:
</code_context>
<issue_to_address>
**issue:** 建议将 ROI 坐标限制在图像边界内,以避免出现负数或越界索引。

由于 `_run_preset``_run_standalone` 使用 `ry:ry+rh` / `rx:rx+rw``argv.image` 进行切片,如果从 JSON 中加载的 ROI 含有负值或超出尺寸的数值,将会依赖 NumPy 的索引环绕/截断行为,这可能导致隐蔽的误检测。将 `rx, ry, rw, rh` 约束在 `[0, w/h]` 范围后再进行切片(并在裁剪结果为空时及早返回)会让这种行为更加明确且更安全。
</issue_to_address>

Sourcery 对开源项目免费——如果你觉得我们的 Review 有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据这些反馈改进之后的 Review。
Original comment in English

Hey - I've found 2 issues, and left some high level feedback:

  • In _label_blobs you use deque but there is no corresponding import in the shown diff; ensure from collections import deque (or equivalent) is present at module level to avoid a runtime NameError.
  • In RedDotDetector._run_preset and _run_standalone you use bare print for hit logs; for consistency with the rest of the module and better log control, consider replacing these with mfaalog.debug/info calls.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `_label_blobs` you use `deque` but there is no corresponding import in the shown diff; ensure `from collections import deque` (or equivalent) is present at module level to avoid a runtime NameError.
- In `RedDotDetector._run_preset` and `_run_standalone` you use bare `print` for hit logs; for consistency with the rest of the module and better log control, consider replacing these with `mfaalog.debug/info` calls.

## Individual Comments

### Comment 1
<location path="agent/recognition/binarymatch.py" line_range="620-622" />
<code_context>
+            print(f"[RedDotDetector] [preset:{preset_node}] 命中 → {adjusted}")
</code_context>
<issue_to_address>
**suggestion:** Avoid using bare `print` for logging and use the existing logging facility instead.

Using `print` creates an unconfigured logging path that bypasses our logging setup and can spam stdout in production. Please route this through `mfaalog` (e.g. `mfaalog.info`/`debug`) for consistency and centralized control.

```suggestion
            adjusted = (bx + rx, by + ry, bw, bh)
            mfaalog.debug(f"[RedDotDetector] [preset:{preset_node}] 命中 → {adjusted}")
            return CustomRecognition.AnalyzeResult(box=adjusted, detail={"preset": preset_node})
```
</issue_to_address>

### Comment 2
<location path="agent/recognition/binarymatch.py" line_range="606-611" />
<code_context>
+        """
+        preset_node = params["preset"]
+        roi = argv.roi
+        if roi is not None:
+            rx, ry, rw, rh = roi.x, roi.y, roi.w, roi.h
+        else:
+            rx = ry = rw = rh = 0
+
+        if rw > 0 and rh > 0:
+            cropped = argv.image[ry:ry + rh, rx:rx + rw]
+        else:
</code_context>
<issue_to_address>
**issue:** Consider clamping ROI coordinates to image bounds to avoid negative or out-of-range indexing.

Since `_run_preset` and `_run_standalone` slice `argv.image` with `ry:ry+rh` / `rx:rx+rw`, an ROI loaded from JSON with negative or oversized values will rely on NumPy’s index wrapping/truncation, which can cause subtle mis-detections. Clamping `rx, ry, rw, rh` to `[0, w/h]` before slicing (and early-returning if the clamped crop is empty) would make this behavior explicit and safer.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread agent/recognition/binarymatch.py
Comment thread agent/recognition/binarymatch.py
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (4)
assets/resource/base/pipeline/Global.json (1)

727-744: 💤 Low value

红色色相仅覆盖单段 0–10,可能漏检环绕段红色。

HSV 色相空间中红色横跨 0 与 180 两端。本节点 lower:[0,150,230] / upper:[10,255,255] 只覆盖低色相段,而同 PR 的 RedDot_Preset 红色阈值是 0–12 与 165–180 双段。若目标红色文字/背景偏向高色相段,会被漏检。如确认目标红仅落在 0–10,可忽略;否则建议补一段高色相判定(ColorMatch 单节点无法同时覆盖两段,可拆为 Or 复合两段色核)。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/resource/base/pipeline/Global.json` around lines 727 - 744, The
Sub_Ocr_Red_Clr ColorMatch node only covers red hue 0–10 and may miss red hues
near 165–180; update the pipeline so red is matched in both hue ranges by either
splitting Sub_Ocr_Red_Clr into two ColorMatch nodes (one for 0–10 and one for
165–180) and combine them with an Or node, or mirror the approach used by
RedDot_Preset (dual-range thresholds); ensure the new nodes keep the same roi
"OCR", method, connected/count settings and that the combined result replaces
the original Sub_Ocr_Red_Clr output.
assets/resource/base/pipeline/Daily.json (1)

113-141: ⚡ Quick win

建议澄清/清理 Daily_UnionBacktarget(不要直接补 Click

Daily_UnionBack 未配置 action,默认按 DoNothing 执行,因此 target: [120, 35] 不会触发点击;其返回主页实际依赖 next 跳转到 Global_ToHomePage_Enter/Global_ToHomePage,而 Global.jsonGlobal_ToHomePage_HomeButtonGlobal_ToHomePage_Reset 才包含 action: "Click" 来完成返回。建议删除该无用 target(或补注释说明由 Global 承担),避免误加 action: "Click" 导致重复/误触。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/resource/base/pipeline/Daily.json` around lines 113 - 141, The
Daily_UnionBack node declares a target ([120,35]) but has no action so it
defaults to DoNothing and that target is misleading; either remove the target
entry or add a comment clarifying that navigation is handled by next ->
Global_ToHomePage_Enter/Global_ToHomePage and that the actual Click actions live
in Global_ToHomePage_HomeButton and Global_ToHomePage_Reset; do not add
action:"Click" here (would duplicate/trigger unintended clicks).
agent/recognition/binarymatch.py (2)

621-621: ⚡ Quick win

命中日志建议统一走 mfaalog,而非 print

本文件其余位置(含异常、调试图保存)均使用 mfaalog,而预设模式(Line 621)与独立模式(Line 716)的“命中”成功日志却用了 printprint 会绕过项目日志系统,导致这些关键命中信息不进日志文件、难以事后排查。

♻️ 统一日志
-            print(f"[RedDotDetector] [preset:{preset_node}] 命中 → {adjusted}")
+            mfaalog.info(f"[RedDotDetector] [preset:{preset_node}] 命中 → {adjusted}")
-            print(f"[RedDotDetector] 命中: box={result_box}, red_area={area}")
+            mfaalog.info(f"[RedDotDetector] 命中: box={result_box}, red_area={area}")

Also applies to: 716-716

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent/recognition/binarymatch.py` at line 621, Replace the direct print calls
that log hits with the project logger: change the print in the RedDotDetector
hit path (the statement printing f"[RedDotDetector] [preset:{preset_node}] 命中 →
{adjusted}") and the similar print in the independent mode branch to use mfaalog
(e.g. mfaalog.info) with the same message/variables so the hit messages go
through the standard logging pipeline and retain consistent formatting and
levels; keep the message text unchanged and reuse existing mfaalog import/usages
in this module for consistency.

617-622: 调整:detail.box 的解包大概率是可行的,不应按“重大静默失效”处理

公开的 MaaFramework Python 绑定里 Rect 表示 [x, y, w, h],并且仓库内也已有对 box[0]box[2] 这类下标访问的实际用法(如 agent/fishing_agent.py),因此把 bx, by, bw, bh = detail.box 直接认定为 Rect 不可解包从而导致预设模式“恒返回 None”的判断依据不足。可保留当前写法;仅建议为一致性把红点检测处的 box 访问风格与 roi.x/roi.y/roi.w/roi.h(或其它 box 用法)统一。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent/recognition/binarymatch.py` around lines 617 - 622, The current change
treats unpacking detail.box as unsafe and causes presets to always return None;
instead keep treating detail.box as a Rect and make the access style consistent
with the rest of the code: in the RedDotDetector matching block (where detail =
context.run_recognition(preset_node, cropped) and you currently use bx, by, bw,
bh = detail.box and return CustomRecognition.AnalyzeResult), either retain the
tuple unpacking or switch to explicit index access (detail.box[0],
detail.box[1], detail.box[2], detail.box[3]) so it matches other usages like
roi.x/roi.y/roi.w/roi.h and agent/fishing_agent.py; ensure the adjusted box is
constructed the same way (e.g., (bx + rx, by + ry, bw, bh)) and return the
AnalyzeResult as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@agent/recognition/binarymatch.py`:
- Around line 339-343: The comment's documented default for red_area is
inconsistent with the actual default used in _run_standalone; update the comment
to match the code by changing the red_area default from [50, 1200] to [30,
1200], and optionally mention that _run_standalone reads params.get("red_area",
[30, 1200]) so callers not passing red_area will get 30 as the min; keep
references to hsv_ranges and red_area in the same comment block so readers see
both parameter purposes and the corrected default.

In `@assets/interface.json`:
- Around line 411-436: The "风" and "光" entries have an incorrect nested
pipeline_override: they wrap QuickHunt_StoneSelect_* entries inside
QuickHunt_FastBattleTouch_StoneSelect, which treats them as fields rather than
node overrides; remove the QuickHunt_FastBattleTouch_StoneSelect wrapper so
pipeline_override is a flat mapping keyed directly by node names
(QuickHunt_StoneSelect_Fire, QuickHunt_StoneSelect_Wind for 风 and
QuickHunt_StoneSelect_Fire, QuickHunt_StoneSelect_Light for 光) and set the
correct enabled values (Fire: false, Wind/Light: true) to match the working
pattern used by the "水" and "暗" entries.

In `@assets/resource/base/pipeline/Battle.json`:
- Around line 792-808: The QuickHunt_StoneSelect_Wind node is missing the
"action":"Click" field so it never triggers a click like its siblings
QuickHunt_StoneSelect_Fire/Water/Light/Duck; update the
QuickHunt_StoneSelect_Wind JSON object to include "action": "Click" (placed
after "expected") so that when "风之洞穴" is recognized the automation performs the
click and proceeds, preserving the same behavior described by the node's desc
("圣石选属性.Loc分离").
- Around line 1069-1078: The replace mapping in
QuickHunt_CollectMap_Initialize_Out_Ty2 currently contains a no-op entry
["跡","跡"] which prevents OCR normalization to simplified Chinese; update the
second tuple in the "replace" array for the handler
QuickHunt_CollectMap_Initialize_Out_Ty2 to map "跡" to "迹" (i.e., ["跡","迹"]) so
OCR outputs like "哥布林遺跡" are normalized to "哥布林遗迹" and downstream
match/next/all_of checks (e.g., QuickHunt_CollectMap_Initialize_Out_Ty1,
QuickHunt_CollectMapAdventureRouteDoubleCk2No_ToCentral_CK,
QuickHunt_CrystalCave_End, QuickHunt_CollectMap_SwipLeft,
QuickHunt_CollectMap_SwipNoth) will work correctly.

In `@assets/resource/base/pipeline/Global.json`:
- Around line 877-889: The regex in the Rec_Reward_Ocr entry uses character
classes like [点击画面] which match individual characters rather than the full
phrases; replace those with phrase lookaheads so OCR must contain the full
substrings—for example change the "expected" value to use
(?=.*点击画面)(?=.*即可)(?=.*返回).{4,12}$ (ensure any JSON escaping needed for
backslashes is applied in the file) so the key "Rec_Reward_Ocr" and its
"expected" field require the whole phrases instead of single characters.

---

Nitpick comments:
In `@agent/recognition/binarymatch.py`:
- Line 621: Replace the direct print calls that log hits with the project
logger: change the print in the RedDotDetector hit path (the statement printing
f"[RedDotDetector] [preset:{preset_node}] 命中 → {adjusted}") and the similar
print in the independent mode branch to use mfaalog (e.g. mfaalog.info) with the
same message/variables so the hit messages go through the standard logging
pipeline and retain consistent formatting and levels; keep the message text
unchanged and reuse existing mfaalog import/usages in this module for
consistency.
- Around line 617-622: The current change treats unpacking detail.box as unsafe
and causes presets to always return None; instead keep treating detail.box as a
Rect and make the access style consistent with the rest of the code: in the
RedDotDetector matching block (where detail =
context.run_recognition(preset_node, cropped) and you currently use bx, by, bw,
bh = detail.box and return CustomRecognition.AnalyzeResult), either retain the
tuple unpacking or switch to explicit index access (detail.box[0],
detail.box[1], detail.box[2], detail.box[3]) so it matches other usages like
roi.x/roi.y/roi.w/roi.h and agent/fishing_agent.py; ensure the adjusted box is
constructed the same way (e.g., (bx + rx, by + ry, bw, bh)) and return the
AnalyzeResult as before.

In `@assets/resource/base/pipeline/Daily.json`:
- Around line 113-141: The Daily_UnionBack node declares a target ([120,35]) but
has no action so it defaults to DoNothing and that target is misleading; either
remove the target entry or add a comment clarifying that navigation is handled
by next -> Global_ToHomePage_Enter/Global_ToHomePage and that the actual Click
actions live in Global_ToHomePage_HomeButton and Global_ToHomePage_Reset; do not
add action:"Click" here (would duplicate/trigger unintended clicks).

In `@assets/resource/base/pipeline/Global.json`:
- Around line 727-744: The Sub_Ocr_Red_Clr ColorMatch node only covers red hue
0–10 and may miss red hues near 165–180; update the pipeline so red is matched
in both hue ranges by either splitting Sub_Ocr_Red_Clr into two ColorMatch nodes
(one for 0–10 and one for 165–180) and combine them with an Or node, or mirror
the approach used by RedDot_Preset (dual-range thresholds); ensure the new nodes
keep the same roi "OCR", method, connected/count settings and that the combined
result replaces the original Sub_Ocr_Red_Clr output.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8eb0b41e-3329-4bb3-8a5f-d384fafbd0bb

📥 Commits

Reviewing files that changed from the base of the PR and between e71745a and d9aff50.

⛔ Files ignored due to path filters (18)
  • .gitignore is excluded by none and included by none
  • assets/resource/PC/model/.gitignore is excluded by none and included by none
  • assets/resource/base/image/ActiveGe.png is excluded by !**/*.png, !**/*.png and included by none
  • assets/resource/base/image/ActivePeerGe.png is excluded by !**/*.png, !**/*.png and included by none
  • assets/resource/base/image/FreeGacha.png is excluded by !**/*.png, !**/*.png and included by none
  • assets/resource/base/image/GACHA_Free.ReservedRights_Red_GE.png is excluded by !**/*.png, !**/*.png and included by none
  • assets/resource/base/image/GACHA_ListFull2_GE.png is excluded by !**/*.png, !**/*.png and included by none
  • assets/resource/base/image/GACHA_ListFull3.png is excluded by !**/*.png, !**/*.png and included by none
  • assets/resource/base/image/GACHA_ListFull_GE.png is excluded by !**/*.png, !**/*.png and included by none
  • assets/resource/base/image/GACHA_PoolSort.png is excluded by !**/*.png, !**/*.png and included by none
  • assets/resource/base/image/GACHA_Special.ReservedRights_Red_GE.png is excluded by !**/*.png, !**/*.png and included by none
  • assets/resource/base/image/GaChaEquRDGE.png is excluded by !**/*.png, !**/*.png and included by none
  • assets/resource/base/image/Gacha-homepage.png is excluded by !**/*.png, !**/*.png and included by none
  • assets/resource/base/image/MailAtMainRedGe.png is excluded by !**/*.png, !**/*.png and included by none
  • assets/resource/base/image/MailRedPr.png is excluded by !**/*.png, !**/*.png and included by none
  • assets/resource/base/image/MissionsGE.png is excluded by !**/*.png, !**/*.png and included by none
  • assets/resource/base/image/Pass.png is excluded by !**/*.png, !**/*.png and included by none
  • assets/resource/base/image/pass1.png is excluded by !**/*.png, !**/*.png and included by none
📒 Files selected for processing (14)
  • agent/recognition/binarymatch.py
  • assets/interface.json
  • assets/resource/base/pipeline/Activities.json
  • assets/resource/base/pipeline/Battle.json
  • assets/resource/base/pipeline/Daily.json
  • assets/resource/base/pipeline/Dummy.json
  • assets/resource/base/pipeline/GACHA.json
  • assets/resource/base/pipeline/GACHA_ADV.json
  • assets/resource/base/pipeline/Global.json
  • assets/resource/base/pipeline/Mail.json
  • assets/resource/base/pipeline/Pass.json
  • assets/resource/base/pipeline/QuestList.json
  • assets/resource/base/pipeline/StartGame.json
  • assets/resource/base/pipeline/Test.json

Comment thread agent/recognition/binarymatch.py
Comment thread assets/interface.json
Comment thread assets/resource/base/pipeline/Battle.json
Comment thread assets/resource/base/pipeline/Battle.json
Comment thread assets/resource/base/pipeline/Global.json
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
agent/recognition/binarymatch.py (2)

566-623: 💤 Low value

建议统一使用 mfaalog 替代 print()

Line 621 使用 print() 输出命中信息,与文件其他位置使用 mfaalog.info() / mfaalog.debug() 风格不一致。生产环境下 print() 输出可能不会被日志系统捕获。

♻️ 建议修改
-            print(f"[RedDotDetector] [preset:{preset_node}] 命中 → {adjusted}")
+            mfaalog.info(f"[RedDotDetector] [preset:{preset_node}] 命中 → {adjusted}")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent/recognition/binarymatch.py` around lines 566 - 623, The preset branch
in RedDotDetector._run_preset currently logs hits via print(f"[RedDotDetector]
[preset:{preset_node}] 命中 → {adjusted}") which is inconsistent with the module
logging; replace that print call with an mfaalog logging call (e.g.,
mfaalog.info or mfaalog.debug) and include the same message and variables
(preset_node and adjusted) so hits are captured by the logging system.

629-722: 💤 Low value

同上,建议统一日志输出方式

Line 716 同样使用 print() 而非 mfaalog

♻️ 建议修改
-            print(f"[RedDotDetector] 命中: box={result_box}, red_area={area}")
+            mfaalog.info(f"[RedDotDetector] 命中: box={result_box}, red_area={area}")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent/recognition/binarymatch.py` around lines 629 - 722, The final hit
logging in _run_standalone uses print(...) instead of the project's logger;
replace the print call inside _run_standalone that outputs "[RedDotDetector] 命中:
box=..." with a mfaalog logging call (e.g., mfaalog.info or mfaalog.debug to
match surrounding messages) and include the same context (result_box and red
area) in the formatted log string so it follows the same logging conventions as
the other messages in this function.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@agent/recognition/binarymatch.py`:
- Around line 566-623: The preset branch in RedDotDetector._run_preset currently
logs hits via print(f"[RedDotDetector] [preset:{preset_node}] 命中 → {adjusted}")
which is inconsistent with the module logging; replace that print call with an
mfaalog logging call (e.g., mfaalog.info or mfaalog.debug) and include the same
message and variables (preset_node and adjusted) so hits are captured by the
logging system.
- Around line 629-722: The final hit logging in _run_standalone uses print(...)
instead of the project's logger; replace the print call inside _run_standalone
that outputs "[RedDotDetector] 命中: box=..." with a mfaalog logging call (e.g.,
mfaalog.info or mfaalog.debug to match surrounding messages) and include the
same context (result_box and red area) in the formatted log string so it follows
the same logging conventions as the other messages in this function.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d7663e83-3263-4a4f-b22d-9c73e1b38b8a

📥 Commits

Reviewing files that changed from the base of the PR and between 87fbda4 and 1a9fb0f.

📒 Files selected for processing (1)
  • agent/recognition/binarymatch.py

@sunyink sunyink merged commit d0b481d into main May 30, 2026
21 checks passed
@sunyink sunyink deleted the feat/Agent-RedDot branch May 30, 2026 07:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant