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

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

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

相关推荐
GesLuck几秒前
C#控件开发3—文本显示、文本设值
前端·c#
神秘的土鸡5 分钟前
基于矩阵乘积态的生成模型:量子力学与生成任务的结合
深度学习·目标检测·计算机视觉
平凡シンプル2 小时前
OpenCV 入门
opencv·计算机视觉
liangmou21213 小时前
解释小部分分WPI函数(由贪吃蛇游戏拓展)
android·游戏·c#
利白3 小时前
我的Qt作品(20)使用Qt+OpenCV写一个旋转/抠图/mask生成工具
qt·opencv·旋转·抠图·mask
lili-felicity3 小时前
指针与数组:深入C语言的内存操作艺术
c语言·开发语言·数据结构·算法·青少年编程·c#
四口鲸鱼爱吃盐4 小时前
Pytorch | 利用GNP针对CIFAR10上的ResNet分类器进行对抗攻击
人工智能·pytorch·python·深度学习·神经网络·计算机视觉
小码贾4 小时前
OpenCV-Python实战(6)——图相运算
人工智能·python·opencv
Thomas_YXQ4 小时前
Unity3D Huatuo:划时代的原生C#热更新技术详解
开发语言·游戏·unity·c#·unity3d
❦丿多像灬笑话、℡4 小时前
leetcode 热题100(208. 实现 Trie (前缀树))数组模拟c++
算法·leetcode·c#