Przewodnik po klasyfikacji obrazów w systemie iOS

Zadanie Klasyfikator obrazów umożliwia klasyfikację obrazów. Możesz użyć tego zadania, aby określić, co obraz reprezentuje w zbiorze kategorii zdefiniowanych w czasie trenowania. Te instrukcje pokazują, jak używać klasyfikatora obrazów w aplikacjach na iOS. Przykładowy kod opisany w tych instrukcjach jest dostępny na GitHub.

Aby zobaczyć, jak działa to zadanie, obejrzyj tę prezentację internetową. Więcej informacji o możliwościach, modelach i opcjach konfiguracji dostępnych w tym zadaniu znajdziesz w omówieniu.

Przykładowy kod

Przykładowy kod MediaPipe Tasks to podstawowa implementacja aplikacji Image Classifier na iOS. Ten przykład korzysta z aparatu w fizycznym urządzeniu z iOS, aby stale klasyfikować obiekty. Może też używać obrazów i filmów z galerii urządzenia do statycznego klasyfikowania obiektów.

Możesz użyć tej aplikacji jako punktu wyjścia dla własnej aplikacji na iOS lub odwołać się do niej podczas modyfikowania istniejącej aplikacji. Przykładowy kod klasyfikatora obrazów jest przechowywany na stronie GitHub.

Pobieranie kodu

Poniższe instrukcje pokazują, 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 możesz skonfigurować w instancji git rozproszony proces płatności, dzięki czemu będziesz mieć tylko pliki przykładowej aplikacji Image Classifier:

    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_classification/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 elementy

Poniższe pliki zawierają kluczowy kod przykładowej aplikacji Klasyfikator obrazów:

Konfiguracja

W tej sekcji znajdziesz najważniejsze czynności, które musisz wykonać, aby skonfigurować środowisko programistyczne i projekty kodu pod kątem użycia klasyfikatora obrazów. 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

Image Classifier używa biblioteki MediaPipeTasksVision, którą trzeba zainstalować za pomocą CocoaPods. Biblioteka jest zgodna z aplikacjami Swift i Objective-C oraz nie wymaga dodatkowej konfiguracji języka.

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

Dodaj pod MediaPipeTasksVision w tabeli Podfile przy użyciu tego kodu:

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

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

Model

Zadanie MediaPipe Image Classifier wymaga wytrenowanego modelu, który jest zgodny z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach na potrzeby klasyfikatora obrazów 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, by określić ścieżkę do modelu w pakiecie aplikacji. Przykładowy kod znajdziesz w następnej sekcji.

Tworzenie zadania

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

Jeśli nie potrzebujesz klasyfikatora obrazów zainicjowanego z niestandardowymi opcjami konfiguracji, możesz użyć inicjatora ImageClassifier(modelPath:), aby utworzyć klasyfikator obrazów z opcjami domyślnymi. Więcej informacji o opcjach konfiguracji znajdziesz w artykule Omówienie konfiguracji.

Zadanie Klasyfikator obrazów obsługuje 3 typy danych wejściowych: obrazy, pliki wideo i strumieni wideo na żywo. Domyślnie ImageClassifier(modelPath:) inicjuje zadanie dotyczące obrazów nieruchomych. Jeśli chcesz zainicjować zadanie przetwarzania plików wideo lub transmisji wideo na żywo, użyj właściwości ImageClassifier(options:), aby określić tryb działania wideo lub transmisji na żywo. Tryb transmisji na żywo wymaga też dodatkowej opcji konfiguracji imageClassifierLiveStreamDelegate, która umożliwia klasyfikatorowi obrazów asynchroniczne dostarczanie wyników klasyfikacji obrazów do przekazanego dostępu.

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

Swift

Obraz

import MediaPipeTasksVision

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

let options = ImageClassifierOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .image
options.maxResults = 5

let imageClassifier = try ImageClassifier(options: options)
    

Wideo

