Skip to content

Commit 8410eab

Browse files
authored
Merge pull request #394 from Integration-Automation/feat/color-match-batch
Add color_match: colour-aware (HSV) template matching
2 parents 5b4eb97 + 612c4eb commit 8410eab

15 files changed

Lines changed: 392 additions & 0 deletions

File tree

README/WHATS_NEW_zh-CN.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# 本次更新 — AutoControl
22

3+
## 本次更新 (2026-06-24) — 色彩感知模板匹配(HSV)
4+
5+
区分形状相同的红色与绿色状态点。完整参考:[`docs/source/Zh/doc/new_features/v179_features_doc.rst`](../docs/source/Zh/doc/new_features/v179_features_doc.rst)
6+
7+
- **`match_color` / `match_color_all`**(`AC_match_color``AC_match_color_all`):`visual_match` 每个匹配器都先转灰阶,故形状相同的红 vs 绿无法区分;`color_region` 找已知颜色的 blob 却无法对多色字形做模板匹配。本功能在 HSV 色相/饱和度上以色彩*距离*度量(`TM_SQDIFF_NORMED`——相关会把绝对色相正规化掉,使红→绿边与黑→蓝边同分)。重用 `color_region` 的 RGB 加载器 + `visual_match` 的 resize/NMS/`Match``channels` 默认 `("h","s")`(平坦饱和度目标用 `("h",)`);纯色 blob 请用 `find_color_region`。不导入 `PySide6`
8+
39
## 本次更新 (2026-06-24) — 多模板共识匹配
410

511
把同一目标的多个参考裁切投票成单一可信位置。完整参考:[`docs/source/Zh/doc/new_features/v178_features_doc.rst`](../docs/source/Zh/doc/new_features/v178_features_doc.rst)

README/WHATS_NEW_zh-TW.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# 本次更新 — AutoControl
22

3+
## 本次更新 (2026-06-24) — 色彩感知樣板比對(HSV)
4+
5+
區分形狀相同的紅色與綠色狀態點。完整參考:[`docs/source/Zh/doc/new_features/v179_features_doc.rst`](../docs/source/Zh/doc/new_features/v179_features_doc.rst)
6+
7+
- **`match_color` / `match_color_all`**(`AC_match_color``AC_match_color_all`):`visual_match` 每個比對器都先轉灰階,故形狀相同的紅 vs 綠無法區分;`color_region` 找已知顏色的 blob 卻無法對多色字形做樣板比對。本功能在 HSV 色相/飽和度上以色彩*距離*度量(`TM_SQDIFF_NORMED`——相關會把絕對色相正規化掉,使紅→綠邊與黑→藍邊同分)。重用 `color_region` 的 RGB 載入器 + `visual_match` 的 resize/NMS/`Match``channels` 預設 `("h","s")`(平坦飽和度目標用 `("h",)`);純色 blob 請用 `find_color_region`。不匯入 `PySide6`
8+
39
## 本次更新 (2026-06-24) — 多模板共識比對
410

511
把同一目標的多個參考裁切投票成單一可信位置。完整參考:[`docs/source/Zh/doc/new_features/v178_features_doc.rst`](../docs/source/Zh/doc/new_features/v178_features_doc.rst)

WHATS_NEW.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# What's New — AutoControl
22

3+
## What's new (2026-06-24) — Colour-Aware Template Matching (HSV)
4+
5+
Tell a red status dot from a green one of identical shape. Full reference: [`docs/source/Eng/doc/new_features/v179_features_doc.rst`](docs/source/Eng/doc/new_features/v179_features_doc.rst).
6+
7+
- **`match_color` / `match_color_all`** (`AC_match_color`, `AC_match_color_all`): every `visual_match` matcher grayscales first, so red vs green of identical shape is indistinguishable; `color_region` finds known-colour blobs but can't template-match a multi-colour glyph. This matches on HSV hue/saturation with a colour-*distance* metric (`TM_SQDIFF_NORMED` — correlation would normalise away the absolute hue, scoring a red→green edge same as black→blue). Reuses `color_region`'s RGB loaders + `visual_match`'s resize/NMS/`Match`. `channels` default `("h","s")` (use `("h",)` for flat-saturation targets); for solid blobs use `find_color_region`. No `PySide6`.
8+
39
## What's new (2026-06-24) — Multi-Template Consensus Matching
410

