Swift 4:如何使用ios11视觉框架从脸部地标点创建脸部地图

问题描述:

我使用ios 11视觉框架实时生成脸部地标点。我能够获得人脸标志点,并将相机图层与人脸标志点的UIBezier路径叠加。但是,我想获得类似右下图的内容。目前我有一些看起来像左图的东西,我尝试循环遍历点并添加中点,但我不知道如何从点生成所有这些三角形。我将如何从左侧的点生成右侧的地图?Swift 4:如何使用ios11视觉框架从脸部地标点创建脸部地图

我不确定我能否满足所有要点,并不是说它会帮助太大,但我也从整个脸部的边界框中获得了点数。最后,是否有任何框架可以让我认识到我需要的所有要点,比如openCV或其他,请让我知道。谢谢!

face_map

这里是我已经从https://github.com/DroidsOnRoids/VisionFaceDetection使用的代码:

func detectLandmarks(on image: CIImage) { 
    try? faceLandmarksDetectionRequest.perform([faceLandmarks], on: image) 
    if let landmarksResults = faceLandmarks.results as? [VNFaceObservation] { 

     for observation in landmarksResults { 

      DispatchQueue.main.async { 
       if let boundingBox = self.faceLandmarks.inputFaceObservations?.first?.boundingBox { 
        let faceBoundingBox = boundingBox.scaled(to: self.view.bounds.size) 
        //different types of landmarks 



        let faceContour = observation.landmarks?.faceContour 
        self.convertPointsForFace(faceContour, faceBoundingBox) 

        let leftEye = observation.landmarks?.leftEye 
        self.convertPointsForFace(leftEye, faceBoundingBox) 

        let rightEye = observation.landmarks?.rightEye 
        self.convertPointsForFace(rightEye, faceBoundingBox) 

        let leftPupil = observation.landmarks?.leftPupil 
        self.convertPointsForFace(leftPupil, faceBoundingBox) 

        let rightPupil = observation.landmarks?.rightPupil 
        self.convertPointsForFace(rightPupil, faceBoundingBox) 

        let nose = observation.landmarks?.nose 
        self.convertPointsForFace(nose, faceBoundingBox) 

        let lips = observation.landmarks?.innerLips 
        self.convertPointsForFace(lips, faceBoundingBox) 

        let leftEyebrow = observation.landmarks?.leftEyebrow 
        self.convertPointsForFace(leftEyebrow, faceBoundingBox) 

        let rightEyebrow = observation.landmarks?.rightEyebrow 
        self.convertPointsForFace(rightEyebrow, faceBoundingBox) 

        let noseCrest = observation.landmarks?.noseCrest 
        self.convertPointsForFace(noseCrest, faceBoundingBox) 

        let outerLips = observation.landmarks?.outerLips 
        self.convertPointsForFace(outerLips, faceBoundingBox) 
       } 
      } 
     } 
    } 

} 

func convertPointsForFace(_ landmark: VNFaceLandmarkRegion2D?, _ boundingBox: CGRect) { 
    if let points = landmark?.points, let count = landmark?.pointCount { 
     let convertedPoints = convert(points, with: count) 



     let faceLandmarkPoints = convertedPoints.map { (point: (x: CGFloat, y: CGFloat)) -> (x: CGFloat, y: CGFloat) in 
      let pointX = point.x * boundingBox.width + boundingBox.origin.x 
      let pointY = point.y * boundingBox.height + boundingBox.origin.y 

      return (x: pointX, y: pointY) 
     } 

     DispatchQueue.main.async { 
      self.draw(points: faceLandmarkPoints) 
     } 
    } 
} 


func draw(points: [(x: CGFloat, y: CGFloat)]) { 
    let newLayer = CAShapeLayer() 
    newLayer.strokeColor = UIColor.blue.cgColor 
    newLayer.lineWidth = 4.0 

    let path = UIBezierPath() 
    path.move(to: CGPoint(x: points[0].x, y: points[0].y)) 
    for i in 0..<points.count - 1 { 
     let point = CGPoint(x: points[i].x, y: points[i].y) 
     path.addLine(to: point) 
     path.move(to: point) 
    } 
    path.addLine(to: CGPoint(x: points[0].x, y: points[0].y)) 
    newLayer.path = path.cgPath 

    shapeLayer.addSublayer(newLayer) 
} 
+1

不是轻浮,但是什么让你认为你*可以*?只要看额头,就可以检测到*零*点(从我的测试中可以得知),但你认为你可以*十八个三角形? – dfd

+0

@dfd我已更新我的问题以反映您的问题。 – Ali

+1

充其量,边界框会给你4点以上。我一直在玩这个GitHub的脸部细节(https://github.com/artemnovichkov/iOS-11-by-Examples),而且我用的头发每张脸都没有额头。一些想法,可能没有太大的帮助:(1)最好的OpenCV/OpenGL,或者CoreImage/CoreGraphics,你可以用某种方式来分析事物,以便通过颜色来破解发际线和/或颧骨。但是那做了很多假设,包括没有刘海或长发,以及适当的照明。 (2)另一种可能性是机器学习 - 培训你自己的模型并使用CoreML。 – dfd

我确实最终找到了一个可行的解决方案。我通过https://github.com/AlexLittlejohn/DelaunaySwift使用了delaunay三角剖分,并将其修改为与通过视觉框架的人脸标志检测请求生成的点一起工作。这不是一个简单的代码片段解释,所以我已经链接我的github回购下面显示我的解决方案。请注意,这不会从额头获得点数,因为视觉框架只能从眉毛中获得点数。

https://github.com/ahashim1/Face

+0

的下方看到我的回答你有没有想过为什么面具会滞后于输入框?如果你指向正确的方向,我可以玩弄它并制作一个公关。 –

+1

@AdityaGarg我认为这是因为面部标记请求是异步完成的,而三角形绘制在主线程上。不太清楚如何完成同步过程。祝你好运 – Ali

你想在右边的图像中什么是Candide网。你需要将这些点映射到网格,这就是它。我不认为你需要去评论中讨论过的路线。

P.S我发现Candide时,通过一个着名的过滤器应用程序的APK内容(让我想起casper) - 还没有时间自己尝试一下。