9:OpenCV—模板匹配

模版匹配

1、模板匹配概念

  模板匹配是一项在一副图像中寻找与另一幅模板图像最匹配(相似)部分的技术。模板匹配不是基于直方图的,而是通过在输入图像上滑动图像块(模板)同时对比相似度,来对模板和输入图像进行匹配的一种方法。

应用:

  (1)目标查找定位

  (2)运动物体跟踪

2、模板匹配 — matchTemplate()

1 CV_EXPORTS_W void matchTemplate(InputArray image, InputArray temp1, OutputArray result, int method);

  image:待搜索图像(大图)

  temp1:搜索模板,需和原图一样数据类型且尺寸大小不能大于源图像

  reuslt:比较结果的映射图像,其必须为单通道的,32位浮点型图像,如果原图(待搜索图像)尺寸为W*H,二temp1的尺寸为w*h,则result的尺寸一定是(W-w+1)*(H-h+1)

  method:指定的匹配方法,有如下六种:


CV_TM_SQDIFF --- 平方差匹配法(最好匹配0)
CV_TM_SQDIFF_NORMED --- 归一化平方差匹配法(最好匹配0)
CV_TM_CCORR --- 相关匹配法(最坏匹配0)
CV_TM_CCORR_NORMED ---归一化相关匹配法(最坏匹配0)
CV_TM_CCOEFF --- 系数匹配法(最好匹配1)
CV_TM_CCOEFF_NORMED --- 归一化系数匹配法(最好匹配1)

2、矩阵归一化 — normalize()


void normalize(InputArray src,OutputArray dst, double alpha=1, double beta=0, int norm_type=NORM_L2, int dtype=-1, InputArray mask=noArray() )

  src:输入源图像,Mat类型

  dst:输出结果图像,需要和原图一样的尺寸和类型

  alpha:归一化后的最小值,默认为1

  beta:归一化后的最大值,默认为0

  norm_type:归一化类型,可选:NORM_INF, NORM_L1, NORM_L2(默认)等

  dtype:默认值为-1,此参数为负值时,输出矩阵和src有同样的类型

  mask:可选的掩码操作

normallize()函数的作用是进行矩阵归一化。

3、寻找最值 — minMaxLoc()


1void minMaxLoc(InputArray src, CV_OUT double* minVal, CV_OUT double* maxVal = 0, CV_OUT Point* minLoc=0, CV_OUT Point* maxLoc=0, InputArray mask=noArray());

  src:输入源图像,单通道图像

  minVal:返回最小值的指针,若无需返回,则置为0

  maxVal:返回最大值的指针,若无需返回,则置为0

  minLoc:返回最小位置的指针,若无需返回,则置为0

  maxLoc:返回最大位置的指针,若无需返回,则置为0

  mask:可选的掩码操作

minMaxLoc()函数的作用是在数组中找到全局最小值和最大值

4、单模板案例


//模板匹配
#include "opencv2/opencv.hpp"
#include <iostream>using namespace std;
using namespace cv;int main()
{Mat temp=imread("mu.jpg");Mat src=imread("1.jpg");Mat dst=src.clone();imshow("temp",temp);int width=src.cols-temp.cols+1;//result宽度int height=src.rows-temp.rows+1;//result高度Mat result(height,width,CV_32FC1);//创建结果映射图像//matchTemplate(srcImg, templateImg, resultImg, CV_TM_SQDIFF); //平方差匹配法(最好匹配0)//matchTemplate(srcImg, templateImg, resultImg, CV_TM_SQDIFF_NORMED); //归一化平方差匹配法(最好匹配0)//matchTemplate(srcImg, templateImg, resultImg, CV_TM_CCORR); //相关匹配法(最坏匹配0)//matchTemplate(srcImg, templateImg, resultImg, CV_TM_CCORR_NORMED); //归一化相关匹配法(最坏匹配0)//matchTemplate(srcImg, templateImg, resultImg, CV_TM_CCOEFF); //系数匹配法(最好匹配1)matchTemplate(src,temp,result,CV_TM_CCOEFF_NORMED);//化相关系数匹配,最佳值1imshow("result",result);normalize(result,result,0,1,NORM_MINMAX,-1);//归一化到0-1范围double minValue,maxValue;Point minLoc,maxLoc;minMaxLoc(result,&minValue,&maxValue,&minLoc,&maxLoc);cout<<"minValue="<<minValue<<endl;cout<<"maxValue="<<maxValue<<endl;rectangle(dst,maxLoc,Point(maxLoc.x+temp.cols,maxLoc.y+temp.rows),Scalar(0,255,0),2,8);imshow("dst",dst);waitKey(0);return 0;
}

