感知哈希算法(以下简称PHA)是哈希算法的一类,主要用来做相似图片的搜索工作。
PHA是一类比较哈希方法的统称。图片所包含的特征被用来生成一组指纹(不过它不是唯一的),而这些指纹是可以进行比较的。
下面是简单的步骤,来说明对图像进行PHA的运算过程:
第一步,缩小尺寸。
最快速的去除高频和细节,只保留结构明暗的方法就是缩小尺寸。
将图片缩小到8x8的尺寸,总共64个像素。摒弃不同尺寸、比例带来的图片差异。
-
- - (UIImage *)scaleToSize:(UIImage *)img size:(CGSize)size{
- UIGraphicsBeginImageContext(size);
- [img drawInRect:CGRectMake(0,0, size.width, size.height)];
- UIImage* scaledImage =UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- return scaledImage;
- }
第二步,简化色彩。
将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。
-
- -(UIImage*)getGrayImage:(UIImage*)sourceImage
- {
- int width = sourceImage.size.width;
- int height = sourceImage.size.height;
-
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
- CGContextRef context = CGBitmapContextCreate (nil,width,height,8,0,colorSpace,kCGImageAlphaNone);
- CGColorSpaceRelease(colorSpace);
- if (context == NULL) {
- return nil;
- }
- CGContextDrawImage(context,CGRectMake(0, 0, width, height), sourceImage.CGImage);
- UIImage *grayImage = [UIImage imageWithCGImage:CGBitmapContextCreateImage(context)];
- CGContextRelease(context);
- return grayImage;
- }
第三步,计算平均值,比较像素的灰度。
计算所有64个像素的灰度平均值,将每个像素的灰度,与平均值进行比较,大于或等于平均值,记为1;小于平均值,记为0。
-
- -(NSString *)pHashValueWithImage:(UIImage *)image{
- NSMutableString * pHashString = [NSMutableString string];
- CGImageRef imageRef = [image CGImage];
- unsigned long width = CGImageGetWidth(imageRef);
- unsigned long height = CGImageGetHeight(imageRef);
- CGDataProviderRef provider = CGImageGetDataProvider(imageRef);
- NSData* data = (id)CFBridgingRelease(CGDataProviderCopyData(provider));
-
- const charchar * heightData = (char*)data.bytes;
- int sum = 0;
-
- for (int i = 0; i < width * height; i++)
- {
- printf("%d ",heightData[i]);
- if (heightData[i] != 0)
- {
- sum += heightData[i];
- }
- }
- int avr = sum / (width * height);
- NSLog(@"%d",avr);
- for (int i = 0; i < width * height; i++)
- {
- if (heightData[i] >= avr) {
- [pHashString appendString:@"1"];
- }
- else {
- [pHashString appendString:@"0"];
- }
- }
- NSLog(@"pHashString = %@,pHashStringLength = %lu",pHashString,(unsigned long)pHashString.length);
- return pHashString;
- }
-
第四步,计算哈希值。
得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。在理论上,这等同于计算Hammingdistance)。如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。
-
- -(NSInteger)getDifferentValueCountWithString:(NSString *)str1 andString:(NSString *)str2{
- NSInteger diff = 0;
- const charchar * s1 = [str1 UTF8String];
- const charchar * s2 = [str2 UTF8String];
- for (int i = 0 ; i < str1.length ;i++){
- if(s1[i] != s2[i]){
- diff++;
- }
- }
- return diff;
- }
-
例子:
- UIImage * mImage1 = [self getGrayImage:[self scaleToSize:_image1 size:CGSizeMake(8, 8)]];
- UIImage * mImage2 = [self getGrayImage:[self scaleToSize:_image2 size:CGSizeMake(8, 8)]];
- NSInteger diff = [self getDifferentValueCountWithString:[self pHashValueWithImage:mImage1] andString:[self pHashValueWithImage:mImage2]];
- p;