2009年1月2日 星期五

OpenCV統計應用-直方圖比較

cvCompareHist(),是比較兩個統計直方圖的分布,總共有四個方法,被定義如下:

#define CV_COMP_CORREL 0
#define CV_COMP_CHISQR 1
#define CV_COMP_INTERSECT 2
#define CV_COMP_BHATTACHARYYA 3

而這些方法分別為相關係數,卡方,交集法以及在做常態分布比對的Bhattacharyya距離,這些方法都是用來做統計直方圖的相似度比較的方法,而且,都是根據統計學的概念,這邊就簡單的拿來用灰階統計直方圖來比較,而這部份的比較方式,是由圖形的色彩結構來著手,下面就簡單的用三種情況來分析它們距離比較的方式

直方圖比較實作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
#include <stdlib.h>

int HistogramBins = 256;
float HistogramRange1[2]={0,255};
float *HistogramRange[1]={&HistogramRange1[0]};

int main()
{
    IplImage *Image1=cvLoadImage("RiverBank.jpg",0);
    IplImage *Image2=cvLoadImage("DarkClouds.jpg",0);

    CvHistogram *Histogram1=cvCreateHist(1,&HistogramBins,CV_HIST_ARRAY,HistogramRange);
    CvHistogram *Histogram2=cvCreateHist(1,&HistogramBins,CV_HIST_ARRAY,HistogramRange);

    cvCalcHist(&Image1,Histogram1);
    cvCalcHist(&Image2,Histogram2);

    cvNormalizeHist(Histogram1,1);
    cvNormalizeHist(Histogram2,1);

    printf("CV_COMP_CORREL : %.4f\n",cvCompareHist(Histogram1,Histogram2,CV_COMP_CORREL));
    printf("CV_COMP_CHISQR : %.4f\n",cvCompareHist(Histogram1,Histogram2,CV_COMP_CHISQR));
    printf("CV_COMP_INTERSECT : %.4f\n",cvCompareHist(Histogram1,Histogram2,CV_COMP_INTERSECT));
    printf("CV_COMP_BHATTACHARYYA : %.4f\n",cvCompareHist(Histogram1,Histogram2,CV_COMP_BHATTACHARYYA));

    cvNamedWindow("Image1",1);
    cvNamedWindow("Image2",1);
    cvShowImage("Image1",Image1);
    cvShowImage("Image2",Image2);
    cvWaitKey(0);
}

原始圖片:





 

執行結果:

(1)RiverBank.jpg & DarkClouds.jpg

Output:
CV_COMP_CORREL : -0.1407
CV_COMP_CHISQR : 0.6690
CV_COMP_INTERSECT : 0.4757
CV_COMP_BHATTACHARYYA : 0.4490

(2)RiverBank.jpg & RiverBank.jpg

Output:
CV_COMP_CORREL : 1
CV_COMP_CHISQR : 0
CV_COMP_INTERSECT : 1
CV_COMP_BHATTACHARYYA : 0

(3)Black.jpg & White.jpg

Output:
CV_COMP_CORREL : 1
CV_COMP_CHISQR : 1
CV_COMP_INTERSECT : 0
CV_COMP_BHATTACHARYYA : 1

這邊的直方圖比較,則是將它們的統計直方圖用cvNormalizeHist()正規化成1,在由正規化的統計分佈來做直方圖的比較,從上面的輸出結果可以推測出,卡方法以及Bhattacharyya是數值越小圖形越相似,而相關係數則是看圖形的分佈程度,因此第三個Black.jpg&White.jpg所顯示相關係數的結果才會是1,這邊的圖形比較用的是統計學的方法,而一般的比較方式還有歐幾里德距離的方式,在這個cvCompareHist()的函式,也可以實作出多通道的多維度直方圖比較,而且支援CV_HIST_ARRAY及CV_HIST_SPARSE這兩種直方圖資料結構的格式,而這些比對方法的相關公式如下


相關係數法

而它的公式推導如下



再來是卡方的方式

這邊的卡方法跟一般的卡方檢定不太一樣,下面是一般適合度檢定(Goodness of fit test)的公式

o為觀察者次數,e為期望值次數


交集的方式就比較簡單了,兩個直方圖取最小的做累加



再來就是常態分配比對的Bhattacharyya距離






2 意見:

匿名 提到...

