Przewodnik wykrywania twarzy w iOS

Zadanie Wykrywanie twarzy umożliwia wykrywanie twarzy na obrazie lub w filmie. Za pomocą tego zadania możesz zlokalizować twarze i cechy twarzy w ramce. W tym zadaniu używamy modelu uczenia maszynowego, który działa z pojedynczymi obrazami lub ciągłym strumieniem obrazów. Zadanie zwraca pozycje twarzy oraz następujące kluczowe punkty twarzy: lewe oko, prawe oko, czubek nosa, usta, lewy kącik oka i prawy kącik oka.

Przykładowy kod opisany w tych instrukcjach jest dostępny na GitHub. Aby zobaczyć, jak to zadanie działa w praktyce, obejrzyj to demo. Więcej informacji o możliwościach, modelach i opcjach konfiguracji tego zadania znajdziesz w omówieniu.

Przykładowy kod

Przykładowy kod MediaPipe Tasks to prosta implementacja aplikacji wykrywającej twarz na iOS. Przykład wykorzystuje kamerę na fizycznym urządzeniu z Androidem do wykrywania twarzy w ciągłym strumieniu wideo. Aplikacja może też wykrywać twarze na zdjęciach i filmach z galerii urządzenia.

Możesz użyć tej aplikacji jako punktu wyjścia do utworzenia własnej aplikacji na iOS lub skorzystać z niej podczas modyfikowania istniejącej aplikacji. Przykładowy kod usługi Face Detector jest hostowany na GitHub.

Pobieranie kodu

Z tych instrukcji dowiesz się, jak utworzyć lokalną kopię przykładowego kodu za pomocą narzędzia wiersza poleceń git.

Aby pobrać przykładowy kod:

  1. Sklonuj repozytorium Git za pomocą tego polecenia:

    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. Opcjonalnie skonfiguruj instancję git, aby używać rzadkiego sprawdzania, dzięki czemu będziesz mieć tylko pliki przykładowej aplikacji Face Detector:

    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/face_detector/ios/
    

Po utworzeniu lokalnej wersji przykładowego kodu możesz zainstalować bibliotekę zadań MediaPipe, otworzyć projekt za pomocą Xcode i uruchomić aplikację. Instrukcje znajdziesz w Przewodniku konfiguracji dla iOS.

Kluczowe komponenty

Te pliki zawierają kluczowy kod aplikacji przykładowej Wykrywanie twarzy:

  • FaceDetectorService.swift inicjalizuje detektor, obsługuje wybór modelu i wykonuje wnioskowanie na podstawie danych wejściowych.
  • CameraViewController: implementuje interfejs użytkownika w trybie wejścia z obrazu na żywo z kamery i wizualizuje wyniki wykrywania.
  • MediaLibraryViewController.swift: implementuje interfejs użytkownika do obsługi trybu wprowadzania nieruchomych obrazów i plików wideo oraz wizualizuje wyniki wykrywania.

Konfiguracja

W tej sekcji znajdziesz najważniejsze czynności, które musisz wykonać, aby skonfigurować środowisko programistyczne i projekty kodu pod kątem używania Wykrywania twarzy. Ogólne informacje o konfigurowaniu środowiska programistycznego do korzystania z zadań MediaPipe, w tym wymagania dotyczące wersji platformy, znajdziesz w przewodniku konfiguracji dla iOS.

Zależności

Funkcja wykrywania twarzy korzysta z biblioteki MediaPipeTasksVision, którą należy zainstalować za pomocą CocoaPods. Biblioteka jest zgodna z aplikacją w języku Swift i Objective-C i nie wymaga dodatkowej konfiguracji językowej.

Instrukcje instalacji CocoaPods na macOS znajdziesz w przewodniku instalacji CocoaPods. Instrukcje tworzenia Podfile z podami niezbędnymi dla aplikacji znajdziesz w artykule Korzystanie z CocoaPods.

Dodaj podproces MediaPipeTasksVision w pliku Podfile, używając tego kodu:

