-
-
Save randomsequence/7f5bfb154b91fbac59ff59f7c9f4531a to your computer and use it in GitHub Desktop.
A couple of swift functions for comparing two CGImage using CIImage in OS X
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Thanks Kevin! | |
// https://gist.github.com/SheffieldKevin/566dc048dd6f36716bcd | |
// | |
import CoreGraphics | |
import CoreImage | |
extension CGImage { | |
static func fromPNGAt(url: URL) -> CGImage? { | |
guard let provider = CGDataProvider.init(url: url as CFURL) else { | |
print("Could not make a data provider at url:", url) | |
return nil | |
} | |
return CGImage.init(pngDataProviderSource: provider, decode: nil, shouldInterpolate: false, intent: CGColorRenderingIntent.defaultIntent) | |
} | |
@discardableResult func toPNGAt(url: URL) -> Bool { | |
guard let destination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypePNG, 1, nil) else { return false } | |
CGImageDestinationAddImage(destination, self, nil) | |
return CGImageDestinationFinalize(destination) | |
} | |
func metadataString() -> String { | |
let image = self | |
return "\(image.width)x\(image.height) bitsPerComponent:\(image.bitsPerComponent) bytesPerRow:\(image.bytesPerRow) bitsPerPixel:\(image.bitsPerPixel)" | |
} | |
func differenceWith(image: CGImage) -> (Float, Float) { | |
var maxDiff: Float = -1 | |
var averageDiff: Float = -1 | |
// First create the CIImage representations of the CGImage. | |
let ciImage1 = CIImage(cgImage: self) | |
let ciImage2 = CIImage(cgImage: image) | |
let source = """ | |
kernel vec4 subtractKernel(sampler image0, sampler image1) { | |
vec2 coord = samplerCoord(image0); | |
vec4 a = sample(image0, coord); | |
vec4 b = sample(image1, coord); | |
return abs(b-a); | |
} | |
""" | |
guard let subtractKernel = CIKernel.init(source: source) else { fatalError()} | |
let diffOutput = subtractKernel.apply(extent: ciImage1.extent, roiCallback: {index, rect in | |
return rect | |
}, arguments: [ciImage1, ciImage2])! | |
let diffExtentVector = CIVector(cgRect: diffOutput.extent) | |
// The filters have been setup, now set up the CGContext bitmap context the | |
// output is drawn to. Setup the context with our supplied buffer. | |
let alphaInfo = CGImageAlphaInfo.premultipliedLast | |
let bitmapInfo = CGBitmapInfo(rawValue: alphaInfo.rawValue) | |
let colorSpace = CGColorSpaceCreateDeviceRGB() | |
var buf: [CUnsignedChar] = Array<CUnsignedChar>(repeating: 255, count: 16) | |
let context = CGContext(data: &buf, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 16, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)! | |
context.setBlendMode(.copy) | |
// Now create the core image context CIContext from the bitmap context. | |
let ciContext = CIContext(cgContext: context, options: [ | |
kCIContextWorkingColorSpace: colorSpace, | |
kCIContextUseSoftwareRenderer: false, | |
]) | |
// Create the area max filter and set its properties. | |
let areaMaxFilter = CIFilter(name: "CIAreaMaximum")! | |
areaMaxFilter.setDefaults() | |
areaMaxFilter.setValue(diffOutput, forKey: kCIInputImageKey) | |
areaMaxFilter.setValue(diffExtentVector, forKey: kCIInputExtentKey) | |
if let maxImage = areaMaxFilter.outputImage { | |
ciContext.draw(maxImage, in: CGRect(x: 0, y: 0, width: 1, height: 1), | |
from: maxImage.extent) | |
} | |
let maxVal = Float(buf[0]) + Float(buf[1]) + Float(buf[2]) + Float(buf[3]) / (255*4) | |
maxDiff = Float(maxVal) | |
// Create the area max filter and set its properties. | |
let areaAverageFilter = CIFilter(name: "CIAreaAverage")! | |
areaAverageFilter.setDefaults() | |
areaAverageFilter.setValue(diffOutput, forKey: kCIInputImageKey) | |
areaAverageFilter.setValue(diffExtentVector, forKey: kCIInputExtentKey) | |
// Get the output CIImage and draw that to the Core Image context. | |
let averageImage = areaAverageFilter.value(forKey: kCIOutputImageKey) as! CIImage | |
ciContext.draw(averageImage, in: CGRect(x: 0, y: 0, width: 1, height: 1), | |
from: averageImage.extent) | |
let averageVal = (Float(buf[0]) + Float(buf[1]) + Float(buf[2]) + Float(buf[3]))/(255*4) | |
averageDiff = Float(averageVal) | |
return (maxDiff, averageDiff) | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment