æç¥åå¸ç®æ³(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 plaincopyprint?
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;
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;