注意:result的长宽正好是(原图-模板图)的长宽,result图中白亮程度表示匹配程度

5、视频模板匹配


//视频模板匹配
#include "opencv2/opencv.hpp"
#include <iostream>using namespace std;
using namespace cv;int main()
{Mat frame,resultImg;Mat templateImg = imread("green.jpg");VideoCapture cap("1.mp4");if(!cap.isOpened())return;int resultImg_cols,resultImg_rows;while(1){cap>>frame;if(frame.empty())    break;Mat showImg = frame.clone();resultImg_cols = frame.cols -  templateImg.cols + 1;resultImg_rows = frame.rows -  templateImg.rows + 1;resultImg.create(resultImg_cols, resultImg_rows, CV_32FC1);matchTemplate(frame, templateImg, resultImg, CV_TM_CCOEFF_NORMED); //归一化相关系数匹配法(最好匹配1)normalize(resultImg, resultImg, 0, 1, NORM_MINMAX);double minValue, maxValue;Point minLoc, maxLoc;Point matchLoc;minMaxLoc(resultImg, &minValue, &maxValue, &minLoc, &maxLoc);cout<<"max_value= "<<maxValue<<endl;//cout<<"min_value= "<<minValue<<endl;if(maxValue>=0.7)rectangle(showImg, maxLoc, Point(maxLoc.x + templateImg.cols, maxLoc.y + templateImg.rows), Scalar(0, 255, 0), 2);imshow("frame", frame);imshow("result", showImg);if(27 == waitKey(10))break;}destroyAllWindows();waitKey(0);return 0;
}

6、多模板匹配


//多模板匹配
#include "opencv2/opencv.hpp"
#include <iostream>
#include <stdio.h>using namespace std;
using namespace cv;int main()
{Mat srcImg = imread("E://src.png");Mat templateImg = imread("E://temp.png");Mat resultImg;Mat showImg = srcImg.clone();int resultImg_cols = srcImg.cols -  templateImg.cols + 1;int resultImg_rows = srcImg.rows -  templateImg.rows + 1;resultImg.create(resultImg_cols, resultImg_rows, CV_32FC1);matchTemplate(srcImg, templateImg, resultImg, CV_TM_CCOEFF_NORMED); //化相关系数匹配法(最好匹配1)normalize(resultImg, resultImg, 0, 1, NORM_MINMAX);Mat midImg = resultImg.clone();//多目标模板匹配---方法一/*double matchValue;int count0=0;int tempW=0, tempH=0;char matchRate[10];for(int i=0; i<resultImg_rows; i++){for(int j=0; j<resultImg_cols; j++){matchValue = resultImg.at<float>(i, j);sprintf(matchRate, "%0.2f", matchValue);if(matchValue>=0.85 && (abs(j - tempW)>5) && (abs(i - tempH)>5) ){count0++;putText(showImg, matchRate, Point(j-5, i-5), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 1);rectangle(showImg, Point(j, i), Point(j + templateImg.cols, i + templateImg.rows), Scalar(0, 255, 0), 2);tempW = j;tempH = i;}}}cout<<"count="<<count0<<endl;imshow("resultImg", resultImg);imshow("dst", showImg);*///多目标模板匹配---方法二double minValue, maxValue;Point minLoc, maxLoc;Point matchLoc;char matchRate[10];for(int i=0; i<100; i++){int startX = maxLoc.x - 4;int startY = maxLoc.y - 4;int endX = maxLoc.x + 4;int endY = maxLoc.y + 4;if(startX<0 || startY<0){startX = 0;startY = 0;}if(endX > resultImg.cols - 1 || endY > resultImg.rows - 1){endX = resultImg.cols - 1;endY = resultImg.rows- 1;}Mat temp = Mat::zeros(endX - startX, endY - startY, CV_32FC1);//Mat ROI = resultImg(Rect(Point(startX, startY), temp.cols, temp.rows));temp.copyTo(resultImg(Rect(startX, startY, temp.cols, temp.rows)));minMaxLoc(resultImg, &minValue, &maxValue, &minLoc, &maxLoc);if(maxValue<0.8)    break;cout<<"max_value= "<<maxValue<<endl;sprintf(matchRate, "%0.2f", maxValue);putText(showImg, matchRate, Point(maxLoc.x - 5, maxLoc.y - 5), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 1);rectangle(showImg, maxLoc, Point(maxLoc.x + templateImg.cols, maxLoc.y + templateImg.rows), Scalar(0, 255, 0), 2);}imshow("midImg", midImg);imshow("resultImg", resultImg);imshow("dst", showImg);waitKey(0);return 0;
}

轮廓查找与绘制

1、轮廓的相关概念

1)什么是轮廓

  轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度,提取轮廓就是提取这些具有相同颜色或者灰度的曲线,或者说是连通域,轮廓在形状分析和物体的检测和识别中非常有用。

