如何将图像与另一张图像进行比较?
谢谢!
答案 0 :(得分:3)
这是我在单元测试中用来比较图像的方法。与其他方法(例如UIImagePNGRepresentation
)不同,即使图像具有不同的色彩空间(例如,RGB和灰度),它也可以工作。
@implementation UIImage (HPIsEqualToImage)
- (BOOL)hp_isEqualToImage:(UIImage*)image
{
NSData *data = [image hp_normalizedData];
NSData *originalData = [self hp_normalizedData];
return [originalData isEqualToData:data];
}
- (NSData*)hp_normalizedData
{
const CGSize pixelSize = CGSizeMake(self.size.width * self.scale, self.size.height * self.scale);
UIGraphicsBeginImageContext(pixelSize);
[self drawInRect:CGRectMake(0, 0, pixelSize.width, pixelSize.height)];
UIImage *drawnImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return UIImagePNGRepresentation(drawnImage);
}
@end
效率不高,所以我建议不要在生产代码中使用它,除非性能不是问题。
答案 1 :(得分:2)
如果您有两个UIImages,则应从这些对象中获取CGImageRef
石英表示。然后创建两个新的位图上下文,由您创建并传入的内存缓冲区支持,每个映像一个。然后使用CGContextDrawImage
将图像绘制到位图上下文中。现在,图像的字节都在缓冲区中。然后,您可以手动循环或memcmp
来检查差异。
Apple关于创建位图上下文并将其绘制到其中的详细说明和示例代码如下:
您的不同之处在于您将现有图像绘制到上下文中。请使用CGContextDrawImage
。
答案 2 :(得分:2)
此处的代码示例
-(NSMutableArray*)getImageBinary:(UIImage*)ImageToCompare
{
int i = 0;
int step = 4;
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
//void * bitmapData;
//int bitmapByteCount;
int bitmapBytesPerRow;
// Get image width, height. We'll use the entire image.
size_t pixelsWide = CGImageGetWidth(ImageToCompare.CGImage);
size_t pixelsHigh = CGImageGetHeight(ImageToCompare.CGImage);
// Declare the number of bytes per row. Each pixel in the bitmap in this
// example is represented by 4 bytes; 8 bits each of red, green, blue, and
// alpha.
bitmapBytesPerRow = (pixelsWide * 4);
NSMutableArray *firstImagearray=[[NSMutableArray alloc]init];
//bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);
// Use the generic RGB color space.
colorSpace = CGColorSpaceCreateDeviceRGB();
if (colorSpace == NULL)
{
fprintf(stderr, "Error allocating color space\n");
return nil;
}
// Allocate memory for image data. This is the destination in memory
// where any drawing to the bitmap context will be rendered.
//bitmapData = malloc( bitmapByteCount );
// if (bitmapData == NULL)
// {
// fprintf (stderr, "Memory not allocated!");
// CGColorSpaceRelease( colorSpace );
// return NULL;
// }
// Create the bitmap context. We want pre-multiplied ARGB, 8-bits
// per component. Regardless of what the source image format is
// (CMYK, Grayscale, and so on) it will be converted over to the format
// specified here by CGBitmapContextCreate.
context = CGBitmapContextCreate (NULL,
pixelsWide,
pixelsHigh,
8, // bits per component
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedFirst);
if (context == NULL)
{
//free (bitmapData);
fprintf (stderr, "Context not created!");
}
CGRect rect = {{0,0},{pixelsWide, pixelsHigh}};
//
// Draw the image to the bitmap context. Once we draw, the memory
// allocated for the context for rendering will then contain the
// raw image data in the specified color space.
CGContextDrawImage(context, rect, ImageToCompare.CGImage);
// Make sure and release colorspace before returning
CGColorSpaceRelease( colorSpace );
/////**********
size_t _width = CGImageGetWidth(ImageToCompare.CGImage);
size_t _height = CGImageGetHeight(ImageToCompare.CGImage);
unsigned char* data = CGBitmapContextGetData (context);
if (data != NULL)
{
int max = _width * _height * 4;
for (i = 0; i < max; i+=step)
{
[firstImagearray addObject:[NSNumber numberWithInt:data[i + 0]]];
[firstImagearray addObject:[NSNumber numberWithInt:data[i + 1]]];
[firstImagearray addObject:[NSNumber numberWithInt:data[i + 2]]];
[firstImagearray addObject:[NSNumber numberWithInt:data[i + 3]]]; }
}
if (context == NULL)
// error creating context
return nil;
//if (data) { free(data); }
if (context) {
CGContextRelease(context);
}
return firstImagearray;
}
-(BOOL)Compare:(UIImage*)ImageToCompare secondImage:(UIImage*)secondImage
{
ImageToCompare=[ImageToCompare scaleToSize:CGSizeMake(self.appdelegate.ScreenWidth,self.appdelegate.ScreenHeigth)];
secondImage=[secondImage scaleToSize:CGSizeMake(self.appdelegate.ScreenWidth, self.appdelegate.ScreenHeigth)];
NSArray *first=[[NSArray alloc] initWithArray:(NSArray *)[self getImageBinary:ImageToCompare]];
NSArray *second=[[NSArray alloc] initWithArray:(NSArray *)[self getImageBinary:secondImage]];
for (int x=0; x<first.count; x++)
{
if ([((NSNumber*)[first objectAtIndex:x]) intValue] ==[((NSNumber*)[second objectAtIndex:x]) intValue])
{
}
else
{
return NO;
}
}
return YES;
}
答案 3 :(得分:2)
更新
基于Skycamelfalling's的注释,我验证了使用UIImage的pngData()
方法而不是使用图像上下文进行绘制时,单元测试仍然可以通过。简单得多!
出于历史利益:这是hpique's答案的Swift 4变体。当我需要测试两个UIImage的“相同性”时,它对我的单元测试有效。
fileprivate extension UIImage {
func makeNormalizedData() -> Data? {
defer { UIGraphicsEndImageContext() }
let pixelSize = CGSize(width: size.width * scale, height: size.height * scale)
UIGraphicsBeginImageContext(pixelSize)
draw(in: CGRect(origin: CGPoint.zero, size: pixelSize))
guard let drawnImage = UIGraphicsGetImageFromCurrentImageContext() else { return nil }
return UIImagePNGRepresentation(drawnImage)
}
}