private (string iconKey, float conf, Vector2 pos) MatchIcon(Size iconSlotSize, Mat source, bool useStaticIcons) { (string iconKey, float conf, Vector2 pos)matchResult = (null, 0f, Vector2.Zero()); Dictionary <string, Mat> iconTemplates; if (useStaticIcons) { iconTemplates = IconManager.GetStaticIcons(iconSlotSize); } else { iconTemplates = IconManager.GetDynamicIcons(iconSlotSize); } if (iconTemplates == null) { return(matchResult); } var firstIcon = iconTemplates.First().Value; if (source.Width < firstIcon.Width || source.Height < firstIcon.Height) { var infoText = "\nsW: " + source.Width + " | sH: " + source.Height; infoText += "\ntW: " + firstIcon.Width + " | tH: " + firstIcon.Height; Logger.LogWarning("Source dimensions smaller than template dimensions!" + infoText); return(matchResult); } // hm = highest match var hmConf = 0f; var hmKey = ""; var hmPos = Vector2.Zero(); Parallel.ForEach(iconTemplates, icon => { // TODO Prepare masks when loading icons var mask = icon.Value.InRange(new Scalar(0, 0, 0, 128), new Scalar(255, 255, 255, 255)); mask = mask.CvtColor(ColorConversionCodes.GRAY2BGR, 3); var iconNoAlpha = icon.Value.CvtColor(ColorConversionCodes.BGRA2BGR, 3); var matches = source.MatchTemplate(iconNoAlpha, TemplateMatchModes.CCorrNormed, mask); matches.MinMaxLoc(out _, out var maxVal, out _, out var maxLoc); lock (_matchLock) { if (maxVal > hmConf) { hmConf = (float)maxVal; hmKey = icon.Key; hmPos = new Vector2(maxLoc); } } });