《Opencv3编程入门》学习笔记—第九章

news2024/12/25 10:49:56

《Opencv3编程入门》学习笔记

记录一下在学习《Opencv3编程入门》这本书时遇到的问题或重要的知识点。

第九章 直方图与匹配

一、图像直方图概述

1、作用:
  在每个兴趣点设置一个有相近特征的直方图所构成的标签,通过标记帧与帧之间显著的边缘、颜色、角度等特征的统计变化,来检测视频中场景的变化。
2、概念:
  图像直方图是图像中像素强度分布的图形表达方式,统计了每一个强度值所具有的像素个数,并将统计结果分布于一系列预定义的bins中。直方图中,横坐标的左侧为纯黑较暗区域,右侧为纯白较亮区域。
3、术语:
(1)dims:需要统计的特征数目
(2)bins:每个特征空间子区段的数目,称为“直条”或“组距”
(3)Range:每个特征空间的取值范围
4、例如:
  假设一个矩阵包含一张图像的信息(灰度值0-255),已知数字范围包含256个值,将范围分成子区域(bins),然后统计每个bin的像素数目,如:
在这里插入图片描述

二、直方图的计算与绘制

使用calcHist()函数

(一)计算直方图:calcHist()函数

计算一个或多个阵列的直方图

void calcHist(const Mat* image, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false)

(1)输入数组(集)
(2)输入数组个数
(3)需要统计的通道(dim)索引,第一个数组通道从0到images[0].channels()-1,第二个数组通道从images[0].channels()计算到images[0].channels()+images[1].channels()-1。
(4)可选的操作掩码,为空或与images[i]同样大小的8位数组,非零掩码元素用于标记出统计直方图的数组元素数据。
(5)输出的目标直方图,二维数组
(6)需要计算的直方图维度,必须是正数且不大于CV_MAX_DIMS
(7)存放每个维度的直方图尺寸的数组
(8)表示每一个维度数组的每一维的边界阵列,即每一位数组的取值范围
(9)指示直方图是否均匀的标识符,默认true
(10)累计标识符,默认值false,为true时直方图在配置阶段不会被清零,主要是允许从多个阵列中计算单个直方图,或用于在特定时间更新直方图。

(二)找寻最值:minMaxLoc()函数

在数组中找到全局最小/大值

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

(1)输入的单通道阵列
(2)返回最小值的指针,若无需返回则置为NULL
(3)返回最大值的指针,若无需返回则置为NULL
(4)返回最小位置的指针,若无需返回则置为NULL
(5)返回最大位置的指针,若无需返回则置为NULL
(6)用于选择子阵列的可选掩模

(三)示例程序:绘制H-S直方图

即“色调(Hue)—饱和度(Saturation)直方图”
示例代码

/*
程序说明:计算彩色图像的色调(Hue)-饱和度(Saturation)二维直方图
*/
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;

int main()
{
	//【1】载入原图,转化为HSV颜色模型
	Mat srcImage, hsvImage;
	srcImage = imread("D://lili/Desktop/jpg/opencv/10.jpg");
	cvtColor(srcImage, hsvImage, COLOR_RGB2HSV);
	
	//【2】参数准备
	//定义存储直方图的数据结构(单通道阵列) MatND是多维矩阵
	MatND dstHist;
	//将色调量化为30个等级,将饱和度量化为32个等级
	int hueBinNum = 30;//色调直方图直条数量
	int saturationBinNum = 32;//饱和度直方图直条数量
	int histSize[] = { hueBinNum,saturationBinNum };
	//定义变化范围
	float hueRanges[] = { 0,180 };//定义色调的变化范围为0-179
	float saturationRanges[] = { 0,256 };//定义饱和度的变化范围为0-255
	const float* ranges[] = { hueRanges,saturationRanges };
	//calcHist函数中将计算第0通道和第1通道的直方图
	int channels[] = { 0,1 };

	//【3】正式调用calcHist,进行直方图计算
	//输入数组,数组个数为1,通道索引,不使用掩模,输出目标直方图,需要计算的直方图维度为2,存放每个维度的直方图尺寸的数组,每一维数组的取值范围数组,指示直方图均匀,直方图在配置阶段会被清零
	calcHist(&hsvImage, 1, channels, Mat(), dstHist, 2, histSize, ranges, true, false);

	//【4】绘制直方图准备参数
	double maxValue = 0;//最大值
	minMaxLoc(dstHist, 0, &maxValue, 0, 0);//查找数组和子数组的全局最大值存入maxValue中
	int scale = 10;
	Mat histImage = Mat::zeros(saturationBinNum*scale, hueBinNum * 10, CV_8UC3);

	//【5】双层循环,进行直方图绘制(如何绘制有些没太理解?)
	for (int hue = 0; hue < hueBinNum; hue++)
	{
		for (int saturation = 0; saturation < saturationBinNum; saturation++)
		{
			float binValue = dstHist.at<float>(hue, saturation);//直方图直条的值
			int intensity = cvRound(binValue * 255 / maxValue);//强度
			//正式绘制
			rectangle(histImage, Point(hue*scale, saturation*scale), Point((hue + 1)*scale - 1, (saturation+1)*scale - 1), Scalar::all(intensity), 1);
		}	
	}
	//【6】显示效果图
	imshow("素材图", srcImage);
	imshow("H-S直方图", histImage);

	waitKey(0);
	return 0;
}

