位置: IT常识 - 正文

OPENCV多种模板匹配使用对比(opencv模板匹配多目标旋转)

编辑:rootadmin
OPENCV多种模板匹配使用对比

推荐整理分享OPENCV多种模板匹配使用对比(opencv模板匹配多目标旋转),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:opencv模板匹配多目标旋转,opencv 模板匹配得到坐标和角度,opencvsharp模板匹配,opencv多模板匹配,opencv模板匹配算法改进,opencv模板匹配算法改进,opencv模板匹配多目标旋转,opencv模板匹配算法改进,内容如对您有帮助,希望把文章链接给更多的朋友!

前文简单提到模板匹配中的一种:NCC多角度模板匹配,博主结合实际的检测项目(已落地)发现其准确率和稳定性有待提升,特别是一些复杂背景的图形,又或是模板选取不当都会造成不理想的效果;同时也借鉴过基于梯度变化的匹配策略,但要说落实到实际项目上去总是差强人意(可能也是鄙人技术不够,哈哈);所以博主今天分享另外两种比较适用的匹配方式!

   1).  当图像中存在完整且容易提取的外形轮廓时,shapematch形状匹配不失为一种简单快捷的方法,不需要额外去按照固定角度旋转图像来搜索图像,亦不需要担心模板图像旋转后的留白区域影响匹配得分,按照固定的模式来操作即可:

使用Opencv已有方法MatchShapes进行匹配即可,不过匹配后的重心和角度 需要做进一步处理,重心计算公式:

//获取重心点Moments M = Cv2.Moments(bestcontour);double cX = (M.M10 / M.M00);double cY = (M.M01 / M.M00);

   角度计算公式:

//-90~90度//由于先验目标最小包围矩形是长方形 //因此最小包围矩形的中心和重心的向量夹角为旋转RotatedRect rect_template = Cv2.MinAreaRect(imgTemplatecontours);RotatedRect rect_search = Cv2.MinAreaRect(bestcontour);//两个旋转矩阵是否同向float sign = (rect_template.Size.Width - rect_template.Size.Height) * (rect_search.Size.Width - rect_search.Size.Height);float angle=0;if (sign > 0)// 可以直接相减 angle = rect_search.Angle - rect_template.Angle;elseangle = (90 + rect_search.Angle) - rect_template.Angle;if (angle > 90)angle -= 180;

  测试效果如下:

0度:

-30度:

50度:

如同为shapematch形状匹配方式,测试时间约40毫秒左右,当然这个也会与图像大小与轮廓大小相关,不管也可以通过构建金字塔模型来加快搜索速度。

       2).  下面来针对NCC归一化模板匹配做一下简单说明,NCC有几种不同的匹配模式,分别为:

关键的匹配方法如下:

for (int i = 0; i <= (int)range / step; i++) { newtemplate = ImageRotate(model, start + step * i, ref rotatedRect, ref mask); if (newtemplate.Width > src.Width || newtemplate.Height > src.Height) continue; Cv2.MatchTemplate(src, newtemplate, result, matchMode, mask); Cv2.MinMaxLoc(result, out double minval, out double maxval, out CVPoint minloc, out CVPoint maxloc, new Mat()); if (double.IsInfinity(maxval)) { Cv2.MatchTemplate(src, newtemplate, result, TemplateMatchModes.CCorrNormed, mask); Cv2.MinMaxLoc(result, out minval, out maxval, out minloc, out maxloc, new Mat()); } if (maxval > temp) { location = maxloc; temp = maxval; angle = start + step * i; modelrrect = rotatedRect; } }OPENCV多种模板匹配使用对比(opencv模板匹配多目标旋转)

 为了提高匹配速度,可使用金字塔下采样-》上采样来完成:

