C# 图像模板匹配并标注

01

需求

这个是粉丝在我的技术群提的一个需求

1、 模板匹配 :

功能:

  (1)在一张大图像中,选取一小块区域作为模板

  (2)可在大图像中匹配到模板图像和位置。

模板匹配是图像处理中最基本、最常用的匹配方法。目前我司用hacon去做的,还进行了二次封装,可以设置图片的旋转角度等信息,这个设计公司机密,这里我就用opencv(NET封装版叫emgucv)去实现这个功能。

02


功能演示

49ac022daea729bb19ae49fce342325a.gif

03


核心代码

using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using PropertyChanged;
using System;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Windows.Media;
using System.Windows.Media.Imaging;namespace Caliburn.Micro.Hello
{[AddINotifyPropertyChangedInterface]public class MatchTemplateViewModel: IViewModel{public ImageSource TemplateImage { get; set; }public string TemplateImagePath { get; set; }public ImageSource MarkImage { get; set; }public string  MarkImagePath { get; set; }public string ResultString { get; set; }public  void  MatchTemplate(){Mat src = CvInvoke.Imread(TemplateImagePath, LoadImageType.AnyColor);//从本地读取图片Mat result = src.Clone();Mat tempImg = CvInvoke.Imread(MarkImagePath, LoadImageType.AnyColor);int matchImg_rows = src.Rows - tempImg.Rows + 1;int matchImg_cols = src.Cols - tempImg.Cols + 1;Mat matchImg = new Mat(matchImg_rows, matchImg_rows, DepthType.Cv32F, 1); //存储匹配结果#region 模板匹配参数说明采用系数匹配法,匹配值越大越接近准确图像。IInputArray image:输入待搜索的图像。图像类型为8位或32位浮点类型。设图像的大小为[W, H]。IInputArray templ:输入模板图像,类型与待搜索图像类型一致,并且大小不能大于待搜索图像。设图像大小为[w, h]。IOutputArray result:输出匹配的结果,单通道,32位浮点类型且大小为[W - w + 1, H - h + 1]。TemplateMatchingType method:枚举类型标识符,表示匹配算法类型。Sqdiff = 0 平方差匹配,最好的匹配为 0。SqdiffNormed = 1 归一化平方差匹配,最好效果为 0。Ccorr = 2 相关匹配法,数值越大效果越好。CcorrNormed = 3 归一化相关匹配法,数值越大效果越好。Ccoeff = 4 系数匹配法,数值越大效果越好。CcoeffNormed = 5 归一化系数匹配法,数值越大效果越好。#endregionCvInvoke.MatchTemplate(src, tempImg, matchImg, TemplateMatchingType.CcoeffNormed);#region 归一化函数参数说明IInputArray src:输入数据。IOutputArray dst:进行归一化后输出数据。double alpha = 1; 归一化后的最大值,默认为 1。double beta = 0:归一化后的最小值,默认为 0。#endregionCvInvoke.Normalize(matchImg, matchImg, 0, 1, NormType.MinMax, matchImg.Depth); //归一化double minValue = 0.0, maxValue = 0.0;Point minLoc = new Point();Point maxLoc = new Point();#region 极值函数参数说明IInputArray arr:输入数组。ref double minVal:输出数组中的最小值。ref double maxVal; 输出数组中的最大值。ref Point minLoc:输出最小值的坐标。ref Point maxLoc; 输出最大值的坐标。IInputArray mask = null:蒙版。#endregionCvInvoke.MinMaxLoc(matchImg, ref minValue, ref maxValue, ref minLoc, ref maxLoc);StringBuilder tb_result = new StringBuilder();tb_result.Append("min=" + minValue + ",max=" + maxValue);tb_result.Append(Environment.NewLine);tb_result.Append("最小值坐标:\n" + minLoc.ToString());tb_result.Append(Environment.NewLine);tb_result.Append("最大值坐标:\n" + maxLoc.ToString());ResultString = tb_result.ToString();//Console.WriteLine(tb_result);CvInvoke.Rectangle(src, new Rectangle(maxLoc, tempImg.Size), new MCvScalar(0, 0, 255), 3);//绘制矩形,匹配得到的效果。CvInvoke.Imshow("result", src);CvInvoke.WaitKey(0);}/// <summary>/// 加载模板图片/// </summary>public void LoadTemplateImage(){TemplateImage = LoadImage(ImageLoadType.TemplateImage);}/// <summary>/// 加载标记图片/// </summary>public void LoadMarkImage(){MarkImage = LoadImage(ImageLoadType.MarkImage);}public ImageSource LoadImage(ImageLoadType imageType ){OpenFileDialog openFileDialog1 = new OpenFileDialog();openFileDialog1.Filter = "图片|*.jpg;*.jpeg;*.bmp;*.png;*.gif";openFileDialog1.FilterIndex = 1;//当前使用第二个过滤字符串openFileDialog1.RestoreDirectory = true;//对话框关闭时恢复原目录openFileDialog1.Multiselect = false;openFileDialog1.Title = "选择文件";ImageSource iSouce = null;try{if (openFileDialog1.ShowDialog() == DialogResult.OK){iSouce = LoadImageFreeze(openFileDialog1.FileName);//加载显示完成需要释放switch(imageType){case ImageLoadType.MarkImage:MarkImagePath = openFileDialog1.FileName;break;case ImageLoadType.TemplateImage:TemplateImagePath = openFileDialog1.FileName; break;default: break;}return iSouce;}return null;}catch (Exception ex){Console.WriteLine($"[MatchTemplateViewModel]:Load() execute error:{ex}");return null;}}/// <summary>/// 图片加载显示完成后释放/// </summary>/// <param name="imagePath"></param>/// <returns></returns>public static BitmapImage LoadImageFreeze(string imagePath){try{BitmapImage bitmap = new BitmapImage();if (File.Exists(imagePath)){bitmap.BeginInit();bitmap.CacheOption = BitmapCacheOption.OnLoad;using (Stream ms = new MemoryStream(File.ReadAllBytes(imagePath))){bitmap.StreamSource = ms;bitmap.EndInit();bitmap.Freeze();}}return bitmap;}catch (Exception){return null;}}}
}

04


说明

界面分别加载模板图片和标记图片,然后点击匹配按钮进行匹配,匹配结果在模板图片上用矩形标注,并把位置信息显示在界面上

①在NUGET上安装emgucv库:我这里适应的是3.1。0.1,注意emgucv每个版本不兼容

8bd307ec3b00860e5f05f38a8f2eeddd.png

②模板匹配接口MatchTemplate说明,详细注释代码里面都有

#region 模板匹配参数说明采用系数匹配法,匹配值越大越接近准确图像。IInputArray image:输入待搜索的图像。图像类型为8位或32位浮点类型。设图像的大小为[W, H]。IInputArray templ:输入模板图像,类型与待搜索图像类型一致,并且大小不能大于待搜索图像。设图像大小为[w, h]。IOutputArray result:输出匹配的结果,单通道,32位浮点类型且大小为[W - w + 1, H - h + 1]。TemplateMatchingType method:枚举类型标识符,表示匹配算法类型。Sqdiff = 0 平方差匹配,最好的匹配为 0。SqdiffNormed = 1 归一化平方差匹配,最好效果为 0。Ccorr = 2 相关匹配法,数值越大效果越好。CcorrNormed = 3 归一化相关匹配法,数值越大效果越好。Ccoeff = 4 系数匹配法,数值越大效果越好。CcoeffNormed = 5 归一化系数匹配法,数值越大效果越好。#endregionCvInvoke.MatchTemplate(src, tempImg, matchImg, TemplateMatchingType.CcoeffNormed);

③外部加载 图片,加载显示完成后释放,返回BitmapImage 可以直接赋值给wpf控件的ImageSource

public static BitmapImage LoadImageFreeze(string imagePath){try{BitmapImage bitmap = new BitmapImage();if (File.Exists(imagePath)){bitmap.BeginInit();bitmap.CacheOption = BitmapCacheOption.OnLoad;using (Stream ms = new MemoryStream(File.ReadAllBytes(imagePath))){bitmap.StreamSource = ms;bitmap.EndInit();bitmap.Freeze();}}return bitmap;}catch (Exception){return null;}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/292388.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入浅出Mybatis系列(八)---mapper映射文件配置之select、resultMap[转]

上篇《深入浅出Mybatis系列&#xff08;七&#xff09;---mapper映射文件配置之insert、update、delete》介绍了insert、update、delete的用法&#xff0c;本篇将介绍select、resultMap的用法。select无疑是我们最常用&#xff0c;也是最复杂的&#xff0c;mybatis通过resultMa…

李洪强经典面试题146-网络

李洪强经典面试题146-网络 网络 http请求方式&#xff1f; 通常&#xff0c;HTTP的请求方式有3种&#xff0c;分别是&#xff1a;POST、GET、HEAD。POST和GET方法是用于数据发送的。 POST&#xff1a;它将要发送的数据单独放在一个流中进行发送&#xff0c;而不是附加在URL地址…

北大保送、硕博连读!《西游记》红孩儿扮演者现成中科院博士!

全世界只有3.14 % 的人关注了爆炸吧知识本文转自&#xff1a;募格学术86版《西游记》可以说是很多人的记忆&#xff0c;男女老幼几乎都看过这个版本&#xff0c;虽然已经过去三十多年&#xff0c;但如今依旧是经典无法超越之作。看过86版《西游记》的小伙伴应该都还记得里面牛魔…

Android插件化开发之运行未安装apk的activity

1、介绍 我们知道PathClassLoader是一个应用的默认加载器(而且他只能加载data/app/xxx.apk的文件)&#xff0c;但是我们加载插件一般使用DexClassLoader加载器&#xff0c;所以这里就有问题了&#xff0c;其实如果对于开始的时候&#xff0c;每个人都会认为很简单&#xff0c;…

理解UI线程——SWT, Android, 和Swing的UI机理

2019独角兽企业重金招聘Python工程师标准>>> 在做GUI的时候, 无论是SWT, AWT, Swing 还是Android, 都需要面对UI线程的问题, UI线程往往会被单独的提出来单独对待, 试着问自己, 当GUI启动的时候, 后台会运行几个线程? 比如 1. SWT 从Main函数启动 2. Swing 从Ma…

python自动填写小程序表单_新年好!教大家用Python写一个自动回复拜年信息的小程序!...

原标题&#xff1a;新年好&#xff01;教大家用Python写一个自动回复拜年信息的小程序&#xff01;过年期间&#xff0c;想必大家都收到很多拜年信息吧&#xff01;有没有也被拜年短信(大部分是群发)搞得很焦虑&#xff1f;不回复似乎显得很没有礼貌&#xff0c;一一回复又累心…

C#多线程开发-并发集合中的ConcurrentQueue

前言大家好&#xff0c;我是阿辉。上一篇博文简单介绍了C#中支持并发的数据字典&#xff0c;简单举例说明比较了常规集合与ConcurrentDictionary的读写速度。下来简单介绍其中一个线程安全队列ConcurrentQueue;ConcurrentQueue队列我们不陌生&#xff0c;在数据结构这门课中就有…

HDU 5141

这个题 LIS 并查集的思想 链式前向星 要求找s(i,j)使i j 能有最长的LIS 。。。 做法是枚举每一个j 即终点 算 起点 的可能 无力吐槽了 bc 的时候写错了一个地方 导致TLE 后来幡然醒悟了 改了就a了 不想说什么了 直接上代码 #include <cstdio> #include <…

MySQL存储过程相互调用

什么都不说了上代码&#xff1a; 方式一&#xff1a; 第一个存储过程&#xff1a;test1,参数如下&#xff1a;IN user_name VARCHAR(50),OUT uid bigint(20) BEGIN#Routine body goes here...DECLARE u_id BIGINT(20) DEFAULT 11;SELECT user_id INTO uid FROM tbl_useralias …

一个人动情之后的表现......

1 卖家能有什么坏心思呢&#xff08;via.城与橙与澄&#xff0c;侵删&#xff09;▼2 严重怀疑传了答案▼3 别说我还真没留意到&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼4 领导说“辛苦了”&#xff0c;你要怎么回答▼5 哦吼&#xff08;素材来源网络&#…

Android之推荐看的Android源码

推荐阅读的源码 AOSP项目这么庞大,就算是Framework部分也有够看上一阵子的,所以推荐从常用的看起,由浅及深,同时向横向和纵向深入阅读。 开始 Handler-Message-Looper Handler被称为“异步提交器”,是Android开发入门教程必定谈及的东西,这也是Activity等组件的工作机…

线性代数第五版吉尔伯特课后答_线性代数同济第五版第六章课后习题答案!

搜集 | 整理 | 测试 | 小愉免责声明&#xff1a;以下资源或软件均来自互联网&#xff0c;仅供学习和交流使用&#xff0c;如有侵权请联系删除&#xff0c;请勿用于商业和非法途径等&#xff0c;如有法律纠纷与本人无关&#xff01;本文未经允许&#xff0c;不得转载&#xff0…

2021,我的输入输出

前言2021年&#xff0c;我到底进行了哪些输入&#xff0c;又是如何输出的&#xff0c;借由这篇文章回顾一下。新技术.NET技术日新月异&#xff0c;今年我也尝试学习了其中一部分。BlazorBlazor允许我们使用C#而不是JavaScript构建交互式客户端Web应用程序&#xff0c;对于后端出…

iOS笔记之UIKit_UINavigationController

//设置导航条的样式 self.navigationController.navigationBar.barStyle UIBarStyleBlackTranslucent; //默认是白色 Bar 字体颜色黑色&#xff0c;如果样式设置黑色&#xff0c;对应的字体就是白色。 //定义导航条的时候使用 self.navigationController.navigationBar.trans…

字符串之找到字符串的最大无重复字符串子串

题目: 字符串之找到字符串的最大无重复字符子串 举例: str = "adcd" return 4 str = "aabcd" I know this str is adc so return 3 要求: 时间复杂度为O(N) 代码实现: package com.chenyu.string.cn;public class MaxUnique {public static v…

hive日期函数

今天select from_unixtime(unix_timestamp(),yyyy-MM-dd HH:mm:ss) UNIX时间戳转日期函数: from_unixtime 语法: from_unixtime(bigint unixtime[, string format]) 返回值: string 说明: 转化UNIX时间戳&#xff08;从1970-01-01 00:00:00 UTC到指定时间的秒数&#xff09;到…

sql长整型_SQL 性能优化梳理

先简单梳理下Mysql的基本概念&#xff0c;然后分创建时和查询时这两个阶段的优化展开。1 基本概念简述1.1 逻辑架构第一层&#xff1a;客户端通过连接服务&#xff0c;将要执行的sql指令传输过来第二层&#xff1a;服务器解析并优化sql&#xff0c;生成最终的执行计划并执行第三…

网络的东西南北

前一陣子連續出差, 加上許多的內部會議, 搞的差點想去撞牆把自己搞昏之後就可以休息一下. 但是家中還有嗷嗷待哺的嬰兒需要爸爸幫他洗屁屁, 所以只有咬牙繼續撐下去. 不過這兩個月來, 不過在公司內部還是外部, 我都收到一樣類似的老問題那就是&#xff1a;&#xff08;認識我的…

K8s 中使用 cert-manager 申请免费 Https 证书

K8s 中使用 cert-manager 申请免费 Https 证书Intro最近在尝试将自己的应用从自己用 kind 部署的一个 k8s 集群迁移到 Azure 的 AKS 上&#xff0c;其中一个问题就是 https 证书&#xff0c;原来的 k8s 集群是放在 nginx 后端的并没有直接管理 https 证书&#xff0c;https 证书…