运行效果
在这里插入图片描述

(四)示例程序:计算并绘制图像一维直方图

示例代码

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;

int main()
{
	//【1】载入原灰度图并显示
	Mat srcImage = imread("D://lili/Desktop/jpg/opencv/10.jpg", 0);
	if (!srcImage.data)
	{
		printf("载入原图失败~!\n");
		return  false;
	}
	imshow("【原始图】", srcImage);

	//【2】定义变量
	MatND dstHist;
	int dims = 1;
	float hranges[] = { 0,255 };
	const float *ranges[] = { hranges };
	int size = 256;
	int channels = 0;

	//【3】计算图像的直方图
	calcHist(&srcImage, 1, &channels, Mat(), dstHist, dims, &size, ranges, true, false);
	int scale = 1;
	Mat dstImage(size*scale, size, CV_8U, Scalar(0));

	//【4】获取最大值和最小值
	double minValue = 0;
	double maxValue = 0;
	minMaxLoc(dstHist, &minValue, &maxValue, 0, 0);

	//【5】绘制出直方图
	int hpt = saturate_cast<int>(0.9*size);
	for (int i = 0; i < 256; i++)
	{
		float binValue = dstHist.at<float>(i);
		int realValue = saturate_cast<int>(binValue*hpt / maxValue);
		rectangle(dstImage, Point(i*scale, size - 1), Point((i + 1)*scale - 1, size - realValue), Scalar(255));
	}
	imshow("一维直方图", dstImage);

	waitKey(0);
	return 0;
}

运行效果
在这里插入图片描述

(五)示例程序:绘制RGB三色直方图

示例代码

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;

int main()
{
	//【1】载入原图并显示
	Mat srcImage = imread("D://lili/Desktop/jpg/opencv/10.jpg");
	imshow("【原始图】", srcImage);
	//【2】初始化直方图计算参数
	int bins = 256;
	int hist_size[] = { bins };
	float range[] = { 0,256 };
	const float* ranges[] = { range };
	MatND redHist, grayHist, blueHist;
	
	//【3】进行直方图计算(红色分量部分)
	int channels_r[] = { 0 };
	calcHist(&srcImage, 1, channels_r, Mat(), redHist, 1, hist_size, ranges, true, false);

	//【4】进行直方图计算(绿色分量部分)
	int channels_g[] = { 1 };
	calcHist(&srcImage, 1, channels_g, Mat(), grayHist, 1, hist_size, ranges, true, false);

	//【5】进行直方图计算(蓝色分量部分)
	int channels_b[] = { 2 };
	calcHist(&srcImage, 1, channels_b, Mat(), blueHist, 1, hist_size, ranges, true, false);

	//绘制三色直方图
	//参数准备
	double maxValue_red, maxValue_green, maxValue_blue;
	minMaxLoc(redHist, 0, &maxValue_red, 0, 0);
	minMaxLoc(grayHist, 0, &maxValue_green, 0, 0);
	minMaxLoc(blueHist, 0, &maxValue_blue, 0, 0);
	
	int scale = 1;
	int histHeight = 256;
	Mat histImage = Mat::zeros(histHeight, bins * 3, CV_8UC3);

	//正式绘制
	for (int i = 0; i < bins; i++)
	{
		//参数准备
		float binValue_red = redHist.at<float>(i);
		float binValue_green = grayHist.at<float>(i);
		float binValue_blue = blueHist.at<float>(i);
		int intensity_red = cvRound(binValue_red*histHeight / maxValue_red);//要绘制的高度
		int intensity_green = cvRound(binValue_green*histHeight / maxValue_green);//要绘制的高度
		int intensity_blue = cvRound(binValue_blue*histHeight / maxValue_blue);//要绘制的高度
		
		//绘制红色分量的直方图
		rectangle(histImage, Point(i*scale, histHeight - 1), Point((i + 1)*scale - 1, histHeight - intensity_red), Scalar(255, 0, 0));
		//绘制绿色分量的直方图
		rectangle(histImage, Point((i + bins)*scale, histHeight - 1), Point((i + bins + 1)*scale - 1, histHeight - intensity_green), Scalar(0, 255, 0));
		//绘制蓝色分量的直方图
		rectangle(histImage, Point((i + bins * 2)*scale, histHeight - 1), Point((i + bins * 2 + 1)*scale - 1, histHeight - intensity_blue), Scalar(0, 0, 255));
	}
	//显示直方图
	imshow("图像的RGB直方图", histImage);

	waitKey(0);
	return 0;
}