请教个问题:
把直方图映射到2D或3D空间有哪些办法?

问题源于我有一系列特征点,我可以计算每个点的直方图,目的是基于直方图比较特征点的相似度。

如果可以把这些直方图映射(project)到2D或3D,我就可以画出这些点看看能否分组(cluster)?

谢谢

Jesse Stone 提到...

#include
#include
#include
#include
#include

int main( int argc, char** argv )
{
IplImage* src[4];
int i,j,k;

//if( argc >= 5)
{
src[0] = cvLoadImage("HandIndoorColor.jpg");
src[1] = cvLoadImage("HandIndoorColor.jpg");
src[2] = cvLoadImage("HandOutdoorColor.jpg");
src[3] = cvLoadImage("HandOutdoorSunColor.jpg");

// Compute the HSV image, and decompose it into separate planes.
//
IplImage *hsv[4], *y_plane[4],*s_plane[4],*v_plane[4],*planes[4][3];
CvHistogram* hist[4];
IplImage* histimg[4];
int y_bins = 255, s_bins = 255, v_bins= 255;
int hist_size[] = { y_bins };
float h_ranges[2] = { 0, 255 };
//float s_ranges[2] = { 0, 255 };
//float v_ranges[2] = { 0, 255 };
float* ranges[1] = { h_ranges };
int bin_w;
float max_val;

for(i=0; i<=3; i++)
{
hsv[i] = cvCreateImage( cvGetSize(src[i]), 8, 3 );
cvCvtColor( src[i], hsv[i], CV_BGR2YCrCb );

y_plane[i] = cvCreateImage( cvGetSize(src[i]), 8, 1 );
s_plane[i] = cvCreateImage( cvGetSize(src[i]), 8, 1 );
v_plane[i] = cvCreateImage( cvGetSize(src[i]), 8, 1 );
planes[i][0] = y_plane[i];
planes[i][1] = s_plane[i];
planes[i][2] = v_plane[i];
cvCvtPixToPlane( hsv[i], y_plane[i], s_plane[i], v_plane[i], 0 );
// Build the histogram and compute its contents.

hist[i] = cvCreateHist( 1, hist_size, CV_HIST_ARRAY, ranges, 1 );
cvCalcHist( &y_plane[i], hist[i], 0, 0 );
//cvNormalizeHist( hist[i], 1.0 );

histimg[i] = cvCreateImage( cvSize(720,480), 8, 3 );
cvZero( histimg[i] );

cvGetMinMaxHistValue( hist[i], 0, &max_val, 0, 0 ); // 硐梑郔湮硉
cvConvertScale( hist[i]->bins, hist[i]->bins, max_val?256.00f/max_val:0.00f, 0 ); // 坫溫 bin 善潔 [0,360]
cvZero( histimg[i] );
bin_w = histimg[i]->width / y_bins; // hdims: 沭腔跺杅ㄛ寀 bin_w 峈沭腔遵僅

// 賒眻源芞
for( k = 0; k < y_bins; k++ )
{
double val = ( cvGetReal1D(hist[i]->bins,k) * histimg[i]->height/256.00f );
CvScalar color = CV_RGB(255,0,0);
cvRectangle(histimg[i],
cvPoint(k*bin_w,histimg[i]->height),
cvPoint((k+1)*bin_w,(int)(histimg[i]->height - val)),
color,
1,
8,
0 );
}
}//For the 5 images

cvNamedWindow( "Histogram 0", 0 );
cvShowImage( "Histogram 0", histimg[0] );

cvNamedWindow( "Histogram 1", 0 );
cvShowImage( "Histogram 1", histimg[1] );

cvNamedWindow( "Histogram 2", 0 );
cvShowImage( "Histogram 2", histimg[2] );

cvNamedWindow( "Histogram 3", 0 );
cvShowImage( "Histogram 3", histimg[3] );

for(i=0; i<=3; ++i)
cvNormalizeHist( hist[i], 1.00f );

for(i=1; i<=3; ++i)
{//For histogram
printf("Map0 : Map%d\n",i);
for(j=0; j<=3; j++)
{
printf("Method %d ",j);
printf("%lf",cvCompareHist(hist[0],hist[i],j));
printf("\n");
}
printf("\n");
}

cvWaitKey(0);
}
}

//Jesse Stone Taiwan

Copyright 2008-2009,yester