import MediaPipeTasksVision

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

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

let imageClassifier = try ImageClassifier(options: options)
    

Transmisja na żywo

import MediaPipeTasksVision

// Class that conforms to the `ImageClassifierLiveStreamDelegate` protocol and
// implements the method that the image classifier calls once it
// finishes performing classification on each input frame.
class ImageClassifierResultProcessor: NSObject, ImageClassifierLiveStreamDelegate {

   func imageClassifier(
    _ imageClassifier: ImageClassifier,
    didFinishClassification result: ImageClassifierResult?,
    timestampInMilliseconds: Int,
    error: Error?) {

    // Process the image classifier result or errors here.

  }
}

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

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

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

let imageClassifier = try ImageClassifier(options: options)
    

Objective-C

Obraz

@import MediaPipeTasksVision;

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

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

MPPImageClassifier *imageClassifier =
      [[MPPImageClassifier alloc] initWithOptions:options error:nil];
    

Wideo

@import MediaPipeTasksVision;

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

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

MPPImageClassifier *imageClassifier =
      [[MPPImageClassifier alloc] initWithOptions:options error:nil];
    

Transmisja na żywo

@import MediaPipeTasksVision;

// Class that conforms to the `MPPImageClassifierLiveStreamDelegate` protocol
// and implements the method that the image classifier calls once it finishes
// performing classification on each input frame.

@interface APPImageClassifierResultProcessor : NSObject 

@end

@implementation APPImageClassifierResultProcessor

-   (void)imageClassifier:(MPPImageClassifier *)imageClassifier
    didFinishClassificationWithResult:(MPPImageClassifierResult *)imageClassifierResult
              timestampInMilliseconds:(NSInteger)timestampInMilliseconds
                                error:(NSError *)error {

    // Process the image classifier result or errors here.

}

@end

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

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

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

MPPImageClassifier *imageClassifier =
      [[MPPImageClassifier 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: ten tryb używany do przesyłania pojedynczego obrazu.

WIDEO: tryb zdekodowanych klatek filmu.

TRANSMISJA NA ŻYWO: tryb transmisji danych wejściowych, np. z kamery. W tym trybie musisz wywołać funkcję resultListener, aby skonfigurować detektor do asynchronicznego otrzymywania wyników.
{RunningMode.image, RunningMode.video, RunningMode.liveStream} RunningMode.image
displayNamesLocale 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 dodać zlokalizowane etykiety do metadanych modelu niestandardowego za pomocą interfejsu TensorFlow Lite Metadata Writer API. Kod języka en
maxResults Określa opcjonalną maksymalną liczbę zwracanych wyników klasyfikacji z najlepszymi wynikami. Jeśli wartość jest mniejsza niż 0, zwracane są wszystkie dostępne wyniki. Dowolne liczby dodatnie -1
scoreThreshold Ustawia próg wyniku prognozy, który zastępuje próg podany w metadanych modelu (jeśli występuje). 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 klasyfikacji, których nazwy kategorii nie znajdują się w tym zbiorze, zostaną odfiltrowane. Zduplikowane lub nieznane nazwy kategorii są ignorowane. Ta opcja wzajemnie się wyklucza z metodą categoryDenylist i jej użycie powoduje błąd. Dowolne ciągi Nie ustawiono
categoryDenylist Ustawia opcjonalną listę nazw kategorii, które nie są dozwolone. Jeśli pole nie jest puste, wyniki klasyfikacji, których nazwa kategorii znajduje się w tym zbiorze, zostaną odfiltrowane. Zduplikowane lub nieznane nazwy kategorii są ignorowane. Ta opcja wyklucza się z metodą categoryAllowlist i jej użycie powoduje błąd. Dowolne ciągi Nie ustawiono
resultListener Konfiguruje detektor wyników tak, aby asynchronicznie otrzymywał wyniki klasyfikacji, gdy klasyfikator obrazów jest w trybie transmisji na żywo. Tej opcji można używać tylko wtedy, gdy tryb działania jest ustawiony na LIVE_STREAM Nie dotyczy Nie ustawiono

Konfiguracja transmisji na żywo

Gdy tryb działania jest ustawiony na transmisję na żywo, klasyfikator obrazów wymaga dodatkowej opcji konfiguracji imageClassifierLiveStreamDelegate, która umożliwia klasyfikatorowi asynchroniczne dostarczanie wyników klasyfikacji. Delegat implementuje metodę imageClassifier(_:didFinishClassification:timestampInMilliseconds:error:), która jest wywoływana przez klasyfikator obrazów po przetworzeniu wyników klasyfikacji dla każdej ramki.

Nazwa opcji Opis Zakres wartości Wartość domyślna
imageClassifierLiveStreamDelegate Włącza klasyfikator obrazów, aby asynchronicznie otrzymywać wyniki klasyfikacji w trybie transmisji na żywo. Klasa, której instancja jest ustawiona na tę właściwość, musi implementować metodę imageClassifier(_:didFinishClassification:timestampInMilliseconds:error:). Nie dotyczy Nie ustawiono

Przygotuj dane

Musisz przekonwertować obraz lub ramkę wejściową na obiekt MPImage, zanim przekażesz go do klasyfikatora obrazów. MPImage obsługuje różne typy formatów obrazów iOS i może używać ich w dowolnym trybie działania w celu wnioskowania. Więcej informacji o MPImage znajdziesz tutaj: MPImage API.

Wybierz format obrazu na iOS na podstawie przypadku użycia i trybu uruchamiania wymaganej przez aplikację.MPImage akceptuje formaty obrazów na iOS: UIImage, CVPixelBuffer i CMSampleBuffer.

UIImage

Format UIImage sprawdza się w tych trybach biegu:

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

  • Filmy: za pomocą narzędzia AVAssetImageGenerator wyodrębnij klatki wideo do formatu CGImage, a potem przekonwertuj je na UIImage obrazy.

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

Ten przykład inicjuje obiekt MPImage z domyślną orientacją UIImage.Orientation.Up. Możesz zainicjować MPImage przy użyciu dowolnej z obsługiwanych wartości UIImage.Orientation. Klasyfikator obrazów nie obsługuje lustrzanych orientacji, takich jak .upMirrored, .downMirrored, .leftMirrored, .rightMirrored.

Więcej informacji o funkcji UIImage znajdziesz w dokumentacji dla deweloperów Apple dotyczącej interfejsu UIImage.

CVPixelBuffer

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

Format CVPixelBuffer sprawdza się w tych trybach biegu:

  • Obrazy: aplikacje, które po przetworzeniu przy użyciu platformy CoreImage systemu iOS generują obrazy CVPixelBuffer, mogą być wysyłane do klasyfikatora obrazów w trybie uruchamiania obrazów.

  • Filmy: klatki wideo można przekonwertować na format CVPixelBuffer podczas przetwarzania, a potem wysłać do klasyfikatora obrazów w trybie wideo.

  • transmisja na żywo: aplikacje używające aparatu w iOS do generowania klatek mogą być konwertowane do formatu CVPixelBuffer na potrzeby przetwarzania, zanim zostaną przesłane do klasyfikatora obrazó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 funkcji CVPixelBuffer znajdziesz w dokumentacji dla deweloperów Apple (CVPixelBuffer).

CMSampleBuffer

Format CMSampleBuffer przechowuje próbki multimediów w ramach jednolitego typu multimediów i sprawdza się w trybie biegu transmisji na żywo. Klatki na żywo z kamer z iOS są asynchronicznie dostarczane w formacie CMSampleBuffer przez AVCaptureVideoDataOutput w systemie iOS.

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 funkcji CMSampleBuffer znajdziesz w dokumentacji dla programistów Apple CMSampleBuffer.

Uruchamianie zadania

Aby uruchomić klasyfikator obrazów, użyj metody classify() specyficznej dla przypisanego trybu uruchamiania:

  • Zdjęcie: classify(image:)
  • Film: classify(videoFrame:timestampInMilliseconds:)
  • transmisja na żywo: classifyAsync(image:timestampInMilliseconds:)

Klasyfikator obrazów zwraca możliwe kategorie obiektu w obrazie lub ramce wejściowej.

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

Swift

Obraz

let result = try imageClassifier.classify(image: image)
    

Wideo

let result = try imageClassifier.classify(
  videoFrame: image,
  timestampInMilliseconds: timestamp)
    

Transmisja na żywo

try imageClassifier.classifyAsync(
  image: image,
  timestampInMilliseconds: timestamp)
    

Objective-C

Obraz

MPPImageClassifierResult *result = [imageClassifier classifyImage:image
                                                            error:nil];
    

Wideo

MPPImageClassifierResult *result = [imageClassifier classifyVideoFrame:image
                                               timestampInMilliseconds:timestamp
                                                                 error:nil];
    

Transmisja na żywo

BOOL success = [imageClassifier classifyAsyncImage:image
                          timestampInMilliseconds:timestamp
                                            error:nil];
    

Przykładowy kod klasyfikatora obrazów bardziej szczegółowo pokazuje implementacje każdego z tych trybów: classify(image:), classify(videoFrame:timestampInMilliseconds:) i classifyAsync(image:timestampInMilliseconds:). Przykładowy kod pozwala użytkownikowi przełączać się między trybami przetwarzania, co może nie być wymagane w Twoim przypadku użycia.

Uwaga:

  • Gdy pracujesz w trybie wideo lub w trybie transmisji na żywo, musisz też podać w zadaniu Klasyfikator obrazów sygnaturę czasową klatki wejściowej.

  • W trybie obrazu lub wideo zadanie Klasyfikator obrazów blokuje bieżący wątek, dopóki nie zakończy przetwarzania obrazu lub ramki wejściowej. Aby uniknąć zablokowania bieżącego wątku, wykonaj przetwarzanie w wątku w tle za pomocą struktur systemu iOS Dispatch lub NSOperation.

  • W trybie transmisji na żywo zadanie Klasyfikator obrazów zwraca natychmiast i nie blokuje bieżącego wątku. Wywołuje metodę imageClassifier(_:didFinishClassification:timestampInMilliseconds:error:) z wynikiem klasyfikacji po przetworzeniu każdej ramki wejściowej. Klasyfikator obrazów wywołuje tę metodę asynchronicznie z dedykowanej kolejki szeregowej wysyłania. Aby wyświetlać wyniki w interfejsie, po ich przetworzeniu prześlij wyniki do głównej kolejki. Jeśli funkcja classifyAsync jest wywoływana, gdy zadanie klasyfikatora obrazów jest zajętych przetwarzaniem innej klatki, klasyfikator obrazów zignoruje nową ramkę wejściową.

Obsługa i wyświetlanie wyników

Po uruchomieniu wnioskowania zadanie Klasyfikator obrazów zwraca obiekt ImageClassifierResult zawierający listę możliwych kategorii obiektów w obrazie lub ramce wejściowej.

Poniżej znajdziesz przykładowe dane wyjściowe tego zadania:

ImageClassifierResult:
 Classifications #0 (single classification head):
  head index: 0
  category #0:
   category name: "/m/01bwb9"
   display name: "Passer domesticus"
   score: 0.91406
   index: 671
  category #1:
   category name: "/m/01bwbt"
   display name: "Passer montanus"
   score: 0.00391
   index: 670

Ten wynik uzyskano po uruchomieniu Bird Classifier na:

Przykładowy kod klasyfikatora obrazów pokazuje, jak wyświetlić wyniki klasyfikacji zwrócone przez zadanie. Szczegóły znajdziesz w przykładowym kodzie.