运行效果
在这里插入图片描述

三、直方图对比

应用某些具体的标准比较两个直方图的相似度。
compareHist()函数 返回值d(H1,H2)

(一)对比直方图:compareHist()函数

1、作用:比较两幅直方图
2、函数原型:

double compareHist(InputArray H1,InputArray H2, int method)
double compareHist(const SpareMat& H1, const SpareMat& H2, int method)

3、参数说明:
(1)直方图1
(2)直方图2
(3)距离标准,4种,其中Correlation和Intersection标准值越大表示相似度越高:

  • 相关,Correlation(method=CV_COMP_CORREL)
    在这里插入图片描述
    其中:
    在这里插入图片描述
    N等于直方图中bin的个数
  • 卡方,Chi-Square(method=CV_COMP_CHISQR)
    在这里插入图片描述
  • 直方图相交,Intersection(method-CV_COMP_INTERSECT)
  • Bhattacharyya距离,(method=CV_COMP_BHATTACHARYYA)
    Bhattacaryya距离与Hellinger距离相关,也可写作method=CV_COMP_HELLINGER
    在这里插入图片描述

(二)示例程序:直方图对比

示例代码

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;

int main()
{
	//【1】声明储存基准图像和另外两张对比图象的矩阵(RGB和HSV)
	Mat srcImage_base, hsvImage_base;
	Mat srcImage_test1, hsvImage_test1;
	Mat srcImage_test2, hsvImage_test2;
	Mat hsvImage_halfDown;

	//【2】载入基准图像和两张测试图像并显示
	srcImage_base = imread("D://lili/Desktop/jpg/opencv/13.jpg", 1);
	srcImage_test1 = imread("D://lili/Desktop/jpg/opencv/14.jpg", 1);
	srcImage_test2 = imread("D://lili/Desktop/jpg/opencv/15.jpg", 1);
	imshow("基准图像", srcImage_base);
	imshow("测试图像1", srcImage_test1);
	imshow("测试图像2", srcImage_test2);

	//【3】将图像由BGR色彩空间转换到HSV色彩空间
	cvtColor(srcImage_base, hsvImage_base, COLOR_RGB2HSV);
	cvtColor(srcImage_test1, hsvImage_test1, COLOR_RGB2HSV);
	cvtColor(srcImage_test2, hsvImage_test2, COLOR_RGB2HSV);

	//【4】创建包含基准图像下半部的半身图像(HSV格式)
	hsvImage_halfDown = hsvImage_base(Range(hsvImage_base.rows / 2, hsvImage_base.rows - 1), Range(0, hsvImage_base.cols - 1));

	//【5】初始化计算直方图需要的实参
	//对hue通道使用30个bin,对saturation通道使用32个bin
	int h_bins = 50;
	int s_bins = 60;
	int histSize[] = { h_bins,s_bins };
	//hue取值范围0-256,saturation取值范围0-180
	float h_ranges[] = { 0,256 };
	float s_ranges[] = { 0,180 };
	const float* ranges[] = { h_ranges,s_ranges };
	//使用第0和1通道
	int channels[] = { 0,1 };

	//【6】创建存储直方图的MatND类实例
	MatND baseHist, testHist1, testHist2, halfDownHist;

	//【7】计算基准图像,两张测试图像,半身基准图像的HSV直方图
	calcHist(&hsvImage_base, 1, channels, Mat(), baseHist, 2, histSize, ranges, true, false);
	normalize(baseHist, baseHist, 0, 1, NORM_MINMAX, -1, Mat());
	calcHist(&hsvImage_test1, 1, channels, Mat(), testHist1, 2, histSize, ranges, true, false);
	normalize(testHist1, testHist1, 0, 1, NORM_MINMAX, -1, Mat());
	calcHist(&hsvImage_test2, 1, channels, Mat(), testHist2, 2, histSize, ranges, true, false);
	normalize(testHist2, testHist2, 0, 1, NORM_MINMAX, -1, Mat());
	calcHist(&hsvImage_halfDown, 1, channels, Mat(), halfDownHist, 2, histSize, ranges, true, false);
	normalize(halfDownHist, halfDownHist, 0, 1, NORM_MINMAX, -1, Mat());

	//【8】按顺序使用4种对比标准将基准图像的直方图与其余各直方图进行对比
	for (int i = 0; i < 4; i++)
	{
		//进行图像直方图的对比
		int compare_method = i;
		double base_base = compareHist(baseHist, baseHist, compare_method);
		double base_test1 = compareHist(baseHist, testHist1, compare_method);
		double base_test2 = compareHist(baseHist, testHist2, compare_method);
		double base_half = compareHist(baseHist, halfDownHist, compare_method);
		//输出结果
		printf("方法[%d]的匹配结果如下:\n\n【基准图-基准图】:%f,【基准图-测试图1】:%f,【基准图-测试图2】:%f,【基准图-半身图】:%f\n", i, base_base, base_test1, base_test2, base_half);
		printf("----------------------------------------------------------------------------------------------------------------------------------\n");
	}
	printf("检测结束\n");
	waitKey(0);
	return 0;
}