//对模板图像和待检测图像分别进行图像金字塔下采样 for (int i = 0; i < numLevels; i++) { Cv2.PyrDown(src, src, new Size(src.Cols / 2, src.Rows / 2)); Cv2.PyrDown(model, model, new Size(model.Cols / 2, model.Rows / 2)); } Rect cropRegion = new CVRect(0, 0, 0, 0); for (int j = numLevels - 1; j >= 0; j--) { //为了提升速度,直接上采样到最底层 for (int i = 0; i < numLevels; i++) { Cv2.PyrUp(src, src, new Size(src.Cols * 2, src.Rows * 2));//下一层,放大2倍 Cv2.PyrUp(model, model, new Size(model.Cols * 2, model.Rows * 2));//下一层,放大2倍 } location.X *= (int)Math.Pow(2, numLevels); location.Y *= (int)Math.Pow(2, numLevels); modelrrect = new RotatedRect(new Point2f((float)(modelrrect.Center.X * Math.Pow(2, numLevels)),//下一层,放大2倍 (float)(modelrrect.Center.Y * Math.Pow(2, numLevels))), new Size2f(modelrrect.Size.Width * Math.Pow(2, numLevels), modelrrect.Size.Height * Math.Pow(2, numLevels)), 0); CVPoint cenP = new CVPoint(location.X + modelrrect.Center.X, location.Y + modelrrect.Center.Y);//投影到下一层的匹配点位中心 int startX = cenP.X - model.Width; int startY = cenP.Y - model.Height; int endX = cenP.X + model.Width; int endY = cenP.Y + model.Height; cropRegion = new CVRect(startX, startY, endX - startX, endY - startY); cropRegion = cropRegion.Intersect(new CVRect(0, 0, src.Width, src.Height)); Mat newSrc = MatExtension.Crop_Mask_Mat(src, cropRegion); //每下一层金字塔,角度间隔减少2倍 step = 2; //角度开始和范围 range = 20; start = angle - 10; bool testFlag = false; for (int k = 0; k <= (int)range / step; k++) { newtemplate = ImageRotate(model, start + step * k, ref rotatedRect, ref mask); if (newtemplate.Width > newSrc.Width || newtemplate.Height > newSrc.Height) continue; Cv2.MatchTemplate(newSrc, newtemplate, result, TemplateMatchModes.CCoeffNormed, mask); Cv2.MinMaxLoc(result, out double minval, out double maxval, out CVPoint minloc, out CVPoint maxloc, new Mat()); if (double.IsInfinity(maxval)) { Cv2.MatchTemplate(src, newtemplate, result, TemplateMatchModes.CCorrNormed, mask); Cv2.MinMaxLoc(result, out minval, out maxval, out minloc, out maxloc, new Mat()); } if (maxval > temp) { //局部坐标 location.X = maxloc.X; location.Y = maxloc.Y; temp = maxval; angle = start + step * k; //局部坐标 modelrrect = rotatedRect; testFlag = true; } } if (testFlag) { //局部坐标--》整体坐标 location.X += cropRegion.X; location.Y += cropRegion.Y; } }

 为了提高匹配得分,当图片与模板都进行一定角度旋转后,会产生无效区域,影响匹配效果,此时我们需要创建掩膜图像.

