Reputation: 29
I have some problems with aHash and dHash : http://www.hackerfactor.com/blog/?/archives/529-Kind-of-Like-That.html
I used C++ and OpenCV
The problem is that dHash works worse than aHash. Although in theory, it should be better. For example: I chose a picture, did some manipulation with that and calculated the Hamming Distance between hashes of original and modificated images. The result is there
here is the function for aHash
__int64 calcImageHash(IplImage* src, bool show_results)
{
if(!src){
return 0;
}
IplImage *res=0, *gray=0, *bin =0;
res = cvCreateImage( cvSize(8, 8), src->depth, src->nChannels);
gray = cvCreateImage( cvSize(8, 8), IPL_DEPTH_8U, 1);
bin = cvCreateImage( cvSize(8, 8), IPL_DEPTH_8U, 1);
cvResize(src, res);
cvCvtColor(res, gray, CV_BGR2GRAY);
CvScalar average = cvAvg(gray);
printf("[i] average: %.2f \n", average.val[0]);
cvThreshold(gray, bin, average.val[0], 255, CV_THRESH_BINARY);
__int64 hash = 0;
int i=0;
for( int y=0; y<bin->height; y++ ) {
uchar* ptr = (uchar*) (bin->imageData + y * bin->widthStep);
for( int x=0; x<bin->width; x++ ) {
if(ptr[x]){
hash |= (__int64)1<<i;
}
i++;
}
}
printf("[i] hash: %I64X \n", hash);
cvReleaseImage(&res);
cvReleaseImage(&gray);
cvReleaseImage(&bin);
return hash;
}
and function for dHash
__int64 calcImageHash(IplImage* src, bool show_results)
{
if(!src)
{
return 0;
}
IplImage *res=0, *gray=0;
res = cvCreateImage( cvSize(9,8), src->depth, src->nChannels);
gray = cvCreateImage( cvSize(9,8), IPL_DEPTH_8U, 1);
cvResize(src, res);
cvCvtColor(res, gray, COLOR_BGR2GRAY);
__int64 hash = 0;
int i=0;
cout<<gray->height;
for( int y=0; y<gray->height; y++ ) {
uchar* ptr = (uchar*) (gray->imageData + y* gray->widthStep);
for( int x=0; x<gray->width-1; x++ ) {
if( ptr[x+1] > ptr[x] ){
hash |= (__int64)1<<i;
}
i++;
}
}
printf("[i] hash: %I64X \n", hash, "\n");
std::cout<<endl;
cvReleaseImage(&res);
cvReleaseImage(&gray);
return hash;
}
Upvotes: 2
Views: 1341
Reputation: 16394
Just in case someone comes across this as well, I have noticed that dhash has a specific weakness with illustrations and some artwork.
More specifically, it tends toward randomness for any image that has very low contrast, or that contains large areas of solid colors. I am working with a collection of photos of art, and the problem is especially pronounced for sketches, line drawing, or where the artwork itself is framed by solid-colored passepartout.
It's somewhat obvious why this happens: solid areas are liable to randomly see one segment be slightly brighter than an adjacent one with even minor artifacts of lossy compression. But I am somewhat surprised by the magnitude of it: simply scaling an image by 50% will often result in an image that is indistinguishable to the naked eye, but gives dhash differences close to randomness.
I have seen some improvements by making the comparison not about >= vs <, but to add a somewhat arbitrary bias, requiring a >= (b + 15), for example. The reasoning here is that solid-coloured are relatively abundant, but linear gradients (which would result in the same sort of pathology again) are relatively rare. If that's still a problem, one could also make the bias random but location-dependent, i. e. "add 12 at (x=3, y=5), substract 3 at x=20, y=5). The probability of significant number of images having matching patterns would be far lower than it is for solid colors and well-prescribed gradients.
Upvotes: 2