Welcome to Warhol — A library written in Swift that makes easy the process of Face Detection and drawing on top for IOS.
Warhol acts as a wrapper on top of the Apple Vision Framework, detecting the features of a face from camera or image and providing these elements position in your own coordinates, so you can easily draw on top. Forget about the complex Vision or AVFoundation frameworks, just handle the Warhol Face View Model class that encapsulates the features coordinates.
- Face Detection from Camera
- Face Detection from UIImageView
- Face features conversion to the client coordinates.
- Draw on top of the face.
- iOS 11.0+
- Xcode 11.0+
You can use CocoaPods to install Warhol
by adding it to your Podfile
:
platform :ios, '11.0'
use_frameworks!
pod 'Warhol'
To get the full benefits import Warhol
wherever you use it
import Warhol
Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate Alamofire into your Xcode project using Carthage, specify it in your Cartfile
:
github "toupper/Warhol" ~> 0.2.0
The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift
compiler. It is in early development, but Alamofire does support its use on supported platforms.
Once you have your Swift package set up, adding Warhol as a dependency is as easy as adding it to the dependencies
value of your Package.swift
.
dependencies: [
.package(url: "https://github.com/toupper/Warhol.git", .upToNextMajor(from: "0.2.0"))
]
You can also integrate Warhol into your project manually.
-
Open up Terminal,
cd
into your top-level project directory, and run the following command "if" your project is not initialized as a git repository:$ git init
-
Add Warhol as a git submodule by running the following command:
$ git submodule add https://github.com/toupper/Warhol.git
-
Open the new
Warhol
folder, and drag theWarhol.xcodeproj
into the Project Navigator of your application's Xcode project. -
And that's it!
Import Warhol in the file you are going to use it. Create an instance of CameraFaceDetectionViewController
, and asign the view where you are going to draw to the cameraFrontView
property of the former. You can then present the view controller:
import Warhol
let cameraViewController = CameraFaceDetectionViewController()
let faceView = FaceView()
faceView.backgroundColor = .clear
cameraViewController.cameraFrontView = faceView
present(cameraViewController, animated: true, completion: nil)
In order to draw, we should create a subclass of UIView that complies with the Warhol protocol FaceView. We can then draw in their func draw(_ rect: CGRect)
function. Anytime Warhol detects a Face change, it will call setNeedsDisplay()
on the view so it can trigger the draw process:
import Warhol
final class FaceView: UIView, CameraFrontView {
var viewModel: FaceViewModel?
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext(),
let viewModel = viewModel else {
return
}
context.saveGState()
defer {
context.restoreGState()
}
context.addRect(viewModel.boundingBox)
...
If you want to add images on top of each Face Features, you have to compose a FaceLayout
object defining an ImageLayout
object for each type of Face Landmark you want to draw. You can set the desired offset and Size Ratio for each feature. Once you have it, you should then pass it to the faceLayout property of the CameraFaceDetectionViewController
. Please notice that if you do that the cameraFrontView
property gets overriden:
let cameraViewController = CameraFaceDetectionViewController()
let leftEye = ImageLayout(image: UIImage(named: "leftEye")!, sizeRatio: SizeRatio(width: 1, height: 4))
let rightEye = ImageLayout(image: UIImage(named: "rightEye")!, sizeRatio: SizeRatio(width: 1, height: 4))
let nose = ImageLayout(image: UIImage(named: "nose")!)
let faceLayout = FaceLayout(landmarkLayouts: [.leftEye: leftEye,
.rightEye: rightEye,
.nose: nose])
cameraViewController.faceLayout = faceLayout
present(cameraViewController, animated: true, completion: nil)
Apart from that, you can implement the CameraFaceDetectionDelegate
protocol to react to any change in the Face Dectection. This can be convenient for the case when you do not want to draw on top, but just get the face features (landmarks) coordinates. These are encapsulated in the given parameter FaceViewModel
.
In order to detect a face features and draw on top, we should pass the sdk the UIImageView depicting the face, and a closure where we draw on top of the image:
import Warhol
imageView.image = UIImage(named: "Face")
Warhol.drawLandmarks(from: imageView,
draw: { (viewModel, context) in
// draw with CGContext
},
error: {_ in })
If instead of modifying the passed image of the you want to generate a new UIImageView instance, use drawLandmarksInNewImage
:
imageView.image = UIImage(named: "Face")
Warhol.drawLandmarksInNewImage(from: imageView,
draw: { (viewModel, context) in
self.draw(viewModel: viewModel, in: context)
},
completion: { newImage in
self.newImageView.image = newImage
},
error: {_ in })
We would love you for the contribution to Warhol, check the LICENSE
file for more info.
Created and maintained with love by César Vargas Casaseca. You can follow me on Medium @toupper for project updates, releases and more stories.
Warhol is released under the MIT license. See LICENSE for details.