相似圖片搜索原理三(c++)顏色直方圖

圖像的顏色直方圖可以用於圖像檢索,適應有相同色彩,並且可以有平移、縮放、旋轉不變性的圖像檢索,當然了這三大特點不如sift或者surf穩定性強,此外最大的侷限就是如果形狀內容一樣,但色彩不一,結果是搜不到的。不過它在某些情況下達到較好的結果。

顏色直方圖兩種計算方式:

彩色圖像的顏色直方圖,這裏可以有兩種處理方式,得到的效果應該差不多。

首先第一種就是對像素的每個通道都進行劃分,每個通道的最大像素值爲255,可以等分8、16或者64等分,這樣每個通道的範圍就是0~15(以16等分爲例,當然等分越小,像素值取的範圍越大,越精確,但圖像維數就越大,消耗時間複雜度大)。這樣三通道得到圖像維數就是16*16*16=4096維(從[0,0,0]一直到[15,15,15])。代碼中我們使用了得到其下標操作爲i+(j<<4)+(k<<8)就等於i+j*16+k*16*16。比如一個像素爲[4,1,20],那麼就會有hist[4+1*16+20*16*16]++;

第二種方法是單獨計算每個通道像素值的個數,比如一個像素點值爲[4,1,20],那麼就有bhist[4] ++;ghist[1]++; rhist[20]++;這樣就得到3個256維的一維向量,然後可以做疊加操作。

距離的度量

距離的度量通常有歐式距離、皮爾遜相關係數及餘弦距離。但是這裏百度百科上說在做直方圖相似性度量時,巴氏距離效果最佳。我這裏做了簡單測試,發現歐式距離的確效果很差,這可能的原因比如當[5,5]與[1,1]應該相似的,但是歐式距離發現它們距離會很大。此外,這裏餘弦距離,測試效果也行,也是可以用的。

巴氏距離:又叫巴氏係數。用於測量兩離散概率分佈。它常在分類中測量類之間的可分離性。計算公式如下:

其中P, P’分別代表源與候選的圖像直方圖數據,對每個相同i的數據點乘積開平方以後相加得出的結果即爲圖像相似度值(巴氏係數因子值),範圍爲0到1之間。爲什麼是到1之間,這是數學的問題,就不追究了。當p(i)==p’(i) for all i時,結果就會爲1。 p(i)與p’(i)都在0~1之間。p(i)表示爲該像素值出現的次數和除以總的像素個數,就是一個概率,代碼中可以看出。

代碼實現

#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
using namespace std;
using namespace cv;

void calc_histogram(Mat &img,int* histValue){

MatND hist;
int channels[] = { 0, 1, 2 };
int size[] = { 16, 16, 16 };
float range_b[] = { 0, 255 };
float range_g[] = { 0, 255 };
float range_r[] = { 0, 255 };
const float* rangs[] = { range_b, range_g, range_r };
calcHist(&img, 1, channels, Mat(), hist, 3, size, rangs);

for (int i = 0; i < 16;i++){
for (int j = 0; j < 16;j++){
for (int k = 0; k < 16; k++){
float value = hist.at<float>(i, j, k);
int realValue = saturate_cast<int>(value);
int index = i + (j << 4) + (k << 8);
histValue[index] = realValue;
}
}
}
}
float getDistance(int *sur,int* dst){
float sum = 0;
for (int i = 0; i < 4096; i++){
sum += pow(sur[i]-dst[i]+0.0,2);
}
return sqrt(sum);
}
float getCosDistance(int *sur, int *dst){
float surSum = 0, dstSum = 0, sum = 0;
for (int i = 0; i < 4096; i++){
surSum += pow(sur[i] + 0.0, 2);
dstSum += pow(dst[i] + 0.0, 2);
sum += sur[i] * dst[i];
}
surSum = sqrt(surSum);
dstSum = sqrt(dstSum);
return sum / (surSum*dstSum);
}
float getPSDistance(int *sur, int*dst, const float sTotal, const float dTotal){
float sum = 0;
for (int i = 0; i < 4096; i++){
sum += sqrt((sur[i] / sTotal)*(dst[i] / dTotal));
}
return sum;
}
int main(){

Mat img = imread(“yaleB05//1.pgm”);
int* histValue = new int[4096];

memset(histValue, 0, sizeof(histValue) * 256);

int* histValue1 = new int[4096];

memset(histValue1, 0, sizeof(histValue1) * 256);
for (int num = 1; num < 17;num++){

Mat src;
String str;
std::string pos;
std::stringstream ss;
ss << num;
ss >> pos;
str = “yaleB05//” + pos+”.pgm”;
src = imread(str);
imshow(str,src);

calc_histogram(img, histValue);
float total = 0;
for (int i = 0; i < 4096; i++){
total += histValue[i];
}

calc_histogram(src, histValue1);
float total1 = 0;
for (int i = 0; i < 4096; i++){
total1 += histValue[i];
}
float Cosdistance = getCosDistance(histValue, histValue1);
cout <<“prepon:”<<num<<” “<< “Cosdistance:” << Cosdistance << endl;
float bhattacryya = getPSDistance(histValue, histValue1, img.rows*img.cols, src.rows*src.cols);
cout <<“prepon:”<<num<<” “<< “PSDdistance:” << bhattacryya << endl;
}
delete[] histValue;
delete[] histValue1;
return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章