From 0a2b003fcea3de027b65fca0b98cba9285fe2ec1 Mon Sep 17 00:00:00 2001 From: zzyyyl Date: Sun, 28 Jul 2024 01:11:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=A0=E5=8E=BB=20CcoeffHSV,=20HSVCo?= =?UTF-8?q?unt=20=E6=97=B6=E7=9A=84=E6=A8=A1=E6=9D=BF=E5=8C=B9=E9=85=8D?= =?UTF-8?q?=E9=87=87=E7=94=A8=20RGB=20=E7=9A=84=20Ccoeff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CcoeffHSV 有致命缺陷: (0, 0, 0) 与 (179, 0, 0) 应为相似颜色,因为 Hue 是循环的 * feat: HSVCount & RGBCount 的返回结果为点积 为了尽量保证 0.8 的阈值 * workaround: HSVCount & RGBCount 时 maskRange 不再对模板匹配生效 否则数色时的模板匹配结果将不准确,之后可以分开 maskRange 和 colorRange, 后者的格式可以讨论后再做决定 --- docs/zh-cn/protocol/task-schema.md | 5 +++-- resource/tasks.json | 2 -- src/MaaCore/Common/AsstTypes.h | 7 +++---- src/MaaCore/Vision/Matcher.cpp | 28 ++++++++++++++++------------ 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/docs/zh-cn/protocol/task-schema.md b/docs/zh-cn/protocol/task-schema.md index 39b92e4c67..1a0d50d948 100644 --- a/docs/zh-cn/protocol/task-schema.md +++ b/docs/zh-cn/protocol/task-schema.md @@ -109,9 +109,10 @@ icon: material-symbols:task "method": "Ccoeff", // 可选项,模板匹配算法,可以是列表 // 不填写时默认为 Ccoeff // - Ccoeff: 对应 cv::TM_CCOEFF_NORMED - // - CcoeffHSV: 转换为 HSV 颜色空间后再进行 CCOEFF // - RGBCount: 先将待匹配区域和模板图片依据 maskRange 二值化, - // 以 F1-score 为指标计算 RGB 颜色空间内的相似度 + // 以 F1-score 为指标计算 RGB 颜色空间内的相似度, + // 再将结果与 Ccoeff 的结果点积 + // 总之是一个颜色敏感的模板匹配算法 // - HSVCount: 类似 RGBCount,颜色空间换为 HSV /* 以下字段仅当 algorithm 为 OcrDetect 时有效 */ diff --git a/resource/tasks.json b/resource/tasks.json index 8704eed7db..1fa0f4cbd1 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -9455,14 +9455,12 @@ }, "Sarkaz@Roguelike@StageFilterTruthCanCombine": { "action": "ClickSelf", - "method": "CcoeffHSV", "templThreshold": 0.95, "roi": [750, 525, 188, 129], "next": ["Sarkaz@Roguelike@StageFilterTruthChooseCollection", "Sarkaz@Roguelike@StageFilterTruthConfirm"] }, "Sarkaz@Roguelike@StageFilterTruthCannotCombine": { "action": "DoNothing", - "method": "CcoeffHSV", "templThreshold": 0.95, "roi": [750, 525, 188, 129], "next": ["Sarkaz@Roguelike@StageFilterTruthLeave"] diff --git a/src/MaaCore/Common/AsstTypes.h b/src/MaaCore/Common/AsstTypes.h index fc548b5ab9..11d19ed014 100644 --- a/src/MaaCore/Common/AsstTypes.h +++ b/src/MaaCore/Common/AsstTypes.h @@ -361,7 +361,6 @@ namespace asst { Invalid = -1, Ccoeff = 0, - CcoeffHSV, RGBCount, HSVCount, }; @@ -370,8 +369,9 @@ namespace asst { utils::tolowers(method_str); static const std::unordered_map method_map = { - { "ccoeff", MatchMethod::Ccoeff }, { "ccoeffhsv", MatchMethod::CcoeffHSV }, - { "rgbcount", MatchMethod::RGBCount }, { "hsvcount", MatchMethod::HSVCount }, + { "ccoeff", MatchMethod::Ccoeff }, + { "rgbcount", MatchMethod::RGBCount }, + { "hsvcount", MatchMethod::HSVCount }, }; if (auto it = method_map.find(method_str); it != method_map.end()) { return it->second; @@ -384,7 +384,6 @@ namespace asst static const std::unordered_map method_map = { { MatchMethod::Invalid, "Invalid" }, { MatchMethod::Ccoeff, "Ccoeff" }, - { MatchMethod::CcoeffHSV, "CcoeffHSV" }, { MatchMethod::RGBCount, "RGBCount" }, { MatchMethod::HSVCount, "HSVCount" }, }; diff --git a/src/MaaCore/Vision/Matcher.cpp b/src/MaaCore/Vision/Matcher.cpp index 066936ef22..67940c7939 100644 --- a/src/MaaCore/Vision/Matcher.cpp +++ b/src/MaaCore/Vision/Matcher.cpp @@ -96,13 +96,17 @@ std::vector Matcher::preproc_and_match(const cv::Mat& image, cv::Mat matched; cv::Mat image_for_match; cv::Mat templ_for_match; - if (method == MatchMethod::CcoeffHSV || method == MatchMethod::HSVCount) { - cv::cvtColor(image, image_for_match, cv::COLOR_BGR2HSV); - cv::cvtColor(templ, templ_for_match, cv::COLOR_BGR2HSV); + cv::Mat image_for_count; + cv::Mat templ_for_count; + cv::cvtColor(image, image_for_match, cv::COLOR_BGR2RGB); + cv::cvtColor(templ, templ_for_match, cv::COLOR_BGR2RGB); + if (method == MatchMethod::HSVCount) { + cv::cvtColor(image, image_for_count, cv::COLOR_BGR2HSV); + cv::cvtColor(templ, templ_for_count, cv::COLOR_BGR2HSV); } - else { - cv::cvtColor(image, image_for_match, cv::COLOR_BGR2RGB); - cv::cvtColor(templ, templ_for_match, cv::COLOR_BGR2RGB); + else if (method == MatchMethod::RGBCount) { + image_for_count = image_for_match; + templ_for_count = templ_for_match; } // 目前所有的匹配都是用 TM_CCOEFF_NORMED @@ -136,7 +140,9 @@ std::vector Matcher::preproc_and_match(const cv::Mat& image, return mask; }; - if (params.mask_range.empty()) { + if (params.mask_range.empty() || method == MatchMethod::RGBCount || method == MatchMethod::HSVCount) { + // workaround: 数色时的模板匹配忽略 maskRange + // TODO: 区分 maskRange 和 colorRange cv::matchTemplate(image_for_match, templ_for_match, matched, match_algorithm); } else { @@ -150,9 +156,8 @@ std::vector Matcher::preproc_and_match(const cv::Mat& image, } if (method == MatchMethod::RGBCount || method == MatchMethod::HSVCount) { - // 待匹配图像与模板中指定颜色的像素数量比值,越接近1越相似 - auto templ_active_opt = calc_mask(templ_for_match, false); - auto image_active_opt = calc_mask(image_for_match, false); + auto templ_active_opt = calc_mask(templ_for_count, false); + auto image_active_opt = calc_mask(image_for_count, false); if (!image_active_opt || !templ_active_opt) [[unlikely]] { return {}; } @@ -171,9 +176,8 @@ std::vector Matcher::preproc_and_match(const cv::Mat& image, fp.convertTo(fp, CV_32S); cv::Mat count_result; // 数色结果为 f1_score cv::divide(2 * tp, tp + fp + tp_fn, count_result, 1, CV_32F); - // 返回的是数色和模板匹配的几何平均 + // 返回的是数色和模板匹配的点积 cv::multiply(matched, count_result, matched); - cv::sqrt(matched, matched); } results.emplace_back(RawResult { .matched = matched, .templ = templ, .templ_name = templ_name }); }