感知哈希算法(perceptual hash algorithm),它的做用是對每張圖像生成一個「指紋」(fingerprint)字符串,而後比較不一樣圖像的指紋。結果越接近,就說明圖像越類似。算法
實現步驟:code
1. 縮小尺寸:將圖像縮小到8*8的尺寸,總共64個像素。這一步的做用是去除圖像的細節,只保留結構/明暗等基本信息,摒棄不一樣尺寸/比例帶來的圖像差別;ip
2. 簡化色彩:將縮小後的圖像,轉爲64級灰度,即全部像素點總共只有64種顏色;字符串
3. 計算平均值:計算全部64個像素的灰度平均值;string
4. 比較像素的灰度:將每一個像素的灰度,與平均值進行比較,大於或等於平均值記爲1,小於平均值記爲0;hash
5. 計算哈希值:將上一步的比較結果,組合在一塊兒,就構成了一個64位的整數,這就是這張圖像的指紋。組合的次序並不重要,只要保證全部圖像都採用一樣次序就好了;it
6. 獲得指紋之後,就能夠對比不一樣的圖像,看看64位中有多少位是不同的。在理論上,這等同於」漢明距離」(Hamming distance,在信息論中,兩個等長字符串之間的漢明距離是兩個字符串對應位置的不一樣字符的個數)。若是不相同的數據位數不超過5,就說明兩張圖像很類似;若是大於10,就說明這是兩張不一樣的圖像。class
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;