运行效果
在这里插入图片描述

在这里插入图片描述

四、反向投影

(一)引言

所谓反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征的方法。

(二)反向投影的工作原理

EG:H-S肤色直方图
在这里插入图片描述

使用模型直方图(代表手掌的皮肤色调)来检测测试图像中的皮肤区域。以下是检测步骤
(1)对图像中每个像素(p(i,j)),获取色调数据并找到该色调/饱和度在直方图中的bin的位置
(2)查询模型直方图中对应的bin的数值
(3)将此数值存储在新的反射投影图像中。也可以先归一化直方图数值到0-255范围内,这样可以直接显示反射投影图像
(4)通过对图像中的每个像素执行以上步骤,可以得到最终的反射投影图像,如图所示:
在这里插入图片描述

(5)使用统计学语言进行分析,反向投影中储存的数值代表了图像中该像素属于区域的概率

(三)反向投影的作用

在输入图像中查找与特定图像最匹配的点或区域,即定位模板图像出现在输入图像的位置

(四)反向投影的结果

包含了以每个输入图像像素点为起点的直方图对比结果的二维浮点型数组/二维矩阵/单通道浮点型图像

(五)计算反向投影:calcBackProject()函数

计算直方图反向投影

void calcBackProject(const Mat* image, int nimages, const int* channels, InputArray hist, OutputArray backProject, const float** ranges, double scale=1, bool uniform=true)

(1)输入数组(集)
(2)输入数组个数
(3)需要统计的通道(dim)索引,第一个数组通道从0到images[0].channels()-1,第二个数组通道从images[0].channels()计算到images[0].channels()+images[1].channels()-1。
(4)输入直方图
(5)目标反向投影阵列,单通道且与image[0]大小深度相同
(6)表示每一个维度数组的每一维的边界阵列,即每一维数值的取值范围
(7)输出方向投影可选的缩放因子,默认1
(8)指示直方图是否均匀的标识符,默认true

(六)通道复制:mixChannels()函数

由输入参数复制到某通道到输出参数特定的通道中,实现图像通道重排

1void mixChannels(const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, const int* fromTo, size_t npairs)2void mixChannels(const vector<Mat>& src, vector<Mat>& dst, const int* fromTo, size_t npairs)

