zoukankan      html  css  js  c++  java
  • 图像相似度计算之哈希值方法OpenCV实现

    http://blog.csdn.net/fengbingchun/article/details/42153261

    图像相似度计算之哈希值方法OpenCV实现

     分类:
     
     

    感知哈希算法(perceptual hash algorithm),它的作用是对每张图像生成一个“指纹”(fingerprint)字符串,然后比较不同图像的指纹。结果越接近,就说明图像越相似。

    实现步骤:

    1.      缩小尺寸:将图像缩小到8*8的尺寸,总共64个像素。这一步的作用是去除图像的细节,只保留结构/明暗等基本信息,摒弃不同尺寸/比例带来的图像差异;

    2.      简化色彩:将缩小后的图像,转为64级灰度,即所有像素点总共只有64种颜色;

    3.      计算平均值:计算所有64个像素的灰度平均值;

    4.      比较像素的灰度:将每个像素的灰度,与平均值进行比较,大于或等于平均值记为1,小于平均值记为0;

    5.      计算哈希值:将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图像的指纹。组合的次序并不重要,只要保证所有图像都采用同样次序就行了;

    6.      得到指纹以后,就可以对比不同的图像,看看64位中有多少位是不一样的。在理论上,这等同于”汉明距离”(Hamming distance,在信息论中,两个等长字符串之间的汉明距离是两个字符串对应位置的不同字符的个数)。如果不相同的数据位数不超过5,就说明两张图像很相似;如果大于10,就说明这是两张不同的图像。

    以上内容摘自:http://www.ruanyifeng.com/blog/2011/07/principle_of_similar_image_search.html

    下面是用OpenCV实现的测试代码:

    [cpp] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. string strSrcImageName = "src.jpg";  
    2.   
    3. cv::Mat matSrc, matSrc1, matSrc2;  
    4.   
    5. matSrc = cv::imread(strSrcImageName, CV_LOAD_IMAGE_COLOR);  
    6. CV_Assert(matSrc.channels() == 3);  
    7.   
    8. cv::resize(matSrc, matSrc1, cv::Size(357, 419), 0, 0, cv::INTER_NEAREST);  
    9. //cv::flip(matSrc1, matSrc1, 1);  
    10. cv::resize(matSrc, matSrc2, cv::Size(2177, 3233), 0, 0, cv::INTER_LANCZOS4);  
    11.   
    12. cv::Mat matDst1, matDst2;  
    13.   
    14. cv::resize(matSrc1, matDst1, cv::Size(8, 8), 0, 0, cv::INTER_CUBIC);  
    15. cv::resize(matSrc2, matDst2, cv::Size(8, 8), 0, 0, cv::INTER_CUBIC);  
    16.   
    17. cv::cvtColor(matDst1, matDst1, CV_BGR2GRAY);  
    18. cv::cvtColor(matDst2, matDst2, CV_BGR2GRAY);  
    19.   
    20. int iAvg1 = 0, iAvg2 = 0;  
    21. int arr1[64], arr2[64];  
    22.   
    23. for (int i = 0; i < 8; i++) {  
    24.     uchar* data1 = matDst1.ptr<uchar>(i);  
    25.     uchar* data2 = matDst2.ptr<uchar>(i);  
    26.   
    27.     int tmp = i * 8;  
    28.   
    29.     for (int j = 0; j < 8; j++) {  
    30.         int tmp1 = tmp + j;  
    31.   
    32.         arr1[tmp1] = data1[j] / 4 * 4;  
    33.         arr2[tmp1] = data2[j] / 4 * 4;  
    34.   
    35.         iAvg1 += arr1[tmp1];  
    36.         iAvg2 += arr2[tmp1];  
    37.     }  
    38. }  
    39.   
    40. iAvg1 /= 64;  
    41. iAvg2 /= 64;  
    42.   
    43. for (int i = 0; i < 64; i++) {  
    44.     arr1[i] = (arr1[i] >= iAvg1) ? 1 : 0;  
    45.     arr2[i] = (arr2[i] >= iAvg2) ? 1 : 0;  
    46. }  
    47.   
    48. int iDiffNum = 0;  
    49.   
    50. for (int i = 0; i < 64; i++)  
    51.     if (arr1[i] != arr2[i])  
    52.         ++iDiffNum;  
    53.   
    54. cout<<"iDiffNum = "<<iDiffNum<<endl;  
    55.   
    56. if (iDiffNum <= 5)  
    57.     cout<<"two images are very similar!"<<endl;  
    58. else if (iDiffNum > 10)  
    59.     cout<<"they are two different images!"<<endl;  
    60. else  
    61.     cout<<"two image are somewhat similar!"<<endl;  
  • 相关阅读:
    模块化 —— CommonJS、AMD、UMD、ESM(下)
    模块化 —— CommonJS、AMD、UMD、ESM(上)
    移动端事件(四)—— 函数防抖和函数节流
    移动端事件(三)—— 横竖屏与加速度、移动的方块
    一起来学JavaScript吧(JS兔子领进门)
    【资源】一些常用的前端资源网站(不定期更新)
    redis
    django-高并发解决方案--负载均衡
    输入某年某月某日,判断这一天是这一年的第几天
    一篇英文文档中找出频数最多的10个单词
  • 原文地址:https://www.cnblogs.com/donaldlee2008/p/5277914.html
Copyright © 2011-2022 走看看