Сравнение UIImage - PullRequest
       19

Сравнение UIImage

9 голосов
/ 04 августа 2010

Как я могу сравнить изображение с другим?

Спасибо!

Ответы [ 4 ]

3 голосов
/ 18 мая 2014

Это то, что я использую в своих модульных тестах для сравнения изображений. В отличие от других методов (например, 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

Это не очень эффективно, поэтому я бы рекомендовал не использовать его в рабочем коде, если производительность не является проблемой.

2 голосов
/ 29 октября 2018

Обновление

На основе комментария Skycamelfalling я подтвердил, что мои модульные тесты по-прежнему проходят при использовании метода pngData() UIImage вместо рисования с контекстом изображения,Гораздо проще!

Для исторического интереса: Вот вариант Swift 4 ответа hpique .Это работает для меня в моих юнит-тестах, когда мне нужно проверить два 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)
    }
}
2 голосов
/ 27 октября 2012

пример кода

-(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 голосов
/ 04 августа 2010

Если у вас есть два UIImages, вы должны получить их CGImageRef кварцевые представления от этих объектов.Затем создайте два новых растровых контекста, поддерживаемых буфером памяти, который вы создаете и передаете, по одному для каждого из изображений.Затем используйте CGContextDrawImage, чтобы нарисовать изображения в контекстах растрового изображения.Теперь байты изображений находятся в буферах.Затем вы можете выполнить цикл вручную или memcmp, чтобы проверить различия.

Подробное объяснение Apple и пример кода для создания растровых контекстов и рисования в них находятся здесь:

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

Разница для вас в том, что вы рисуете существующее изображение в контексте.Для этого используйте CGContextDrawImage.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...