2)注意事项:

  ①为了更加准确,要使用二值化图像。在寻找轮廓之前,要进行阈值化处理 或者 Canny 边界检测

  ②查找轮廓的函数会修改原始图像。如果你在找到轮廓之后还想使用原始图像的话,你应该将原始图像存储到其他变量中(clone(), copyTo())

  ③在OpenCV 中,查找轮廓就像在黑色背景中找白色物体。你应该记住,要找的物体应该是白色而背景应该是黑色。

3)常用函数:

  findContours()—–查找轮廓

   drawContours()—–绘制轮廓

2、查找轮廓


void findContours(InputArray image, OutputArrayofArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point());

  image: 输入图像, Mat类型8位单通道图像(一般为二值图)

  contours: 检测到的轮廓, 每个轮廓存储为一个点向量, 即Point类型的vector表示

  hierarchy: 可选的输出向量, 包含图像的拓扑信息。其作为轮廓数量的表示, 包含了许多元素, 每个轮廓contours[i]对应4个hierarchy元素hierarchy[i][0]~hierarchy[i][3], 分别表示后一轮廓、前一轮廓、父轮廓、内嵌轮廓的索引编号, 如果没有对应项, 设置为负数

  mode: 轮廓检索模式, 取值如下:


CV_RETR_EXTERNAL=0-----表示只检测最外层轮廓   
CV_RETR_LIST=1------提取所有轮廓并放置在list中, 轮廓不建立等级关系
CV_RETR_CCOMP=2------提取所有轮廓并组织为双层结构   
CV_RETR_TREE=3------提取所有轮廓并重新建立网状轮廓结构 

  method: 轮廓的近似方法, 取值如下:


CV_CHAIN_APPROX_NONE ---连续存储所有的轮廓点,任何两个相邻的点都是水平、垂直或者相邻的。也就是说max(abs(x1-x2), abs(y2-y1)) == 1
CV_CHAIN_APPROX_SIMPLE --- 压缩存储,对于水平、垂直或者斜向的线段,比如一个四边形,只会存储四个顶点
CV_CHAIN_APPROX_TC89_L1/CV_CHAIN_APPROX_TC89_KCOS        

  offset: 每个轮廓的可选偏移量, 默认值Point()

3、绘制轮廓


1 CV_EXPORTS_W void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point());

  image: 目标图像, Mat类型对象即可

  contours: 所有的输入轮廓, 每个轮廓存储为一个点向量

  contourIdx: 轮廓绘制指示变量(索引), 若为负值, 则表示绘制所有轮廓

  color: 绘制轮廓的颜色

  thickness: 轮廓线条的粗细, 默认值1, 如果为负值, 则绘制轮廓内部, 可选宏 CV_FILLED

  lineType: 线条类型, 默认值8

  hierarcy: 可选的层次结构信息, 默认值noArray()

  maxLevel: 表示用于绘制轮廓的最大等级, 默认值INT_MAX

  offset: 可选的轮廓偏移参数, 默认值Point()


//轮廓查找  轮廓绘制
#include"opencv2/opencv.hpp"
#include<iostream>using namespace std;
using namespace cv;int main()
{Mat srcImg = imread("2.png");Mat tempImg = srcImg.clone();//Mat draw(srcImg.rows, srcImg.cols, CV_8UC3);cvtColor(srcImg, srcImg, CV_BGR2GRAY); //转为灰度图threshold(srcImg, srcImg,100, 255, CV_THRESH_BINARY);//图像二值化,value>threshold(即100)?255:0imshow("srcImg", srcImg);  //轮廓查找前vector<vector<Point>> contours;vector<Vec4i> hierarchy;//findContours(srcImg, contours, hierarchy,RETR_EXTERNAL, CHAIN_APPROX_SIMPLE ); //查找外轮廓,压缩存储轮廓点findContours(srcImg, contours, hierarchy,RETR_LIST, CHAIN_APPROX_SIMPLE ); //查找所有轮廓//findContours(srcImg, contours, hierarchy,CV_RETR_CCOMP, CHAIN_APPROX_SIMPLE ); //查找所有轮廓//findContours(srcImg, contours, hierarchy,RETR_TREE, CHAIN_APPROX_NONE ); //查找所有轮廓,存储所有轮廓点imshow("cont", srcImg);  //轮廓查找后drawContours(tempImg, contours,-1, Scalar(0, 255, 0),2);  //绘制轮廓:-1代表绘制所有轮廓cout<<"num="<<contours.size()<<endl; //输出轮廓个数imshow("contours", tempImg);waitKey(0);return 0;
}

