通过哈希指纹搜索图像


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

(1)缩小尺寸:去除高频和细节的最快方法是缩小图片,将图片缩小到8x8的尺寸,总共64个像素。不要保持纵横比,只需将其变成8*8的正方形。这样就可以比较任意大小的图片,摒弃不同尺寸、比例带来的图片差异。
(2)简化色彩:将8*8的小图片转换成灰度图像。
(3)计算平均值:计算所有64个像素的灰度平均值。
(4)比较像素的灰度:将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。
(5)计算hash值:将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。

比较两个图片的相似性,就是先计算这两张图片的hash指纹,也就是64位0或1值,然后计算不同位的个数(汉明距离)。如果这个值为0,则表示这两张图片非常相似,如果汉明距离小于5,则表示有些不同,但比较相近,如果汉明距离大于10则表明完全不同的图片。

 1 // 递归获得文件夹下面所有的图片路径
 2 void getFolderDayFile(CString pathStr, vector<CString>& strFileVector)
 3 {
 4     CString myDataPath, fdPath;
 5     myDataPath = pathStr + _T("\*.*");
 6     CString strTmp;
 7     CFileFind find;
 8     bool bf = find.FindFile(myDataPath);
 9 
10     while(bf) {
11         bf = find.FindNextFile();
12         if(!find.IsDots())
13         {
14             fdPath = find.GetFilePath();
15             if(find.IsDirectory())
16                 getFolderDayFile(fdPath, strFileVector);        // 是文件夹,递归,继续查询
17             else
18             {
19                 strTmp = fdPath.Right(4);                    // 是文件,判断是否是*.jpg文件
20                 strTmp.MakeLower();
21                 if(strTmp == ".jpg")
22                     strFileVector.push_back(fdPath);
23             }
24         }
25     }
26     find.Close();
27 }
28 
29 
30 // 哈希指纹获取 
31 vector<int> Perceptual_hash(IplImage *image)
32 {
33     IplImage * temp = cvCreateImage(cvSize(8,8),8,3);
34     cvResize(image, temp, CV_INTER_CUBIC);        // 8*8大小--缩小尺寸
35     IplImage * grayImg = cvCreateImage(cvSize(8,8),8,1);
36     cvCvtColor(temp,grayImg,CV_BGR2GRAY);        // 转灰度--简化色彩
37 
38     char *data = (char *)grayImg->imageData;    // 新图象数据信息
39     int  wp = grayImg->widthStep;
40 
41     int average = 0;
42     for(int i = 0;i < 8;i++)
43         for(int j = 0;j < 8;j++)
44             average += data[i * wp + 3 * j];
45     average /= 64;
46     vector<int> VImg;
47     for(int m = 0;m < 8;m++)
48         for(int n = 0;n < 8;n++)
49             if(data[m * wp + 3 * n] >= average)
50                 VImg.push_back(1);
51             else
52                 VImg.push_back(0);
53     return VImg;
54 }
55 
56 
57 // 通过哈希指纹搜索图片
58 void Hash_search(IplImage *image, CString path)
59 {
60     vector<int> hash_image = Perceptual_hash(image);
61     vector<CString> strFileVector;
62     getFolderDayFile(path, strFileVector);
63     printf("%d
", strFileVector.size());
64 
65     for(int i = 0;i < strFileVector.size();i++)
66     {
67         IplImage * src = cvLoadImage(strFileVector[i]);
68         vector<int> hash_src = Perceptual_hash(src);
69         int com = 0;
70         for(int j = 0;j < 64;j++)
71             if(hash_src[j] != hash_image[j])
72                 com++;
73         if(com <= 5) {            // 相似度量
74             CString str;
75             str.Format("D:\101_Image\%d.jpg",i);
76             cvSaveImage(str, src);
77         }
78         cvReleaseImage(&src);
79     }
80 }

搜索得到的图像(距离太小,只搜索到原图像):

另附一个直方图搜索:

 1 // 通过直方图搜索图像
 2 void Histogram_search(IplImage *image, CString path)
 3 {
 4     CvHistogram * image_hist = Histogram_Image(image);
 5     vector<CString> strFileVector;
 6     getFolderDayFile(path, strFileVector);
 7     printf("%d
", strFileVector.size());
 8     for(int i = 0;i < strFileVector.size();i++) {
 9         IplImage * src = cvLoadImage(strFileVector[i]);
10         CvHistogram * src_hist = Histogram_Image(src);
11         // 直方图相似--Bhattacharyya距离
12         double com = cvCompareHist(image_hist, src_hist, CV_COMP_BHATTACHARYYA);
13         if(com < 0.1) {            // 相似度量
14             CString str;
15             str.Format("D:\101_Image\%d.jpg",i);
16             cvSaveImage(str, src);
17         }
18         cvReleaseImage(&src);
19     }
20 }

2021-06-04

原文地址:https://www.cnblogs.com/2015-16/p/14851208.html