CAShapeLayer flipped coordinate while using with iOS11 vision

352 views Asked by At

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)
}

enter image description here

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))
1

There are 1 answers

0
Jasmeet Kaur On

Try only below transformation

shapeLayer.setAffineTransform(CGAffineTransform(scaleX: 1, y: -1)) or

look at my code Facelandmarkdetection