From 741ba6ba2a4ef52e0b8bcaa4107e6c5a092f05b8 Mon Sep 17 00:00:00 2001 From: zhangjf <1061683512@qq.com> Date: Sat, 16 May 2026 18:41:32 +0800 Subject: [PATCH] feat: add background-masked matching method --- src/EasyCon.Capture/ImgLabel.cs | 22 +++++++++++++++++++--- src/EasyCon.Capture/MatchFacts.cs | 10 ++++++++++ src/EasyCon.Capture/Search.cs | 1 + src/EasyCon.Capture/SearchMethod.cs | 4 +++- 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/EasyCon.Capture/ImgLabel.cs b/src/EasyCon.Capture/ImgLabel.cs index 025d20c6..320bbc5c 100644 --- a/src/EasyCon.Capture/ImgLabel.cs +++ b/src/EasyCon.Capture/ImgLabel.cs @@ -179,9 +179,25 @@ public static List Search(this ImgLabel self, Mat ss, out double md) } else { - byte[] imageBytes = Convert.FromBase64String(self.ImgBase64); - using var target = imageBytes.ToMat(); - result = ECSearch.FindPic(range, target, self.searchMethod, out md); + if (self.searchMethod == SearchMethod.MaskedSqDiffNormed) + { + byte[] imageBytes = Convert.FromBase64String(self.ImgBase64); + using var targetRGBA = Cv2.ImDecode(imageBytes, ImreadModes.Unchanged); + if (targetRGBA.Channels() != 4) + throw new Exception("Masked matching requires RGBA image"); + Cv2.Split(targetRGBA, out var channels); + using var bgr = new Mat(); + Cv2.Merge([channels[0], channels[1], channels[2]], bgr); + using var mask = channels[3]; + var pt = MatchFacts.MatchTemplateMasked(range, bgr, mask, out md); + result = [new Point(pt.X, pt.Y)]; + } + else + { + byte[] imageBytes = Convert.FromBase64String(self.ImgBase64); + using var target = imageBytes.ToMat(); + result = ECSearch.FindPic(range, target, self.searchMethod, out md); + } } md *= 100; diff --git a/src/EasyCon.Capture/MatchFacts.cs b/src/EasyCon.Capture/MatchFacts.cs index 78d86714..67657dcb 100644 --- a/src/EasyCon.Capture/MatchFacts.cs +++ b/src/EasyCon.Capture/MatchFacts.cs @@ -8,6 +8,16 @@ internal static class MatchFacts /// /// 简化的字符串匹配度计算,使用编辑距离方法 /// + public static Point MatchTemplateMasked(Mat big, Mat small, Mat mask, out double matchDegree) + { + matchDegree = 0; + using var result = new Mat(); + Cv2.MatchTemplate(big, small, result, TemplateMatchModes.SqDiffNormed, mask); + Cv2.MinMaxLoc(result, out double min, out double max, out var minLoc, out var maxLoc); + matchDegree = (1 - min) / 1.0; + return minLoc; + } + public static Point MatchTemplate(Mat big, Mat small, SearchMethod method, out double matchDegree) { matchDegree = 0; diff --git a/src/EasyCon.Capture/Search.cs b/src/EasyCon.Capture/Search.cs index 2b616510..b36d303d 100644 --- a/src/EasyCon.Capture/Search.cs +++ b/src/EasyCon.Capture/Search.cs @@ -15,6 +15,7 @@ public static IEnumerable GetEnableSearchMethods() SearchMethod.SqDiffNormed, SearchMethod.CCorrNormed, SearchMethod.CCoeffNormed, + SearchMethod.MaskedSqDiffNormed, SearchMethod.EdgeDetectXY, SearchMethod.EdgeDetectLaplacian, SearchMethod.TesserDetect, diff --git a/src/EasyCon.Capture/SearchMethod.cs b/src/EasyCon.Capture/SearchMethod.cs index 38e8d066..1d4ef4b4 100644 --- a/src/EasyCon.Capture/SearchMethod.cs +++ b/src/EasyCon.Capture/SearchMethod.cs @@ -28,11 +28,13 @@ public enum SearchMethod EdgeDetectLaplacian = 12, [Description("Canny边缘检测")] EdgeDetectCanny = 13, + [Description("透明背景标准差匹配")] + MaskedSqDiffNormed = 14, [Description("OCR单行文本识别")] TesserDetect = 107, } public static class SearchMethodExtension { - public static bool IsImageMethod(this SearchMethod method) => method <= SearchMethod.EdgeDetectLaplacian; + public static bool IsImageMethod(this SearchMethod method) => method <= SearchMethod.EdgeDetectLaplacian || method == SearchMethod.MaskedSqDiffNormed; } \ No newline at end of file