2017-07-09 11 views
7

Korzystam z systemu wizyjnego ios 11, aby uzyskać punkt orientacyjny twarzy w czasie rzeczywistym. Jestem w stanie zdobyć punkty orientacyjne twarzy i pokryć warstwę kamery za pomocą UIBezierPath punktów orientacyjnych twarzy. Chciałbym jednak uzyskać coś w rodzaju prawego dolnego obrazu. Obecnie mam coś, co wygląda jak lewy obrazek, i próbowałem zapętlić punkty i dodać punkty środkowe, ale nie wiem, jak wygenerować te wszystkie trójkąty z punktów. Jak mam wygenerować mapę po prawej od punktów po lewej?Swift 4: Jak utworzyć mapę twarzy z ramą wizji ios11 z punktów orientacyjnych twarzy

Nie jestem pewien, czy potrafię z wszystkimi punktami, które mam, nie, że to pomoże za dużo, ale mam też punkty z obwiedni całej twarzy. Wreszcie, czy istnieje jakaś struktura, która pozwoliłaby mi rozpoznać wszystkie punkty, których potrzebuję, takie jak openCV lub coś innego, proszę dać mi znać. Dzięki!

face_map

Oto kod używam od 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

Nie być niepoważnym, ale co sprawia, że ​​myślisz, że * możesz *? Wystarczy spojrzeć na czoło, masz * zero * wykrytych punktów (co odpowiada moim próbom), a jednak uważasz, że możesz * osiemnaście * trójkątów? – dfd

+0

@dfd Zaktualizowałem moje pytanie, aby odzwierciedlić Twoje wątpliwości. – Ali

+1

Co najwyżej ramka graniczna da ci 4 dodatkowe punkty. Gram z detalami twarzy z tego GitHub (https://github.com/artemnovichkov/iOS-11-by-Examples) i każda twarz z włosami, których używam, nie ma nic od czoła do góry. Kilka myśli, prawdopodobnie niewiele pomoże: (1) Najlepsze OpenCV/OpenGL lub CoreImage/CoreGraphics, możesz analizować rzeczy w taki sposób, aby odszyfrować linię włosów i/lub kości policzkowe według koloru. Ale to sprawia, że ​​wiele założeń, w tym nie grzywka lub długie włosy, i właściwe oświetlenie. (2) Inną możliwością jest uczenie maszynowe - szkolenie własnego modelu i korzystanie z CoreML. – dfd

Odpowiedz

2

W końcu znalazłem rozwiązanie, które działa. Użyłem triangulacji delaunay przez https://github.com/AlexLittlejohn/DelaunaySwift i zmodyfikowałem ją tak, aby działała z punktami generowanymi przez żądanie detekcji twarzy w ramce wizji. Tego nie da się łatwo wyjaśnić za pomocą fragmentu kodu, więc połączyłem moje repozytorium github poniżej, które pokazuje moje rozwiązanie. Zwróć uwagę, że nie dostaniesz punktów z czoła, ponieważ ramka widzenia dostaje tylko punkty od brwi w dół.

https://github.com/ahashim1/Face

+0

Czy masz pojęcie, dlaczego maska ​​pozostaje w tyle za wprowadzeniem przez kilka ramek? Jeśli wskażesz mi właściwy kierunek, będę mógł się z nim obejść i zrobić PR. –

+1

@AdityaGarg Myślę, że dzieje się tak dlatego, że żądanie orientacji twarzy jest wykonywane asynchronicznie, podczas gdy trójkąty są rysowane w głównym wątku. Nie jestem pewien, jak całkowicie zsynchronizować procesy. Powodzenia – Ali

0

Co chcesz na obrazku po prawej stronie jest Candide siatki. Musisz zmapować te punkty do siatki i to będzie to. Nie sądzę, że musisz iść na trasę, którą omówiono w komentarzach.

P. Znalazłem Kandyda podczas przeglądania zawartości APK słynnej aplikacji filtrującej (przypomina mi casper) - nie miałem jeszcze czasu, aby samemu spróbować.