Za pomocą pakietu ML Kit możesz wykrywać twarze na obrazach i w filmach.
Zanim zaczniesz
- Jeśli nie masz jeszcze dodanej usługi Firebase do swojej aplikacji, wykonaj czynności opisane we wprowadzeniu.
- Dodaj biblioteki ML Kit do pliku Podfile:
pod 'Firebase/MLVision', '6.25.0' # If you want to detect face contours (landmark detection and classification # don't require this additional model): pod 'Firebase/MLVisionFaceModel', '6.25.0'
Po zainstalowaniu lub zaktualizowaniu podów projektu pamiętaj, aby otworzyć projekt Xcode za pomocą pliku.xcworkspace
. - W aplikacji zaimportuj Firebase:
Swift
import Firebase
Objective-C
@import Firebase;
Wytyczne dotyczące obrazu wejściowego
Aby ML Kit mógł precyzyjnie wykrywać twarze, obrazy wejściowe muszą zawierać twarze reprezentowane przez wystarczającą ilość danych pikseli. Ogólnie każda twarz, którą chcesz wykryć na obrazie, powinna mieć co najmniej 100 x 100 pikseli. Jeśli chcesz wykrywać kontury twarzy, ML Kit wymaga wyższej rozdzielczości: każda twarz powinna mieć co najmniej 200 x 200 pikseli.
Jeśli wykrywasz twarze w aplikacji czasu rzeczywistego, warto również wziąć pod uwagę ogólne wymiary obrazów wejściowych. Mniejsze obrazy mogą być przetwarzane szybciej, więc aby skrócić czas oczekiwania, zrób zdjęcia w niższej rozdzielczości (pamiętając o powyższych wymaganiach dotyczących dokładności) i dopilnuj, aby twarz obiektu zajmowała jak największą część obrazu. Zobacz też wskazówki, jak zwiększyć wydajność w czasie rzeczywistym.
Słaba ostrość obrazu może negatywnie wpływać na dokładność. Jeśli nie uzyskujesz akceptowalnych wyników, poproś użytkownika o ponowne przechwycenie obrazu.
Orientacja twarzy względem aparatu może też mieć wpływ na to, jakie rysy twarzy wykrywane przez ML Kit. Zobacz Pojęcia związane z wykrywaniem twarzy.
1. Konfigurowanie wykrywania twarzy
Jeśli chcesz zmienić domyślne ustawienia wykrywania twarzy, to zanim zastosujesz tę funkcję do zdjęcia, użyj obiektuVisionFaceDetectorOptions
. Możesz zmienić te ustawienia:
Ustawienia | |
---|---|
performanceMode |
fast (domyślna) | accurate
Większa szybkość lub dokładność podczas wykrywania twarzy. |
landmarkMode |
none (domyślna) | all
Określa, czy należy podjąć próbę wykrycia „punktów orientacyjnych” wszystkich wykrytych twarzy – oczu, uszu, nosa, policzków czy ust. |
contourMode |
none (domyślna) | all
Określa, czy wykrywać kontury rysów twarzy. Kontury są wykrywane tylko w przypadku najbardziej widocznej twarzy na zdjęciu. |
classificationMode |
none (domyślna) | all
Określa, czy twarze mają być klasyfikowane w kategoriach takich jak „uśmiech” i „oczy otwarte”. |
minFaceSize |
CGFloat (domyślnie: 0.1 )
Minimalny rozmiar twarzy do wykrycia w odniesieniu do obrazu. |
isTrackingEnabled |
false (domyślna) | true
Określa, czy przypisywać do twarzy identyfikator, który może służyć do śledzenia twarzy na zdjęciach. Pamiętaj, że przy włączonym wykrywaniu kontur wykrywana jest tylko jedna twarz, więc śledzenie twarzy nie daje żadnych użytecznych wyników. Z tego powodu i aby zwiększyć szybkość wykrywania, nie włączaj jednocześnie wykrywania kontur i śledzenia twarzy. |
Na przykład utwórz obiekt VisionFaceDetectorOptions
jak w tych przykładach:
Swift
// High-accuracy landmark detection and face classification let options = VisionFaceDetectorOptions() options.performanceMode = .accurate options.landmarkMode = .all options.classificationMode = .all // Real-time contour detection of multiple faces let options = VisionFaceDetectorOptions() options.contourMode = .all
Objective-C
// High-accuracy landmark detection and face classification FIRVisionFaceDetectorOptions *options = [[FIRVisionFaceDetectorOptions alloc] init]; options.performanceMode = FIRVisionFaceDetectorPerformanceModeAccurate; options.landmarkMode = FIRVisionFaceDetectorLandmarkModeAll; options.classificationMode = FIRVisionFaceDetectorClassificationModeAll; // Real-time contour detection of multiple faces FIRVisionFaceDetectorOptions *options = [[FIRVisionFaceDetectorOptions alloc] init]; options.contourMode = FIRVisionFaceDetectorContourModeAll;
2. Uruchom wykrywanie twarzy
Aby wykrywać twarze na obrazie, przekaż obraz jakoUIImage
lub CMSampleBufferRef
do metody detect(in:)
VisionFaceDetector
:
- Pobierz instancję
VisionFaceDetector
:Swift
lazy var vision = Vision.vision() let faceDetector = vision.faceDetector(options: options)
Objective-C
FIRVision *vision = [FIRVision vision]; FIRVisionFaceDetector *faceDetector = [vision faceDetector]; // Or, to change the default settings: // FIRVisionFaceDetector *faceDetector = // [vision faceDetectorWithOptions:options];
-
Utwórz obiekt
VisionImage
za pomocąUIImage
lubCMSampleBufferRef
.Aby użyć karty
UIImage
:- W razie potrzeby obróć obraz, by jego właściwość
imageOrientation
miała wartość.up
. - Utwórz obiekt
VisionImage
przy użyciu prawidłowo wykonanej rotacji wUIImage
. Nie określaj żadnych metadanych rotacji – należy użyć wartości domyślnej.topLeft
.Swift
let image = VisionImage(image: uiImage)
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
Aby użyć karty
CMSampleBufferRef
:-
Utwórz obiekt
VisionImageMetadata
, który określa orientację danych obrazu zawartych w buforzeCMSampleBufferRef
.Aby sprawdzić orientację obrazu:
Swift
func imageOrientation( deviceOrientation: UIDeviceOrientation, cameraPosition: AVCaptureDevice.Position ) -> VisionDetectorImageOrientation { switch deviceOrientation { case .portrait: return cameraPosition == .front ? .leftTop : .rightTop case .landscapeLeft: return cameraPosition == .front ? .bottomLeft : .topLeft case .portraitUpsideDown: return cameraPosition == .front ? .rightBottom : .leftBottom case .landscapeRight: return cameraPosition == .front ? .topRight : .bottomRight case .faceDown, .faceUp, .unknown: return .leftTop } }
Objective-C
- (FIRVisionDetectorImageOrientation) imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation cameraPosition:(AVCaptureDevicePosition)cameraPosition { switch (deviceOrientation) { case UIDeviceOrientationPortrait: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationLeftTop; } else { return FIRVisionDetectorImageOrientationRightTop; } case UIDeviceOrientationLandscapeLeft: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationBottomLeft; } else { return FIRVisionDetectorImageOrientationTopLeft; } case UIDeviceOrientationPortraitUpsideDown: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationRightBottom; } else { return FIRVisionDetectorImageOrientationLeftBottom; } case UIDeviceOrientationLandscapeRight: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationTopRight; } else { return FIRVisionDetectorImageOrientationBottomRight; } default: return FIRVisionDetectorImageOrientationTopLeft; } }
Następnie utwórz obiekt metadanych:
Swift
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Objective-C
FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init]; AVCaptureDevicePosition cameraPosition = AVCaptureDevicePositionBack; // Set to the capture device you used. metadata.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
- Utwórz obiekt
VisionImage
, używając obiektuCMSampleBufferRef
i metadanych rotacji:Swift
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- W razie potrzeby obróć obraz, by jego właściwość
-
Następnie przekaż obraz do metody
detect(in:)
:Swift
faceDetector.process(visionImage) { faces, error in guard error == nil, let faces = faces, !faces.isEmpty else { // ... return } // Faces detected // ... }
Objective-C
[faceDetector detectInImage:image completion:^(NSArray<FIRVisionFace *> *faces, NSError *error) { if (error != nil) { return; } else if (faces != nil) { // Recognized faces } }];
3. Uzyskiwanie informacji o wykrytych twarzy
Jeśli wykrywanie twarzy się powiedzie, detektor twarzy przekaże tablicę obiektówVisionFace
do modułu obsługi uzupełniania. Każdy obiekt VisionFace
reprezentuje twarz wykrytą na obrazie. W przypadku każdej twarzy można sprawdzić współrzędne ograniczające twarz na obrazie wejściowym, a także wszelkie inne informacje, które ma być wykrywany przez detektor twarzy. Przykład:
Swift
for face in faces { let frame = face.frame if face.hasHeadEulerAngleY { let rotY = face.headEulerAngleY // Head is rotated to the right rotY degrees } if face.hasHeadEulerAngleZ { let rotZ = face.headEulerAngleZ // Head is rotated upward rotZ degrees } // If landmark detection was enabled (mouth, ears, eyes, cheeks, and // nose available): if let leftEye = face.landmark(ofType: .leftEye) { let leftEyePosition = leftEye.position } // If contour detection was enabled: if let leftEyeContour = face.contour(ofType: .leftEye) { let leftEyePoints = leftEyeContour.points } if let upperLipBottomContour = face.contour(ofType: .upperLipBottom) { let upperLipBottomPoints = upperLipBottomContour.points } // If classification was enabled: if face.hasSmilingProbability { let smileProb = face.smilingProbability } if face.hasRightEyeOpenProbability { let rightEyeOpenProb = face.rightEyeOpenProbability } // If face tracking was enabled: if face.hasTrackingID { let trackingId = face.trackingID } }
Objective-C
for (FIRVisionFace *face in faces) { // Boundaries of face in image CGRect frame = face.frame; if (face.hasHeadEulerAngleY) { CGFloat rotY = face.headEulerAngleY; // Head is rotated to the right rotY degrees } if (face.hasHeadEulerAngleZ) { CGFloat rotZ = face.headEulerAngleZ; // Head is tilted sideways rotZ degrees } // If landmark detection was enabled (mouth, ears, eyes, cheeks, and // nose available): FIRVisionFaceLandmark *leftEar = [face landmarkOfType:FIRFaceLandmarkTypeLeftEar]; if (leftEar != nil) { FIRVisionPoint *leftEarPosition = leftEar.position; } // If contour detection was enabled: FIRVisionFaceContour *upperLipBottomContour = [face contourOfType:FIRFaceContourTypeUpperLipBottom]; if (upperLipBottomContour != nil) { NSArray<FIRVisionPoint *> *upperLipBottomPoints = upperLipBottomContour.points; if (upperLipBottomPoints.count > 0) { NSLog("Detected the bottom contour of the subject's upper lip.") } } // If classification was enabled: if (face.hasSmilingProbability) { CGFloat smileProb = face.smilingProbability; } if (face.hasRightEyeOpenProbability) { CGFloat rightEyeOpenProb = face.rightEyeOpenProbability; } // If face tracking was enabled: if (face.hasTrackingID) { NSInteger trackingID = face.trackingID; } }
Przykład konturu twarzy
Gdy wykrywanie konturu twarzy jest włączone, otrzymujesz listę punktów za każdą wykrytą cechę twarzy. Te punkty reprezentują kształt obiektu. Szczegółowe informacje o tym, jak przedstawiane są kontury, znajdziesz w artykule Omówienie zagadnień związanych z wykrywaniem twarzy.
Na poniższym obrazie przedstawiono mapowanie tych punktów na twarz (kliknij obraz, aby go powiększyć):
Wykrywanie twarzy w czasie rzeczywistym
Jeśli chcesz używać wykrywania twarzy w aplikacjach działających w czasie rzeczywistym, postępuj zgodnie z tymi wskazówkami, aby uzyskać najlepszą liczbę klatek na sekundę:
Skonfiguruj wykrywacz twarzy, aby używał wykrywania kontur lub klasyfikacji twarzy i wykrywania punktów orientacyjnych, ale nie obu naraz:
Wykrywanie konturów
Wykrywanie punktów orientacyjnych
Klasyfikacja
Wykrywanie i klasyfikacja punktów orientacyjnych
Wykrywanie kontur i wykrywanie punktów orientacyjnych
Wykrywanie i klasyfikacja kontur
Wykrywanie konturu, wykrywanie punktów orientacyjnych i klasyfikacjaWłącz tryb
fast
(domyślnie włączony).Rozważ robienie zdjęć w niższej rozdzielczości. Pamiętaj jednak o wymaganiach tego interfejsu API dotyczących wymiarów obrazu.
- Ogranicz wywołania do detektora. Jeśli podczas działania detektora dostępna będzie nowa klatka wideo, upuść ją.
- Jeśli używasz danych wyjściowych detektora do nakładania grafiki na obraz wejściowy, najpierw pobierz wynik z ML Kit, a potem wyrenderuj obraz i nakładkę w jednym kroku. Dzięki temu renderowanie na powierzchni wyświetlania będzie odbywać się tylko raz na każdą klatkę wejściową. Przykład znajdziesz w klasach previewOverlayView i FIRDetectionOverlayView w przykładowej aplikacji z funkcją prezentacji.