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. Z tych instrukcji dowiesz się, jak korzystać z zadania Wykrywanie obiektów na iOS. Przykładowy kod opisany w tych instrukcjach jest dostępny na GitHub.

Aby zobaczyć, jak to zadanie działa w praktyce, obejrzyj prezentację internetową. 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 ObjectDetector na iOS. Przykład wykorzystuje aparat 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 tworzenia 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 wprowadzania danych z kamery na żywo i wizualizuje wyniki wykrywania.
  • MediaLibraryViewController.swift implementuje interfejs użytkownika dla trybu wprowadzania statycznych obrazów i plików wideo oraz wizualizuje wyniki wykrywania.

Konfiguracja

W tej sekcji opisaliśmy najważniejsze kroki konfiguracji środowiska programistycznego i projektów kodu na potrzeby korzystania z Obiektowego modułu rozpoznawania. 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

Detektor obiektów 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 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 testów jednostkowych, dodatkowe informacje o konfigurowaniu Podfile znajdziesz w przewodniku konfiguracji na iOS.

Model

Zadanie Wykrywanie 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

Zadaniem wykrywania obiektów możesz utworzyć, wywołując jedną z jego funkcji inicjującej. Inicjalizator ObjectDetector(options:) ustawia wartości opcji konfiguracji, w tym tryb działania, język wyświetlania 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

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:

OBRAZ: tryb dla pojedynczych obrazów wejściowych.

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
displayNamesLocales Określa język etykiet, których należy używać do 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 modelu niestandardowego, korzystając z 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 (zwracane są 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 zmiennych typu float 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 jest wzajemnie wykluczająca się z opcją categoryAllowlist, a użycie obu spowoduje 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 go do usługi Object Detector 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 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 do 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ą interfejsu CoreImage w iOS, mogą wysyłać je do usługi Object 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 Object Detector w trybie wideo.

  • transmisja na żywo: aplikacje korzystające z aparatu 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 trybie wideo lub transmisji na żywo musisz też podać sygnaturę czasową ramki wejściowej do zadania Detector obiektów.

  • 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 wykrywania obiektów zwraca wynik 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. Wzorzec do wykrywania obiektów wywołuje tę metodę asynchronicznie na dedykowanej kolejce wysyłania sekwencyjnego. Aby wyświetlić wyniki w interfejsie, prześlij je do kolejki głównej po przetworzeniu. 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 wejściowym obrazie.

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

Na ilustracji poniżej widać wizualizację wyniku zadania:

2 psy wyróżnione za pomocą ramek ograniczających

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.