UIImage Comparison

How to compare the image with another?

Thank!

+9
ios iphone cocoa-touch uiimage
Aug 03 '10 at 20:56
source share
4 answers

If you have two UIImages, you should get their CGImageRef quartz representations from these objects. Then create two new bitmap contexts supported by the memory buffer that you create and transfer, one for each image. Then use CGContextDrawImage to draw images in bitmap contexts. Image bytes are now in buffers. Then you can run the loop manually or memcmp to check the differences.

Apple has a detailed explanation and sample code around creating raster contexts, and drawing them here:

https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html

The difference is that you are drawing an existing image in context. Use CGContextDrawImage for this.

+2
Aug 03 '10 at 9:26 a.m.
source share

This is what I use in my unit tests to compare images. Unlike other methods (e.g. UIImagePNGRepresentation ), it works even if images have a different color space (e.g. RGB and grayscale).

 @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 

This is not very efficient, so I would recommend not using it in production code unless performance is an issue.

+3
May 18 '14 at 17:53
source share

here is a sample code

 -(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; } 
+2
Oct 27 '12 at 17:41
source share

Refresh

Based on a Skycamelfalling comment, I made sure my unit tests still pass when using the pngData() method instead of drawing with the image context. Much easier!

For historical interest: here is the Swift 4 option of hpique's answer. This works for me in my unit tests, when I need to check two UIImage for “sameness”.

 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) } } 
+2
Oct 29 '18 at 14:10
source share



All Articles