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;
        }

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

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

相关推荐
张人玉7 小时前
C# 通讯关键类的API
开发语言·c#
深瞳智检7 小时前
YOLO算法原理详解系列 第002期-YOLOv2 算法原理详解
人工智能·算法·yolo·目标检测·计算机视觉·目标跟踪
dlraba80211 小时前
用 Python+OpenCV 实现实时文档扫描:从摄像头捕捉到透视矫正全流程
开发语言·python·opencv
春末的南方城市12 小时前
开放指令编辑创新突破!小米开源 Lego-Edit 登顶 SOTA:用强化学习为 MLLM 编辑开辟全新赛道!
人工智能·深度学习·机器学习·计算机视觉·aigc
却道天凉_好个秋15 小时前
OpenCV(四):视频采集与保存
人工智能·opencv·音视频
WWZZ202516 小时前
ORB_SLAM2原理及代码解析:SetPose() 函数
人工智能·opencv·算法·计算机视觉·机器人·自动驾驶
William_cl16 小时前
C# MVC 修复DataTable时间排序以及中英文系统的时间筛选问题
开发语言·c#·mvc
c#上位机16 小时前
wpf之RelativeSource用法总结
c#·wpf
一人の梅雨16 小时前
1688 拍立淘接口深度开发:从图像识别到供应链匹配的技术实现
人工智能·算法·计算机视觉
Dm_dotnet17 小时前
WPF应用最小化到系统托盘
c#