-
-
Save sooop/b497dd84fea5db13559c498792dd5374 to your computer and use it in GitHub Desktop.
Detect faces and apply pixellate filter on it
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
#!/usr/bin/swift | |
// | |
// main.swift | |
// Anonymizer | |
// | |
// Created by sooopd on 2018. 3. 30.. | |
// Copyright © 2018년 sooopd. All rights reserved. | |
// | |
import Cocoa | |
import CoreImage | |
import Vision | |
/// find facial feature and process it | |
func detectFaces(in source: CIImage, completionHandler:((CIImage) -> Void)?) | |
{ | |
let request = VNDetectFaceLandmarksRequest { req, error in | |
guard error == nil else { | |
NSLog("Error: \(error!.localizedDescription)") | |
return | |
} | |
guard let results = req.results as? [VNFaceObservation] else { | |
NSLog("Fail: Not supported result type.") | |
return | |
} | |
print("> found \(results.count) faces in the image") | |
print("> anonymizing...") | |
// Create Reulst Image | |
let boundingBoxes = results.map{ $0.boundingBox } | |
let resultImage = createAnonymizedImage(from: source, | |
boundingBoxes: boundingBoxes) | |
// call completeionHandler | |
completionHandler?(resultImage) | |
} | |
let handler = VNImageRequestHandler(ciImage: source, | |
options: [:]) | |
try? handler.perform([request]) | |
} | |
func createAnonymizedImage(from source: CIImage, boundingBoxes: [CGRect]) -> CIImage | |
{ | |
let (imageWidth, imageHeight): (Int, Int) = { | |
let size = source.extent.size | |
return (Int(size.width), Int(size.height)) | |
}() | |
// Create Bitmap Context | |
let maskImage: CIImage = { | |
let ctx = CGContext(data: nil, | |
width: imageWidth, | |
height: imageHeight, | |
bitsPerComponent: 8, | |
bytesPerRow: 0, | |
space: CGColorSpaceCreateDeviceGray(), | |
bitmapInfo: CGImageAlphaInfo.none.rawValue)! | |
ctx.setFillColor(NSColor.white.cgColor) | |
// fill(_ rects:) 를 사용하여 얼굴 영역을 칠한다. | |
ctx.fill(boundingBoxes.map{VNImageRectForNormalizedRect($0, imageWidth, imageHeight)}) | |
return CIImage(cgImage: ctx.makeImage()!) | |
}() | |
let inputImage = source.applyingFilter("CIPixellate", parameters: | |
[kCIInputScaleKey: 18.0]) | |
let resultImage = inputImage.applyingFilter("CIBlendWithMask", parameters: | |
[kCIInputMaskImageKey: maskImage, | |
kCIInputBackgroundImageKey: source]) | |
return resultImage | |
} | |
func main() { | |
guard case let arguments = CommandLine.arguments, arguments.count > 1 | |
else { | |
print("Usage: anonymizer <filepath>") | |
return | |
} | |
let context = CIContext() | |
if case let fileURL = URL(fileURLWithPath:(arguments[1] as NSString).expandingTildeInPath), | |
let image = CIImage(contentsOf:fileURL) | |
{ | |
let saveFileURL: URL = { | |
let filename = fileURL.lastPathComponent | |
let path = fileURL.deletingLastPathComponent() | |
return path.appendingPathComponent("anony-\(filename).png") | |
}() | |
print("Analyze Image...") | |
detectFaces(in: image){ resultImage in | |
defer { | |
DispatchQueue.main.async{ | |
CFRunLoopStop(CFRunLoopGetMain()) | |
} | |
} | |
print("Trying to save processed file.") | |
do { | |
try context.writePNGRepresentation( | |
of: resultImage, | |
to: saveFileURL, | |
format: kCIFormatARGB8, | |
colorSpace: CGColorSpaceCreateDeviceRGB(), | |
options: [:]) | |
print("Complete.") | |
} catch { | |
fatalError("Fail to write image data.") | |
} | |
} | |
CFRunLoopRun() | |
} | |
} | |
main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment