I'm playing with iOS 11vision framework to detect facial features like nose, eyes, lips etc.
Vision frame work gives very accurate normalize points for all facial features. Now I'm trying to draw a red line over right eye with help of bezier path and below is the code I'm using to draw same.
1) addFaceLandmarksToImage()
method is detecting only right eye through vision framework and getting all normalize points. context is created and used to draw a linear line.
2) addNewPathToImage()
method is defined to add shapelayer on the detected right eye so I can crop that in next shape.
func addFaceLandmarksToImage(_ face: VNFaceObservation) {
UIGraphicsBeginImageContextWithOptions(image.size, false, 1.0)
let context = UIGraphicsGetCurrentContext()
image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
context?.translateBy(x: 0, y: image.size.height)
context?.scaleBy(x: 1.0, y: -1.0)
// draw the face rect
let w = face.boundingBox.size.width * image.size.width
let imgViewWidth = face.boundingBox.size.width * imageView.frame.size.width
let h = face.boundingBox.size.height * image.size.height
let imgViewHeight = face.boundingBox.size.height * imageView.frame.size.height
let x = face.boundingBox.origin.x * image.size.width
let imgViewX = face.boundingBox.origin.x * imageView.frame.size.width
let y = face.boundingBox.origin.y * image.size.height
let imgViewY = face.boundingBox.origin.y * imageView.frame.size.height
let faceRect = CGRect(x: x, y: y, width: w, height: h)
context?.saveGState()
context?.setStrokeColor(UIColor.red.cgColor)
context?.setLineWidth(5.0)
context?.addRect(faceRect)
context?.drawPath(using: .stroke)
context?.restoreGState()
// right eye
context?.saveGState()
context?.setStrokeColor(UIColor.red.cgColor)
if let landmark = face.landmarks?.rightEye {
for i in 0...landmark.pointCount - 1 {
let point = landmark.normalizedPoints[i]
if i == 0 {
eyePath.move(to: CGPoint(x: imgViewX + CGFloat(point.x) * imgViewWidth, y: imgViewY + CGFloat(point.y) * imgViewHeight))
context?.move(to: CGPoint(x: x + CGFloat(point.x) * w, y: y + CGFloat(point.y) * h))
} else {
eyePath.addLine(to: CGPoint(x: imgViewX + CGFloat(point.x) * imgViewWidth, y: imgViewY + CGFloat(point.y) * imgViewHeight))
context?.addLine(to: CGPoint(x: x + CGFloat(point.x) * w, y: y + CGFloat(point.y) * h))
addNewPathToImage(path: eyePath)
}
}
}
addNewPathToImage(path: eyePath)
eyePath.close()
context?.closePath()
context?.setLineWidth(2.0)
context?.drawPath(using: .stroke)
context?.saveGState()
let finalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
imageView.image = finalImage
}
func addNewPathToImage(path: UIBezierPath){
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = UIColor.blue.cgColor
shapeLayer.fillColor = UIColor.red.cgColor
shapeLayer.lineWidth = 1.0
imageView.layer.addSublayer(shapeLayer)
}
Now as you can see I'm able to draw the right eye accurately via current context on imageview. I've already applied translate and scale property on my context.
But the shapeLayer that I'm trying to add with help of addNewPathToImage() is flipped. I know that UIkit is using ULO (upper left origin) and Core graphics is base on LLO (lower left origin) system.
What transformation do I need to apply in this process in order to place that shapeLayer exactly on the right eye.
Note: I've already tried to give below transformation on shapeLayer without success.
shapeLayer.setAffineTransform(CGAffineTransform(translationX: 0, y: image.size.height))
shapeLayer.setAffineTransform(CGAffineTransform(scaleX: 1, y: -1))
Try only below transformation
shapeLayer.setAffineTransform(CGAffineTransform(scaleX: 1, y: -1))
orlook at my code Facelandmarkdetection