如何比较两个UIImage对象

时间:2012-07-05 10:55:46

标签: ios

我正在开发一个应用程序。我正在使用imageviews。在更改UIImageview图像之前,我需要在UIimage obejct中拍摄该图像并与另一个{{1}进行比较用于查找两者的对象是否为sam。所以请告诉我如何做到这一点。

20 个答案:

答案 0 :(得分:117)

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

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

    return [data1 isEqual:data2];
}

答案 1 :(得分:20)

Swift实现@ Simon的回答:

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

或者根据@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)
    }

}

答案 2 :(得分:8)

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

答案 3 :(得分:6)

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

  1. 最简单的方法只是为了比较数据。
  2. 如果你想知道图像是否是从一个本地文件创建的 - 你可以使用-isEqual :(但是有一种危险的方式,因为我不确定,如果图像缓存会发生什么由于某种原因明确)。
  3. 困难的方法是提供每像素比较(当然,系统将花费更多时间)。由于法律原因,我无法提供公司图书馆的代码:(
  4. 但是你可以在facebook的ios-snapshot-test-case项目上查看好的例子:link right to the needed file。 您可以使用性能测试来测量处理时间。

    对于伟大的正义,我将从下面复制代码:

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

答案 4 :(得分:5)

将图像转换为JPG / PNG,或依赖可访问性标识符要么是昂贵的操作,要么是脆弱的&amp;容易失败。

在此,我遵循Apple在following link

提供的建议
  

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

为简化起见,我创建了以下扩展来进行比较,这样我就可以避免转换第一张图片的问题:

add_action('genesis_after_content_sidebar_wrap', 'add_undergrad_Highlight', 1);

function add_undergrad_Highlight(){

global $post;
global $meta;


echo'<div id="highlightBox">';

if(isset($meta['HighlightImage'])){
    $HighlightImage = '<img src="';
    $HighlightImage .= $meta['HighlightImage'];
    $HighlightImage .= '"/>';
}

if(isset($meta['HighlightImage'])){
    echo $HighlightImage;
}

echo'</div>';

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

import UIKit

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

答案 5 :(得分:5)

我对Mark的答案进行了一些更改,并使用了Data和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)
    }
}

答案 6 :(得分:4)

我的首选(Swift)解决方案

import UIKit

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

  return data1.isEqual(data2)
}

答案 7 :(得分:4)

  

Swift 3

有两种方法。如: -

1)使用isEqual()函数。

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

2)使用accessibilityIdentifier

将accessibilityIdentifier设置为图像名称

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

然后使用以下代码。

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

最后,识别方法的调用方式

myImageView.getFileName()

答案 8 :(得分:3)

将Mark Tickner的解决方案更新为Swift 4

import UIKit

extension UIImage {

    func isEqualToImage(image: UIImage) -> Bool {
        let data1 = self.pngData()
        let data2 = image.pngData()
        return data1 == data2
    }

}

这两个变量可能是过大的,但它们可能有助于向新手解释。可以缩短为:

import UIKit

extension UIImage {

    func isEqualToImage(image: UIImage) -> Bool {
        return self.pngData() == image.pngData()
    }

}

答案 9 :(得分:2)

最初比较图像尺寸

对于较便宜的方法,最初比较图像大小。即使图像内部发生微小变化,尺寸也会不同。

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.
}

在比较来自相同来源(相同尺寸,格式等)的图像时成功进行了测试。

答案 10 :(得分:1)

这种方法效果很好:

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

答案 11 :(得分:1)

Swift 4.x版本的Facebook比较算法:

/// Value in range 0...100 %
typealias Percentage = Float