target 'MyFaceDetectorApp' do
  use_frameworks!
  pod 'MediaPipeTasksVision'
end

Jeśli Twoja aplikacja zawiera cele testów jednostkowych, dodatkowe informacje o konfigurowaniu Podfile znajdziesz w przewodniku konfiguracji na iOS.

Model

Zadanie MediaPipe Face Detector wymaga wytrenowanego modelu, który jest zgodny z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach na potrzeby Wykrywania twarzy znajdziesz w omówieniu zadania w sekcji Modele.

Wybierz i pobierz model, a następnie dodaj go do katalogu projektu za pomocą Xcode. Instrukcje dodawania plików do projektu Xcode znajdziesz w artykule Zarządzanie plikami i folderami w projekcie Xcode.

Użyj właściwości BaseOptions.modelAssetPath, aby określić ścieżkę do modelu w pakiecie aplikacji. Przykładowy kod znajdziesz w następnej sekcji.

Tworzenie zadania

Zadanie wykrywania twarzy możesz utworzyć, wywołując jedną z jego funkcji inicjującej. Inicjalizator FaceDetector(options:) może przyjmować wartości opcji konfiguracji.

Jeśli nie potrzebujesz wzorca do wykrywania twarzy zainicjowanego za pomocą niestandardowych opcji konfiguracji, możesz użyć funkcji inicjalizującej FaceDetector(modelPath:), aby utworzyć wzorzec do wykrywania twarzy z opcjami domyślnymi. Więcej informacji o opcjach konfiguracji znajdziesz w artykule Omówienie konfiguracji.

Zadanie wykrywacza twarzy obsługuje 3 typy danych wejściowych: obrazy, pliki wideo i transmisje wideo na żywo. Domyślnie FaceDetector(modelPath:) inicjuje zadanie dotyczące obrazów statycznych. Jeśli chcesz, aby zadanie zostało zainicjowane w celu przetwarzania plików wideo lub transmisji na żywo, użyj parametru FaceDetector(options:), aby określić tryb działania związany z odtwarzaniem filmów lub transmisji na żywo. Tryb transmisji na żywo wymaga też dodatkowej opcji konfiguracji faceDetectorLiveStreamDelegate, która umożliwia detekcja twarzy asynchroniczne przesyłanie wyników wykrywania twarzy do delegata.

Aby dowiedzieć się, jak utworzyć zadanie i przeprowadzić wnioskowanie, wybierz kartę odpowiadającą trybowi działania.

Swift

Obraz

import MediaPipeTasksVision

let modelPath = Bundle.main.path(forResource: "model",
                                      ofType: "tflite")

let options = FaceDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .image

let faceDetector = try FaceDetector(options: options)
    

Wideo

import MediaPipeTasksVision

let modelPath = Bundle.main.path(forResource: "model",
                                      ofType: "tflite")

let options = FaceDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .video

let faceDetector = try FaceDetector(options: options)
    

Transmisja na żywo

import MediaPipeTasksVision

// Class that conforms to the `FaceDetectorLiveStreamDelegate` protocol and
// implements the method that the face detector calls once it finishes
// detecting faces in each input frame.
class FaceDetectorResultProcessor: NSObject, FaceDetectorLiveStreamDelegate {

  func faceDetector(
    _ faceDetector: FaceDetector,
    didFinishDetection result: FaceDetectorResult?,
    timestampInMilliseconds: Int,
    error: Error?) {

    // Process the face detection result or errors here.

  }
}

let modelPath = Bundle.main.path(
  forResource: "model",
  ofType: "tflite")

let options = FaceDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .liveStream

// Assign an object of the class to the `faceDetectorLiveStreamDelegate`
// property.
let processor = FaceDetectorResultProcessor()
options.faceDetectorLiveStreamDelegate = processor

let faceDetector = try FaceDetector(options: options)
    

Objective-C

Obraz

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPFaceDetectorOptions *options = [[MPPFaceDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeImage;

MPPFaceDetector *faceDetector =
      [[MPPFaceDetector alloc] initWithOptions:options error:nil];
    

Wideo

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPFaceDetectorOptions *options = [[MPPFaceDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeVideo;

MPPFaceDetector *faceDetector =
      [[MPPFaceDetector alloc] initWithOptions:options error:nil];
    

Transmisja na żywo

@import MediaPipeTasksVision;

// Class that conforms to the `MPPFaceDetectorLiveStreamDelegate` protocol
// and implements the method that the face detector calls once it finishes
// detecting faces in each input frame.

@interface APPFaceDetectorResultProcessor : NSObject 

@end

@implementation APPFaceDetectorResultProcessor

-   (void)faceDetector:(MPPFaceDetector *)faceDetector
    didFinishDetectionWithResult:(MPPFaceDetectorResult *)faceDetectorResult
         timestampInMilliseconds:(NSInteger)timestampInMilliseconds
                           error:(NSError *)error {

    // Process the face detector result or errors here.

}

@end

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPFaceDetectorOptions *options = [[MPPFaceDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeLiveStream;

// Assign an object of the class to the `faceDetectorLiveStreamDelegate`
// property.
APPFaceDetectorResultProcessor *processor = [APPFaceDetectorResultProcessor new];
options.faceDetectorLiveStreamDelegate = processor;

MPPFaceDetector *faceDetector =
      [[MPPFaceDetector alloc] initWithOptions:options error:nil];
    

Uwaga: jeśli używasz trybu wideo lub transmisji na żywo, funkcja wykrywania twarzy korzysta z śledzenia, aby uniknąć uruchamiania modelu wykrywania na każdym klatce, co pomaga zmniejszyć opóźnienie.

Opcje konfiguracji

W tym zadaniu dostępne są te opcje konfiguracji aplikacji na iOS:

Nazwa opcji Opis Zakres wartości Wartość domyślna
runningMode Ustawia tryb działania zadania. Dostępne są 3 tryby:

IMAGE (Obraz): tryb do wprowadzania pojedynczych obrazów.

FILM: tryb dekodowanych klatek filmu.

LIVE_STREAM: tryb transmisji na żywo danych wejściowych, takich jak dane z kamery. W tym trybie należy wywołać metodę resultListener, aby skonfigurować odbiornik, który będzie asynchronicznie odbierał wyniki.
{RunningMode.image, RunningMode.video, RunningMode.liveStream} RunningMode.image
minDetectionConfidence Minimalny wynik ufności, który pozwala uznać wykrywanie twarzy za skuteczne. Float [0,1] 0.5
minSuppressionThreshold Minimalny próg niemaksymalizacji dla wykrywania twarzy, który ma być uznany za nakładający się. Float [0,1] 0.3

Konfiguracja transmisji na żywo

Gdy tryb działania jest ustawiony na transmisję na żywo, detektor twarzy wymaga dodatkowej opcji konfiguracji faceDetectorLiveStreamDelegate, która umożliwia mu przesyłanie wyników wykrywania asynchronicznie. Przedstawiciel implementuje metodę faceDetector(_:didFinishDetection:timestampInMilliseconds:error:), którą detektor twarzy wywołuje po przetworzeniu wyników wykrywania twarzy w każdej klatce.

Nazwa opcji Opis Zakres wartości Wartość domyślna
faceDetectorLiveStreamDelegate Umożliwia detekcja twarzy odbieranie wyników wykrywania twarzy asynchronicznie w trybie transmisji na żywo. Klasa, której instancja jest ustawiona w tej właściwości, musi implementować metodę faceDetector(_:didFinishDetection:timestampInMilliseconds:error:). Nie dotyczy Nie ustawiono

Przygotuj dane

Przed przekazaniem go do usługi Detector Face musisz przekonwertować wejściowy obraz lub ramkę na obiekt MPImage. MPImage obsługuje różne typy formatów obrazów iOS i może ich używać w dowolnym trybie działania do wnioskowania. Więcej informacji o MPImage znajdziesz w dokumentacji interfejsu MPImage API.

Wybierz format obrazu iOS na podstawie przypadku użycia i trybułu działania wymaganego przez aplikację. MPImage obsługuje formaty obrazów iOS UIImage, CVPixelBufferCMSampleBuffer.

UIImage

Format UIImage jest odpowiedni do tych trybów działania:

  • Obrazy: obrazy z pakietu aplikacji, galerii użytkownika lub systemu plików sformatowane jako obrazy UIImage można przekształcić w obiekt MPImage.

  • Filmy: użyj narzędzia AVAssetImageGenerator, aby wyodrębnić klatki wideo do formatu CGImage, a następnie przekonwertuj je na obrazy UIImage.

Swift

// Load an image on the user's device as an iOS `UIImage` object.

// Convert the `UIImage` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(uiImage: image)
    

Objective-C

// Load an image on the user's device as an iOS `UIImage` object.

// Convert the `UIImage` object to a MediaPipe's Image object having the default
// orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
    

Przykład inicjalizuje MPImage z domyślnym ułożeniem UIImage.Orientation.Up. Możesz zainicjować MPImage przy użyciu dowolnej z obsługiwanych wartości UIImage.Orientation. Wykrywanie twarzy nie obsługuje lustrzanych orientacji, takich jak .upMirrored, .downMirrored, .leftMirrored, .rightMirrored.

Więcej informacji o UIImage znajdziesz w dokumentacji UIImage dla deweloperów Apple.

CVPixelBuffer

Format CVPixelBuffer jest odpowiedni dla aplikacji, które generują klatki i korzystają z ramy CoreImage na iOS do przetwarzania.

Format CVPixelBuffer jest odpowiedni do tych trybów działania:

  • Obrazy: aplikacje, które generują obrazy CVPixelBuffer po przetworzeniu ich za pomocą platformy CoreImage w iOS, mogą wysyłać je do usługi Face Detector w trybie uruchamiania obrazu.

  • Filmy: ramki wideo można przekształcić w format CVPixelBuffer do przetwarzania, a następnie wysłać do usługi Detector twarzy w trybie wideo.

  • transmisja na żywo: aplikacje korzystające z aparatu w iOS do generowania klatek mogą być konwertowane do formatu CVPixelBuffer w celu przetworzenia, zanim zostaną przesłane do wykrywania twarzy w trybie transmisji na żywo.

Swift

// Obtain a CVPixelBuffer.

// Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(pixelBuffer: pixelBuffer)
    

Objective-C

// Obtain a CVPixelBuffer.

// Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the
// default orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
    

Więcej informacji o CVPixelBuffer znajdziesz w dokumentacji dla deweloperów Apple dotyczącej CVPixelBuffer.

CMSampleBuffer

Format CMSampleBuffer przechowuje próbki multimediów o jednolitym typie i jest odpowiedni do uruchamiania transmisji na żywo. Ramki na żywo z kamer iOS są asynchronicznie dostarczane w formacie CMSampleBuffer przez AVCaptureVideoDataOutput.

Swift

// Obtain a CMSampleBuffer.

// Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(sampleBuffer: sampleBuffer)
    

Objective-C

// Obtain a `CMSampleBuffer`.

// Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the
// default orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithSampleBuffer:sampleBuffer error:nil];
    

Więcej informacji o CMSampleBuffer znajdziesz w dokumentacji CMSampleBuffer dla deweloperów Apple.

Uruchamianie zadania

Aby uruchomić funkcję wykrywania twarzy, użyj metody detect() odpowiedniej do przypisanego trybu działania:

  • Zdjęcie: detect(image:)
  • Film: detect(videoFrame:timestampInMilliseconds:)
  • Transmisja na żywo: detectAsync(image:timestampInMilliseconds:)

Wykrywanie twarzy zwraca wykryte twarze na zdjęciu lub w ramce.

Poniżej znajdziesz przykładowy kod pokazujący, jak uruchomić Wykrywacz twarzy w różnych trybach działania:

Swift

Obraz

let result = try faceDetector.detect(image: image)
    

Wideo

let result = try faceDetector.detect(
  videoFrame: image,
  timestampInMilliseconds: timestamp)
    

Transmisja na żywo

try faceDetector.detectAsync(
  image: image,
  timestampInMilliseconds: timestamp)
    

Objective-C

Obraz

MPPFaceDetectorResult *result = [faceDetector detectInImage:image
                                                      error:nil];
    

Wideo

MPPFaceDetectorResult *result = [faceDetector detectInVideoFrame:image
                                         timestampInMilliseconds:timestamp
                                                           error:nil];
    

Transmisja na żywo

BOOL success = [faceDetector detectAsyncInImage:image
                        timestampInMilliseconds:timestamp
                                          error:nil];
    

Przykład kodu wykrywania twarzy bardziej szczegółowo pokazuje implementacje każdego z tych trybów: detect(image:), detect(videoFrame:timestampInMilliseconds:) i detectAsync(image:timestampInMilliseconds:). Przykładowy kod umożliwia użytkownikowi przełączanie się między trybami przetwarzania, które mogą nie być wymagane w Twoim przypadku.

Pamiętaj:

  • W trybie wideo lub transmisji na żywo musisz też podać sygnaturę czasową ramki wejściowej do zadania Wykrywanie twarzy.

  • W trybie obrazu lub filmu zadanie wykrywacza twarzy blokuje bieżący wątek, dopóki nie przetworzy podawanego obrazu lub klatki. Aby uniknąć blokowania bieżącego wątku, przeprowadź przetwarzanie w wątku tła za pomocą frameworków iOS Dispatch lub NSOperation.

  • W trybie transmisji na żywo zadanie wykrywania twarzy zwraca wynik natychmiast i nie blokuje bieżącego wątku. Po przetworzeniu każdej ramki wejściowej wywołuje metodę faceDetector(_:didFinishDetection:timestampInMilliseconds:error:) z wynikiem wykrywania twarzy. Wykrywanie twarzy wywołuje tę metodę asynchronicznie w dedykowanej kolejce szeregowej kolejki. Aby wyświetlić wyniki w interfejsie, prześlij je do kolejki głównej po przetworzeniu. Jeśli funkcja detectAsync zostanie wywołana, gdy zadanie Wykrywanie twarzy jest zajęte przetwarzaniem innego kadru, funkcja Wykrywanie twarzy zignoruje nowy kadr wejściowy.

Obsługa i wyświetlanie wyników

Po przeprowadzeniu wnioskowania zadanie wykrywania twarzy zwraca obiekt FaceDetectorResult, który zawiera ramki ograniczające wykryte twarze oraz wskaźnik ufności dla każdej z nich.

Poniżej znajdziesz przykład danych wyjściowych z tego zadania:

FaceDetectionResult:
  Detections:
    Detection #0:
      BoundingBox:
        origin_x: 126
        origin_y: 100
        width: 463
        height: 463
      Categories:
        Category #0:
          index: 0
          score: 0.9729152917861938
      NormalizedKeypoints:
        NormalizedKeypoint #0:
          x: 0.18298381567001343
          y: 0.2961040139198303
        NormalizedKeypoint #1:
          x: 0.3302789330482483
          y: 0.29289937019348145
        ... (6 keypoints for each face)
    Detection #1:
      BoundingBox:
        origin_x: 616
        origin_y: 193
        width: 430
        height: 430
      Categories:
        Category #0:
          index: 0
          score: 0.9251380562782288
      NormalizedKeypoints:
        NormalizedKeypoint #0:
          x: 0.6151331663131714
          y: 0.3713381886482239
        NormalizedKeypoint #1:
          x: 0.7460576295852661
          y: 0.38825345039367676
        ... (6 keypoints for each face)

Ten obraz przedstawia wizualizację danych wyjściowych zadania:

Obraz bez ramek ograniczających znajdziesz w oryginale.

Przykładowy kod usługi Face Detector pokazuje, jak wyświetlać wyniki. Szczegółowe informacje znajdziesz w przykładowym kodzie.