Przewodnik po wykrywaniu obiektów w iOS

Zadanie wykrywania obiektów pozwala wykrywać obecność i lokalizację wielu klas obiektów. Detektor obiektów może na przykład zlokalizować psy na zdjęciu. W tych instrukcjach pokazujemy, jak korzystać z zadania Wykrywacz obiektów w iOS. 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 sekcji Omówienie.

Przykładowy kod

Przykładowy kod MediaPipe Tasks to podstawowa implementacja aplikacji do wykrywania obiektów na iOS. W tym przykładzie użyto kamery w fizycznym urządzeniu z iOS do ciągłego wykrywania obiektów, a także do statycznego wykrywania obiektów za pomocą obrazów i filmów 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 detektora obiektów 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 dla przykładowej aplikacji do wykrywania 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 po konfiguracji na iOS.

Kluczowe elementy

Poniższe pliki zawierają najważniejszy kod przykładowej aplikacji do wykrywania obiektów:

Konfiguracja

W tej sekcji opisujemy najważniejsze czynności, jakie należy wykonać, aby skonfigurować środowisko programistyczne i projekty kodu, w których będzie używany detektor obiektów. 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

Detektor obiektów korzysta z biblioteki MediaPipeTasksVision, którą należy zainstalować 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 'MyObjectDetectorApp' 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 wykrywania obiektów MediaPipe wymaga wytrenowanego modelu, który jest zgodny z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach służących do wykrywania obiektów znajdziesz w sekcji poświęconej modelom zadania.

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

Możesz utworzyć zadanie Wykrywacz obiektów, wywołując jeden z jego inicjatorów. Inicjator ObjectDetector(options:) ustawia wartości opcji konfiguracji, w tym trybu działającego, ustawień regionalnych nazw wyświetlanych, maksymalnej liczby wyników, progu ufności, listy dozwolonych kategorii i listy odrzuconych.

Jeśli nie potrzebujesz detektora obiektów zainicjowanego z niestandardowymi opcjami konfiguracji, możesz użyć inicjatora ObjectDetector(modelPath:), aby utworzyć detektor 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: obrazy, pliki wideo i strumienie wideo na żywo. Domyślnie ObjectDetector(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 ObjectDetector(options:), aby określić tryb transmisji wideo lub transmisji na żywo. Tryb transmisji na żywo wymaga też dodatkowej opcji konfiguracji objectDetectorLiveStreamDelegate, która umożliwia detektorowi obiektów asynchronicznie dostarczanie wyników wykrywania do delegata.

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 = 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 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
displayNamesLocales Ustawia język etykiet, które mają być używane w przypadku nazw wyświetlanych w metadanych modelu zadania (jeśli są dostępne). Wartość domyślna w języku angielskim to en. Za pomocą TensorFlow Lite MetadataWriter API możesz dodawać zlokalizowane etykiety do metadanych modelu niestandardowego. Kod języka en
maxResults Określa opcjonalną maksymalną liczbę wyników wykrywania o najwyższych wynikach do zwrócenia. 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 istnieją). Wyniki poniżej tej wartości zostały odrzucone. Dowolna liczba zmiennoprzecinkowa Nie ustawiono
categoryAllowlist Ustawia opcjonalną listę dozwolonych nazw kategorii. Jeśli pole nie jest puste, wyniki wykrywania, których nazwy kategorii nie ma w tym zbiorze, zostaną odfiltrowane. Zduplikowane i nieznane nazwy kategorii są ignorowane. Ta opcja wzajemnie się wyklucza, categoryDenylist i ich użycie kończy się błędem. Dowolne ciągi Nie ustawiono
categoryDenylist Ustawia opcjonalną listę niedozwolonych nazw kategorii. Jeśli pole nie jest puste, wyniki wykrywania, których nazwa kategorii znajduje się w tym zbiorze, zostaną odfiltrowane. Zduplikowane i nieznane nazwy kategorii są ignorowane. Ta opcja wzajemnie się wyklucza z categoryAllowlist, a korzystanie z obu daje błąd. Dowolne ciągi Nie ustawiono

Konfiguracja transmisji na żywo

Gdy tryb działania jest ustawiony na transmisję na żywo, detektor obiektów wymaga dodatkowej opcji konfiguracji objectDetectorLiveStreamDelegate, co umożliwia asynchroniczne dostarczanie wyników wykrywania. Delegat wdraża metodę objectDetector(_objectDetector:didFinishDetection:timestampInMilliseconds:error:), która jest wywoływana przez detektor obiektów po przetworzeniu wyniku wykrywania dla każdej ramki.

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 na tę właściwość, musi implementować metodę objectDetector(_:didFinishDetection:timestampInMilliseconds:error:). Nie dotyczy Nie ustawiono

Przygotuj dane

Zanim prześlesz obraz lub ramkę do detektora obiektów, musisz przekonwertować go 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. Detektor obiektów nie obsługuje odbicia lustrzanego orientacji, takich jak .upMirrored, .downMirrored, .leftMirrored, .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, które po przetworzeniu niektórych obrazów przy użyciu platformy CoreImage systemu iOS generują obrazy CVPixelBuffer, mogą być wysyłane do detektora obiektów w trybie działania obrazów.

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

  • transmisja na żywo: aplikacje korzystające z kamery w iOS do generowania klatek można skonwertować do formatu CVPixelBuffer w celu przetworzenia, zanim zostaną wysłane do wzorca do wykrywania 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 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 obiektów, użyj metody detect() odpowiedniej dla przypisanego trybu uruchamiania:

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

Poniższe przykłady kodu pokazują podstawowe przykłady uruchamiania wykrywania obiektów w różnych trybach działania:

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];
    

W przykładowym kodzie wykrywania obiektów znajdziesz bardziej szczegółowe implementacje każdego z tych trybów: detect(image:), detect(videoFrame:) i detectAsync(image:). Przykładowy kod pozwala użytkownikowi przełączać się między trybami przetwarzania, które mogą nie być wymagane w Twoim przypadku użycia.

Uwaga:

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

  • W trybie obrazu lub filmu zadanie wykrywania obiektów blokuje bieżący wątek do momentu zakończenia przetwarzania obrazu lub klatki wejściowej. 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 wykrywania obiektów jest natychmiast zwracane i nie blokuje bieżącego wątku. Po przetworzeniu każdej ramki wejściowej wywołuje metodę objectDetector(_objectDetector:didFinishDetection:timestampInMilliseconds:error:) z wynikiem wykrywania. Detektor obiektów wywołuje tę metodę asynchronicznie w dedykowanej szeregowej kolejce wysyłki. W przypadku wyświetlania wyników w interfejsie po ich przetworzeniu wysyłaj do głównej kolejki. Jeśli funkcja detectAsync zostanie wywołana, gdy zadanie wykrywania obiektów jest zajęte przetwarzaniem innej ramki, detektor obiektów ignoruje nową ramkę wejściową.

Obsługa i wyświetlanie wyników

Po uruchomieniu wnioskowania zadanie wykrywania 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

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

Przykładowy kod detektora obiektów pokazuje, jak wyświetlić wyniki wykrywania zwrócone z zadania. Szczegółowe informacje znajdziesz w przykładowym kodzie.