附录:

QT集合OpenCV库


# 添加我们包含路径
INCLUDEPATH += D:\Application\opencvdev\opencv3.4.6\rebuild_for_qt\install\include
# 添加对应类库文件
LIBS += D:\Application\opencvdev\opencv3.4.6\rebuild_for_qt\lib\libopencv_*.a
上面配置的磁盘路径是你电脑编译OpenCV的路径

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

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

相关文章

Composer 常规操作说明与问题处理

目录 一、 Composer 简介&#xff0c;安装二、全局配置三、项目配置&#xff08;composer.json&#xff09;3.1 composer.json 文件1. 基础字段信息2. **require&#xff08;生产环境依赖&#xff09;**3. **require-dev&#xff08;开发环境依赖&#xff09;** 3.2 composer.l…

Spring Boot 3.0与Java 17:企业级应用开发的新范式

引言 随着Spring Boot 3.0和Java 17的正式发布&#xff0c;企业级应用开发迎来了新的技术范式。这两项技术的结合不仅带来了性能提升&#xff0c;还引入了众多现代化的编程特性&#xff0c;为开发者提供了更强大、更高效的开发体验。本文将深入探讨Spring Boot 3.0与Java 17的…

Vue 组件 - 指令

Vue 渐进式JavaScript 框架 基于Vue2的学习笔记 - Vue指令 目录 指令写法 自定义指令 简单封装指令 指令传递字符串 update事件 指令应用 指令实现轮播 指令函数简写 指令函数列表 bind inserted update componentUpdated unbind Vue3指令轮播 nextick 总结 指…

5.28 后端面经

为什么golang在并发环境下更有优势 Go语言&#xff08;Golang&#xff09;在并发环境下的优势主要源自其设计哲学和内置的并发机制&#xff0c;这些机制在语言层面提供了高效、简洁且安全的并发编程工具。以下是其核心优势的详细分析&#xff1a; 1. Goroutine&#xff1a;轻量…

Linux线程入门

目录 Linux线程概念 什么是线程 重新理解进程 线程的优点 线程的缺点 线程的异常 线程用途 Linux线程概念 什么是线程 在一个程序里的一个执行路线就叫做线程&#xff08;thread&#xff09;。更准确的定义是&#xff1a;线程是“一个进程内部的控制序列”。一切进程至…

通信应用高速模数转换器ADC

在5G通信、医疗成像、航空航天及工业自动化等关键领域&#xff0c;高速ADC模数转换器作为信号链的“心脏”&#xff0c;其性能直接决定了系统的精度与效率。然而&#xff0c;如何精确测试高速ADC的动态参数、优化设计验证流程、应对复杂应用场景的挑战&#xff0c;始终是工程师…

PostgreSQL 中 JSONB 数据类型的深度解析以及如何使用

一、JSONB 核心特性解析 1. 存储结构与优势 ​​二进制存储​​&#xff1a;将 JSON 数据解析为二进制格式&#xff08;分解键值对&#xff0c;去除空格和重复键&#xff09;​​高效查询​​&#xff1a;支持 GIN/GiST 索引&#xff0c;查询速度比 JSON 类型快 10 倍​​数据…

C++_核心编程_ 左移运算符重载 “<<” 左移运算符

作用&#xff1a;可以输出自定义数据类型 */ //目标 调用p1,输出Person 中的属性 m_A ,m_B &#xff1a; /* #### 4.5.2 左移运算符重载 “<<” 左移运算符 作用&#xff1a;可以输出自定义数据类型 *///目标 调用p1,输出Person 中的属性 m_A ,m_B &#xff1a; class…

thinkphp 5.1 部分知识记录<一>

