基础学习笔记之opencv(4):直方图使用学习

目的:

  直方图在cv领域到处可见,因为其功能在cv算法的实现中必不可少。Opencv库中也集成了关于直方图的不少函数,比如直方图的计算,均衡,归一化,相似度比较等等。

为了体验这些函数,做了个小实验,功能是:打开摄像头,鼠标选定一个框,框内图像作为标准图像,计算出其直方图并显示出来;然后继续鼠标选定框,该框内的图像的直方

图与标准图像的进行相似度计算,计算结果在终端输出,数值越大表示相似度越大。

  工程环境:opencv2.3.1+vs2010。

 

工程代码:

  1 // hist_test.cpp : 定义控制台应用程序的入口点。

  2 //

  3 

  4 #include "stdafx.h"

  5 #include <opencv2/core/core.hpp>

  6 #include <opencv2/imgproc/imgproc.hpp>

  7 #include <opencv2/highgui/highgui.hpp>

  8 #include <iostream>

  9 #include <stdio.h>

 10 

 11 using namespace cv;

 12 using namespace std;

 13 

 14 int nFrame_num=0;

 15 bool pause=false;

 16 bool tracking=false;

 17 Rect preselectROI,selectROI;//用于存放手选的矩形

 18 bool comp=true;

 19 

 20 Mat rhist,ghist,bhist;

 21 int channels[]={0,1,2};

 22 //const int histsize[]={256,256,256};

 23 const int histsize[]={16,16,16};

 24 const int histsize1=16;

 25 float rranges[]={0,255};

 26 float granges[]={0,255};

 27 float branges[]={0,255};

 28 float range[]={0,255};

 29 const float *ranges1={range};//这里的ranges就相当于一个双指针了

 30 const float *ranges[]={rranges,granges,branges};//ranges是个双指针,且前面一定要用const,即不可改变常量,提高程序的可读性和稳健性

 31 //const float *ranges[]={{0,255},{0,255},{0,255}};

 32 

 33 void onMouse(int event,int x,int y,int,void *)

 34 {

 35     if(event==CV_EVENT_LBUTTONDOWN)

 36     {

 37         selectROI.x=x;

 38         selectROI.y=y;

 39         tracking=false;

 40     }

 41     else if(event==CV_EVENT_LBUTTONUP)

 42     {

 43         selectROI.width=x-selectROI.x;

 44         selectROI.height=y-selectROI.y;

 45         tracking=true;

 46         comp=true;

 47         nFrame_num++;//选定后才算真正意义上的第一帧

 48         if(nFrame_num>=10)nFrame_num=10;//防止nFrame_num溢出

 49     }

 50 }

 51 

 52 int  main(int argc, const char* argv[])

 53 {

 54     Mat frame,img;

 55     Mat staRoiHist;

 56     MatND RoiHist;

 57     int DRAW_H=400,DRAW_W=400;

 58     Mat draw(DRAW_W,DRAW_H,CV_8UC3,Scalar(0,0,0));//建立一个显示直方图的图片,背景为纯黑色

 59     int DRAW_BIN_W=cvRound(DRAW_W/histsize1);

 60 

 61     /****打开摄像头****/

 62     VideoCapture cam(0);

 63     if(!cam.isOpened())

 64         return -1;

 65 

 66     /****鼠标捕捉****/

 67     namedWindow("camera",1);

 68     namedWindow("rgb_hist",1);

 69     setMouseCallback("camera",onMouse,0);//这里用的是面向对象的思想,只要有鼠标动作就会调用鼠标响应函数

 70 

 71     while(1)

 72     {

 73         if(!pause)//暂停按钮只需控制视频的读取

 74         {        

 75         cam>>frame;

 76         if(frame.empty())

 77             break;//break此处跳出的是while语句,一般是跳出for或while语句,不要理解为跳出if语句

 78         }

 79     /*    if(1==nFrame_num)

 80         {

 81 

 82         }*/

 83         if(tracking)

 84         {

 85             Mat RoiImage(frame,selectROI);

 86 

 87             /*************************************************************************************************************************/

 88             /****                                    calcHist():计算图像块的直方图矩阵                                                ****/

 89             /****calcHist(),第1个参数为原数组区域列表;第二个参数为有计算几个原数组;参数3为需要统计的通道索引数;参数4为操作掩码****/

 90             /****第5个参数为存放目标直方图矩阵;参数6为需要计算的直方图的维数;参数7为每一维的bin的个数;参数8为每一维数值的取值范围****/

 91             /****参数10为每个bin的大小是否相同的标志,默认为1,即bin的大小都相同;参数11为直方图建立时清除内存痕迹标志,默认为0,即清除****/

 92             /*************************************************************************************************************************/

 93             calcHist(&RoiImage,1,channels,Mat(),RoiHist,3,histsize,ranges);//原数组区域RoiImage,1个源,需要统计的通道索引为{0,1,2},

 94                                                                             //目标直方图RoiHist,3维,每一维的bin数histsize,取值范围为

 95                                                                             //ranges,实际上计算出的目标矩阵类似一维矩阵。

 96                                                                             

 97 

 98             /*************************************************************************************************************************/

 99             /****                                normalize():根据某种范数或者数值范围归一化数组                                     ****/

100             /**** normalize(),参数1表示需要归一化的数组;参数2为归一化后的目的数组;参数3表示输出数值的最小值/最大值或者输出数值的范数;****/

101             /****  参数4表示输出数值的最小值/最大值;参数5表示归一化数组使用的归一化类型,默认值为使用L2范数;参数6为对应元素的掩膜矩阵 ****/

102             /****                                              默认值为空,即不采用掩膜操作                                            ****/

103             /*************************************************************************************************************************/

104             normalize(RoiHist,RoiHist);//使用L2范数将RoiHist直方图原地归一化

105 

106             vector<Mat> rgb_planes;//这里的vector为向量,向量的数据类型为Mat结构体,向量的长度为3

107             split(RoiImage,rgb_planes);//将rgb图分解到rgb_planes各个分量中

108             calcHist(&rgb_planes[0],1,0,Mat(),rhist,1,&histsize1,&ranges1);

109             normalize(rhist,rhist,0,DRAW_H,NORM_MINMAX);//进行最大最小值归一化

110             calcHist(&rgb_planes[1],1,0,Mat(),ghist,1,&histsize1,&ranges1);

111             normalize(ghist,ghist,0,DRAW_H,NORM_MINMAX);

112             calcHist(&rgb_planes[2],1,0,Mat(),bhist,1,&histsize1,&ranges1);

113             normalize(bhist,bhist,0,DRAW_H,NORM_MINMAX);

114             if(nFrame_num==1)

115             {

116 //                preselectROI=selectROI;

117                 preselectROI.x=selectROI.x;

118                 preselectROI.y=selectROI.y;

119                 preselectROI.width=selectROI.width;

120                 preselectROI.height=selectROI.height;

121                 staRoiHist=RoiHist.clone();//第一次选定目标,作为标准模板目标

122             }

123             else if(nFrame_num>1&&comp==true)

124             {

125                 /*************************************************************************************************************************/

126                 /****                                        compareHist():比较2个直方图的相似度                                         ****/

127                 /****        compareHist(),参数1为比较相似度的直方图1;参数2为比较相似度的直方图2;参数3为相似度的计算方式。有四种,         ****/

128                 /****                  分别为CV_COMP_CORREL,CV_COMP_CHISQR,CV_COMP_INTERSECT,CV_COMP_BHATTACHARYYA                     ****/

129                 /*************************************************************************************************************************/

130                 double distence=compareHist(staRoiHist,RoiHist,CV_COMP_INTERSECT);//计算后面选定的与这次选定的相似度,使用INTERSECT,值越大越相似

131                 printf("与第1次选定的图像区域相似度为:%f\n",distence);//数组越大,相似度越大

132 

133                 //显示直方图

134                 for(int i=1;i<histsize1;i++)

135                 {

136                     //画直线中要注意2点,因为图片的原点在左上角,而直方图坐标系的原点在左下角,所以高度值都需要被直方图图纸高度减掉,另外取一维直方图时只能用at运算符

137                     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);

138                     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);

139                     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);

140                 }

141                 imshow("rgb_hist",draw);

142                 draw=Mat::zeros(DRAW_W,DRAW_H,CV_8UC3);//每画完一次直方图后都进行一次清0操作

143                 comp=false;

144             }

