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

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

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

相关推荐
懷淰メ8 小时前
【AI赋能】基于PyQt+YOLO+DeepSeek水上漂浮物检测系统(详细介绍)
人工智能·yolo·目标检测·计算机视觉·pyqt·漂浮物·水上漂浮物
蓝斯4978 小时前
[原创]《C#高级GDI+实战:从零开发一个流程图》第章:增加贝塞尔曲线,上、下、左、右连接点
java·c#·流程图
西门啐血16 小时前
上位机开发之假装有设备,使用 C# 模拟串口设备
开发语言·mongodb·c#
丙氨酸長鏈17 小时前
[Bukkit插件开发]手持发射器箭矢机枪 教学文档 面向Python/C#开发者入门Java与Bukkit API
java·python·c#
淡海水17 小时前
12-01-YooAsset工程化-Unity资源管理规范
unity·c#·游戏引擎·yooasset
脚踏实地皮皮晨18 小时前
003003001_Grid控件
开发语言·windows·算法·c#·visual studio
caishenzhibiao19 小时前
降雨带波段点差 同花顺期货通指标
java·c语言·c#
bryant_meng19 小时前
【Point Cloud】Point Cloud Fundamentals(1)
计算机视觉·点云·点云配准·点云分割·点云检测·点云特征提取
半夢半醒119 小时前
[原创]《C#高级GDI+实战:从零开发一个流程图》第章:增加菱形、平行四边形、圆角矩形,文本居中显示
算法·c#·流程图
蓝斯4971 天前
C# 调用邮箱应用发送带附件的邮件
网络·c#·github