두 UIImage 객체를 비교하는 방법
하나의 응용 프로그램을 개발 중입니다 imageviews
. UIImageview
이미지를 변경 하기 전에 .SO를 사용하고 있다는 점에서 해당 이미지를 UIimage
obejct 로 가져 와서 다른 UIImage
개체 와 비교하여 둘 다 샘인지 아닌지 확인해야합니다. 그 방법을 알려주세요.
한 가지 방법은 먼저 이미지 데이터로 변환 한 다음 비교하는 것입니다.
- (BOOL)image:(UIImage *)image1 isEqualTo:(UIImage *)image2
{
NSData *data1 = UIImagePNGRepresentation(image1);
NSData *data2 = UIImagePNGRepresentation(image2);
return [data1 isEqual:data2];
}
@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)
}
}
둘 다 사용할 때 [UIImage imageNamed:]
를 사용할 수 있습니다 isEqual:
. 그렇지 않으면 데이터를 비교할 수 있습니다.
정답은 "어떤 종류의 비교를 원하십니까?"에 달려 있습니다.
- 가장 쉬운 방법은 바로 비교 데이터입니다.
- 이미지가 하나의 로컬 파일에서 생성되었는지 여부 를 알고 싶다면 -isEqual :을 사용할 수 있습니다. (하지만 어떤 이유로 이미지 캐시가 삭제되면 어떻게되는지 잘 모르겠 기 때문에 위험한 방법이 있습니다.)
- 어려운 방법은 픽셀 당 비교를 제공하는 것입니다 (확실히 시스템이 이에 더 많은 시간을 할애 할 것임). 법적 사유로 인해 회사 라이브러리의 코드를 제공 할 수 없습니다.
하지만 여기에서 페이스 북의 ios-snapshot-test-case 프로젝트에 대한 좋은 예를 확인할 수 있습니다 : 필요한 파일에 바로 연결 . 성능 테스트를 사용하여 프로세스 시간을 측정 할 수 있습니다.
위대한 정의를 위해 아래에서 코드를 복사하겠습니다.
- (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;
}
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()
}
}
이미지를 JPG / PNG로 변환하거나 접근성 식별자에 의존하는 것은 비용이 많이 드는 작업이거나 깨지기 쉽고 실패하기 쉽습니다.
여기에서 다음 링크 에서 Apple이 제공 한 제안을 따릅니다 .
isEqual ( :) 메서드는 두 이미지에 동일한 이미지 데이터가 포함되어 있는지 확인할 수있는 유일한 방법입니다. 생성 한 이미지 객체는 캐시 된 동일한 이미지 데이터로 초기화하더라도 서로 다를 수 있습니다. 동등성을 결정하는 유일한 방법 은 실제 이미지 데이터를 비교하는 isEqual ( :) 메서드 를 사용하는 것 입니다. 목록 1은 이미지를 비교하는 정확하고 잘못된 방법을 보여줍니다.
작업을 단순화하기 위해 비교를 수행하기 위해 다음 확장을 생성하여 첫 번째 이미지를 변환하는 문제를 피할 수 있습니다.
import UIKit
extension UIImage {
func isEqual(to image: UIImage) -> Bool {
return isEqual(image)
}
}
이를 통해 이제 한 쌍의 이미지에서 비교하는 예제를 설정할 수 있습니다.
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
Mark의 답변을 약간 변경하고 NSData와 isEqual 대신 Data 및 elementsEqual을 사용했습니다.
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)
}
}
내가 선호하는 (Swift) 솔루션
import UIKit
func ==(lhs: UIImage, rhs: UIImage) -> Bool
{
guard let data1 = UIImagePNGRepresentation(lhs),
data2 = UIImagePNGRepresentation(rhs)
else { return false }
return data1.isEqual(data2)
}
스위프트 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()
처음에 이미지 크기 비교
저렴한 방법의 경우 처음에 이미지 크기를 비교하십시오. 이미지 내부에 작은 변화가 있어도 크기가 달라집니다.
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.
}
동일한 소스 (동일한 크기, 형식 등)의 이미지를 비교하여 성공적으로 테스트했습니다.
Facebook 비교 알고리즘의 Swift 4.x 버전 :
/// 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
}
이 방법은 훌륭하게 작동합니다.
func isEqualImages(image1: UIImage, image2: UIImage) -> Bool {
let data1: Data? = UIImagePNGRepresentation(image1)
let data2: Data? = UIImagePNGRepresentation(image2)
return data1 == data2
}
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
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
}
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
참고URL : https://stackoverflow.com/questions/11342897/how-to-compare-two-uiimage-objects
'IT Share you' 카테고리의 다른 글
Xcode에서 특정 방법으로 이동하는 방법이 있습니까? (0) | 2020.12.13 |
---|---|
플롯 영역에 상대적인 범례 배치, ggplot (0) | 2020.12.13 |
값보다 큰 행렬의 모든 값 계산 (0) | 2020.12.13 |
트위터 부트 스트랩 다중 모달 오류 (0) | 2020.12.13 |
Docker Hello-world : 인증 오류 (0) | 2020.12.13 |