// See: https://github.com/facebookarchive/ios-snapshot-test-case/blob/master/FBSnapshotTestCase/Categories/UIImage%2BCompare.m
private func compare(tolerance: Percentage, expected: Data, observed: Data) throws -> Bool {
    guard let expectedUIImage = UIImage(data: expected), let observedUIImage = UIImage(data: observed) else {
        throw Error.unableToGetUIImageFromData
    }
    guard let expectedCGImage = expectedUIImage.cgImage, let observedCGImage = observedUIImage.cgImage else {
        throw Error.unableToGetCGImageFromData
    }
    guard let expectedColorSpace = expectedCGImage.colorSpace, let observedColorSpace = observedCGImage.colorSpace else {
        throw Error.unableToGetColorSpaceFromCGImage
    }
    if expectedCGImage.width != observedCGImage.width || expectedCGImage.height != observedCGImage.height {
        throw Error.imagesHasDifferentSizes
    }
    let imageSize = CGSize(width: expectedCGImage.width, height: expectedCGImage.height)
    let numberOfPixels = Int(imageSize.width * imageSize.height)

    // Checking that our `UInt32` buffer has same number of bytes as image has.
    let bytesPerRow = min(expectedCGImage.bytesPerRow, observedCGImage.bytesPerRow)
    assert(MemoryLayout<UInt32>.stride == bytesPerRow / Int(imageSize.width))

    let expectedPixels = UnsafeMutablePointer<UInt32>.allocate(capacity: numberOfPixels)
    let observedPixels = UnsafeMutablePointer<UInt32>.allocate(capacity: numberOfPixels)

    let expectedPixelsRaw = UnsafeMutableRawPointer(expectedPixels)
    let observedPixelsRaw = UnsafeMutableRawPointer(observedPixels)

    let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
    guard let expectedContext = CGContext(data: expectedPixelsRaw, width: Int(imageSize.width), height: Int(imageSize.height),
                                          bitsPerComponent: expectedCGImage.bitsPerComponent, bytesPerRow: bytesPerRow,
                                          space: expectedColorSpace, bitmapInfo: bitmapInfo.rawValue) else {
        expectedPixels.deallocate()
        observedPixels.deallocate()
        throw Error.unableToInitializeContext
    }
    guard let observedContext = CGContext(data: observedPixelsRaw, width: Int(imageSize.width), height: Int(imageSize.height),
                                          bitsPerComponent: observedCGImage.bitsPerComponent, bytesPerRow: bytesPerRow,
                                          space: observedColorSpace, bitmapInfo: bitmapInfo.rawValue) else {
        expectedPixels.deallocate()
        observedPixels.deallocate()
        throw Error.unableToInitializeContext
    }

    expectedContext.draw(expectedCGImage, in: CGRect(origin: .zero, size: imageSize))
    observedContext.draw(observedCGImage, in: CGRect(origin: .zero, size: imageSize))

    let expectedBuffer = UnsafeBufferPointer(start: expectedPixels, count: numberOfPixels)
    let observedBuffer = UnsafeBufferPointer(start: observedPixels, count: numberOfPixels)

    var isEqual = true
    if tolerance == 0 {
        isEqual = expectedBuffer.elementsEqual(observedBuffer)
    } else {
        // Go through each pixel in turn and see if it is different
        var numDiffPixels = 0
        for pixel in 0 ..< numberOfPixels where expectedBuffer[pixel] != observedBuffer[pixel] {
            // If this pixel is different, increment the pixel diff count and see if we have hit our limit.
            numDiffPixels += 1
            let percentage = 100 * Float(numDiffPixels) / Float(numberOfPixels)
            if percentage > tolerance {
                isEqual = false
                break
            }
        }
    }

    expectedPixels.deallocate()
    observedPixels.deallocate()

    return isEqual
}

答案 12 :(得分:0)

我需要检测视频馈送帧中的差异并确定该差异的阈值,以便决定在我的代码中执行某些操作。您可以使用类似的像素比较来查看UIImage的pngData。

查看我的答案here

答案 13 :(得分:0)

快捷简便的解决方案

extension UIImage: Equatable {
    static func ==(lhs: UIImage, rhs: UIImage) -> Bool {
        return lhs.pngData() == rhs.pngData()
    }
}

答案 14 :(得分:0)

Swift 5.x

您可以使用

let image: UIImage!
let anotherImage: UIImage!

image == anotherImage

答案 15 :(得分:0)

Swift5

func checkequal(img1:UIImage,imag2:UIImage)->布尔{

    let data1 = img1.pngData()
    let data2 = imag2.pngData()

    return data1 == data2
}

答案 16 :(得分:0)

我不确定比较UIImage数据,因为它的预处理成本很高。你可以做的是子类Uimage并添加你自己的标签属性,然后在更改图像之前比较标签。分配

答案 17 :(得分:-1)

我们需要在Objective-C中使用isEqualToData方法。苹果文件指出

Two data objects are equal if they hold the same number of bytes, and if the bytes at the same position in the objects are the same.

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

    return [data1 isEqualToData:data2];
}

答案 18 :(得分:-1)

如果您知道一个图像名称,它会对您有帮助....

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

答案 19 :(得分:-2)

您还可以使用'tag'属性来识别程序后期的对象。只需设置整数值就可以了