Image similarity calculation hash value method OpenCV implementation

The perceptual hash algorithm, which works by generating a string of "fingerprints" for each image, and then comparing the fingerprints of the different images. The closer the results are, the more similar the images are.

Implementation steps:

1. Reduce size: reduce the image to 8*8 size, 64 pixels in total. The function of this step is to remove the details of the image, retain only the basic information such as structure/light and shade, and discard the image differences caused by different sizes/ratios;

2. Simplify colors: Convert the reduced image to 64-level grayscale, that is, all pixels have only 64 colors in total;

3. Calculate the average value: Calculate the grayscale average value of all 64 pixels;

4. Compare the grayscale of the pixels: compare the grayscale of each pixel with the average value, if it is greater than or equal to the average value, it is recorded as 1, and if it is less than the average value, it is recorded as 0;

5. Calculate the hash value: Combine the comparison results in the previous step to form a 64-bit integer, which is the fingerprint of this image. The order of the combination is not important, as long as all images are in the same order;

6. After getting the fingerprint, you can compare different images to see how many bits in the 64 bits are different. In theory, this is equivalent to the "Hamming distance" (in information theory, the Hamming distance between two strings of equal length is the number of different characters in the corresponding positions of the two strings). If the number of different data bits does not exceed 5, it means that the two images are very similar; if it is greater than 10, it means that these are two different images.

string strSrcImageName = "src.jpg";  
  
cv::Mat matSrc, matSrc1, matSrc2;  
  
matSrc = cv::imread(strSrcImageName, CV_LOAD_IMAGE_COLOR);  
CV_Assert(matSrc.channels() == 3);  
  
cv::resize(matSrc, matSrc1, cv::Size(357, 419), 0, 0, cv::INTER_NEAREST);  
//cv::flip(matSrc1, matSrc1, 1);  
cv::resize(matSrc, matSrc2, cv::Size(2177, 3233), 0, 0, cv::INTER_LANCZOS4);  
  
cv::Mat matDst1, matDst2;  
  
cv::resize(matSrc1, matDst1, cv::Size(8, 8), 0, 0, cv::INTER_CUBIC);  
cv::resize(matSrc2, matDst2, cv::Size(8, 8), 0, 0, cv::INTER_CUBIC);  
  
cv::cvtColor(matDst1, matDst1, CV_BGR2GRAY);  
cv::cvtColor(matDst2, matDst2, CV_BGR2GRAY);  
  
int iAvg1 = 0, iAvg2 = 0;  
int arr1[64], arr2[64];  
  
for (int i = 0; i < 8; i++) {  
    uchar* data1 = matDst1.ptr<uchar>(i);  
    uchar* data2 = matDst2.ptr<uchar>(i);  
  
    int tmp = i * 8;  
  
    for (int j = 0; j < 8; j++) {  
        int tmp1 = tmp + j;  
  
        arr1[tmp1] = data1[j] / 4 * 4;  
        arr2[tmp1] = data2[j] / 4 * 4;  
  
        iAvg1 += arr1[tmp1];  
        iAvg2 += arr2[tmp1];  
    }  
}  
  
iAvg1 /= 64;  
iAvg2 /= 64;  
  
for (int i = 0; i < 64; i++) {  
    arr1[i] = (arr1[i] >= iAvg1) ? 1 : 0;  
    arr2[i] = (arr2[i] >= iAvg2) ? 1 : 0;  
}  
  
int iDiffNum = 0;  
  
for (int i = 0; i < 64; i++)  
    if (arr1[i] != arr2[i])  
        ++iDiffNum;  
  
cout<<"iDiffNum = "<<iDiffNum<<endl;  
  
if (iDiffNum <= 5)  
    cout<<"two images are very similar!"<<endl;  
else if (iDiffNum > 10)  
    cout<<"they are two different images!"<<endl;  
else  
    cout<<"two image are somewhat similar!"<<endl;  

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325046391&siteId=291194637