如何比较两个UIImage对象

时间:2022-08-31 23:05:33

I am developing one application.In that i am using the imageviews.SO before changeing the UIImageview image I need to take that image in UIimage obejct and compare with another UIImage object for finding both are sam or not. So please tell me how to do that one.

我正在开发一个应用程序。我使用的是imageviews。在修改UIImageview图像之前,我需要在UIimage obejct中选取这个图像并与另一个UIimage对象进行比较以找到两者是否都是sam。请告诉我怎么做。

13 个解决方案

#1


110  

One way is to convert them to image data first, and then compare that.

一种方法是先将它们转换成图像数据,然后再进行比较。

- (BOOL)image:(UIImage *)image1 isEqualTo:(UIImage *)image2
{
    NSData *data1 = UIImagePNGRepresentation(image1);
    NSData *data2 = UIImagePNGRepresentation(image2);

    return [data1 isEqual:data2];
}

#2


16  

A Swift implementation of @Simon's answer:

@Simon回答的快速实现:

func image(image1: UIImage, isEqualTo image2: UIImage) -> Bool {
    let data1: NSData = UIImagePNGRepresentation(image1)!
    let data2: NSData = UIImagePNGRepresentation(image2)!
    return data1.isEqual(data2)
}

Or by extending UIImage based on @nhgrif's suggestion:

或者根据@nhgrif的建议扩展UIImage:

import UIKit

extension UIImage {

    func isEqualToImage(image: UIImage) -> Bool {
        let data1: NSData = UIImagePNGRepresentation(self)!
        let data2: NSData = UIImagePNGRepresentation(image)!
        return data1.isEqual(data2)
    }

}

#3


7  

when both using [UIImage imageNamed:], we can use isEqual:, otherwise we could compare the data.

当使用[UIImage imageNamed:]时,我们可以使用isEqual:,否则我们可以比较数据。

#4


4  

The right answer depends on "What kind of comparison you want to do?".

正确的答案取决于“你想做什么样的比较?”

  1. The easiest way is just to compare data.
  2. 最简单的方法就是比较数据。
  3. If you want to know whether image were created from one local file – you can use -isEqual: (but there is an dangerous way, because I'm not sure, what happens if image cache clear for some reason).
  4. 如果您想知道映像是否由一个本地文件创建——您可以使用- isequal:(但是有一种危险的方式,因为我不确定,如果由于某些原因而清除映像会发生什么情况)。
  5. The hard way is provide per-pixel comparison (surely, system will spend more time on it). I can't provide the code from our company's library because of legal reason :(
  6. 困难的方法是提供每个像素的比较(当然,系统会在这上面花费更多的时间)。由于法律原因,我不能提供我们公司图书馆的代码。

But you can check good example on facebook's ios-snapshot-test-case project here: link right to the needed file. You can use performance tests to measure process time.

但是你可以在facebook的ios-snapshot-test-case项目中找到一个很好的例子:链接到需要的文件。您可以使用性能测试来度量过程时间。

For the Great Justice I'll copy code from there below:

为了伟大的正义,我将复制下面的代码:

- (BOOL)fb_compareWithImage:(UIImage *)image tolerance:(CGFloat)tolerance
{
  NSAssert(CGSizeEqualToSize(self.size, image.size), @"Images must be same size.");

  CGSize referenceImageSize = CGSizeMake(CGImageGetWidth(self.CGImage), CGImageGetHeight(self.CGImage));
  CGSize imageSize = CGSizeMake(CGImageGetWidth(image.CGImage), CGImageGetHeight(image.CGImage));

  // The images have the equal size, so we could use the smallest amount of bytes because of byte padding
  size_t minBytesPerRow = MIN(CGImageGetBytesPerRow(self.CGImage), CGImageGetBytesPerRow(image.CGImage));
  size_t referenceImageSizeBytes = referenceImageSize.height * minBytesPerRow;
  void *referenceImagePixels = calloc(1, referenceImageSizeBytes);
  void *imagePixels = calloc(1, referenceImageSizeBytes);

  if (!referenceImagePixels || !imagePixels) {
    free(referenceImagePixels);
    free(imagePixels);
    return NO;
  }

  CGContextRef referenceImageContext = CGBitmapContextCreate(referenceImagePixels,
                                                             referenceImageSize.width,
                                                             referenceImageSize.height,
                                                             CGImageGetBitsPerComponent(self.CGImage),
                                                             minBytesPerRow,
                                                             CGImageGetColorSpace(self.CGImage),
                                                             (CGBitmapInfo)kCGImageAlphaPremultipliedLast
                                                             );
  CGContextRef imageContext = CGBitmapContextCreate(imagePixels,
                                                    imageSize.width,
                                                    imageSize.height,
                                                    CGImageGetBitsPerComponent(image.CGImage),
                                                    minBytesPerRow,
                                                    CGImageGetColorSpace(image.CGImage),
                                                    (CGBitmapInfo)kCGImageAlphaPremultipliedLast
                                                    );

  if (!referenceImageContext || !imageContext) {
    CGContextRelease(referenceImageContext);
    CGContextRelease(imageContext);
    free(referenceImagePixels);
    free(imagePixels);
    return NO;
  }

  CGContextDrawImage(referenceImageContext, CGRectMake(0, 0, referenceImageSize.width, referenceImageSize.height), self.CGImage);
  CGContextDrawImage(imageContext, CGRectMake(0, 0, imageSize.width, imageSize.height), image.CGImage);

  CGContextRelease(referenceImageContext);
  CGContextRelease(imageContext);

  BOOL imageEqual = YES;

  // Do a fast compare if we can
  if (tolerance == 0) {
    imageEqual = (memcmp(referenceImagePixels, imagePixels, referenceImageSizeBytes) == 0);
  } else {
    // Go through each pixel in turn and see if it is different
    const NSInteger pixelCount = referenceImageSize.width * referenceImageSize.height;

    FBComparePixel *p1 = referenceImagePixels;
    FBComparePixel *p2 = imagePixels;

    NSInteger numDiffPixels = 0;
    for (int n = 0; n < pixelCount; ++n) {
      // If this pixel is different, increment the pixel diff count and see
      // if we have hit our limit.
      if (p1->raw != p2->raw) {
        numDiffPixels ++;

        CGFloat percent = (CGFloat)numDiffPixels / pixelCount;
        if (percent > tolerance) {
          imageEqual = NO;
          break;
        }
      }

      p1++;
      p2++;
    }
  }

  free(referenceImagePixels);
  free(imagePixels);

  return imageEqual;
}

#5


3  

My preferred (Swift) solution

我喜欢(迅速)的解决方案

import UIKit

func ==(lhs: UIImage, rhs: UIImage) -> Bool
{
  guard let data1 = UIImagePNGRepresentation(lhs),
            data2 = UIImagePNGRepresentation(rhs)
    else { return false }

  return data1.isEqual(data2)
}

#6


3  

Swift 3

斯威夫特3

There is two ways. Like:-

有两种方式。如:-

1) Use isEqual() function.

1)使用isEqual()函数。

 self.image?.isEqual(UIImage(named: "add-image"))

