feat: 删去 CcoeffHSV, HSVCount 时的模板匹配采用 RGB 的 Ccoeff

CcoeffHSV 有致命缺陷: (0, 0, 0) 与 (179, 0, 0) 应为相似颜色,因为 Hue 是循环的

* feat: HSVCount & RGBCount 的返回结果为点积

为了尽量保证 0.8 的阈值

* workaround: HSVCount & RGBCount 时 maskRange 不再对模板匹配生效

否则数色时的模板匹配结果将不准确,之后可以分开 maskRange 和 colorRange, 后者的格式可以讨论后再做决定
This commit is contained in:
zzyyyl
2024-07-28 01:11:59 +08:00
parent 2a7ecf6074
commit 0a2b003fce
4 changed files with 22 additions and 20 deletions

View File

@@ -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 */

View File

@@ -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"]

View File

@@ -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<std::string, MatchMethod> 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<MatchMethod, std::string> method_map = {
{ MatchMethod::Invalid, "Invalid" },
{ MatchMethod::Ccoeff, "Ccoeff" },
{ MatchMethod::CcoeffHSV, "CcoeffHSV" },
{ MatchMethod::RGBCount, "RGBCount" },
{ MatchMethod::HSVCount, "HSVCount" },
};

View File

@@ -96,13 +96,17 @@ std::vector<Matcher::RawResult> 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::RawResult> 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::RawResult> 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::RawResult> 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 });
}