参数说明1:
(1)输入数组
(2)src输入的矩阵数
(3)输出的数组,所有矩阵必须被初始化,且大小和深度必须与src[0]相同
(4)dst输入的矩阵数
(5)对指定的通道进行复制的数组索引
(6)参数fromTo的索引数

参数说明2:
(1)输入的矩阵向量
(2)输出的矩阵向量,所有矩阵必须被初始化,且大小和深度必须与src[0]相同
(3)对指定的通道进行复制的数组索引
(4)参数fromTo的索引数

示例:将一个4通道RGBA图像转化为3通道BGR和一个单独的Alpha通道图像

Mat rgba(100, 100, CV_8UC4, Scalar(1, 2, 3, 4));
Mat bgr(rgba.rows, rgba.cols, CV_8UC3);
Mat alpha(rgba.rows, rgba.cols, CV_8UC1);
//组成矩阵数组操作
Mat out[] = { bgr,alpha };
//说明:将rgba[0]->bgr[2],rgba[1]->bgr[1],将rgba[0]->bgr[0],rgba[3]->alpha[0]
int from_to[] = { 0,2,1,1,2,0,3,3 };
mixChannels{ &rgba,1,out,2,from_to,4 };

(七)综合程序:反向投影

略懂
示例代码

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
//定义辅助宏
#define WINDOW_NAME1 "【原始图】"
#define WINDOW_NAME2 "【反向投影图】"
//全局变量
Mat g_srcImage, g_hsvImage, g_hueImage;
int g_bins = 30;//直方图组距
//全局函数
void on_BinChange(int, void*);
int main()
{
	//【1】载入原图,转换到HSV空间
	g_srcImage = imread("D://lili/Desktop/jpg/opencv/5.jpg", 1);
	if (!g_srcImage.data)
	{
		printf("载入原图失败~!\n");
		return false;
	} 
	cvtColor(g_srcImage, g_hsvImage, COLOR_BGR2HSV);
	//【2】分离Hue色调通道
	g_hueImage.create(g_hsvImage.size(), g_hsvImage.depth());
	int ch[] = { 0,0 };
	mixChannels(&g_hsvImage, 1, &g_hueImage, 1, ch, 1);
	//【3】创建Trackbar来输入bin的数目
	namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE);
	createTrackbar("色调组距", WINDOW_NAME1, &g_bins, 180, on_BinChange);
	on_BinChange(0, 0);
	//【4】显示原图
	imshow(WINDOW_NAME1, g_srcImage);

	waitKey(0);
	return 0;
}
void on_BinChange(int, void*)
{
	//【1】参数准备
	MatND hist;
	int histSize = MAX(g_bins, 2);
	float hue_range[] = { 0,180 };
	const float* ranges = { hue_range };
	//【2】计算直方图并归一化
	calcHist(&g_hueImage, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false);
	normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat());
	//【3】计算反向投影
	MatND backproj;
	calcBackProject(&g_hueImage, 1, 0, hist, backproj, &ranges, 1, true);
	//【4】显示反向投影
	imshow(WINDOW_NAME2, backproj);
	//【5】绘制直方图的参数准备
	int w = 400, h = 400;
	int bin_w = cvRound((double)w / histSize);
	Mat histImg = Mat::zeros(w, h, CV_8UC3);
	//【6】绘制直方图
	for (int i = 0; i < g_bins; i++)
	{
		rectangle(histImg, Point(i*bin_w, h), Point((i + 1)*bin_w, h - cvRound(hist.at<float>(i)*h / 255.0)), Scalar(100, 123, 255), -1);
	}
	//【7】显示直方图窗口
	imshow("直方图", histImg);
}

运行效果
在这里插入图片描述

五、模版匹配

(一)模版匹配的概念与原理

基本思想:在一幅图像中寻找与另一幅模板图像最匹配的部分,通过在输入图像上滑动图像块,对实际的图像块和输入图像进行匹配。

(二)实现模版匹配:matchTemplate()函数

匹配出和模板重叠的图像区域

void matchTemplate(InputArray image, InputArray templ, OuputArray result, int method)