2) Use accessibilityIdentifier

2)使用accessibilityIdentifier

Set the accessibilityIdentifier as image Name

将accessibilityIdentifier设置为图像名称

myImageView.image?.accessibilityIdentifier = "add-image"

Then Use the following code.

然后使用以下代码。

extension UIImageView
{
func getFileName() -> String? {
// First set accessibilityIdentifier of image before calling.
let imgName = self.image?.accessibilityIdentifier
return imgName
}
}

Finally, The calling way of method to identify

最后,对调用方法进行识别

myImageView.getFileName()

#7


2  

Converting the images to JPG / PNG, or relying on accessibility identifiers is either an expensive operation, or fragile & prone to failure.

将图像转换为JPG / PNG,或者依赖于可访问性标识符,这要么是一个昂贵的操作,要么是脆弱的,容易出错的。

Here, I follow the suggestion provided by Apple at the following link:

在此,我遵循苹果公司在以下链接提供的建议:

The isEqual(:) method is the only reliable way to determine whether two images contain the same image data. The image objects you create may be different from each other, even when you initialize them with the same cached image data. The only way to determine their equality is to use the isEqual(:) method, which compares the actual image data. Listing 1 illustrates the correct and incorrect ways to compare images.

isEqual(:)方法是确定两个图像是否包含相同图像数据的唯一可靠方法。您创建的映像对象可能彼此不同,即使您使用相同的缓存映像数据初始化它们。确定它们相等性的唯一方法是使用isEqual(:)方法,该方法比较实际的图像数据。清单1说明了比较图像的正确和错误的方法。

To simplify things, I create the following extension for doing comparisons, so that I can avoid the issue of converting the first image:

为了简化事情,我创建了下面的扩展来进行比较,这样我就可以避免转换第一个图像的问题:

import UIKit

extension UIImage {
    func isEqual(to image: UIImage) -> Bool {
        return isEqual(image)
    }
}

With this, I can now setup an example to compare it on a pair of images:

有了这个,我现在可以建立一个例子来比较它在一对图像:

