基礎學習筆記之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分開畫的)顯示如下:

  

 

   第一次比較結果圖:

  

 

  第二次比較結果圖:

  

 

   第三次比較結果圖(2個框選定的基本重合):

  

 

  三次比較相似度結果:

  

  可以看出,第三次的框與標准框內圖像(即第1次選定的圖像區域)的相似度值最大。

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM