web-dev-qa-db-fra.com

Swift 4: Comment créer une carte du visage avec le cadre de vision ios11 à partir de points de repère de visage

J'utilise le framework de vision iOS 11 pour générer les points de repère du visage en temps réel. Je peux obtenir les points de repère du visage et superposer le calque de caméra avec le chemin UIBezierPath des points de repère du visage. Cependant, j'aimerais obtenir quelque chose comme l'image en bas à droite. Actuellement, j'ai quelque chose qui ressemble à l'image de gauche et j'ai essayé de faire une boucle entre les points et d'ajouter des points médians, mais je ne sais pas comment générer tous ces triangles à partir des points. Comment pourrais-je générer la carte à droite à partir des points à gauche?

Je ne suis pas sûr de pouvoir le faire avec tous les points que j'ai, non pas que cela aide beaucoup, mais j'ai aussi des points dans la boîte de sélection de tout le visage. Enfin, existe-t-il un cadre qui me permettrait de reconnaître tous les points dont j'ai besoin, tels que openCV ou autre chose, faites-le-moi savoir. Merci!

face_map

Voici le code que j'utilise depuis 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)
}
8
Ali

J'ai fini par trouver une solution qui fonctionne. J'ai utilisé la triangulation de delaunay via https://github.com/AlexLittlejohn/DelaunaySwift , et je l'ai modifiée pour utiliser les points générés via la demande de détection de points de repère du visage de la structure de vision. Cela n’est pas facile à expliquer avec un extrait de code, j’ai donc lié mon dépôt github ci-dessous qui montre ma solution. Notez que cela ne prend pas les points du front, car la structure de vision ne les obtient que des sourcils.

https://github.com/ahashim1/Face

4
Ali

Ce que vous voulez dans l'image de droite est un Candide mesh. Vous devez mapper ces points sur le maillage et ce sera tout. Je ne pense pas que vous deviez suivre la voie qui a été discutée dans les commentaires.

P.S J'ai trouvé Candide en parcourant le contenu APK d'une célèbre application filtres (ça me rappelle Casper) - je n'ai pas encore eu le temps de l'essayer moi-même.

0
Faraz Hassan