(1)带搜索图像,8位或32位浮点型
(2)搜索模板,与原图像数据类型相同,尺寸不大于原图像
(3)比较结果的映射图像,单通道32位浮点型图像,如果图像尺寸为WH,而templ尺寸为wh,则参数一定为(W-w+1)*(H-h+1).
(4)指定的匹配方法,6种方法越来越准确,计算量越来越大:

  • 平方差匹配法 method=TM_SQDIFF
        匹配越差,匹配值越大,最好匹配为0
    在这里插入图片描述
  • 归一化平方差匹配法 method=TM_SQDIFF_NORMED
    在这里插入图片描述
  • 相关匹配法 method=TM_CCORR
        采用模板和图像间的乘法操作,较大的数表示匹配程度较高,最坏匹配为0
    在这里插入图片描述
  • 归一化相关匹配法 method=TM_CCORR_NORMED
    在这里插入图片描述
  • 系数匹配法 method=TM_CCOEFF
        将模板对其均值的相对值与图像对其均值的相关值进行匹配,1表示完美匹配,-1表示糟糕匹配,0表示无相关性(随机序列)
    在这里插入图片描述
    其中:
    在这里插入图片描述  在这里插入图片描述
  • 归一化相关系数匹配法 method=TM_CCOEFF_NORMED
                  
    在这里插入图片描述

(三)综合示例:模版匹配

就类似kmp字符串匹配
示例代码

/*
    程序说明:模板匹配,滑动条选择匹配方法
*/
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
//定义辅助宏
#define WINDOW_NAME1 "【原始图窗口】"
#define WINDOW_NAME2 "【效果图窗口】"
//全局变量
Mat g_srcImage, g_templateImage, g_dstImage;
int g_nMatchmethod;
int g_nMaxTrackbarNum = 5;
//全局函数
void on_Matching(int, void*);
void ShowHelpText();

int main()
{
	//显示帮助文字
	ShowHelpText();
	//载入原图和模板块
	g_srcImage = imread("D://lili/Desktop/jpg/opencv/2.jpg", 1);
	g_templateImage = imread("D://lili/Desktop/jpg/opencv/16.jpg", 1);
	//创建窗口
	namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE);
	namedWindow(WINDOW_NAME2, WINDOW_AUTOSIZE);
	//创建滑动条并初始化
	createTrackbar("方法", WINDOW_NAME1, &g_nMatchmethod, g_nMaxTrackbarNum, on_Matching);
	on_Matching(0, 0);

	waitKey(0);
	return 0;
}
void on_Matching(int, void*)
{
	//[【1】给局部变量初始化
	Mat srcImage;
	g_srcImage.copyTo(srcImage);
	//【2】初始化用于结果输出的矩阵
	int dstImage_cols = g_srcImage.cols - g_templateImage.cols + 1;
	int dstImage_rows = g_srcImage.rows - g_templateImage.rows + 1;
	g_dstImage.create(dstImage_cols, dstImage_rows, CV_32FC1);
	//【3】进行匹配和标准化
	matchTemplate(g_srcImage, g_templateImage, g_dstImage, g_nMatchmethod);
	normalize(g_dstImage, g_dstImage, 0, 1, NORM_MINMAX, -1, Mat());
	//【4】通过函数minMaxLoc定位最匹配的位置
	double minValue, maxValue;
	Point minLocation, maxLocation, matchLocation;
	minMaxLoc(g_dstImage, &minValue, &maxValue, &minLocation, &maxLocation, Mat());
	//【5】对于方法SQDIFF和SQDIFF_NORMED,越小的数值匹配越好,而其余方法数值越大匹配越好
	if (g_nMatchmethod == TM_SQDIFF || g_nMatchmethod == TM_SQDIFF_NORMED)
	{
		matchLocation = minLocation;
	}
	else
	{
		matchLocation = maxLocation;
	}
	//【6】绘制矩形,显示结果
	rectangle(srcImage, matchLocation, Point(matchLocation.x + g_templateImage.cols, matchLocation.y + g_templateImage.rows), Scalar(0, 0, 255), 2, 8, 0);
	rectangle(g_dstImage, matchLocation, Point(matchLocation.x + g_templateImage.cols, matchLocation.y + g_templateImage.rows), Scalar(0, 0, 255), 2, 8, 0);
	
	imshow(WINDOW_NAME1, srcImage);
	imshow(WINDOW_NAME2, g_dstImage);
}
void ShowHelpText()
{
	printf("\n\t欢迎来到【模板匹配】示例程序~\n");
	printf("\n\t请调整滑动条观察图像效果\n");
	printf("\n\t滑动条对应的方法数值说明:\n");
	printf("\t\t方法【0】- 平方差匹配法(TM_SQDIFF)\n");
	printf("\t\t方法【1】- 归一化平方差匹配法(TM_SQDIFF_NORMED)\n");
	printf("\t\t方法【2】- 相关匹配法(TM_CCORR)\n");
	printf("\t\t方法【3】- 归一化相关匹配法(TM_CCORR_NORMED)\n");
	printf("\t\t方法【4】- 系数匹配法(TM_CCOEFF)\n");
	printf("\t\t方法【5】- 归一化相关系数匹配法(TM_CCOEFF_NORMED)\n");
}

