上周,正在忙,突然有個同學找我幫忙,說有個需求:圖片相似度比較。
網上搜了一下,感覺不是很難,就寫了下,這里分享給需要的小伙伴。
首先,本次采用的是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