Przewodnik po wykrywaniu obiektów w iOS

Zadanie detektora obiektów umożliwia wykrywanie obecności i lokalizacji wielu klas obiektów. Na przykład detektor obiektów może wykrywać psy na obrazie. Te instrukcje pokazują, jak korzystać z zadania Wykrywacz obiektów w systemie iOS. 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 sekcji Przegląd.

Przykładowy kod

Przykładowy kod MediaPipe Tasks to podstawowe wdrożenie aplikacji wykrywającej obiekty na iOS. Przykład wykorzystuje kamerę na fizycznym urządzeniu z iOS, aby nieprzerwanie wykrywać obiekty. Może też używać obrazów i filmów z galerii urządzenia do wykrywania obiektów w sposób statyczny.

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 Object 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 do korzystania z rzadkiego sprawdzania, aby mieć tylko pliki przykładowej aplikacji Detector obiektów:

    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/object_detection/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 na iOS.

Kluczowe komponenty

Te pliki zawierają kluczowy kod aplikacji przykładowej wykrywacza obiektów:

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

Konfiguracja

W tej sekcji opisaliśmy najważniejsze kroki konfigurowania środowiska programistycznego i projektów kodu na potrzeby korzystania z Obiektowego modułu rozpoznawania. Ogólne informacje o konfigurowaniu środowiska programistycznego na potrzeby zadań MediaPipe, w tym o wymaganej wersji platformy, znajdziesz w przewodniku konfiguracji dla iOS.

Zależności

Wykrywacz obiektów używa biblioteki MediaPipeTasksVision, którą trzeba 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 podstawowymi komponentami potrzebnymi do działania aplikacji znajdziesz w artykule Korzystanie z CocoaPods.

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

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

Jeśli Twoja aplikacja zawiera cele testu jednostkowego, zapoznaj się z przewodnikiem konfiguracji dla iOS, w którym znajdziesz dodatkowe informacje o konfigurowaniu Podfile.

Model

Zadanie wykrywania obiektów MediaPipe wymaga wytrenowanego modelu, który jest zgodny z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach usługi Object Detector znajdziesz w sekcji „Modele” w omówieniu zadania.

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ład kodu znajdziesz w następnej sekcji.

Tworzenie zadania

Zadanie Wykrywacz obiektów możesz utworzyć, wywołując jeden z jego inicjatorów. Inicjalizator ObjectDetector(options:) ustawia wartości opcji konfiguracji, w tym tryb działania, język wyświetlanych nazw, maksymalną liczbę wyników, próg ufności oraz listę dozwolonych i zabronionych kategorii.

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

