opencv直方图使用学习
来源:互联网 发布:儿童 编程 编辑:程序博客网 时间:2024/05/16 18:42
from:http://www.cnblogs.com/tornadomeet/archive/2012/05/03/2480824.html
基础学习笔记之opencv(4):直方图使用学习
目的:
直方图在cv领域到处可见,因为其功能在cv算法的实现中比不可少。Opencv库中也集成了关于直方图的不少函数,比如直方图的计算,均衡,归一化,相似度比较等等。
为了体验这些函数,做了个小实验,功能是:打开摄像头,鼠标选定一个框,框内图像作为标准图像,计算出其直方图并显示出来;然后继续鼠标选定框,该框内的图像的直方
图与标准图像的进行相似度计算,计算结果在终端输出,数值越大表示相似度越大。
工程环境:opencv2.3.1+vs2010。
// hist_test.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> #include <stdio.h> using namespace cv; using namespace std; int nFrame_num=0; bool pause=false; bool tracking=false; Rect preselectROI,selectROI;//用于存放手选的矩形 bool comp=true; Mat rhist,ghist,bhist; int channels[]={0,1,2}; //const int histsize[]={256,256,256}; const int histsize[]={16,16,16}; const int histsize1=16; float rranges[]={0,255}; float granges[]={0,255}; float branges[]={0,255}; float range[]={0,255}; const float *ranges1={range};//这里的ranges就相当于一个双指针了 const float *ranges[]={rranges,granges,branges};//ranges是个双指针,且前面一定要用const,即不可改变常量,提高程序的可读性和稳健性 //const float *ranges[]={{0,255},{0,255},{0,255}}; void onMouse(int event,int x,int y,int,void *) { if(event==CV_EVENT_LBUTTONDOWN) { selectROI.x=x; selectROI.y=y; tracking=false; } else if(event==CV_EVENT_LBUTTONUP) { selectROI.width=x-selectROI.x; selectROI.height=y-selectROI.y; tracking=true; comp=true; nFrame_num++;//选定后才算真正意义上的第一帧 if(nFrame_num>=10)nFrame_num=10;//防止nFrame_num溢出 } } int main(int argc, const char* argv[]) { Mat frame,img; Mat staRoiHist; MatND RoiHist; int DRAW_H=400,DRAW_W=400; Mat draw(DRAW_W,DRAW_H,CV_8UC3,Scalar(0,0,0));//建立一个显示直方图的图片,背景为纯黑色 int DRAW_BIN_W=cvRound(DRAW_W/histsize1); /****打开摄像头****/ VideoCapture cam(0); if(!cam.isOpened()) return -1; /****鼠标捕捉****/ namedWindow("camera",1); namedWindow("rgb_hist",1); setMouseCallback("camera",onMouse,0);//这里用的是面向对象的思想,只要有鼠标动作就会调用鼠标响应函数 while(1) { if(!pause)//暂停按钮只需控制视频的读取 { cam>>frame; if(frame.empty()) break;//break此处跳出的是while语句,一般是跳出for或while语句,不要理解为跳出if语句 } /* if(1==nFrame_num) { }*/ if(tracking) { Mat RoiImage(frame,selectROI); /*************************************************************************************************************************/ /**** calcHist():计算图像块的直方图矩阵 ****/ /****calcHist(),第1个参数为原数组区域列表;第二个参数为有计算几个原数组;参数3为需要统计的通道索引数;参数4为操作掩码****/ /****第5个参数为存放目标直方图矩阵;参数6为需要计算的直方图的维数;参数7为每一维的bin的个数;参数8为每一维数值的取值范围****/ /****参数10为每个bin的大小是否相同的标志,默认为1,即bin的大小都相同;参数11为直方图建立时清除内存痕迹标志,默认为0,即清除****/ /*************************************************************************************************************************/ calcHist(&RoiImage,1,channels,Mat(),RoiHist,3,histsize,ranges);//原数组区域RoiImage,1个源,需要统计的通道索引为{0,1,2}, //目标直方图RoiHist,3维,每一维的bin数histsize,取值范围为 //ranges,实际上计算出的目标矩阵类似一维矩阵。 /*************************************************************************************************************************/ /**** normalize():根据某种范数或者数值范围归一化数组 ****/ /**** normalize(),参数1表示需要归一化的数组;参数2为归一化后的目的数组;参数3表示输出数值的最小值/最大值或者输出数值的范数;****/ /**** 参数4表示输出数值的最小值/最大值;参数5表示归一化数组使用的归一化类型,默认值为使用L2范数;参数6为对应元素的掩膜矩阵 ****/ /**** 默认值为空,即不采用掩膜操作 ****/ /*************************************************************************************************************************/ normalize(RoiHist,RoiHist);//使用L2范数将RoiHist直方图原地归一化 vector<Mat> rgb_planes;//这里的vector为向量,向量的数据类型为Mat结构体,向量的长度为3 split(RoiImage,rgb_planes);//将rgb图分解到rgb_planes各个分量中 calcHist(&rgb_planes[0],1,0,Mat(),rhist,1,&histsize1,&ranges1); normalize(rhist,rhist,0,DRAW_H,NORM_MINMAX);//进行最大最小值归一化 calcHist(&rgb_planes[1],1,0,Mat(),ghist,1,&histsize1,&ranges1); normalize(ghist,ghist,0,DRAW_H,NORM_MINMAX); calcHist(&rgb_planes[2],1,0,Mat(),bhist,1,&histsize1,&ranges1); normalize(bhist,bhist,0,DRAW_H,NORM_MINMAX); if(nFrame_num==1) { // preselectROI=selectROI; preselectROI.x=selectROI.x; preselectROI.y=selectROI.y; preselectROI.width=selectROI.width; preselectROI.height=selectROI.height; staRoiHist=RoiHist.clone();//第一次选定目标,作为标准模板目标 } else if(nFrame_num>1&&comp==true) { /*************************************************************************************************************************/ /**** compareHist():比较2个直方图的相似度 ****/ /**** compareHist(),参数1为比较相似度的直方图1;参数2为比较相似度的直方图2;参数3为相似度的计算方式。有四种, ****/ /**** 分别为CV_COMP_CORREL,CV_COMP_CHISQR,CV_COMP_INTERSECT,CV_COMP_BHATTACHARYYA ****/ /*************************************************************************************************************************/ double distence=compareHist(staRoiHist,RoiHist,CV_COMP_INTERSECT);//计算后面选定的与这次选定的相似度,使用INTERSECT,值越大越相似 printf("与第1次选定的图像区域相似度为:%f\n",distence);//数组越大,相似度越大 //显示直方图 for(int i=1;i<histsize1;i++) { //画直线中要注意2点,因为图片的原点在左上角,而直方图坐标系的原点在左下角,所以高度值都需要被直方图图纸高度减掉,另外取一维直方图时只能用at运算符 line(draw,Point(DRAW_BIN_W*(i-1),DRAW_H-cvRound(rhist.at<float>((i-1)))),Point(DRAW_BIN_W*(i),DRAW_H-cvRound(rhist.at<float>(i))),Scalar(255,0,0),2,8,0); line(draw,Point(DRAW_BIN_W*(i-1),DRAW_H-cvRound(ghist.at<float>((i-1)))),Point(DRAW_BIN_W*(i),DRAW_H-cvRound(ghist.at<float>(i))),Scalar(0,255,0),2,8,0); line(draw,Point(DRAW_BIN_W*(i-1),DRAW_H-cvRound(bhist.at<float>((i-1)))),Point(DRAW_BIN_W*(i),DRAW_H-cvRound(bhist.at<float>(i))),Scalar(0,0,255),2,8,0); } imshow("rgb_hist",draw); draw=Mat::zeros(DRAW_W,DRAW_H,CV_8UC3);//每画完一次直方图后都进行一次清0操作 comp=false; } rectangle(frame,selectROI,Scalar(0,255,0),2,8);//手动选定一次就显示一次 }//end tracking rectangle(frame,preselectROI,Scalar(0,0,255),5,8);//初始的选定目标一直不变 imshow("camera",frame); //键盘响应 char c = (char)waitKey(10); if( c == 27 ) break; switch(c) { case 'p'://暂停键 pause = !pause; break; default: ; } }//end while; return 0; }
实验结果:
选定框内的模板用红色框标出,其他待比较的模板用绿色框标出。
模板图像块的简单直方图(rgb分开画的)显示如下:
第一次比较结果图:
第二次比较结果图:
第三次比较结果图(2个框选定的基本重合):
三次比较相似度结果:
可以看出,第三次的框与标准框内图像(即第1次选定的图像区域)的相似度值最大。
总结:是不是可以通过直方图来完成图像匹配的操作!?
normalize¶
Normalizes the norm or value range of an array.
- C++: void normalize(InputArraysrc, OutputArraydst, doublealpha=1, doublebeta=0, intnorm_type=NORM_L2, intdtype=-1, InputArraymask=noArray())¶
- C++: void normalize(const SparseMat&src, SparseMat&dst, doublealpha, intnormType)¶
- Python:cv2.normalize(src[, dst[, alpha[, beta[, norm_type[, dtype[, mask]]]]]]) → dst¶
Parameters: - src – input array.
- dst – output array of the same size as src .
- alpha – norm value to normalize to or the lower range boundary in case of the range normalization.
- beta – upper range boundary in case of the range normalization; it is not used for the norm normalization.
- normType – normalization type (see the details below).
- dtype – when negative, the output array has the same type assrc; otherwise, it has the same number of channels assrc and the depth =CV_MAT_DEPTH(dtype).
- mask – optional operation mask.
注:当norm_type为NORM_MINMAX时,alpha为最小值;beta为最大值
The functions normalize scale and shift the input array elements so that
(where p=Inf, 1 or 2) when normType=NORM_INF,NORM_L1, orNORM_L2, respectively; or so that
when normType=NORM_MINMAX (for dense arrays only). The optional mask specifies a sub-array to be normalized. This means that the norm or min-n-max are calculated over the sub-array, and then this sub-array is modified to be normalized. If you want to only use the mask to calculate the norm or min-max but modify the whole array, you can usenorm() andMat::convertTo().
In case of sparse matrices, only the non-zero values are analyzed and transformed. Because of this, the range transformation for sparse matrices is not allowed since it can shift the zero level.
See also
norm(),Mat::convertTo(),SparseMat::convertTo()
- opencv直方图使用学习
- opencv学习-imgprocess-直方图
- opencv 学习之 直方图
- opencv学习笔记--直方图
- OpenCV直方图的使用
- OpenCV直方图的使用
- Opencv 直方图使用
- OpenCV深入学习(5)--直方图之calcHist使用
- OpenCV深入学习(6)--直方图之calcHist使用(补)
- 【从零学习openCV】使用直方图统计像素
- 【OpenCV学习笔记 007】使用直方图统计像素
- opencv学习_6 (灰度直方图)
- opencv学习笔记---图像直方图
- opencv学习之直方图绘制
- opencv 学习之直方图统计
- opencv学习_6 (灰度直方图)
- OpenCV学习笔记五:直方图
- Opencv学习之图像直方图
- javascript 正则表达式数量词,字符串方法(match,search,replace,split),贪婪模式,惰性模式总结
- 简单的php登陆类及后台权限的控制
- 关于计算Java程序运行时间
- linux 网络配置和问题解决
- Linux(Ubuntu12.04)环境的Nexus搭建
- opencv直方图使用学习
- c++工作宝贵经验呀,我去。。。。
- C++堆和栈详细介绍
- Project Euler problem 38
- jQuery Ajax 请求
- 回收VMWare虚拟机占用的磁盘空间
- SIGSEGV和SIGBUS
- break和continue的区别
- 最大流poj1273