let imageA = UIImage(named: "a")!
let imageB = UIImage(named: "b")!
let imageC = UIImage(named: "a")!

print(imageA.isEqual(to: imageA)) // true
print(imageA.isEqual(to: imageC)) // true
print(imageA.isEqual(to: imageB)) // false

#8


2  

Compare the image size initially

For a less expensive method, compare the image size initially. Even if there is a small change inside an image, the size will be different.

对于较便宜的方法,首先比较图像的大小。即使图像内部有一个小的变化,大小也会不同。

NSData *data1 = UIImagePNGRepresentation(image1);
NSData *data2 = UIImagePNGRepresentation(image2);

if(data1.length == data2.length) {
    // if required, compare the data to confirm it
    if(data1 isEqual:data2) {
        // images are exactly same
    } else {
        // even though size is same images are different
    }
} else {
    // images are different.
}

Successfully tested in comparing images from same source (same dimension, format etc).

成功测试了来自相同来源(相同尺寸、格式等)的图像对比。

#9


1  

I did some changes to Mark's answer and used Data and elementsEqual instead NSData and isEqual.

我对Mark的答案做了一些修改,使用了Data and elementsEqual代替了NSData和isEqual。

extension UIImage {
    func isEqual(to image: UIImage) -> Bool {
        guard let data1: Data = UIImagePNGRepresentation(self),
            let data2: Data = UIImagePNGRepresentation(image) else {
                return false
        }
        return data1.elementsEqual(data2)
    }
}

#10


0  

i not sure about comparing the UIImage data as it would be prettry expensive. What you could do is subclass Uimage and add tag property your self and then compare tag before changing the image. assign

我不确定是否要比较UIImage数据,因为它会很贵。您可以做的是子类化Uimage并添加标签属性,然后在修改图片之前比较标签。分配

#11


0  

This method works great:

这方法好:

func isEqualImages(image1: UIImage, image2: UIImage) -> Bool {
    let data1: Data? = UIImagePNGRepresentation(image1)
    let data2: Data? = UIImagePNGRepresentation(image2)
    return data1 == data2
}

#12


-1  

Well you can also the 'tag' property to identify the objects at latter stages of your program. Just set the integer value and you are good to go

你也可以使用"标签"属性来识别程序后期的对象。只要设置整数值就可以了

#13


-1  

if one image name is known to you,it will help you....

如果一个图像的名字是已知的,它将帮助你....

CGImageRef cgImage = [imageView.image CGImage];
if (cgImage == [UIImage imageNamed:@"imagename.png"].CGImage) {
   // True Statement
}

#1


110  

One way is to convert them to image data first, and then compare that.

一种方法是先将它们转换成图像数据,然后再进行比较。

- (BOOL)image:(UIImage *)image1 isEqualTo:(UIImage *)image2
{
    NSData *data1 = UIImagePNGRepresentation(image1);
    NSData *data2 = UIImagePNGRepresentation(image2);

    return [data1 isEqual:data2];
}

#2


16  

A Swift implementation of @Simon's answer:

@Simon回答的快速实现:

func image(image1: UIImage, isEqualTo image2: UIImage) -> Bool {
    let data1: NSData = UIImagePNGRepresentation(image1)!
    let data2: NSData = UIImagePNGRepresentation(image2)!
    return data1.isEqual(data2)
}

Or by extending UIImage based on @nhgrif's suggestion:

或者根据@nhgrif的建议扩展UIImage:

import UIKit

extension UIImage {

    func isEqualToImage(image: UIImage) -> Bool {
        let data1: NSData = UIImagePNGRepresentation(self)!
        let data2: NSData = UIImagePNGRepresentation(image)!
        return data1.isEqual(data2)
    }

}

#3


7  

when both using [UIImage imageNamed:], we can use isEqual:, otherwise we could compare the data.

当使用[UIImage imageNamed:]时,我们可以使用isEqual:,否则我们可以比较数据。

#4


4  

The right answer depends on "What kind of comparison you want to do?".

正确的答案取决于“你想做什么样的比较?”

  1. The easiest way is just to compare data.
  2. 最简单的方法就是比较数据。
  3. If you want to know whether image were created from one local file – you can use -isEqual: (but there is an dangerous way, because I'm not sure, what happens if image cache clear for some reason).
  4. 如果您想知道映像是否由一个本地文件创建——您可以使用- isequal:(但是有一种危险的方式,因为我不确定,如果由于某些原因而清除映像会发生什么情况)。
  5. The hard way is provide per-pixel comparison (surely, system will spend more time on it). I can't provide the code from our company's library because of legal reason :(
  6. 困难的方法是提供每个像素的比较(当然,系统会在这上面花费更多的时间)。由于法律原因,我不能提供我们公司图书馆的代码。

But you can check good example on facebook's ios-snapshot-test-case project here: link right to the needed file. You can use performance tests to measure process time.

但是你可以在facebook的ios-snapshot-test-case项目中找到一个很好的例子:链接到需要的文件。您可以使用性能测试来度量过程时间。

For the Great Justice I'll copy code from there below:

为了伟大的正义,我将复制下面的代码:

- (BOOL)fb_compareWithImage:(UIImage *)image tolerance:(CGFloat)tolerance
{
  NSAssert(CGSizeEqualToSize(self.size, image.size), @"Images must be same size.");

  CGSize referenceImageSize = CGSizeMake(CGImageGetWidth(self.CGImage), CGImageGetHeight(self.CGImage));
  CGSize imageSize = CGSizeMake(CGImageGetWidth(image.CGImage), CGImageGetHeight(image.CGImage));

  // The images have the equal size, so we could use the smallest amount of bytes because of byte padding
  size_t minBytesPerRow = MIN(CGImageGetBytesPerRow(self.CGImage), CGImageGetBytesPerRow(image.CGImage));
  size_t referenceImageSizeBytes = referenceImageSize.height * minBytesPerRow;
  void *referenceImagePixels = calloc(1, referenceImageSizeBytes);
  void *imagePixels = calloc(1, referenceImageSizeBytes);

  if (!referenceImagePixels || !imagePixels) {
    free(referenceImagePixels);
    free(imagePixels);
    return NO;
  }

  CGContextRef referenceImageContext = CGBitmapContextCreate(referenceImagePixels,
                                                             referenceImageSize.width,
                                                             referenceImageSize.height,
                                                             CGImageGetBitsPerComponent(self.CGImage),
                                                             minBytesPerRow,
                                                             CGImageGetColorSpace(self.CGImage),
                                                             (CGBitmapInfo)kCGImageAlphaPremultipliedLast
                                                             );
  CGContextRef imageContext = CGBitmapContextCreate(imagePixels,
                                                    imageSize.width,
                                                    imageSize.height,
                                                    CGImageGetBitsPerComponent(image.CGImage),
                                                    minBytesPerRow,
                                                    CGImageGetColorSpace(image.CGImage),
                                                    (CGBitmapInfo)kCGImageAlphaPremultipliedLast
                                                    );

  if (!referenceImageContext || !imageContext) {
    CGContextRelease(referenceImageContext);
    CGContextRelease(imageContext);
    free(referenceImagePixels);
    free(imagePixels);
    return NO;
  }

  CGContextDrawImage(referenceImageContext, CGRectMake(0, 0, referenceImageSize.width, referenceImageSize.height), self.CGImage);
  CGContextDrawImage(imageContext, CGRectMake(0, 0, imageSize.width, imageSize.height), image.CGImage);

  CGContextRelease(referenceImageContext);
  CGContextRelease(imageContext);

  BOOL imageEqual = YES;

  // Do a fast compare if we can
  if (tolerance == 0) {
    imageEqual = (memcmp(referenceImagePixels, imagePixels, referenceImageSizeBytes) == 0);
  } else {
    // Go through each pixel in turn and see if it is different
    const NSInteger pixelCount = referenceImageSize.width * referenceImageSize.height;

    FBComparePixel *p1 = referenceImagePixels;
    FBComparePixel *p2 = imagePixels;

    NSInteger numDiffPixels = 0;
    for (int n = 0; n < pixelCount; ++n) {
      // If this pixel is different, increment the pixel diff count and see
      // if we have hit our limit.
      if (p1->raw != p2->raw) {
        numDiffPixels ++;

        CGFloat percent = (CGFloat)numDiffPixels / pixelCount;
        if (percent > tolerance) {
          imageEqual = NO;
          break;
        }
      }

      p1++;
      p2++;
    }
  }

  free(referenceImagePixels);
  free(imagePixels);

  return imageEqual;
}

#5


3  

My preferred (Swift) solution

我喜欢(迅速)的解决方案

import UIKit

func ==(lhs: UIImage, rhs: UIImage) -> Bool
{
  guard let data1 = UIImagePNGRepresentation(lhs),
            data2 = UIImagePNGRepresentation(rhs)
    else { return false }

  return data1.isEqual(data2)
}

#6


3  

Swift 3

斯威夫特3

There is two ways. Like:-

有两种方式。如:-

1) Use isEqual() function.

1)使用isEqual()函数。

 self.image?.isEqual(UIImage(named: "add-image"))

