c# 实现多尺度的模板匹配

Cv2.MatchTemplate()方法在模板图像与测试图像分辨率不同的情况下会失效,因为模板匹配的原理是将模板从测试图片中从左到右,从上到下依次滑动来找到匹配度最高的地方;

因此,为了实现多尺度的模板匹配,需要对其进行改进;

主要思路:循环缩放模板图像的大小再与测试图像进行匹配(很暴力)。

实现的核心代码如下(c#):

cs 复制代码
public void MultiSixeMatch(String sourceImagePath, bool isSaveResult, int samllResizeLoop = 20, double samllResize = 0.02, int largeResizeLoop = 40, double largeResize = 0.02, bool earlyStop = true, double stopConfidence = 0.8)
        {
            Mat testPic = Cv2.ImRead(sourceImagePath, ImreadModes.Color);
            //用来存储每次匹配的结果:匹配信任度、最大匹配位置
            double tempConfidence = double.NegativeInfinity;
            Point tempMaxLocal = new Point();

            // 缩放模板 当前模版为最大尺寸,每次循环缩小2%,循环20次
            for (int index = -samllResizeLoop; index < 0; index++)
            {
                Mat tempTemplate = templatePic.Clone();
                int newRows = (int)(templatePic.Rows + index * samllResize * templatePic.Rows);
                int newCols = (int)(templatePic.Cols + index * samllResize * templatePic.Cols);

                // resize模板图像大小
                Cv2.Resize(tempTemplate, tempTemplate, new Size(newCols, newRows));

                // 将得到的小模板进行与测试图像进行匹配
                Mat matchResult = new Mat();
                Cv2.MatchTemplate(testPic, tempTemplate, matchResult, TemplateMatchModes.CCoeffNormed);

                // 解析模板匹配的结果 最大匹配区域以及匹配度
                Cv2.MinMaxLoc(matchResult, out _, out tempConfidence, out _, out tempMaxLocal);
                Rect tempRect = new Rect(tempMaxLocal, tempTemplate.Size());

                // 判断当前匹配信任度 如果高于阈值 则结束匹配
                if(earlyStop && tempConfidence > stopConfidence)
                {
                    updateResult(index, tempMaxLocal, tempRect, tempConfidence);
                    saveResult(testPic, sourceImagePath, isSaveResult);
                    showPicture(testPic);
                    return;
                }
                // 记录当前最好的结果
                if (tempConfidence > confidence)
                {
                    updateResult(index, tempMaxLocal, tempRect, tempConfidence);
                }
            }

            // 放大模板 当前模版为最小尺寸,每次循环放大2%,循环40次
            for (int index = 0; index < largeResizeLoop; index++)
            {
                Mat tempTemplate = templatePic.Clone();
                int newRows = (int)(templatePic.Rows + index * largeResize * templatePic.Rows);
                int newCols = (int)(templatePic.Cols + index * largeResize * templatePic.Cols);

                // resize模板图像大小
                Cv2.Resize(tempTemplate, tempTemplate, new Size(newCols, newRows));

                // 将得到的小模板进行与测试图像进行匹配
                Mat matchResult = new Mat();
                Cv2.MatchTemplate(testPic, tempTemplate, matchResult, TemplateMatchModes.CCoeffNormed);

                // 解析模板匹配的结果 最大匹配区域以及匹配度
                Cv2.MinMaxLoc(matchResult, out _, out tempConfidence, out _, out tempMaxLocal);
                Rect tempRect = new Rect(tempMaxLocal, tempTemplate.Size());

                // 判断当前匹配信任度 如果高于阈值 则结束匹配
                if (earlyStop && tempConfidence > stopConfidence)
                {
                    updateResult(index, tempMaxLocal, tempRect, tempConfidence);
                    saveResult(testPic, sourceImagePath, isSaveResult);
                    showPicture(testPic);
                    return;
                }
                // 记录当前最好的结果
                if (tempConfidence > confidence)
                {
                    updateResult(index, tempMaxLocal, tempRect, tempConfidence);
                }
            }
            saveResult(testPic, sourceImagePath, isSaveResult);
            showPicture(testPic);
            return;
        }

        private void saveResult(Mat testPic, String sourceImagePath, bool isSaveResult)
        {
            if (!isSaveResult)
            {
                return;
            }
            Cv2.Rectangle(testPic, rect, Scalar.Green, 3);
            Cv2.PutText(testPic, bestIndex.ToString() + ":" + Math.Round(confidence, 4).ToString(), new Point(maxLocal.X, maxLocal.Y - 50), HersheyFonts.HersheyDuplex, 2, Scalar.Red, 8);
            Cv2.ImWrite(sourceImagePath.Split('.')[0] + "_matchResult.jpg", testPic);
        }

        private void showPicture(Mat testPic)
        {
            Cv2.NamedWindow("Result", WindowFlags.Normal);
            Cv2.ImShow("Result", testPic);
            Cv2.WaitKey(0);
        }

        /// <summary>
        /// 更新最佳的匹配结果
        /// </summary>
        /// <param name="index">最佳序号</param>
        /// <param name="tempMaxLocal">匹配点(左上角坐标)</param>
        /// <param name="tempRect">、匹配框</param>
        /// <param name="tempConfidence">匹配信任度</param>
        private void updateResult(int index, Point tempMaxLocal, Rect tempRect, double tempConfidence)
        {
            bestIndex = index;
            maxLocal = tempMaxLocal;
            rect = tempRect;
            confidence = tempConfidence;
            return;
        }

写得不是很优雅,只能说能运行起来吧!

看网上很多方法都是通过对比模板与匹配区域图像之间的方差和直方图之类的信息,来选择最终的结果,这是为什么呢?为啥不直接用匹配的分数作为选择依据呢?(以上代码就是依据匹配的分数来选择最好的匹配结果)

相关推荐
千宇宙航4 小时前
闲庭信步使用图像验证平台加速FPGA的开发:第十四课——图像二值化的FPGA实现
图像处理·计算机视觉·fpga开发
橡晟4 小时前
深度学习入门:让神经网络变得“深不可测“⚡(二)
人工智能·python·深度学习·机器学习·计算机视觉
PyAIExplorer5 小时前
图像亮度调整的简单实现
人工智能·计算机视觉
时光追逐者6 小时前
C#/.NET/.NET Core技术前沿周刊 | 第 46 期(2025年7.7-7.13)
c#·.net·.netcore
mit6.8246 小时前
Why C# and .NET are still relevant in 2025
c#
liulilittle6 小时前
.NET ExpandoObject 技术原理解析
开发语言·网络·windows·c#·.net·net·动态编程
AI technophile6 小时前
OpenCV计算机视觉实战(15)——霍夫变换详解
人工智能·opencv·计算机视觉
JNU freshman7 小时前
计算机视觉 之 数字图像处理基础(一)
人工智能·计算机视觉
军训猫猫头7 小时前
5.浏览本地文件获取路径与文件名称 C#例子 WPF例子
开发语言·c#·wpf
千宇宙航7 小时前
闲庭信步使用图像验证平台加速FPGA的开发:第十五课——基于sobel算子边缘检测的FPGA实现
图像处理·计算机视觉·fpga开发