Przewodnik wykrywania twarzy w iOS

Zadanie Wykrywacz twarzy umożliwia wykrywanie twarzy na zdjęciu lub filmie. Dzięki temu możesz zlokalizować twarze w kadrze. To zadanie wykorzystuje model systemów uczących się (ML), który działa z pojedynczymi obrazami lub ciągłym strumieniem obrazów. Zadanie określa lokalizacje twarzy i następujące punkty twarzy: lewe i prawe oko, opuszkę nosa, usta, tragiczne oko dla lewego i prawego oka.

Przykładowy kod opisany w tych instrukcjach jest dostępny na GitHub. Działanie tego zadania możesz zobaczyć w tej wersji demonstracyjnej. Więcej informacji o możliwościach, modelach i opcjach konfiguracji tego zadania znajdziesz w artykule Omówienie.

Przykładowy kod

Przykładowy kod aplikacji MediaPipe Tasks to prosta implementacja aplikacji do wykrywania twarzy na iOS. W tym przykładzie użyto kamery w fizycznym urządzeniu z Androidem, aby wykrywać twarze 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ć aplikacji jako punktu wyjścia dla własnej aplikacji na iOS lub skorzystać z niej podczas modyfikowania istniejącej aplikacji. Przykładowy kod wykrywacza twarzy jest hostowany na GitHub.

Pobieranie kodu

Z instrukcji poniżej 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 tak, aby używała rozproszonego procesu płatności, aby mieć tylko pliki z przykładowej aplikacji do wykrywania twarzy:

    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 po konfiguracji na iOS.

Kluczowe elementy

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

  • FaceDetectorService.swift: inicjuje detektor, wybiera model i uruchamia wnioskowanie na danych wejściowych.
  • CameraViewController: implementuje interfejs do obsługi trybu wprowadzania danych z kamery na żywo i wizualizuje wyniki wykrywania.
  • MediaLibraryViewController.swift: implementuje interfejs użytkownika w trybie wprowadzania plików ze zdjęciami i filmami oraz wizualizuje wyniki wykrywania.

Konfiguracja

W tej sekcji opisano najważniejsze czynności, jakie należy wykonać, aby skonfigurować środowisko programistyczne i projekty kodu tak, aby używały funkcji wykrywania twarzy. Ogólne informacje o konfigurowaniu środowiska programistycznego na potrzeby zadań MediaPipe, w tym o wymaganiach dotyczących wersji platformy, znajdziesz w przewodniku konfiguracji dla iOS.

Zależności

Wykrywacz twarzy korzysta z biblioteki MediaPipeTasksVision, która musi być zainstalowana za pomocą CocoaPods. Biblioteka jest zgodna z aplikacjami Swift i Objective-C i nie wymaga dodatkowej konfiguracji pod kątem określonego języka.

Instrukcje instalowania CocoaPods w systemie macOS znajdziesz w przewodniku instalacji CocoaPods. Instrukcje tworzenia Podfile z podami niezbędnymi do działania aplikacji znajdziesz w artykule Korzystanie z CocoaPods.

Dodaj pod MediaPipeTasksVision w narzędziu Podfile za pomocą tego kodu:

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

Jeśli aplikacja zawiera cele testu jednostkowego, 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 do wykrywania twarzy znajdziesz w sekcji poświęconej modelom, w sekcji omawiającej zadanie.

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

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

Tworzenie zadania

Aby utworzyć zadanie Wykrywacz twarzy, wywołaj jeden z jego inicjatorów. Inicjator FaceDetector(options:) akceptuje wartości opcji konfiguracji.

Jeśli nie potrzebujesz wykrywacza twarzy zainicjowanego z dostosowanymi opcjami konfiguracji, możesz użyć inicjatora FaceDetector(modelPath:), aby utworzyć wykrywacz twarzy z opcjami domyślnymi. Więcej informacji o opcjach konfiguracji znajdziesz w artykule Omówienie konfiguracji.