2) Use accessibilityIdentifier

2)使用accessibilityIdentifier

Set the accessibilityIdentifier as image Name

将accessibilityIdentifier设置为图像名称

myImageView.image?.accessibilityIdentifier = "add-image"

Then Use the following code.

然后使用以下代码。

extension UIImageView
{
func getFileName() -> String? {
// First set accessibilityIdentifier of image before calling.
let imgName = self.image?.accessibilityIdentifier
return imgName
}
}

Finally, The calling way of method to identify

最后,对调用方法进行识别

myImageView.getFileName()

#7


2  

Converting the images to JPG / PNG, or relying on accessibility identifiers is either an expensive operation, or fragile & prone to failure.

将图像转换为JPG / PNG,或者依赖于可访问性标识符,这要么是一个昂贵的操作,要么是脆弱的,容易出错的。

Here, I follow the suggestion provided by Apple at the following link:

在此,我遵循苹果公司在以下链接提供的建议:

The isEqual(:) method is the only reliable way to determine whether two images contain the same image data. The image objects you create may be different from each other, even when you initialize them with the same cached image data. The only way to determine their equality is to use the isEqual(:) method, which compares the actual image data. Listing 1 illustrates the correct and incorrect ways to compare images.

isEqual(:)方法是确定两个图像是否包含相同图像数据的唯一可靠方法。您创建的映像对象可能彼此不同,即使您使用相同的缓存映像数据初始化它们。确定它们相等性的唯一方法是使用isEqual(:)方法,该方法比较实际的图像数据。清单1说明了比较图像的正确和错误的方法。

To simplify things, I create the following extension for doing comparisons, so that I can avoid the issue of converting the first image:

为了简化事情,我创建了下面的扩展来进行比较,这样我就可以避免转换第一个图像的问题:

import UIKit

extension UIImage {
    func isEqual(to image: UIImage) -> Bool {
        return isEqual(image)
    }
}

With this, I can now setup an example to compare it on a pair of images:

有了这个,我现在可以建立一个例子来比较它在一对图像:

let imageA = UIImage(named: "a")!
let imageB = UIImage(named: "b")!
let imageC = UIImage(named: "a")!

print(imageA.isEqual(to: imageA)) // true
print(imageA.isEqual(to: imageC)) // true
print(imageA.isEqual(to: imageB)) // false

#8


2  

Compare the image size initially

For a less expensive method, compare the image size initially. Even if there is a small change inside an image, the size will be different.

对于较便宜的方法,首先比较图像的大小。即使图像内部有一个小的变化,大小也会不同。

NSData *data1 = UIImagePNGRepresentation(image1);
NSData *data2 = UIImagePNGRepresentation(image2);

if(data1.length == data2.length) {
    // if required, compare the data to confirm it
    if(data1 isEqual:data2) {
        // images are exactly same
    } else {
        // even though size is same images are different
    }
} else {
    // images are different.
}

Successfully tested in comparing images from same source (same dimension, format etc).

成功测试了来自相同来源(相同尺寸、格式等)的图像对比。

#9


1  

I did some changes to Mark's answer and used Data and elementsEqual instead NSData and isEqual.

我对Mark的答案做了一些修改,使用了Data and elementsEqual代替了NSData和isEqual。

extension UIImage {
    func isEqual(to image: UIImage) -> Bool {
        guard let data1: Data = UIImagePNGRepresentation(self),
            let data2: Data = UIImagePNGRepresentation(image) else {
                return false
        }
        return data1.elementsEqual(data2)
    }
}

#10


0  

i not sure about comparing the UIImage data as it would be prettry expensive. What you could do is subclass Uimage and add tag property your self and then compare tag before changing the image. assign

我不确定是否要比较UIImage数据,因为它会很贵。您可以做的是子类化Uimage并添加标签属性,然后在修改图片之前比较标签。分配

#11


0  

This method works great:

这方法好:

func isEqualImages(image1: UIImage, image2: UIImage) -> Bool {
    let data1: Data? = UIImagePNGRepresentation(image1)
    let data2: Data? = UIImagePNGRepresentation(image2)
    return data1 == data2
}

#12


-1  

Well you can also the 'tag' property to identify the objects at latter stages of your program. Just set the integer value and you are good to go

你也可以使用"标签"属性来识别程序后期的对象。只要设置整数值就可以了

#13


-1  

if one image name is known to you,it will help you....

如果一个图像的名字是已知的,它将帮助你....

CGImageRef cgImage = [imageView.image CGImage];
if (cgImage == [UIImage imageNamed:@"imagename.png"].CGImage) {
   // True Statement
}