相似图片搜索原理三(颜色直方图—c++实现)

悠悠 2022-08-08 12:49 201阅读 0赞

图像的颜色直方图可以用于图像检索,适应有相同色彩,并且可以有平移、缩放、旋转不变性的图像检索,当然了这三大特点不如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]应该相似的,但是欧式距离发现它们距离会很大。此外,这里余弦距离,测试效果也行,也是可以用的。

巴氏距离:又叫巴氏系数。用于测量两离散概率分布。它常在分类中测量类之间的可分离性。计算公式如下:

Center

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

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

  1. // 欧式距离
  2. float getDistance(int *sur, int *dst){
  3. float sum = 0;
  4. for(int i = 0; i < MaxHistValue; i++){
  5. sum += pow(sur[i]-dst[i]+0.0,2);
  6. }
  7. return sqrt(sum);
  8. }
  9. // 余弦距离
  10. float getCosDistance(int *sur, int *dst){
  11. float surSum = 0, dstSum = 0, sum = 0;
  12. for(int i = 0; i < MaxHistValue; i++){
  13. surSum += pow(sur[i]+0.0,2);
  14. dstSum += pow(dst[i]+0.0,2);
  15. sum += sur[i]*dst[i];
  16. }
  17. surSum = sqrt(surSum);
  18. dstSum = sqrt(dstSum);
  19. return sum/(surSum*dstSum);
  20. }
  21. // 巴氏距离, 需要除以总元素个个数
  22. // 注意:在颜色直方图的相似度比较中,巴氏距离效果最好
  23. float getPSDistance(int *sur, int*dst, const float sTotal, const float dTotal){
  24. float sum = 0;
  25. for(int i = 0; i < MaxHistValue; i++){
  26. sum += sqrt((sur[i]/sTotal)*(dst[i]/dTotal));
  27. }
  28. return sum;
  29. }

测试图片:

Center 1

余弦结果:

Center 2

巴氏距离结果:

Center 3

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

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

计算方式二:

(1)得到颜色直方图

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

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

  1. // 欧式距离
  2. float getDistance(int **sur, int **dst){
  3. float sum = 0;
  4. for(int i = 0; i < 3; i++){
  5. for(int j = 0; j < 256; j++){
  6. sum += pow(sur[i][j]-dst[i][j]+0.0,2);
  7. }
  8. }
  9. return sqrt(sum);
  10. }
  11. // 余弦距离
  12. float getCosDistance(int **sur, int **dst){
  13. float surSum = 0, dstSum = 0, sum = 0;
  14. for(int i = 0; i < 3; i++){
  15. for(int j = 0; j < 256; j++){
  16. surSum += pow(sur[i][j]+0.0,2);
  17. dstSum += pow(dst[i][j]+0.0,2);
  18. sum += sur[i][j]*dst[i][j];
  19. }
  20. }
  21. surSum = sqrt(surSum);
  22. dstSum = sqrt(dstSum);
  23. return sum/(surSum*dstSum);
  24. }
  25. // 巴氏距离, 需要除以总元素个个数
  26. // 注意:在颜色直方图的相似度比较中,巴氏距离效果最好
  27. float getPSDistance(int **sur, int**dst, const float sTotal, const float dTotal){
  28. float sum = 0;
  29. for(int i = 0; i < 3; i++){
  30. for(int j = 0; j < 256; j++){
  31. sum += sqrt((sur[i][j]/sTotal)*(dst[i][j]/dTotal));
  32. }
  33. }
  34. return sum/3; // 因为这里有三个
  35. }

余弦结果:

Center 4

巴氏距离结果:

Center 5

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

完整源码(均匀hash、感知hash、颜色直方图)下载地址:

http://download.csdn.net/detail/lu597203933/8710535

参考文献:

1:http://blog.csdn.net/jia20003/article/details/7771651

2:http://blog.csdn.net/luoweifu/article/details/8690835

3:http://baike.baidu.com/view/10343198.htm巴氏距离

发表评论

表情:
评论列表 (有 0 条评论,201人围观)

还没有评论,来说两句吧...

相关阅读

    相关 相似图片搜索原理

    最近在做一些东西,想到计算两幅图片的相似程度,在知乎上看到这篇文章,特转下来看。 [作者:阮一峰][Link 1] 上个月,Google把["相似图片搜索][Link

    相关 相似图片搜索算法介绍

    前言 之前对图片聚类有一丢丢的研究,最近发现,使用一些相似图片搜索算法也可以实现图片聚类的目标:将同类别或差不多的图片聚在一起。所以整理出相似图片搜索算法介绍这篇文章,主