http://blog.csdn.net/armily/article/details/8965629
最近在研究Meanshift跟蹤算法,遇到一些概念,比如顏色直方圖和反向投影,有些不理解,故百度搜之,並小結,希望能印象深刻。
(一)顏色直方圖
顏色特徵是圖像檢索中應用最爲廣泛的視覺特徵,主要原因在於顏色往往和圖像中所包含的物體或場景十分相關。此外,與其他的視覺特徵相比,顏色特徵對圖像本身的尺寸、方向、視角的依賴性較小,從而具有較高的魯棒性。
首先,我們需要合適的顏色空間來描述顏色特徵;其次,我們要採用一定的量化方法將顏色特徵表達爲向量的形式;最後,還要定義一種相似度(距離)標準用來衡量圖像之間在顏色上的相似性。
顏色直方圖所描述的是不同色彩在整幅圖像中所佔的比例,而並不關心每種色彩所處的空間位置,即無法描述圖像中的對象或物體。顏色直方圖特別適於描述那些難以進行自動分割的圖像。顏色直方圖是基於不同的顏色空間和座標系。最常用的顏色空間是RGB顏色空間,原因在於大部分的數字圖像都是用這種顏色空間表達的。然而,RGB空間結構,並不符合人們對顏色相似性的主觀判斷。因此,有人提出了基於HSV空間、Luv空間和Lab空間的顏色直方圖,因爲它們更接近於人們對顏色的主觀認識。其中HSV空間是直方圖最常用的顏色空間。它的三個分量分別代表色彩(Hue)、飽和度(S)和值(V)。
計算顏色直方圖需要將顏色空間劃分爲若干個小的顏色區間,每個小區間成爲直方圖的一個bin。這個過程成爲顏色量化(color quantization)。然後,通過計算顏色落在每個小區間內的像素數量可以得到顏色直方圖。顏色量化有許多種方法,例如向量量化、聚類方法或者神經網絡方法。
OpenCV中常用的直方圖操作
1)歸一化直方圖
cvNormalizeHist(CvHistogram * hist,double factor); factor通常設爲1
2)閾值函數
cvThreshHist(CvHistogram * hist,double factor);factor是一個開關閾值
3)複製直方圖
void cvCopyHist(const CvHistogram * src,CvHistogram ** dst);
4)獲得直方圖的最小最大值
void cvGetMinMaxHistValue(const CvHistogram * hist,float * min_value, float * max_value,int * min_idx=NULL,int * max_idx=NULL);
5)計算直方圖
void cvCalcHist(IplImage ** image,CvHistogram * hist,int accumulate=0,const CvArr * mask=NULL);
6)對比兩個直方圖
double cvCompareHist(const CvHIstogram *hist1,const CvHistogram *hist2,int method);
7)創建直方圖
CvHistogram * cvCreateHist(int dims,int *size,int type, float ** ranges=NULL,int uniform=1);
舉例:
int h_bins=30,s_bins=32;
int hist_size[]={ h_bins, s_bins};
float h_ranges[]={0,180};
float s_ranges[]={0,255};
float * ranges[]={h_ranges,s_ranges};
CvHistogram * hist;
hist=cvCreateHist(2,hist_size,CV_HIST_ARRAY,ranges,1);
8)在使用直方圖之前給rangs設置數值
void cvSetHistBinRanges(CvHistogram * hist,float ** ranges,int uniform=1);
注意:
I)uniform 說明直方圖是否有均勻的bin,如果設置爲非零值,則直方圖是均勻的,也可以設置爲NULL,意味着rangs是未知的。
II)這個範圍的用處是確定何時計算直方圖或決定反向映射
9)釋放直方圖
如果想重用直方圖,可以對其進行清零操作(即設置所有bins爲0),或者使用通常的釋放函數釋放直方圖
void cvClearHist(CvHistogram * hist);
void cvReleaseHist(CvHistogram ** hist);
10)根據已給出的數據創建直方圖
CvHistogram * cvMakeHistHeaderForArray(int dims,int * sizes,CvHistogram * hist,float * data,float ** ranges=NULL);
11)訪問直方圖
double cvQueryHistValue_1D(CvHistogram * hist,int idx0);
double cvQueryHistValue_2D(CvHistogram * hist,int idx0,int idx1);
double cvQueryHistValue_3D(CvHistogram * hist,int idx0,int idx1,int idx2);
double cvQueryHistValue_nD(CvHistogram * hist,int * idxN);
12)反向投影
http://blog.163.com/chenliangren@126/blog/static/168305659201072761518425/
反向投影是一種記錄像素點或者像素塊如何適應直方圖模型中分佈的方式。
void cvCalcBackProject(IplImage ** image,CvArr * back_project,const CvHistogram * hist);
void cvCalcBackProjectPatch(IplImage ** image,CvArr * dst,CvSize patch_size,CvHistogram * hist ,int method,float factor);
應用:
I)如果我們有一個顏色直方圖,可以利用反向投影在圖像中找到該區域。
II)我們可以用函數cvCalcBackProject()計算一個像素是否是一個已知目標的一部分
III)也可以用函數cvCalcBackProjectPatch()計算一塊區域是否包含已知的目標
13)畫直方圖
http://hi.baidu.com/devisdu/blog/item/2f73ff2d1f15403f349bf712.html
(二)反向投影圖
反向投影圖,用輸入圖像的某一位置上像素值(多維或灰度)對應在直方圖的一個bin上的值來代替該像素值,所以得到的反向投影圖是單通的。用統計學術語,輸出圖像象素點的值是觀測數組在某個分佈(直方圖)下的概率。圖像的反向投影圖,簡單理解,就是一張概率密度圖。反向投影圖上的像素點表徵着一種概率,如果這個點越亮,就說明這個點屬於物體的概率越大。
例子:
Image=
0 1 2 3
4 5 6 7
8 9 10 11
8 9 14 15
Histogram=
4 4 6 2(3)反向投影圖
Back_Projection=
4 4 4 4
4 4 4 4
6 6 6 6
6 6 2 2
例如位置(0,0)上的像素值爲0,對應的bin爲[0,3),所以反向直方圖在該位置上的值這個bin的值4。
用到的函數:
calcBackProject。
calcBackProject的輸入爲圖像及其直方圖,輸出與待跟蹤圖像大小相同,每一個像素點表示該點爲目標區域的概率。這個點越亮,該點屬於物體的概率越大。
- 測試代碼如下:
- #include <iostream>
- using namespace std;
- #include <iomanip>
- #include <highgui.h>
- #include <cv.h>
- int main()
- {
- uchar data[]={0,1,2,3,4,5,6,7,8,9,10,11,8,9,14,15}; //圖像數據
- CvMat mat=cvMat(4,4,CV_8UC1,data);
- IplImage g_img; //灰度圖
- cvGetImage(&mat,&g_img);
- //打印圖像數據
- cout<<"Image="<<endl;
- for(int i=0;i<g_img.height;i++)
- {
- uchar* ptr=(uchar*)(g_img.imageData+i*g_img.widthStep);
- for(int j=0;j<g_img.width;j++)
- {
- cout<<setw(3)<<setprecision(2)<<(int)ptr[j]<<" ";
- }
- cout<<endl;
- }
- //計算圖像直方圖
- IplImage* imgs[]={&g_img};
- int g_bin=4;
- int size[]={g_bin};
- float g_ranges[]={0,4,8,12,16};
- float* ranges[]={g_ranges};
- CvHistogram* hist=cvCreateHist(1,size,CV_HIST_ARRAY,ranges,0);
- cvCalcHist(imgs,hist);
- //打印圖像直方圖數據
- cout<<"Histogram="<<endl;
- for(int i=0;i<g_bin;i++)
- {
- cout<<setw(3)<<setprecision(2)<<*cvGetHistValue_1D(hist,i)<<" ";
- }
- cout<<endl;
- //計算反向投影圖
- IplImage* back_project=cvCreateImage(cvGetSize(&g_img),g_img.depth,1);
- cvCalcBackProject(imgs,back_project,hist);
- //打印反向投影圖數據
- cout<<"Back_Projection="<<endl;
- for(int i=0;i<back_project->height;i++)
- {
- uchar* ptr=(uchar*)(back_project->imageData+i*back_project->widthStep);
- for(int j=0;j<back_project->width;j++)
- {
- cout<<setw(3)<<setprecision(2)<<(int)ptr[j]<<" ";
- }
- cout<<endl;
- }
- }
反向投影的作用:反向投影用於在輸入圖像(通常較大)中查找特定圖像(通常較小或者僅1個像素,以下將其稱爲模板圖像)最匹配的點或者區域,也就是定位模板圖像出現在輸入圖像的位置。