511
Vote several reference crops of one target into a single trustworthy location. Full reference: [`docs/source/Eng/doc/new_features/v178_features_doc.rst`](docs/source/Eng/doc/new_features/v178_features_doc.rst).
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
Colour-Aware Template Matching (HSV)
2+
====================================
3+
4+
Every matcher in ``visual_match`` converts to grayscale first, so a red versus green status
5+
indicator of identical shape is *indistinguishable* to ``match_template`` — the discriminating
6+
signal is thrown away. ``color_region`` finds blobs of a *known* colour but cannot
7+
template-match a multi-colour glyph by appearance. ``color_match`` matches on the HSV
8+
hue / saturation channels using a colour-*distance* metric (``TM_SQDIFF_NORMED``, not a
9+
correlation — correlation normalises away the absolute hue, so a red→green edge and a
10+
black→blue edge would score the same), locating colour-discriminated targets that grayscale
11+
matching collapses.
12+
13+
It reuses ``color_region``'s RGB loaders and ``visual_match``'s resize / NMS / ``Match``. The
14+
``haystack`` is injectable; the search is unit-testable on synthetic arrays. Imports no
15+
``PySide6``.
16+
17+
Note: like any window metric, a *flat* single-colour patch has no per-channel variance — for
18+
solid colour blobs use ``find_color_region``; ``color_match`` is for targets with colour
19+
*structure*.
20+
21+
Headless API
22+
------------
23+
24+
.. code-block:: python
25+
26+
from je_auto_control import match_color, match_color_all
27+
28+
# locate a red status chip, not the green one of the same shape
29+
hit = match_color("status_red.png", channels=("h", "s"), min_score=0.7)
30+
if hit:
31+
click(*hit.center)
32+
33+
for m in match_color_all("tag_green.png", channels=("h",)):
34+
print(m.center, m.score)
35+
36+
``match_color`` returns the best ``Match`` over the chosen ``channels`` (default ``("h", "s")``;
37+
use ``("h",)`` for flat-saturation targets), or ``None``. ``match_color_all`` returns every
38+
match at or above ``min_score`` with overlaps removed by NMS.
39+
40+
Executor commands
41+
-----------------
42+
43+
``AC_match_color`` (``template`` / ``channels`` / ``min_score`` / ``scales`` / ``region`` →
44+
``{found, match}``) and ``AC_match_color_all`` (adds ``max_results`` / ``nms_iou`` →
45+
``{count, matches}``). They are exposed as the MCP tools ``ac_match_color`` /
46+
``ac_match_color_all`` (read-only) and as the Script Builder commands **Match Template
47+
(colour/HSV)** / **Match Template All (colour/HSV)** under **Image**.

docs/source/Eng/eng_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ Comprehensive guides for all AutoControl features.
201201
doc/new_features/v176_features_doc
202202
doc/new_features/v177_features_doc
203203
doc/new_features/v178_features_doc
204+
doc/new_features/v179_features_doc
204205
doc/ocr_backends/ocr_backends_doc
205206
doc/observability/observability_doc
206207
doc/operations_layer/operations_layer_doc
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
色彩感知樣板比對(HSV)
2+
========================
3+
4+
``visual_match`` 的每個比對器都先轉灰階,因此形狀相同的紅色與綠色狀態指示燈對
5+
``match_template`` 而言*無法區分*——具辨別力的訊號被丟棄了。``color_region`` 找*已知*顏色的
6+
blob,卻無法以外觀對多色字形做樣板比對。``color_match`` 在 HSV 色相 / 飽和度通道上以色彩
7+
*距離*度量(``TM_SQDIFF_NORMED``,而非相關——相關會把絕對色相正規化掉,使紅→綠邊與黑→藍邊
8+
得分相同)進行比對,定位灰階比對會塌掉的色彩辨識目標。
9+
10+
本功能重用 ``color_region`` 的 RGB 載入器與 ``visual_match`` 的 resize / NMS / ``Match``。
11+
``haystack`` 可注入;搜尋可在合成陣列上單元測試。不匯入 ``PySide6``。
12+
13+
註:如同任何視窗度量,*平坦*的單色 patch 在各通道無變異——純色 blob 請用
14+
``find_color_region``;``color_match`` 適用於有色彩*結構*的目標。
15+
16+
無頭 API
17+
--------
18+
19+
.. code-block:: python
20+
21+
from je_auto_control import match_color, match_color_all
22+
23+
# 定位紅色狀態 chip,而非同形狀的綠色
24+
hit = match_color("status_red.png", channels=("h", "s"), min_score=0.7)
25+
if hit:
26+
click(*hit.center)
27+
28+
for m in match_color_all("tag_green.png", channels=("h",)):
29+
print(m.center, m.score)
30+
31+
``match_color`` 在選定 ``channels``(預設 ``("h", "s")``;平坦飽和度目標用 ``("h",)``)中回傳
32+
最佳 ``Match``,或 ``None``。``match_color_all`` 回傳所有達到 ``min_score`` 的匹配,重疊以 NMS
33+
移除。
34+
35+
執行器指令
36+
----------
37+
38+
``AC_match_color``(``template`` / ``channels`` / ``min_score`` / ``scales`` / ``region`` →
39+
``{found, match}``)與 ``AC_match_color_all``(另加 ``max_results`` / ``nms_iou`` →
40+
``{count, matches}``)。兩者以 MCP 工具 ``ac_match_color`` / ``ac_match_color_all``(唯讀)及
41+
Script Builder 指令 **Match Template (colour/HSV)** / **Match Template All (colour/HSV)**
42+
(位於 **Image** 分類下)形式提供。