/// <summary> /// 图像旋转,并获旋转后的图像边界旋转矩形 /// </summary> /// <param name="image"></param> /// <param name="angle"></param> /// <param name="imgBounding"></param> /// <returns></returns> public static Mat ImageRotate(Mat image, double angle,ref RotatedRect imgBounding,ref Mat maskMat) { Mat newImg = new Mat(); Point2f pt = new Point2f((float)image.Cols / 2, (float)image.Rows / 2); Mat M = Cv2.GetRotationMatrix2D(pt, -angle, 1.0); var mIndex = M.GetGenericIndexer<double>(); double cos = Math.Abs(mIndex[0, 0]); double sin = Math.Abs(mIndex[0, 1]); int nW = (int)((image.Height * sin) + (image.Width * cos)); int nH = (int)((image.Height * cos) + (image.Width * sin)); mIndex[0, 2] += (nW / 2) - pt.X; mIndex[1, 2] += (nH / 2) - pt.Y; Cv2.WarpAffine(image, newImg, M, new CVSize(nW, nH)); //获取图像边界旋转矩形 Rect rect = new CVRect(0, 0, image.Width, image.Height); Point2f[] srcPoint2Fs = new Point2f[4] { new Point2f(rect.Left,rect.Top), new Point2f (rect.Right,rect.Top), new Point2f (rect.Right,rect.Bottom), new Point2f (rect.Left,rect.Bottom) }; Point2f[] boundaryPoints = new Point2f[4]; var A = M.Get<double>(0, 0); var B = M.Get<double>(0, 1); var C = M.Get<double>(0, 2); //Tx var D = M.Get<double>(1, 0); var E = M.Get<double>(1, 1); var F = M.Get<double>(1, 2); //Ty for(int i=0;i<4;i++) { boundaryPoints[i].X = (float)((A * srcPoint2Fs[i].X) + (B * srcPoint2Fs[i].Y) + C); boundaryPoints[i].Y = (float)((D * srcPoint2Fs[i].X) + (E * srcPoint2Fs[i].Y) + F); if (boundaryPoints[i].X < 0) boundaryPoints[i].X = 0; else if (boundaryPoints[i].X > nW) boundaryPoints[i].X = nW; if (boundaryPoints[i].Y < 0) boundaryPoints[i].Y = 0; else if (boundaryPoints[i].Y > nH) boundaryPoints[i].Y = nH; } Point2f cenP = new Point2f((boundaryPoints[0].X + boundaryPoints[2].X) / 2, (boundaryPoints[0].Y + boundaryPoints[2].Y) / 2); double ang = angle; double width1=Math.Sqrt(Math.Pow(boundaryPoints[0].X- boundaryPoints[1].X ,2)+ Math.Pow(boundaryPoints[0].Y - boundaryPoints[1].Y,2)); double width2 = Math.Sqrt(Math.Pow(boundaryPoints[0].X - boundaryPoints[3].X, 2) + Math.Pow(boundaryPoints[0].Y - boundaryPoints[3].Y, 2)); //double width = width1 > width2 ? width1 : width2; //double height = width1 > width2 ? width2 : width1; imgBounding = new RotatedRect(cenP, new Size2f(width1, width2), (float)ang); Mat mask = new Mat(newImg.Size(), MatType.CV_8UC3, Scalar.Black); mask.DrawRotatedRect(imgBounding, Scalar.White, 1); Cv2.FloodFill(mask, new CVPoint(imgBounding.Center.X, imgBounding.Center.Y), Scalar.White); // mask.ConvertTo(mask, MatType.CV_8UC1); //mask.CopyTo(maskMat); //掩膜复制给maskMat Cv2.CvtColor(mask, maskMat, ColorConversionCodes.BGR2GRAY); Mat _maskRoI = new Mat(); Cv2.CvtColor(mask, _maskRoI, ColorConversionCodes.BGR2GRAY); Mat buf = new Mat(); //# 黑白反转 Cv2.BitwiseNot(_maskRoI, buf); Mat dst = new Mat(); Cv2.BitwiseAnd(newImg, newImg, dst, _maskRoI); //Mat dst2 = new Mat(); //Cv2.BitwiseOr(buf, dst, dst2); return dst; }

这个时候准备工作就完成的差不多,当然关于匹配精度(亚像素处理)这个地方就不做说明了,参考前文即可。测试的效果图如下:

0度:

25度:

-35度:

      3).  在NCC模式的基础上,同是结合shapematch,衍生出另外一种匹配方式:canny模板匹配,大家可以理解为先创捷canny图模板,然后再使用MatchTemplate方法,同时加入金字塔搜索策略。

创建Canny模板:

/// <summary> /// 创建Canny模板图像 /// </summary> /// <param name="src"></param> /// <param name="RegionaRect"></param> /// <param name="thresh"></param> /// <param name="temCannyMat"></param> /// <returns></returns> public Mat CreateTemplateCanny(Mat src,Rect RegionaRect,double thresh,ref Mat temCannyMat, ref double modelX, ref double modelY) { Mat ModelMat = MatExtension.Crop_Mask_Mat(src, RegionaRect); Mat Morphological = Morphological_Proces.MorphologyEx(ModelMat, MorphShapes.Rect, new OpenCvSharp.Size(3, 3), MorphTypes.Open); Mat binMat = new Mat(); Cv2.Threshold(Morphological, binMat, thresh, 255, ThresholdTypes.Binary); temCannyMat = EdgeTool.Canny(binMat, 50, 240); Mat dst = ModelMat.CvtColor(ColorConversionCodes.GRAY2BGR); CVPoint cenP = new CVPoint(RegionaRect.Width / 2, RegionaRect.Height / 2); modelX = RegionaRect.X + RegionaRect.Width / 2; modelY = RegionaRect.Y + RegionaRect.Height / 2; Console.WriteLine(string.Format("模板中心点位:x:{0},y:{1}", RegionaRect.X + RegionaRect.Width / 2, RegionaRect.Y + RegionaRect.Height / 2)); dst.drawCross(cenP, Scalar.Red, 20, 2); return dst; }

 模板图:

