上周,正在忙,突然有个同学找我帮忙,说有个需求:图片相似度比较。
网上搜了一下,感觉不是很难,就写了下,这里分享给需要的小伙伴。
首先,本次采用的是OpenCV,图片哈希值:
先说一下基本思路:
1. 缩小尺寸:将图像缩小到8*8的尺寸,总共64个像素。这一步的作用是去除图像的细节,只保留结构/明暗等基本信息,摒弃不同尺寸/比例带来的图像差异;
注:实际操作时,采取了两种尺寸作对比(10*10,100*100)尺寸再大的话就会性能影响就会较大了,我实现了两种,目的是为了展示怎么设定不同尺寸。
2. 简化色彩:将缩小后的图像,转为64级灰度,即所有像素点总共只有64种颜色;
注:关于多少灰度级的问题,我并没有太在意,采取了一个合适的RGB to GRAY 算法就好,个人理解
3. 计算平均值:计算所有64个像素的灰度平均值;
4. 比较像素的灰度:将每个像素的灰度,与平均值进行比较,大于或等于平均值记为1,小于平均值记为0;
5. 计算哈希值:将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图像的指纹。组合的次序并不重要,只要保证所有图像都采用同样次序就行了;
6. 得到指纹以后,就可以对比不同的图像
参考博客:http://blog.csdn.net/fengbingchun/article/details/42153261
类文件下载链接:http://files.cnblogs.com/files/kongkaikai/GetSimilarity.zip
GetSimilarity.h
1 // 2 // GetSimilarity.h 3 // imgsimlartest 4 // 5 // Created by test on 16/3/3. 6 // Copyright © 2016年 com.facishare.CoreTest. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 #import <UIKit/UIKit.h> 11 typedef double Similarity; 12 13 @interface GetSimilarity : NSObject 14 - (void)setImgWithImgA:(UIImage*)imgA ImgB:(UIImage*)imgB;//设置需要对比的图片 15 - (void)setImgAWidthImg:(UIImage*)img; 16 - (void)setImgBWidthImg:(UIImage*)img; 17 - (Similarity)getSimilarityValue; //获取相似度 18 + (Similarity)getSimilarityValueWithImgA:(UIImage*)imga ImgB:(UIImage*)imgb;//类方法 19 @end
GetSimilarity.m
1 // 2 // GetSimilarity.m 3 // imgsimlartest 4 // 5 // Created by test on 16/3/3. 6 // Copyright © 2016年 com.facishare.CoreTest. All rights reserved. 7 // 8 9 #import "GetSimilarity.h" 10 #define ImgSizeA 10 11 #define ImgSizeB 100 12 typedef enum workday 13 { 14 SizeA, 15 SizeB, 16 }GetSimilarityType; 17 18 19 @interface GetSimilarity() 20 @property (nonatomic,assign) Similarity similarity; 21 @property (nonatomic,strong) UIImage *imga; 22 @property (nonatomic,strong) UIImage *imgb; 23 @end 24 25 @implementation GetSimilarity 26 - (instancetype)init 27 { 28 self = [super init]; 29 if (self) { 30 self.imga = [[UIImage alloc]init]; 31 self.imgb = [[UIImage alloc]init]; 32 } 33 return self; 34 } 35 36 - (void)setImgWithImgA:(UIImage*)imgA ImgB:(UIImage*)imgB 37 { 38 _imga = imgA; 39 _imgb = imgB; 40 } 41 42 - (void)setImgAWidthImg:(UIImage*)img 43 { 44 self.imga = img; 45 } 46 47 - (void)setImgBWidthImg:(UIImage*)img 48 { 49 self.imgb = img; 50 } 51 52 - (Similarity)getSimilarityValue 53 { 54 self.similarity = MAX([self getSimilarityValueWithType:SizeA], [self getSimilarityValueWithType:SizeB]); 55 return self.similarity; 56 } 57 + (Similarity)getSimilarityValueWithImgA:(UIImage *)imga ImgB:(UIImage *)imgb 58 { 59 GetSimilarity * getSimilarity = [[GetSimilarity alloc]init]; 60 [getSimilarity setImgWithImgA:imga ImgB:imgb]; 61 return [getSimilarity getSimilarityValue]; 62 } 63 - (Similarity)getSimilarityValueWithType:(GetSimilarityType)type;// 64 { 65 int cursize = (type == SizeA ? ImgSizeA : ImgSizeB); 66 int ArrSize = cursize * cursize + 1,a[ArrSize],b[ArrSize],i,j,grey,sum = 0; 67 CGSize size = {cursize,cursize}; 68 UIImage * imga = [self reSizeImage:self.imga toSize:size]; 69 UIImage * imgb = [self reSizeImage:self.imgb toSize:size];//缩小图片尺寸 70 71 a[ArrSize] = 0; 72 b[ArrSize] = 0; 73 CGPoint point; 74 for (i = 0 ; i < cursize; i++) {//计算a的灰度 75 for (j = 0; j < cursize; j++) { 76 point.x = i; 77 point.y = j; 78 grey = ToGrey([self UIcolorToRGB:[self colorAtPixel:point img:imga]]); 79 a[cursize * i + j] = grey; 80 a[ArrSize] += grey; 81 } 82 } 83 a[ArrSize] /= (ArrSize - 1);//灰度平均值 84 for (i = 0 ; i < cursize; i++) {//计算b的灰度 85 for (j = 0; j < cursize; j++) { 86 point.x = i; 87 point.y = j; 88 grey = ToGrey([self UIcolorToRGB:[self colorAtPixel:point img:imgb]]); 89 b[cursize * i + j] = grey; 90 b[ArrSize] += grey; 91 } 92 } 93 b[ArrSize] /= (ArrSize - 1);//灰度平均值 94 for (i = 0 ; i < ArrSize ; i++)//灰度分布计算 95 { 96 a[i] = (a[i] < a[ArrSize] ? 0 : 1); 97 b[i] = (b[i] < b[ArrSize] ? 0 : 1); 98 } 99 ArrSize -= 1; 100 for (i = 0 ; i < ArrSize ; i++) 101 { 102 sum += (a[i] == b[i] ? 1 : 0); 103 } 104 105 return sum * 1.0 / ArrSize; 106 } 107 108 - (UIImage *)reSizeImage:(UIImage *)image toSize:(CGSize)reSize//重新设定图片尺寸 109 { 110 UIGraphicsBeginImageContext(CGSizeMake(reSize.width, reSize.height)); 111 [image drawInRect:CGRectMake(0, 0, reSize.width, reSize.height)]; 112 UIImage *reSizeImage = UIGraphicsGetImageFromCurrentImageContext(); 113 UIGraphicsEndImageContext(); 114 return reSizeImage; 115 } 116 117 unsigned int ToGrey(unsigned int rgb)//RGB计算灰度 118 { 119 unsigned int blue = (rgb & 0x000000FF) >> 0; 120 unsigned int green = (rgb & 0x0000FF00) >> 8; 121 unsigned int red = (rgb & 0x00FF0000) >> 16; 122 return ( red*38 + green * 75 + blue * 15 )>>7; 123 } 124 125 - (unsigned int)UIcolorToRGB:(UIColor*)color//UIColor转16进制RGB 126 { 127 unsigned int RGB,R,G,B; 128 RGB = R = G = B = 0x00000000; 129 CGFloat r,g,b,a; 130 [color getRed:&r green:&g blue:&b alpha:&a]; 131 R = r * 256 ; 132 G = g * 256 ; 133 B = b * 256 ; 134 RGB = (R << 16) | (G << 8) | B ; 135 return RGB; 136 } 137 138 - (UIColor *)colorAtPixel:(CGPoint)point img:(UIImage*)img{//获取指定point位置的RGB 139 // Cancel if point is outside image coordinates 140 if (!CGRectContainsPoint(CGRectMake(0.0f, 0.0f, img.size.width, img.size.height), point)) { return nil; } 141 142 NSInteger pointX = trunc(point.x); 143 NSInteger pointY = trunc(point.y); 144 CGImageRef cgImage = img.CGImage; 145 NSUInteger width = img.size.width; 146 NSUInteger height = img.size.height; 147 int bytesPerPixel = 4; 148 int bytesPerRow = bytesPerPixel * 1; 149 NSUInteger bitsPerComponent = 8; 150 unsigned char pixelData[4] = { 0, 0, 0, 0 }; 151 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 152 CGContextRef context = CGBitmapContextCreate(pixelData, 1, 1, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 153 154 CGColorSpaceRelease(colorSpace); 155 CGContextSetBlendMode(context, kCGBlendModeCopy); 156 157 // Draw the pixel we are interested in onto the bitmap context 158 CGContextTranslateCTM(context, -pointX, pointY-(CGFloat)height); 159 CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), cgImage); 160 CGContextRelease(context); 161 // Convert color values [0..255] to floats [0.0..1.0] 162 163 CGFloat red = (CGFloat)pixelData[0] / 255.0f; 164 CGFloat green = (CGFloat)pixelData[1] / 255.0f; 165 CGFloat blue = (CGFloat)pixelData[2] / 255.0f; 166 CGFloat alpha = (CGFloat)pixelData[3] / 255.0f; 167 return [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; 168 } 169 @end