1、配置基础 惯例配置->应用配置->模块配置->动态配置 惯例配置:核心框架内置的配置文件,无需更改。应用配置:每个应用的全局配置文件(框架安装后会生成初始的应用配置文件),有部分配置参数仅能在应用配置文件中设置。模块配置:每个模块的配置文件(相同的配置…

数据结构 -- 树相关面试题

二、树相关的填空题 1.对于一个具有 n 个结点的二叉树&#xff0c;当它为一棵 ________ 二叉树时&#xff0c;具有最小高度&#xff0c;即为 ________&#xff1b;当它为一棵单支树时具有最大高度&#xff0c;即为 ________。 2.对于一个具有 n 个结点的二叉树&#xff0c;当它…

2025河北CCPC 题解(部分)

签到题&#xff1a;AC代码如下 &#xff1a; // Problem: H - What is all you need? // Contest: Virtual Judge - sdccpc20250526 // URL: https://vjudge.net/contest/718568#problem/H // Memory Limit: 1024 MB // Time Limit: 1000 ms // // Powered by CP Editor (ht…

计算机视觉---YOLOv4

YOLOv4&#xff08;You Only Look Once v4&#xff09;于2020年由Alexey Bochkovskiy等人提出&#xff0c;是YOLO系列的重要里程碑。它在YOLOv3的基础上整合了当时最先进的计算机视觉技术&#xff0c;实现了检测速度与精度的显著提升。以下从主干网络、颈部网络、头部检测、训练…

OpenCV 第7课 图像处理之平滑(一)

1. 图像噪声 在采集、处理和传输过程中,数字图像可能会受到不同噪声的干扰,从而导致图像质量降低、图像变得模糊、图像特征被淹没,而图像平滑处理就是通过除去噪声来达到图像增强的目的。常见的图像噪声有椒盐噪声、高斯噪声等。 1.1 椒盐噪声 椒盐噪声(Salt-and-pepper N…

Spring AI 系列3: Promt提示词

一、Promt提示词 Promt提示是引导 AI 模型生成特定输出的输入&#xff0c; 提示的设计和措辞会显著影响模型的响应。 在 Spring AI 中与 AI 模型交互的最低层级&#xff0c;处理提示有点类似于在 Spring MVC 中管理”视图”。 这涉及创建带有动态内容占位符的大段文本。 这些占…

随叫随到的电力补给:移动充电服务如何重塑用户体验?

在快节奏的现代生活中&#xff0c;电力已成为维系日常运转的隐形血脉。智能手机、电动汽车、便携设备的普及&#xff0c;让“电量焦虑”逐渐演变为一种时代症候。而移动充电服务的兴起&#xff0c;正悄然改变这一局面。它像一位隐形的能源管家&#xff0c;随时响应需求&#xf…

LeetCode 75. 颜色分类 - 双指针法高效解决(Java实现)

文章目录 问题描述算法思路&#xff1a;三指针分区法核心思想指针定义 Java实现算法执行流程关键问题解析&#xff1a;为什么交换0后不需要重新检查&#xff1f;交换0时的两种情况分析详细解释&#xff1a; 复杂度分析示例演示&#xff08;输入&#xff1a;[2,0,2,1,1,0]&#…

【MySQL】C语言连接

要使用C语言连接mysql&#xff0c;需要使用mysql官网提供的库&#xff0c;大家可以去官网下载 我们使用C接口库来进行连接 要正确使用&#xff0c;我们需要做一些准备工作: 保证mysql服务有效在官网上下载合适自己平台的mysql connect库&#xff0c;以备后用 下载开发库 s…

NFS 挂载配置与优化最佳实践指南

文章目录 NFS 挂载配置与优化最佳实践指南1. 服务器端配置1.1 安装 NFS 服务1.2 配置共享目录常用配置选项说明 1.3 启动与检查服务 2. 客户端挂载2.1 安装 NFS 客户端2.2 挂载 NFS 共享2.3 自动挂载 3. 客户端挂载选项4. 性能优化与故障排查4.1 性能优化建议4.2 常见问题排查 …

3D PDF如何制作?SOLIDWORKS MBD模板定制技巧

SOLIDWORKS制作3D PDF模版 SOLIDWORKS MBD能够帮助工程师以清晰直观的方式描述产品尺寸信息。在3D PDF文件中&#xff0c;用户可以自由旋转和移动视图&#xff0c;方便查看模型的各个尺寸细节。 本文将带您一步步学习如何使用SOLIDWORKS MBD制作专业的3D PDF模板&#xff0c;…

Unity-QFramework框架学习-MVC、Command、Event、Utility、System、BindableProperty

QFramework QFramework简介 QFramework是一套渐进式、快速开发框架&#xff0c;适用于任何类型的游戏及应用项目&#xff0c;它包含一套开发架构和大量的工具集 QFramework的特性 简洁性&#xff1a;QFramework 强调代码的简洁性和易用性&#xff0c;让开发者能够快速上手&a…