145             rectangle(frame,selectROI,Scalar(0,255,0),2,8);//手动选定一次就显示一次

146         }//end tracking

147         rectangle(frame,preselectROI,Scalar(0,0,255),5,8);//初始的选定目标一直不变

148         imshow("camera",frame);

149 

150         //键盘响应

151         char c = (char)waitKey(10);

152         if( c == 27 )

153             break;

154         switch(c)

155         {

156         case 'p'://暂停键

157             pause = !pause;

158             break;

159         default:

160             ;

161         }

162     }//end while;

163     return 0;

164 }

 

实验结果:

  选定框内的模板用红色框标出,其他待比较的模板用绿色框标出。

  模板图像块的简单直方图(rgb分开画的)显示如下:

  基础学习笔记之opencv(4):直方图使用学习

 

   第一次比较结果图:

  基础学习笔记之opencv(4):直方图使用学习

 

  第二次比较结果图:

  基础学习笔记之opencv(4):直方图使用学习

 

   第三次比较结果图(2个框选定的基本重合):

  基础学习笔记之opencv(4):直方图使用学习

 

  三次比较相似度结果:

  基础学习笔记之opencv(4):直方图使用学习

  可以看出,第三次的框与标准框内图像(即第1次选定的图像区域)的相似度值最大。

 

 

 

 

 

 

你可能感兴趣的:(opencv)