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

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

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

相关推荐
xiaoshuaishuai816 小时前
C# 内存管理与资源泄漏
开发语言·c#
_李小白17 小时前
【android opencv学习笔记】Day 26: 滤波算法之低通滤波与图像缩放插值
android·opencv·学习
2401_8769641317 小时前
【湖北专升本】2026湖北专升本真题PDF+备考资料汇总
数据结构·人工智能·经验分享·深度学习·算法·计算机视觉
z落落20 小时前
C#参数区别
java·算法·c#
影寂ldy20 小时前
C#随机数
开发语言·c#
雪豹阿伟20 小时前
11.C# —— 数组属性、高级方法与 Lambda 表达式
c#·上位机
唐青枫21 小时前
C#.NET YARP 服务发现实战:接入 Consul 和 Kubernetes 动态发现后端服务
c#·.net
largecode1 天前
座机号码认证如何操作?申请热线实名名片,树立统一官方客服形象
linux·sql·华为·c#·.net·wpf·harmonyos
jay神1 天前
深度学习模型优化:P2PNet模型MAE下降17.30%
人工智能·python·深度学习·计算机视觉·毕业设计
2401_876964131 天前
27考研李艳芳网课|王谱2027数学讲义
人工智能·经验分享·深度学习·考研·算法·计算机视觉·概率论