Zadanie wykrywania obiektów obsługuje 3 typy danych wejściowych: zdjęcia, pliki wideo i transmisje wideo na żywo. Domyślnie ObjectDetector(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 ObjectDetector(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 objectDetectorLiveStreamDelegate, która umożliwia detekcja obiektów przesyłanie wyników wykrywania do delegata w trybie asynchronicznym.

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 = ObjectDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .image
options.maxResults = 5

let objectDetector = try ObjectDetector(options: options)
    

Wideo

import MediaPipeTasksVision

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

let options = ObjectDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .video
options.maxResults = 5

let objectDetector = try ObjectDetector(options: options)
    

transmisja na żywo

import MediaPipeTasksVision

// Class that conforms to the `ObjectDetectorLiveStreamDelegate` protocol and
// implements the method that the object detector calls once it
// finishes performing detection on each input frame.
class ObjectDetectorResultProcessor: NSObject, ObjectDetectorLiveStreamDelegate {

  func objectDetector(
    _ objectDetector: ObjectDetector,
    didFinishDetection objectDetectionResult: ObjectDetectorResult?,
    timestampInMilliseconds: Int,
    error: Error?) {
    // Process the detection result or errors here.
  }
}

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

let options = ObjectDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .liveStream
options.maxResults = 5

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

let objectDetector = try ObjectDetector(options: options)
    

Objective-C

Obraz

@import MediaPipeTasksVision;

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

MPPObjectDetectorOptions *options = [[MPPObjectDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeImage;
options.maxResults = 5;

MPPObjectDetector *objectDetector =
      [[MPPObjectDetector alloc] initWithOptions:options error:nil];
    

Wideo

@import MediaPipeTasksVision;

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

MPPObjectDetectorOptions *options = [[MPPObjectDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeVideo;
options.maxResults = 5;

MPPObjectDetector *objectDetector =
      [[MPPObjectDetector alloc] initWithOptions:options error:nil];
    

transmisja na żywo

@import MediaPipeTasksVision;

// Class that conforms to the `ObjectDetectorLiveStreamDelegate` protocol and
// implements the method that the object detector calls once it
// finishes performing detection on each input frame.

@interface APPObjectDetectorResultProcessor : NSObject 

@end

@implementation MPPObjectDetectorResultProcessor

-   (void)objectDetector:(MPPObjectDetector *)objectDetector
    didFinishDetectionWithResult:(MPPObjectDetectorResult *)ObjectDetectorResult
         timestampInMilliseconds:(NSInteger)timestampInMilliseconds
                           error:(NSError *)error {

    // Process the detection result or errors here.

}

@end

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

MPPObjectDetectorOptions *options = [[MPPObjectDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeLiveStream;
options.maxResults = 5;

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

MPPObjectDetector *objectDetector =
      [[MPPObjectDetector alloc] initWithOptions:options error:nil];
    

Opcje konfiguracji

To zadanie zawiera 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: tryb używany do przesyłania pojedynczego obrazu.

WIDEO: tryb zdekodowanych klatek filmu.

LIVE_STREAM: tryb transmisji na żywo danych wejściowych, takich jak dane z kamery. W tym trybie należy wywołać funkcję resultListener, aby skonfigurować odbiornik umożliwiający asynchroniczne otrzymywanie wyników.
{RunningMode.image, RunningMode.video, RunningMode.liveStream} RunningMode.image
displayNamesLocales Określa język etykiet, które mają być używane w przypadku wyświetlanych nazw podanych w metadanych modelu zadania (jeśli są dostępne). Wartość domyślna to en w przypadku języka angielskiego. Możesz dodawać zlokalizowane etykiety do metadanych niestandardowego modelu za pomocą interfejsu TensorFlow Lite Metadata Writer API. Kod języka en
maxResults Ustawia opcjonalną maksymalną liczbę wyników wykrywania o najwyższym wyniku, które mają zostać zwrócone. Dowolne liczby dodatnie -1 (zostaną zwrócone wszystkie wyniki)
scoreThreshold Ustawia próg wyniku prognozy, który zastępuje próg podany w metadanych modelu (jeśli takie istnieją). Wyniki poniżej tej wartości są odrzucane. Dowolna liczba Nie ustawiono
categoryAllowlist Ustawia opcjonalną listę dozwolonych nazw kategorii. Jeśli wyniki wykrywania nie są puste, a nazwa kategorii nie znajduje się w tym zbiorze, zostaną odfiltrowane. Powtarzające się lub nieznane nazwy kategorii są ignorowane. Ta opcja jest wzajemnie wykluczająca się z opcją categoryDenylist. Użycie obu spowoduje błąd. dowolne ciągi znaków; Nie ustawiono
categoryDenylist Ustawia opcjonalną listę nazw kategorii, które są niedozwolone. Jeśli nie jest pusty, wyniki wykrywania, których nazwa kategorii znajduje się w tym zbiorze, zostaną odfiltrowane. Powtarzające się lub nieznane nazwy kategorii są ignorowane. Ta opcja wyklucza się z metodą categoryAllowlist i jej użycie powoduje błąd. dowolne ciągi znaków; Nie ustawiono

Konfiguracja transmisji na żywo

Gdy tryb działania jest ustawiony na transmisję na żywo, detektor obiektów wymaga dodatkowej opcji konfiguracji objectDetectorLiveStreamDelegate, która umożliwia mu przesyłanie wyników wykrywania asynchronicznie. Delegat implementuje metodę objectDetector(_objectDetector:didFinishDetection:timestampInMilliseconds:error:), którą Detektor obiektów wywołuje po przetworzeniu wyniku wykrywania dla każdego kadru.

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

Przygotuj dane

Przed przekazaniem do usługi Object Detector musisz przekonwertować wejściowy obraz lub kadr 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 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];
    

Przykład inicjalizuje MPImage z domyślnym ułożeniem UIImage.Orientation.Up. Możesz zainicjować MPImage dowolną z obsługiwanych wartości UIImage.Orientation. Detektor obiektów nie obsługuje orientacji lustrzanej, takiej 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 po przetworzeniu generują obrazy CVPixelBuffer przy użyciu platformy CoreImage iOS, mogą być wysyłane do wykrywacza obiektów w trybie uruchamiania obrazów.

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

  • transmisja na żywo: aplikacje korzystające z kamery iOS do generowania klatek mogą być konwertowane do formatu CVPixelBuffer na potrzeby przetwarzania przed wysłaniem do usługi Detector obiektów 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ć detektor obiektów, użyj metody detect() odpowiedniej do przypisanego trybu działania:

  • Statyczny obraz: detect(image:)
  • Film: detect(videoFrame:timestampInMilliseconds:)
  • livestream: detectAsync(image:)

Poniższe przykłady kodu pokazują podstawowe przykłady uruchamiania modułu Detektor obiektów w tych trybach:

Swift

Obraz

let objectDetector.detect(image:image)
    

Wideo

let objectDetector.detect(videoFrame:image)
    

transmisja na żywo

let objectDetector.detectAsync(image:image)
    

Objective-C

Obraz

MPPObjectDetectorResult *result = [objectDetector detectInImage:image error:nil];
    

Wideo

MPPObjectDetectorResult *result = [objectDetector detectInVideoFrame:image          timestampInMilliseconds:timestamp error:nil];
    

transmisja na żywo

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

Przykład kodu detektora obiektów pokazuje szczegółowo implementację każdego z tych trybów: detect(image:), detect(videoFrame:)detectAsync(image:). 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 przypadku działania w trybie wideo lub w trybie transmisji na żywo musisz też podać w zadaniu Wykrywacz obiektów sygnaturę czasową klatki wejściowej.

  • W trybie obrazu lub filmu zadanie wykrywania obiektów blokuje bieżący wątek, dopóki nie zakończy przetwarzania obrazu wejściowego 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 Wykrywacz obiektów jest zwracane natychmiast i nie blokuje bieżącego wątku. Po przetworzeniu każdego kadru wejściowego wywołuje metodę objectDetector(_objectDetector:didFinishDetection:timestampInMilliseconds:error:) z wynikiem wykrywania. Wykrywacz obiektów asynchronicznie wywołuje tę metodę w dedykowanej kolejce szeregowej wywołań. Aby wyświetlać wyniki w interfejsie, po przetworzeniu wyników wysyłaj je do głównej kolejki. Jeśli funkcja detectAsync zostanie wywołana, gdy zadanie wykrywacza obiektów jest zajęte przetwarzaniem innego kadru, wykrywacz obiektów zignoruje nowy klatka wejściowa.

Obsługa i wyświetlanie wyników

Po przeprowadzeniu wnioskowania zadanie Wykrywanie obiektów zwraca obiekt ObjectDetectorResult, który opisuje obiekty znalezione na obrazie wejściowym.

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

ObjectDetectorResult:
 Detection #0:
  Box: (x: 355, y: 133, w: 190, h: 206)
  Categories:
   index       : 17
   score       : 0.73828
   class name  : dog
 Detection #1:
  Box: (x: 103, y: 15, w: 138, h: 369)
  Categories:
   index       : 17
   score       : 0.73047
   class name  : dog

Ten obraz przedstawia wizualizację danych wyjściowych zadania:

Przykładowy kod usługi Object Detector pokazuje, jak wyświetlać wyniki wykrywania zwrócone przez zadanie. Szczegółowe informacje znajdziesz w przykładowym kodzie.