测试效果图如下:

      4)通过以上三种对比可发现,它们各有优缺点,shapematch形状匹配强调物体外形的完整性,操作简单,不需要额外构建掩膜和角步循环;NCC不需要选取这个物体来制作模板,只需要前景与背景有一定的区分即可,但是整体匹配效果一般,一些复杂的环境下可能会得不到想要的效果;Canny模板匹配结合了前面2中的部分优点,既可选取物体的局部特征,同时又有NCC匹配方法和策略;大家可以结合实际的项目,选取合适的方法达到最优的效果即可;当然网络上还有一些学术上更优更稳定的方法,如:基于梯度变化的模板匹配,大家也可以尝试一下,反正博主能力有限测试的时候没有达到想要的效果,特别是一些复杂的图像和尺寸较大的图像,测试的结果差强人意,同时实际的项目对于效率的要求也比较高,我们也不可能舍近求远,选择相对合适的即可。同时期待有共同兴趣的大佬们一起来探索发现和指正,大家共同进步。

PS:知识无国界,分享让大家都快乐!

本文链接地址:https://www.jiuchutong.com/zhishi/298530.html 转载请保留说明!

上一篇:vue面试题八股文简答大全 让你更加轻松的回答面试官的vue面试题(vue面试题视频)

下一篇:JavaScript获取数组对象里面的键(key)和值(value)(javascript获取数组索引)

  • 相比经济上的贫穷,失去雄心壮志和勤奋坚持才是最可怕的(经济贫富差距)

    相比经济上的贫穷,失去雄心壮志和勤奋坚持才是最可怕的(经济贫富差距)

  • 苹果se2怎么强制重启(苹果8怎么强制开机)

    苹果se2怎么强制重启(苹果8怎么强制开机)

  • 电脑连接显示器电脑屏幕不显示怎么办(电脑连接显示器电脑屏幕显示无信号)

    电脑连接显示器电脑屏幕不显示怎么办(电脑连接显示器电脑屏幕显示无信号)

  • 对话框中的圆圈表示(对话框中的小方框)

    对话框中的圆圈表示(对话框中的小方框)

  • ipad放大了怎样缩小(ipad屏幕放大了怎么缩小回去)

    ipad放大了怎样缩小(ipad屏幕放大了怎么缩小回去)

  • 苹果手机会不会卡(苹果手机会不会泄露个人信息呢)

    苹果手机会不会卡(苹果手机会不会泄露个人信息呢)

  • 华为nova7和华为nova7pro有什么区别(华为nova7和华为nova8哪个好)

    华为nova7和华为nova7pro有什么区别(华为nova7和华为nova8哪个好)

  • 平板版本低下载不了微信怎么办(平板版本低下载不了光遇怎么办)

    平板版本低下载不了微信怎么办(平板版本低下载不了光遇怎么办)

  • 苹果网络卡怎么解决(苹果网络卡怎么检查是否正常)

    苹果网络卡怎么解决(苹果网络卡怎么检查是否正常)

  • 骑手差评多久能看到(骑手差评多了会怎么样)

    骑手差评多久能看到(骑手差评多了会怎么样)

  • 小米手机能三开微信吗(小米手机能三开游戏吗)

    小米手机能三开微信吗(小米手机能三开游戏吗)

  • 爱奇艺首月一元之后可以取消吗(爱奇艺首月1元)

    爱奇艺首月一元之后可以取消吗(爱奇艺首月1元)

  • ppt的默认保存格式是什么(ppt的默认保存在哪)

    ppt的默认保存格式是什么(ppt的默认保存在哪)

  • peul00是什么型号(pe ul00 是什么手机)

    peul00是什么型号(pe ul00 是什么手机)

  • sav文件怎么打开(sav文件怎么打开 游戏)

    sav文件怎么打开(sav文件怎么打开 游戏)

  • 小米cc9e支持快充吗(小米cc9支持快充)

    小米cc9e支持快充吗(小米cc9支持快充)

  • 手机怎么设置透明壁纸(手机怎么设置透明图标)

    手机怎么设置透明壁纸(手机怎么设置透明图标)

  • mate30呼吸灯在哪(mate30呼吸灯在哪里设置)

    mate30呼吸灯在哪(mate30呼吸灯在哪里设置)

  • 电脑不读优盘如何解决(电脑不读优盘怎么办,但别的可以)

    电脑不读优盘如何解决(电脑不读优盘怎么办,但别的可以)

  • 小程序制作流程(个人制作小程序制作流程)

    小程序制作流程(个人制作小程序制作流程)

  • ldntl10是什么型号(lld-tl10)

    ldntl10是什么型号(lld-tl10)

  • 微信右下角有个蓝勾怎么取消(微信右下角有个蓝勾怎么回事)

    微信右下角有个蓝勾怎么取消(微信右下角有个蓝勾怎么回事)

  • 苹果x和8plus哪个实用(苹果x和8plus哪个贵)

    苹果x和8plus哪个实用(苹果x和8plus哪个贵)

  • 苹果x怎么改运营商名称(苹果x怎么提高运行速度)

    苹果x怎么改运营商名称(苹果x怎么提高运行速度)

  • 如何修改Win10系统注册表,防止意外升级到微软Win11(如何修改win10系统电脑密码)

    如何修改Win10系统注册表,防止意外升级到微软Win11(如何修改win10系统电脑密码)

  • 戛纳,法国 (© Manjik Photography/Alamy)

    戛纳,法国 (© Manjik Photography/Alamy)

  • 前端如何调用后端接口进行数据交互(极简)(前端如何调用后端方法)

    前端如何调用后端接口进行数据交互(极简)(前端如何调用后端方法)

  • 2023美国大学数学建模美赛春季赛Z题思路详细代码(美国大学数学系排名)

    2023美国大学数学建模美赛春季赛Z题思路详细代码(美国大学数学系排名)

  • 什么是Python中的闭包(什么叫python)

    什么是Python中的闭包(什么叫python)

  • 织梦用arclist标签设置当前文章高亮(织梦标签教程)

    织梦用arclist标签设置当前文章高亮(织梦标签教程)

  • 增值税专用发票的税率是多少啊
  • 一般纳税人预缴税款几个点
  • 中级考试报了三门,只考两门行吗
  • 什么情况需要个人档案
  • 交易性金融资产属于什么科目
  • 公司滴滴发票是什么意思
  • 会计凭证装订放哪些报表
  • 开票个人账户的钱怎么查
  • 复合肥生产企业排名
  • 免抵退税怎么做账
  • 印花税缴款了发现报错了怎么办?
  • 结转折旧费会计分录
  • 货车挂靠企业需要交增值税吗?
  • 电子承兑必须对账吗
  • 营改增后购房发票怎么开
  • 超市开发票要交百分之几的税?
  • 增值税发票的开具问题
  • 企事业承包承租方缴纳的管理费税费
  • 案例讲解:将自己的房产用于办公使用,在税收的缴纳中该如何把控?
  • 普票丢失的最新处理2019
  • 个税退税手续费税率
  • 样品开发费用怎么记账
  • 财务费用属于什么会计科目类别
  • 营改增后视同销售的税务处理怎么做?
  • 简易计税劳务分包发票可以差额抵扣吗
  • 增值税专用发票和普通发票的区别
  • 所得税年报能撤销吗
  • win10网页打不开但是有网
  • 关闭自动重新启动会怎样
  • 前期做了无票收入,后期怎么填写
  • 增值税的计税依据包括契税吗
  • hipsdaemon.exe是什么
  • 应付职工薪酬的明细科目有哪些
  • 未分配利润可以转实收吗
  • 企业纳税额包括个人所得税吗
  • php对接mysql
  • vue3当中如何监听新增的属性
  • 基于matlab的随机森林回归和交叉验证
  • 多模态特征融合pytorch
  • 现金折扣退回要考虑财务费用吗
  • mongodb性能优化方案有哪些?
  • 赔偿支出需要纳税调整吗
  • 开票只开大类
  • 用友t3的操作流程
  • 第四季度所得税跟汇算清缴是一样吗
  • 药店主营业务成本怎么算出来的
  • 企业返聘退休人员需要交社保吗
  • 冲减去年管理费怎么做分录
  • 暂估入库的商品能出库吗
  • 无形资产土地入账日期怎么确定
  • 调整以前年度利息支出
  • 公司客户招待费用标准
  • 采购方退货的会计分录
  • 招待费用的进项发票可以抵扣吗
  • 红冲发票显示发票状态不正常
  • 利息收入和应收利息的区别
  • 开了20万销项进项为0交多少税
  • 当期应纳税额是什么意思
  • 旅游业营业税税率
  • 仓库周转率是什么意思
  • 会计入门技巧
  • 在SQL Server 2005中,数据库文件的扩展名为
  • sql语句示例
  • unix系统的最大特点
  • vmmem进程是什么
  • 苹果mac系统怎么安装pip工具
  • 在对linux系统中dir
  • 360修复win7
  • computed缓存
  • j-v测试
  • jquery实现密码和确认密码
  • 安卓游戏模拟游戏制作
  • nodejs npm install全局安装和本地安装的区别
  • Node.js中的什么模块是用于处理文件和目录的
  • android activity回调函数
  • shell脚本识别十六进制数
  • 图片在线预览html5
  • 安徽省税务局发票真伪查询平台
  • 地税局收税标准
  • 云南省地方税务局公告2011年第6号
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设