-
目录
九、直方图与匹配
9.1、图像直方图概述
9.2、直方图的计算与绘制
9.2.1、计算直方图:calcHist函数
9.2.2、找寻最值:minMaxLoc函数
9.2.3、示例程序:绘制H---S直方图
9.2.4、示例程序:计算并绘制一维直方图
9.2.5、绘制RGB三色直方图
9.3、直方图对比
9.3.1、直方图对比:compareHist函数
9.4、反向投影
9.4.1、引言
9.4.2、反向投影的工作原理
9.4.3、反向投影的作用
9.4.4、反向投影的结果
9.4.5、计算反向投影:calcBackProject函数
9.4.6、通道复制:mixChannels()
9.4.7、反向投影
9.5、模板匹配
9.5.1、模板匹配的概念和原理
9.
5.2、实现模板匹配:matchTemplate()
9.5.3、模板匹配
9.6、本章小结
九、直方图与匹配
-
9.1、图像直方图概述
- 直方图就是对数据迸行统计的一种方法,并且将统计值组 织到一系列事先定义好的bin 当中。其中, bin为经常用到的一个概念, 可翻译为"直条"或"组距", 其数值是从数据中计算出的特征统计量,这些数据 可以是诸如梯度、方向、色彩或任何其他特征。且无论如何,直方图获得的是数 据分布的统计图。通常直方图的维数要低于原始数据。总而言之,直方图是计算 机视觉中最经典的工具之一
- 图像直方图是用以表示数字图像中亮度分布的直方图, 标绘了图像中每个亮度值的像素数。 可以借助观察该直方图了解需要如何调整亮度分布。这种直方图中,横坐标的左侧为纯黑、较暗的区域,而右侧为较完、纯白的区域。因此, 一张较暗图片的图像直方图中的数据多集中于左侧和中间部分, 而整体明亮、只有少量阴影的图像则相反。 计算机视觉领域常借助图像直方图 实现图像的二值化。
- 直方图时图像像素强度分布的图形表达方式;统计了每一个强度值所具有的像素个数。
- dims:需要统计的特征的数目;bins:每个特征空间子区段的数目,“组距”;range:每个特征空间的取值范围。
-
9.2、直方图的计算与绘制
-
9.2.1、计算直方图:calcHist函数
-
void calaHist(const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist,int dims, const int* histSize, const float** range, bool uniform = true, bool accumulate=false)
1:图像,输入的数组;2:输入数组的个数,也就是第一个参数中存放了多少张图形,有几个原数组;3:需要统计的通道(dim)索引。第一个数组通道从0计算到image[0].channels()-1,第二个通道从image[0].channels()计算到image[0].channels()+image[1].channels()-1;4:可选的操作掩码。非零掩码元素用于标记出统计直方图的数组元素数据;5:输出的目标直方图;6:需要计算的直方图的维度;7:存放每个维度的直方图尺寸的数组;8:表示每一个维度数组的每一维的边界阵列,即每一维数值的取值范围;9:指示直方图是否均匀的标识符;10:累计标识符,true表示直方图在配置阶段不会被清零。此功能主要是允许从多个阵列中计算单个直方图,或者用于在特定的时间更新直方图。
-
-
9.2.2、找寻最值:minMaxLoc函数
-
void minMaxLoc(InputArray src, double* minVal, double* maxVal=0, Point* minLoc=0; Point* maxLoc=0, InputArray mask= noArray())
1:输入的单通道阵列;2:返回最小值的指针;3:返回最大值的指针;4:返回最小位置的指针(二维情况下);5:返回最大位置的指针(二维情况下);6:用于选择子阵列的可选掩膜。
-
-
9.2.3、示例程序:绘制H---S直方图
-
int main( { Mat srcImage,hsvImage; srcImage = imread("1.jpg"); cvtColor(srcImage,hsvImage,COLOR_BGR2HSV); //将色调量化为30个等级,将饱和度量化为32个等级 int hueBinNum = 30;//色调的直方图直条数量 int saturationBinNum = 32; //饱和度的直方图直条数量 int histSize[] = {hueBinNum, saturationBinNum}; //定义色调的变化范围是0--179 float hueRanges[] = {1,180}; //定义饱和度的范围为0(黑、白、灰),到255(纯光谱颜色) float saturationRanges[]={0,256}; const float* ranges[]={hueRanges,saturationRanges}; MatHD dstHist, //参数准备,calcHist函数中将计算第0通道和第1通道的直方图 int channels[]={0,1}; //调用calcHist calcHist(&hsvImage,//输入的数组 1,//数组个数为1 channels,//通道索引 Mat(),//不使用掩膜 dstHist,//输出的目标直方图 2,//需要计算的直方图的维度为2 histSize,//存放每个维度的直方图尺寸的数组 ranges,//每一维数组的取值范围数组 true,//均匀的表示直方图 false);//累计标识符,在配置阶段会清零 //绘制直方图参数 double maxValue=0; minMaxLoc(dstHist,0,&maxValue,0,0);//查找数组和子数组的全局最小、大值 int scale =10; Mat histImg=Mat::zeros(saturationBinNum*scale,hueBinNum*10,CV_8UC3); //直方图绘制 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);//强度 //进行绘制 rectangele(histImg,Point(hue*scale,saturation*scale), Point((hue+1)*scale-1,(saturation+1)*scale-1), Scalar::all(intensity),FILLED); } imshow("素材图",srcimge); imshow("H---S直方图",histImg); waitKey(); }
-
-
9.2.4、示例程序:计算并绘制一维直方图
-
int main( { Mat srcImage; srcImage = imread("1.jpg",0); imread("原图",srcImage); MatHD dstHist; int dims=1; float hranges[]={0,255}; const float* ranges[]={hranges}; int size = 256; int channels = 0; calcHist(&srcImage,1,&channels,Mat(), dstHist,dims,&size,ranges); int scale =1; Mat dstImage(size*scale,size,CV_8U,Scalar(0)); double minValue=0; double maxValue=0; minMaxLoc(dstHist,&minValue,&maxValue,0,0); //直方图绘制 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); rectangele(dstImg,Point(i*scale,size-1), Point((i+1)*scale-1,size-realValue), Scalar(255)); } imshow("一维直方图图",dstImage); waitKey(0); return 0; }
-
-
9.2.5、绘制RGB三色直方图
-
int main() { Mat srcImage; srcImage = imread("1.jpg"); imread("原图",srcImage); int bins=256; int hist_size[]={bins}; float range[]={0,256}; const float* ranges[]={range}; MatHD redHist,grayHist,blueHist; int channels_r[] = {0}; calcHist(&srcImage,1,&channels_r,Mat(), redHist,1,hist_size,ranges,true,false); int channels_g[] = {1}; calcHist(&srcImage,1,&channels_g,Mat(), grayHist,1,hist_size,ranges,true,false); 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 hitsHeight=256; Mat histImage = Mat::zeros(hitsHeight,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*hitsHeight/maxValue_red); int intensity_green= cvRound(binValue_green*hitsHeight/maxValue_green); int intensity_blue= cvRound(binValue_blue*hitsHeight/maxValue_blue); rectangele(histImage,Point(i*scale,hitsHeight-1), Point((i+1)*scale-1,hitsHeight-intensity_red), Scalar(255,0,0)); rectangele(histImage,Point((i+bins)*scale,hitsHeight-1), Point((i+1+bins)*scale-1,hitsHeight-intensity_green), Scalar(0,255,0)); rectangele(histImage,Point((i+bins*2)*scale,hitsHeight-1), Point((i+1+bins*2)*scale-1,hitsHeight-intensity_blue), Scalar(0,0,255)); } imshow("RGB直方图",histImage); waitKey(0); return 0; }
-
-
-
9.3、直方图对比
-
9.3.1、直方图对比:compareHist函数
- 此函数用来对比两个直方图的相似度
-
double compareHist(InputArray H1,InputArray H2,int method)
-
double compareHist(const SparseMat& H1, const SparseMat& H1,int method)
两个版本的代码原型,前两个参数是要比较的大小相同的直方图,第三个变量是所选择的距离标准。可采用如下四种方法:
-
1、相关,Conrrelation(method=CV_COMP_CORREL),method=1
- 2、卡方,Chi-Square(method=CV_COMP_CHIAQR),method=2
- 3、直方图相交,Intersection(method=CV_COMP_INTERSECT),method=3
- 4、Bhattacharyya距离,(method=CV_COMP_BHATTACHARYYA),4
-
- 9.3.2、直方图对比
-
int main() { //声明存储基准图形和另外两张对比图的矩阵 Mat srcImage_base,hsvImage_base; Mat srcImage_test1,hsvImage_test1; Mat srcImage_test2,hsvImage_test2; Mat hsvImage_halfDown; //再去基准图形和两张测试图像并显示 srcImage_base=imread("1.jpg",1); srcImage_test1=imread("2.jpg",1); srcImage_test2=imread("3.jpg",1); imshow("基准图像",srcImage_base); imshow("测试图像1",srcImage_test1); imshow("测试图像2",srcImage_test2); cvtColor(srcImage_base,hsvImage_base,COLOR_BGR2HSV); cvtColor(srcImage_test1,hsvImage_test1,COLOR_BGR2HSV); cvtColor(srcImage_test2,hsvImage_test2,COLOR_BGR2HSV); //创建包含基准图像下半部的半身图像 hsvImage_halfDown = hsvImage_base(Range( hsvImage_base.rows/2,hsvImage_base.rows-1 ),Range(0,hsvImage_base.cols-1)); //对护额通道使用30个bin,对saturation使用32个bin int h_bins = 50; int s_bins=60; int histSize[]={h_bins,s_bins}; //hue的取值从0---255,saturation :0--180 float h_ranges[]={0,256}; float s_ranges[]={0,180}; const float* ranges[]={h_ranges,s_ranges}; int channels[]={0,1}; MatND baseHist; MatND halfDownHist; MatND testHist1; MatND testHist2; //计算基准图像,两张测试图像,半身基准图像的 HSV立方图 calcHist(&hsvImage_base,1,channels,Mat(),baseHist,2, histSize,ranges,true,false); normalize(baseHist,baseHist,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()); 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()); // 按顺序使用 4 种对比标准将基准图像的直方图与其余各立方图进行对比 for(int i =0;i<4;i++) { int compare_method = i; double base_base = compareHist(baseHist,baseHist,compare_method); double base_half = compareHist(baseHist,halfDownHist,compare_method); double base_test1 = compareHist(baseHist,testHist1,compare_method); double base_test2 = compareHist(baseHist,testHist2,compare_method); printf("方法【%d】的匹配结果如下:\n\n【基准图-基准图】:%f, 【基准图-半身图】:%f,【基准图-测试图1】:%f,【基准图-测试图2】:%f \n---------------------------------------------------------\n", i,base_base,base_half,base_test1,base_test2); } printf("检测结束。"); waitKey(0); return 0; }
-
-
-
9.4、反向投影
-
9.4.1、引言
- 如果一l幅图像的区域中显示的是一种结构纹理或者一个独特的物体,那么这 个区域的直方图可以看作一个概率函数,其表现形式是某个像素属于该纹理或物 体的概率。反向投影就是一种记录给定图像中的像素点如何适应直方图模型像素分布的一种方式。
-
9.4.2、反向投影的工作原理
- 1、对测试图像中的每个像素,获取色调数据并找到该色调在直方图中的bin的位置
- 2、查询模型直方图中对应bin的数值
- 3、将此数值储存在新的反射投影图像中,也可以下先归一化直方图数值到0-255范围,这样可以直接显示反射投影图像
- 4、通过对测试图像中的每个像素采用以上步骤,可以得到最终的反射投影图像。
- 5、反向投影中储存的数值代表了测试图像中该像素属于ROI区域的的概率。炼器的区域表明概率更大。
-
9.4.3、反向投影的作用
- 用于在输入图像中查找与特定图像最匹配的点或区域,也就是定位模板图像出现在输入图像的位置
-
9.4.4、反向投影的结果
- 包含了以每个输入图像像素点为起点的直方图对比结果。
-
9.4.5、计算反向投影:calcBackProject函数
-
void calcBackProject(const Mat* images, int nimages, const int* channels, InputArray hist, OutputArray backProject, const float** ranges, double scale=1, bool uniform=true)
1:输入的数组;2:输入数组的个数;3:需要统计的通道(dim)索引;4:输入的直方图;5:目标反向投影阵列,单通道;6:表示每一个维度数组的每一维的边界阵列,可以理解为每一维数值的取值范围;7:默认为1,输出的方向投影可选的缩放因子;8:指示直方图是否均匀的标识符
-
-
9.4.6、通道复制:mixChannels()
-
void mixChannels( const Mat* src,//输入的数组,所有的矩阵必须有相同的尺寸和深度 size_t nsrcs,//第一个参数src输入的矩阵数 Mat* dst,//输出的数组,所有矩阵必须被初始化 size_t ndsts,//dst输入的矩阵数 const int* fromTo,//对指定的通道进行复制的数组索引 size_t npairs)//fromTo的索引数
void mixChannels( //输入的矩阵向量,所有的矩阵必须有相同的尺寸和深度 const vector<Mat>& src, //输出的矩阵向量,所有矩阵须被初始化 vector<Mat>&dst, const int* fromTo,//对指定的通道进行复制的数组索引 size_t npairs)//上边参数的索引数
-
-
9.4.7、反向投影
-
#define WINDOW_NAME1 "【原始图】" Mat g_srcImage; Mat g_hsvImage; Mat g_hueImage; int g_bins= 30; void on_binChange(int,void*); int main() { g_srcImage = imread("1.jpg",1); cvtColor(g_srcImage,g_hsvImage,COLOR_BGR2HSV); //分离hue色调通道 g_hueImage.create(g_hsvImage.size(),g_hsvImage.depth()); int ch[]={0,0}; mixChannels(&g_hsvImage,1,&g_hueImage,1,ch,1); //输入bin数目 namedWindow(WINDOW_NAME1,WINDOW_AUTOSIZE); createTrackbar("色调组距",WINDOW_NAME1, g_bins,180,on_binChange); on_binChange(0,0); imshow(WINDOW_NAME1,g_srcImage); waitKey(0); return 0; } void on_binChange(int, void*) { MatND hist; int histSize = MAX(g_bins,2); float hue_range[] = {0,180}; const float* ranges={hue_range}; //计算直方图并归一化 calcHist(&g_hueImage,1,0,Mat(),hist,1, &histSize,&ranges,true,false); normalize(hist,hist,0,255,NORM_MINMAX,-1,Mat()); //计算反向投影 MatND backproj; calcBackProject(&g_hueImage,1,0,hist,backproj, &ranges,1,true); imshow("反向投影图",backproj); //绘制直方图参数 int w =400;int h=400; int bin_w = cvRound((double)w /histSize); Mat histImg = Mat::zeros(w,h,CV_8UC3); 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 ); } imshow("直方图",histImg); }
-
-
-
9.5、模板匹配
-
9.5.1、模板匹配的概念和原理
- 模板匹配是在一副图像中寻找另一幅图像最匹配(相似)的部分。模板匹配不是基于直方图的,而是通过在输入图像上滑动图像块,对实际的图像块和输入图像进行匹配的一种匹配方法。
-
9.
目录
九、直方图与匹配
9.1、图像直方图概述
9.2、直方图的计算与绘制
9.2.1、计算直方图:calcHist函数
9.2.2、找寻最值:minMaxLoc函数
9.2.3、示例程序:绘制H---S直方图
9.2.4、示例程序:计算并绘制一维直方图
9.2.5、绘制RGB三色直方图
9.3、直方图对比
9.3.1、直方图对比:compareHist函数
9.4、反向投影
9.4.1、引言
9.4.2、反向投影的工作原理
9.4.3、反向投影的作用
9.4.4、反向投影的结果
9.4.5、计算反向投影:calcBackProject函数
9.4.6、通道复制:mixChannels()
9.4.7、反向投影
9.5、模板匹配
9.5.1、模板匹配的概念和原理
9.5.2、实现模板匹配:matchTemplate()
9.5.3、模板匹配
9.6、本章小结
5.2、实现模板匹配:matchTemplate()
-
void matchTemplate(InputArray image,InputArray temp1, OutputArray result, int method)
1:待搜索的图像;2:搜索模板,尺寸不能大于源图像;3:比较结果的映射图像;4:指定的匹配方法文章来源:https://www.toymoban.com/news/detail-834367.html
-
1、平方差匹配法:method=TM_SQDIFF文章来源地址https://www.toymoban.com/news/detail-834367.html
- 2、归一化平方差匹配法:method=TM_AQDIFF_NORMED
- 3、相关匹配法:method=TM_CCORR
- 4、归一化相关匹配法:method=TM_CCORR_NORMED
- 5、系数匹配法:method=TM_CCOEFF
- 6、化相关系数匹配法:method=TM_CCOEFF_NORMED
-
-
-
9.5.3、模板匹配
-
#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; Mat g_templateImage; Mat g_resultImage; int g_nMatchMethod; int g_nMaxTrackbarNum = 5; void on_Matching(int, void *); static void ShowHelpText(); int main() { g_srcImage = imread("1.jpg",1); g_templateImage = imread("2.jpg",1); namedWindow(WINDOW_NAME1,CV_WINDOW_AUTOSIZE); namedWindow(WINDOW_NAME2,CV_WINDOW_AUTOSIZE); createTrackbar("方法",WINDOW_NAME1, &g_nMatchMethod,g_nMaxTrackbarNum, on_Matching); on_binChange(0,0); waitKey(0); return 0; } void on_Matching(int,void*) { Mat srcImage; g_srcImage.copyTo(srcImage); //初始化用于结果输出的矩阵 int resultImage_cols = g_srcImage.cols- g_templateImage.cols+1; int resultImage_rows = g_srcImage.rows- g_templateImage.rows+1; g_resultImage.create(resultImage_cols,resultImage_rows, CV_32FC1); //进行匹配和标准化 matchTemplate(g_srcImage,g_templateImage, g_resultImage,g_nMatchMethod); normalize(g_resultImage,g_resultImage, 0,1,NORM_MINMAX,-1,Mat()); //通过函数定位最匹配的位置 double minValue;double maxValue; Point minLocation; Point maxLocation; Point matchLocation; minMaxLoc(g_resultImage,&minValue,&maxValue, &minLocation,&maxLocation,Mat()); //对于方法SQDIFF和SQDIFF_NORMED,越小的数值有着更高的匹配结果 //而其余的方法,数值越大匹配效果越好 if(g_nMatchMethod == TM_SQDIFF || g_nMatchMethod == TM_SQDIFF_NORMED) { matchLocation = minLocation; } else{matchLocation=maxLocation;} //绘制矩形,并显示最终结果 rectangle(srcImage,matchLocation,Point(matchLocation.x+ g_templateImage.cols, matchLocation.y+g_templateImage.rows), Scalar(0,0,255),2,8,0); rectangle(g_resultImage, 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_resultImage); } static void ShowHelpText() { printf("\n\n\n\t欢迎来到匹配示例程序···\n\n"); printf("\t请调整滑动条观察图像效果"); printf("\n\n\t数值说明:\n\n" "\t\t 【0】---平方差匹配方法" "\t\t 【1】---归一化平方差法" "\t\t 【2】---相关匹配法" "\t\t 【3】---归一化相关匹配法" "\t\t 【4】---相关系数法" "\t\t 【5】---归一化相关系数法" ) }
-
-
-
9.6、本章小结
-
到了这里,关于OpenCV:第九章、直方图与匹配的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!