Zadanie Wykrywacz twarzy obsługuje 3 typy danych wejściowych: obrazy, pliki wideo i strumienie wideo na żywo. Domyślnie FaceDetector(modelPath:) inicjuje zadanie dotyczące nieruchomych obrazów. Jeśli chcesz zainicjować zadanie na potrzeby przetwarzania plików wideo lub strumieni wideo na żywo, użyj funkcji FaceDetector(options:), aby określić tryb transmisji wideo lub transmisji na żywo. Tryb transmisji na żywo wymaga też dodatkowej opcji konfiguracji faceDetectorLiveStreamDelegate, która umożliwia wykrywanie twarzy asynchronicznie dostarczać wyników wykrywania twarzy przedstawicielowi.

Wybierz kartę odpowiadającą Twojemu trybowi biegowemu, aby zobaczyć, jak utworzyć zadanie i uruchomić wnioskowanie.

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, Wykrywacz twarzy używa śledzenia, aby uniknąć uruchamiania modelu wykrywania przy każdej klatce, co pozwala zmniejszyć opóźnienie.

Opcje konfiguracji

To zadanie ma te opcje konfiguracji w przypadku aplikacji na iOS:

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

IMAGE: tryb wprowadzania pojedynczych obrazów.

WIDEO: tryb dekodowanych klatek filmu.

TRANSMISJA NA ŻYWO: tryb transmisji danych wejściowych na żywo, np. z kamery. W tym trybie należy wywołać metodę resultListener, aby skonfigurować odbiornik, który będzie odbierał wyniki asynchronicznie.
{RunningMode.image, RunningMode.video, RunningMode.liveStream} RunningMode.image
minDetectionConfidence Minimalny stopień pewności, że wykrywanie twarzy zostanie uznane za udane. Float [0,1] 0.5
minSuppressionThreshold Minimalny próg niemaksymalnego ograniczenia wykrywania twarzy, który ma być uznawany za nakładający się. Float [0,1] 0.3

Konfiguracja transmisji na żywo

Gdy tryb biegowy jest ustawiony na transmisję na żywo, wykrywacz twarzy wymaga dodatkowej opcji konfiguracji faceDetectorLiveStreamDelegate, która umożliwia asynchronicznie dostarczanie wyników wykrywania. Osoba, której przekazano dostęp, wdraża metodę faceDetector(_:didFinishDetection:timestampInMilliseconds:error:), która jest wywoływana przez wykrywanie twarzy po przetworzeniu wyników wykrywania twarzy dla każdej klatki.

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

Przygotuj dane

Zanim prześlesz zdjęcie lub klatkę do czytnika twarzy, musisz przekonwertować zdjęcie wejściowe lub klatkę na obiekt MPImage. MPImage obsługuje różne typy formatów obrazów na iOS i może ich używać w każdym trybie działania, aby wnioskować. Więcej informacji na temat MPImage znajdziesz w interfejsie MPImage API

Wybierz format obrazu na iOS zależnie od swojego przypadku użycia i trybu uruchamiania, którego wymaga Twoja aplikacja.MPImage akceptuje formaty obrazów UIImage, CVPixelBuffer i CMSampleBuffer (iOS).

UIImage

Format UIImage dobrze sprawdza się w tych trybach biegania:

  • Obrazy: obrazy z pakietu aplikacji, galerii użytkownika lub systemu plików sformatowane jako obrazy UIImage można przekonwertować na 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];
    

W tym przykładzie inicjuje się MPImage z domyślną orientacją UIImage.Orientation.Up. Możesz zainicjować MPImage przy użyciu dowolnej z obsługiwanych wartości UIImage.Orientation. Czujnik twarzy nie obsługuje odbicia lustrzanego w orientacji, np. .upMirrored, .downMirrored, .leftMirrored i .rightMirrored.

Więcej informacji na temat UIImage znajdziesz w dokumentacji dla programistów Apple dotyczącej UIImage (w języku angielskim).

CVPixelBuffer

Format CVPixelBuffer dobrze sprawdza się w aplikacjach, które generują ramki i wykorzystują do przetwarzania platformę CoreImage w systemie iOS.

Format CVPixelBuffer dobrze sprawdza się w tych trybach biegania:

  • Obrazy: aplikacje generujące obrazy CVPixelBuffer po przetworzeniu przy użyciu platformy CoreImage systemu iOS mogą być wysyłane do funkcji wykrywania twarzy w trybie uruchamiania obrazów.

  • Filmy: klatki wideo można przekonwertować na format CVPixelBuffer w celu przetworzenia, a następnie wysłać do wykrywacza twarzy w trybie wideo.

  • transmisja na żywo: aplikacje korzystające z kamery w systemie iOS do generowania klatek można skonwertować do formatu CVPixelBuffer w celu przetworzenia, zanim zostaną wysłane do wykrywacza 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 na temat CVPixelBuffer znajdziesz w dokumentacji dla programistów Apple CVPixelBuffer.

CMSampleBuffer

Format CMSampleBuffer przechowuje próbki multimediów jednolitego typu i dobrze sprawdza się w trybie transmisji na żywo. Klatki na żywo z kamer na iOS są przesyłane asynchronicznie w formacie CMSampleBuffer przez system iOS 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 na temat CMSampleBuffer znajdziesz w dokumentacji dla programistów Apple CMSampleBuffer.

Uruchamianie zadania

Aby uruchomić wykrywanie twarzy, użyj metody detect() odpowiedniej dla przypisanego trybu biegowego:

  • Nieruchomy obraz: detect(image:)
  • Film: detect(videoFrame:timestampInMilliseconds:)
  • Transmisja na żywo: detectAsync(image:timestampInMilliseconds:)

Wykrywacz twarzy zwraca wykryte twarze na zdjęciu lub ramce.

Na tych przykładach kodu widać proste przykłady uruchamiania czytnika 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 Wykrywacza twarzy szczegółowo przedstawia implementacje każdego z tych trybów: detect(image:), detect(videoFrame:timestampInMilliseconds:) i detectAsync(image:timestampInMilliseconds:). Przykładowy kod pozwala użytkownikowi przełączać się między trybami przetwarzania, które mogą nie być wymagane w Twoim przypadku.

Uwaga:

  • W trybie wideo lub transmisji na żywo musisz też podać sygnaturę czasową klatki wejściowej w zadaniu Wykrywacz twarzy.

  • W trybie obrazu lub filmu zadanie Wykrywacz twarzy blokuje bieżący wątek, dopóki nie zakończy przetwarzania obrazu wejściowego lub klatki. Aby uniknąć zablokowania bieżącego wątku, wykonaj przetwarzanie w wątku w tle za pomocą platform Dispatch lub NSOperation w systemie iOS.

  • W trybie transmisji na żywo zadanie Wykrywanie twarzy wraca natychmiast i nie blokuje bieżącego wątku. Po przetworzeniu każdej klatki wejściowej wywołuje metodę faceDetector(_:didFinishDetection:timestampInMilliseconds:error:) z wynikiem wykrywania twarzy. Wykrywanie twarzy asynchronicznie wywołuje tę metodę w dedykowanej szeregowej kolejce wysyłania. W przypadku wyświetlania wyników w interfejsie po ich przetworzeniu wyślij do głównej kolejki. Jeśli funkcja detectAsync zostanie wywołana, gdy zadanie Wykrywanie twarzy jest zajęte przetwarzaniem innej klatki, Wykrywacz twarzy ignoruje nową klatkę wejściową.

Obsługa i wyświetlanie wyników

Po uruchomieniu wnioskowania zadanie Wykrywacz twarzy zwraca obiekt FaceDetectorResult zawierający ramki ograniczające wykryte twarze oraz poziom ufności każdej wykrytej twarzy.

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)

Poniższy obraz przedstawia wizualizację wyników zadania:

W przypadku obrazu bez ramek ograniczających wyświetl oryginalny obraz.

Przykładowy kod Wykrywacza twarzy pokazuje, jak wyświetlić wyniki. Szczegóły znajdziesz w przykładowym kodzie.