I use another option, a slightly modified Facebook version.
The original code here
func compareWithImage(_ referenceImage: UIImage, tolerance: CGFloat = 0) -> Bool {
guard size.equalTo(referenceImage.size) else {
return false
}
guard let cgImage = cgImage, let referenceCGImage = referenceImage.cgImage else {
return false
}
let minBytesPerRow = min(cgImage.bytesPerRow, referenceCGImage.bytesPerRow)
let referenceImageSizeBytes = Int(referenceImage.size.height) * minBytesPerRow
let imagePixelsData = UnsafeMutablePointer<Pixel>.allocate(capacity: cgImage.width * cgImage.height)
let referenceImagePixelsData = UnsafeMutablePointer<Pixel>.allocate(capacity: cgImage.width * cgImage.height)
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue & CGBitmapInfo.alphaInfoMask.rawValue)
guard let colorSpace = cgImage.colorSpace, let referenceColorSpace = referenceCGImage.colorSpace else { return false }
guard let imageContext = CGContext(data: imagePixelsData, width: cgImage.width, height: cgImage.height, bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: minBytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) else { return false }
guard let referenceImageContext = CGContext(data: referenceImagePixelsData, width: referenceCGImage.width, height: referenceCGImage.height, bitsPerComponent: referenceCGImage.bitsPerComponent, bytesPerRow: minBytesPerRow, space: referenceColorSpace, bitmapInfo: bitmapInfo.rawValue) else { return false }
imageContext.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
referenceImageContext.draw(referenceCGImage, in: CGRect(x: 0, y: 0, width: referenceImage.size.width, height: referenceImage.size.height))
var imageEqual = true
// Do a fast compare if we can
if tolerance == 0 {
imageEqual = memcmp(imagePixelsData, referenceImagePixelsData, referenceImageSizeBytes) == 0
} else {
// Go through each pixel in turn and see if it is different
let pixelCount = referenceCGImage.width * referenceCGImage.height
let imagePixels = UnsafeMutableBufferPointer<Pixel>(start: imagePixelsData, count: cgImage.width * cgImage.height)
let referenceImagePixels = UnsafeMutableBufferPointer<Pixel>(start: referenceImagePixelsData, count: referenceCGImage.width * referenceCGImage.height)
var numDiffPixels = 0
for i in 0..<pixelCount {
// If this pixel is different, increment the pixel diff count and see
// if we have hit our limit.
let p1 = imagePixels[i]
let p2 = referenceImagePixels[i]
if p1.value != p2.value {
numDiffPixels += 1
let percents = CGFloat(numDiffPixels) / CGFloat(pixelCount)
if percents > tolerance {
imageEqual = false
break
}
}
}
}
free(imagePixelsData)
free(referenceImagePixelsData)
return imageEqual
}
struct Pixel {
var value: UInt32
var red: UInt8 {
get { return UInt8(value & 0xFF) }
set { value = UInt32(newValue) | (value & 0xFFFFFF00) }
}
var green: UInt8 {
get { return UInt8((value >> 8) & 0xFF) }
set { value = (UInt32(newValue) << 8) | (value & 0xFFFF00FF) }
}
var blue: UInt8 {
get { return UInt8((value >> 16) & 0xFF) }
set { value = (UInt32(newValue) << 16) | (value & 0xFF00FFFF) }
}
var alpha: UInt8 {
get { return UInt8((value >> 24) & 0xFF) }
set { value = (UInt32(newValue) << 24) | (value & 0x00FFFFFF) }
}
}
CIDifferenceBlendMode
with your two images as inputs and use its output as a mask to the next filter? – Pilcomayo