相似图片搜索原理三(颜色直方图—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)表示为该像素值出现的次数和除以总的像素个数,就是一个概率,代码中可以看出。

代码:

计算方式一:

(1)得到颜色直方图:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 三维直方图 方式一
void getHistogram(Mat &image, int *histValue){
     MatND hist;       // 在cv中用CvHistogram *hist = cvCreateHist
     int dims = 3 ;
 
     float r_hranges[] = { 0 , 255 };
     float g_hranges[] = { 0 , 255 };
     float b_hranges[] = { 0 , 255 };
     const float *ranges[] = {r_hranges, g_hranges, b_hranges};   // 这里需要为const类型
     int size[ 3 ] = { 16 , 16 , 16 };
     int channels[] ={ 0 , 1 , 2 };   //代表 r g通道 2代表b通道
     // 计算图像的直方图
     calcHist(&image, 1 , channels, Mat(), hist, dims, size, ranges);    // cv 中是cvCalcHist
     
 
     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);           //   注意直方图的值是float类型    cv中用cvQueryHistValue_1D
                 int realValue = saturate_cast< int >(value);
                 int index = i + (j<< 4 ) + (k<< 8 );
                 histValue[index] = realValue;
 
             }
         }
     }
 
}</ int ></ float >


 

(2)三种距离度量的代码

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 欧式距离
float getDistance( int *sur, int *dst){
     float sum = 0 ;
     for ( int i = 0 ; i < MaxHistValue; 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 < MaxHistValue; 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 < MaxHistValue; i++){
         sum += sqrt((sur[i]/sTotal)*(dst[i]/dTotal));
     }
     return sum;
}

 

测试图片:

\

余弦结果:

\

巴氏距离结果:

\

其中【i-j】, i代表personi, j代表personi与person的汉明距离。并由结果可见phash对于图片的旋转肯定是无能为力的。

由结果可见,针对person6,很相似,但余弦结果不好,而巴氏距离很好,此外巴氏距离对于原图不是1,是因为计算过程中的精度丢失造成的。

 

计算方式二:

(1)得到颜色直方图

 

?
1
2
3
4
5
6
7
8
9
10
11
// 三维直方图 方式二
void getHistogram2(Mat &image, int **HistValue){
     for ( int i = 0 ; i < image.rows; i++){
         for ( int j = 0 ; j < image.cols; j++){
             HistValue[ 0 ][image.at<vec3b>(i,j)[ 0 ]] ++;
             HistValue[ 1 ][image.at<vec3b>(i,j)[ 1 ]] ++;
             HistValue[ 2 ][image.at<vec3b>(i,j)[ 2 ]] ++;
         }
     }
     
}</vec3b></vec3b></vec3b>

 

(2)三种距离度量的代码

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 欧式距离
float getDistance( int **sur, int **dst){
     float sum = 0 ;
     for ( int i = 0 ; i < 3 ; i++){
         for ( int j = 0 ; j < 256 ; j++){
             sum += pow(sur[i][j]-dst[i][j]+ 0.0 , 2 );
         }
         
     }
     return sqrt(sum);
}
 
// 余弦距离
float getCosDistance( int **sur, int **dst){
     float surSum = 0 , dstSum = 0 , sum = 0 ;
     for ( int i = 0 ; i < 3 ; i++){
         for ( int j = 0 ; j < 256 ; j++){
             surSum += pow(sur[i][j]+ 0.0 , 2 );
             dstSum += pow(dst[i][j]+ 0.0 , 2 );
             sum += sur[i][j]*dst[i][j];
         }
         
     }
     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 < 3 ; i++){
         for ( int j = 0 ; j < 256 ; j++){
             sum += sqrt((sur[i][j]/sTotal)*(dst[i][j]/dTotal));
         }
     }
     return sum/ 3 ;    // 因为这里有三个
}

 

余弦结果:

\

巴氏距离结果:

\

其中【i-j】, i代表personi, j代表personi与person的汉明距离。并由结果可见phash对于图片的旋转肯定是无能为力的。

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值