运行效果
在这里插入图片描述

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

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

相关文章

性能测试讲解超详细Jmeter

目录 什么是性能 性能测试的目的 功能测试和性能测试 基准测试 负载测试 稳定性测试 压力测试 并发测试 总结 性能测试指标 响应时间 并发数 吞吐量 点击数 错误率 资源使用率 总结 性能测试流程 性能测试需求分析 性能测试计划和方案 ​编辑性能测试用例​编辑 性…

【Linux系统编程】shell的感性理解——王婆说媒

文章目录 1. shell是什么&#xff1f;它有什么作用&#xff1f;2. 透过王婆说媒感性理解shell的运行机制开端发展波澜渐起&#xff08;正常命令的处理&#xff09;故事角色与处理过程中各部分的映射走向高潮&#xff08;非法请求的处理&#xff09;shell 存在的意义结尾 1. she…

Elasticsearch:删除快照安全吗?

快速回答&#xff1a;是的&#xff01; 删除快照是安全的&#xff0c;因为每个快照在逻辑上都是独立的。 了解如何以及为何可以继续阅读。 Elasticsearch 使用增量快照&#xff0c;使你能够高效地备份和恢复数据。 你可以在这篇精彩的文章中找到它的工作原理 “Elasticsearch&…

【select2下拉框】带搜索功能以及实现关联下拉框

需求 1、有两个下拉框 地区下拉框机构下拉框 2、地区变化&#xff0c;机构下拉框中内容也随之变化。 3、当地区为空时&#xff0c;显示全部机构列表 效果展示 代码实现 1、前端 &#xff08;具体样式相关代码不在此展示&#xff09; <div class"form-group"…

简单的手机记事本怎么把内容标记为完成状态?

很多人平时会在手机记事本上记录一些自己身边需要记住的事情&#xff0c;有的事情做完之后不想删除&#xff0c;又想要和未完成的内容区分开&#xff0c;那么这种情况下可以将它标记为已完成状态。简单的手机记事本怎么把内容标记为完成状态呢&#xff1f;以iPhone手机端敬业签…

阿里云原生大数据计算服务maxcompute学习体验

这两天有兴趣学习了下阿里的maxcompute大数据&#xff0c;随便谈谈自己的感受。 一、感受 阿里云相关的产品线太多了&#xff0c;热门产品一页已经放不下了。正因为东西太多给人一种杂乱的感觉&#xff0c;也可能这是给技术人员用的&#xff0c;所以不用太讲客户体验&#xf…

C# Lable增删改查

文章目录 C# Lable 增删改查&#xff08;1&#xff09;项目截图Insert&#xff08;新增&#xff09;新增执行SQL语句方法 Delete&#xff08;删除&#xff09;删除执行SQL语句方法 Update&#xff08;修改&#xff09;删除执行SQL语句方法 Select&#xff08;查询&#xff09;查…

DeepC 实用教程(二)建模流程

目 录 一、前言二、单位制与容差三、环境数据四、浮体模型4.1 定义浮体数据4.2 浮力补偿4.3 创建系泊连接点 五、系泊系统5.1 创建系泊连接点5.2 定义各种属性5.3 创建线对象 六、参考文献 一、前言 SESAM &#xff08;Super Element Structure Analysis Module&#xff09;是由…

JUC之CAS和原子操作类