docs/source/Zh/zh_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ AutoControl 所有功能的完整使用指南。
201201
doc/new_features/v176_features_doc
202202
doc/new_features/v177_features_doc
203203
doc/new_features/v178_features_doc
204+
doc/new_features/v179_features_doc
204205
doc/ocr_backends/ocr_backends_doc
205206
doc/observability/observability_doc
206207
doc/operations_layer/operations_layer_doc

je_auto_control/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,10 @@
295295
from je_auto_control.utils.match_ensemble import (
296296
match_ensemble, vote_centers,
297297
)
298+
# Colour-aware template matching on HSV channels
299+
from je_auto_control.utils.color_match import (
300+
match_color, match_color_all,
301+
)
298302
# Otsu auto-thresholding for template matching (no hand-tuned min_score)
299303
from je_auto_control.utils.match_autothresh import (
300304
auto_threshold, match_auto,
@@ -1280,6 +1284,8 @@ def start_autocontrol_gui(*args, **kwargs):
12801284
"chamfer_distance",
12811285
"match_ensemble",
12821286
"vote_centers",
1287+
"match_color",
1288+
"match_color_all",
12831289
"SubPixelMatch",
12841290
"match_subpixel",
12851291
"refine_peak",

je_auto_control/gui/script_builder/command_schema.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,33 @@ def _add_image_specs(specs: List[CommandSpec]) -> None:
431431
),
432432
description="Vote candidate hit centres into one consensus target.",
433433
))
434+
specs.append(CommandSpec(
435+
"AC_match_color", "Image", "Match Template (colour/HSV)",
436+
fields=(
437+
FieldSpec("template", FieldType.FILE_PATH),
438+
FieldSpec("channels", FieldType.STRING, optional=True,
439+
placeholder='["h", "s"]'),
440+
FieldSpec("min_score", FieldType.FLOAT, optional=True, default=0.7,
441+
min_value=0.0, max_value=1.0),
442+
FieldSpec("region", FieldType.STRING, optional=True,
443+
placeholder=_REGION_PLACEHOLDER),
444+
),
445+
description="Match by colour on HSV channels (red vs green, not grayscale).",
446+
))
447+
specs.append(CommandSpec(
448+
"AC_match_color_all", "Image", "Match Template All (colour/HSV)",
449+
fields=(
450+
FieldSpec("template", FieldType.FILE_PATH),
451+
FieldSpec("channels", FieldType.STRING, optional=True,
452+
placeholder='["h", "s"]'),
453+
FieldSpec("min_score", FieldType.FLOAT, optional=True, default=0.7,
454+
min_value=0.0, max_value=1.0),
455+
FieldSpec("max_results", FieldType.INT, optional=True, default=20),
456+
FieldSpec("nms_iou", FieldType.FLOAT, optional=True, default=0.3,
457+
min_value=0.0, max_value=1.0),
458+
),
459+
description="Find every colour (HSV) match of a template (NMS-deduped).",
460+
))
434461
specs.append(CommandSpec(
435462
"AC_grid_cells", "Image", "Grid Cells (coarse grounding)",
436463
fields=(
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"""Colour-aware template matching on HSV channels."""
2+
from je_auto_control.utils.color_match.color_match import (
3+
match_color, match_color_all,
4+
)
5+
6+
__all__ = ["match_color", "match_color_all"]

0 commit comments

Comments
 (0)