ios 如何比较两个 UIImage 对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11342897/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to compare two UIImage objects
提问by user1498119
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
图像之前使用.SO我需要在对象中拍摄该图像UIimage
并与另一个UIImage
对象进行比较以发现两者是否相同。所以请告诉我如何做到这一点。
回答by Simon
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];
}
回答by Mark Tickner
A Swift implementation of @Simon's answer:
@Simon 答案的 Swift 实现:
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)
}
}
回答by xeonwell
when both using [UIImage imageNamed:]
, we can use isEqual:
, otherwise we could compare the data.
当两者都使用时[UIImage imageNamed:]
,我们可以使用isEqual:
,否则我们可以比较数据。
回答by Greg Hilston
Updated Mark Tickner's solution to Swift 4
将 Mark Tickner 的解决方案更新为 Swift 4
import UIKit
extension UIImage {
func isEqualToImage(_ image: UIImage) -> Bool {
let data1 = self.pngData()
let data2 = image.pngData()
return data1 == data2
}
}
The two variables are probably overkill, but they might help explain to someone new to this. Could shorten to:
这两个变量可能有点矫枉过正,但它们可能有助于向新手解释这一点。可以缩短为:
import UIKit
extension UIImage {
func isEqualToImage(_ image: UIImage) -> Bool {
return self.pngData() == image.pngData()
}
}
回答by Austin
My preferred (Swift) solution
我首选的 (Swift) 解决方案
import UIKit
func ==(lhs: UIImage, rhs: UIImage) -> Bool
{
guard let data1 = UIImagePNGRepresentation(lhs),
data2 = UIImagePNGRepresentation(rhs)
else { return false }
return data1.isEqual(data2)
}
回答by Vladlex
The right answer depends on "What kind of comparison you want to do?".
正确的答案取决于“你想做什么样的比较?”。
- The easiest wayis just to compare data.
- 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).
- 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 :(
- 在最简单的方法就是进行数据比较。
- 如果你想知道图像是否是从一个本地文件创建的——你可以使用 -isEqual:(但有一种危险的方法,因为我不确定,如果由于某种原因清除图像缓存会发生什么)。
- 困难的方法是提供每个像素的比较(当然,系统会花更多的时间在上面)。由于法律原因,我无法提供我们公司库中的代码:(
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;
}
回答by CodeBender
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:
在这里,我遵循 Apple 在以下链接中提供的建议:
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
回答by Matheus Campos
I did some changes to Mark's answer and used Data and elementsEqual instead NSData and isEqual.
我对 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)
}
}
回答by Vlad
Swift 4.x version of Facebook's comparison algorithm:
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
}
回答by Abdul Hameed
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()