【问题标题】:Comparing UIImage比较 UIImage
【发布时间】:2011-03-24 23:06:54
【问题描述】:

如何将一张图片与另一张图片进行比较?

谢谢!

【问题讨论】:

  • 比较像素或位图以确定它们是否相同。

标签: ios iphone cocoa-touch uiimage


【解决方案1】:

更新

基于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)
    }
}

【讨论】:

  • 似乎得到的信息和刚刚使用 UIImage.pngData() 一样
【解决方案2】:

如果您有两个 UIImage,您应该从这些对象中获取它们的CGImageRefquartz 表示。然后创建两个由您创建并传入的内存缓冲区支持的新位图上下文,每个图像一个。然后使用CGContextDrawImage 将图像绘制到位图上下文中。现在图像的字节在缓冲区中。然后您可以手动或memcmp 循环以检查差异。

Apple 自己关于创建位图上下文并绘制到其中的详细说明和示例代码如下:

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

对您而言,不同之处在于您将现有图像绘制到上下文中。为此使用CGContextDrawImage

【讨论】:

  • Whoaaaa...这有点令人困惑,我不是在寻找免费乘车(我实际上想从中学习),但您可以发布一些代码。我对任何 CG 方法都不是很熟悉。或者至少尝试为菜鸟更好地解释一下。
  • 我添加了一个指向好信息的链接。如果它仍然有点超出您的想象,请查看教程和 Apple 的有关 Core Graphics 基础知识的文档。在 SO 上作为一个问题来回答这个问题太大了,如果你在 iOS 上做任何实质性的图像工作,你需要明白这一点。
  • 是的,这正是我的回答(和 Apple 文档)告诉你的。 :) 抱歉,但是给定两个 UIImage,直接比较像素的唯一方法是使用 Core Graphics 上下文进行一些细节工作。也许这里的其他人会好心地提供完整的复制和粘贴代码。
  • 嗯。唯一困难的部分是我不知道如何找到所需的一些论据。 (除了宽度和高度之外的所有内容。)我不介意做一些硬编码。
  • @ArshadShaik 什么? 7.5年前的链接不再有效?! ;) 我搜索了内容并更新了链接。
【解决方案3】:

这里是代码示例

-(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;
}

【讨论】:

    【解决方案4】:

    这是我在单元测试中用来比较图像的方法。与其他方法(例如,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
    

    效率不高,所以我建议不要在生产代码中使用它,除非性能不是问题。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多