文章目录 1 CAS1.1 是什么1.2 原理1.3 UnSafe1.4 自旋锁1.5 CAS的问题1.5.1 死循环消耗CPU资源1.5.2 ABA问题 2 原子操作类2.1 引用类型原子类2.1.1 AtomicReference2.1.2 AtomicStampedReference2.1.3 AtomicMarkableReference 2.2 基本类型原子类2.3 数组类型原子类2.4 对象的…

【2022 JCR 期刊影响因子】(四)水资源

原文链接&#xff1a; 【2022 JCR 期刊影响因子】&#xff08;四&#xff09;水资源 微信公众号同步更新 地信学子GISer and Coder 2022 JCR 期刊影响因子刚刚发布&#xff0c;今年的影响因子只保留1位小数。水资源领域的 SCIE 收录期刊的影响因子如下。 微信公众号同步更新 …

Unity基础-Vector3.Lerp的使用给一个简单的实例

一个简单的实例&#xff0c;演示了如何使用Vector3.Lerp来实现物体在两个位置之间平滑移动的效果&#xff1a; using UnityEngine;public class ObjectMovement : MonoBehaviour {public Transform startPoint;public Transform endPoint;public float moveDuration 2f;priva…

[PMLR 2021] Zero-Shot Text-to-Image Generation:零样本文本到图像生成

[PMLR 2021]Zero-Shot Text-to-Image Generation&#xff1a;零样本文本到图像生成 Fig 1. 原始图像(上)和离散VAE重建图像(下)的比较。编码器对空间分辨率进行8倍的下采样。虽然细节(例如&#xff0c;猫毛的纹理、店面上的文字和插图中的细线)有时会丢失或扭曲&#xff0c;但图…

为什么有些前端一直用 div 当按钮,而不是用 button?

&#x1f482; 个人网站:【海拥】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言div 和 button使用…

Linux学习之进程控制和进程之间的关系

nice值的设定 关于vim四种模式一些介绍&#xff0c;可以看《Linux学习之vim正常模式和插入模式》 vim a.sh&#xff0c;按i进入到插入模式&#xff0c;这样才能输入字符到a.sh文件中。 把下边的内容写进去&#xff1a; #!/bin/bashecho $$ while : # 无限循环 do: done按Es…

Redis设计与实现笔记之SDS

1 数据结构与对象 1.1 简单动态字符串 SDS简单动态字符串&#xff08;simple dynamic string&#xff0c;SDS&#xff09;是Redis中字符串的底层数据结构。 struct sdshdr {// 记录 buf 数组中已使用字节的数量// 等于 SDS 所保存字符串的长度int len;// 记录 buf 数组中未使…

房屋信息怎么做二维码?户型文件怎么批量转二维码?

现在很多房产开发商都会用二维码来储存各个楼每户的信息&#xff0c;可能是建筑平面图、验房信息、楼区信息等等。那么如果将每户信息导出单独的文件之后&#xff0c;怎样才能够将每个文件批量转成二维码呢&#xff1f;下面教大家使用二维码生成器&#xff08;免费在线二维码生…

pytorch快速入门中文——07(TensorBoard)

使用 TensorBoard 可视化模型&#xff0c;数据和训练 原文&#xff1a;https://pytorch.org/tutorials/intermediate/tensorboard_tutorial.html 在 60 分钟突击中&#xff0c;我们向您展示了如何加载数据&#xff0c;如何通过定义为nn.Module子类的模型提供数据&#xff0c;如…

HTTP协议、存储、Ajax

HTTP协议、存储、Ajax 前端数据交互与HTTP协议 前后端通信 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><title>初识前后端通信</title></head><body><script>// 1.前后端通信…

手术麻醉临床信息系统源码:实现手术全流程自动化和信息化

手术麻醉临床信息系统遵循“以病人为中心、服务于临床”的宗旨&#xff0c;使医护人员从繁琐的病历书写中解放出来&#xff0c;集中精力关注病人的诊疗&#xff0c;将更多的时间用于分析、诊断。以服务围术期临床业务工作的开展为核心&#xff0c;为医护人员、业务管理人员、院…

APP外包开发闪退解决工具

APP上线后出现闪退问题往往不好解决&#xff0c;解决这些问题耗时耗力&#xff0c;但解决好了会对用户体验有非常大的帮助。今天和大家分享解决APP闪退问题的一般流程&#xff0c;但具体情况可能会因为问题的复杂性和具体情况有所不同。北京木奇移动技术有限公司&#xff0c;专…