Zadanie Segmentator obrazu umożliwia dzielenie obrazów na regiony na podstawie zdefiniowanych wstępnie kategorii i stosowanie efektów wizualnych, takich jak rozmycie tła. Te instrukcje pokazują, jak używać narzędzia do dzielenia obrazu w przypadku aplikacji 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ę demonstracyjną w internecie. Więcej informacji o możliwościach, modelach i opcjach konfiguracji związanych z tym zadaniem znajdziesz w sekcji Omówienie.
Przykładowy kod
Przykładowy kod MediaPipe Tasks zawiera prostą implementację aplikacji Image Segmenter na iOS.
Przykład implementuje segmentator obrazu, który generuje maski kategorii. Używa ona kamery na fizycznym urządzeniu z iOS, aby segmentować obrazy na podstawie obrazu na żywo z kamery lub zdjęć i filmów z galerii urządzenia.
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 Image Segmenter 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:
Sklonuj repozytorium Git za pomocą tego polecenia:
git clone https://github.com/google-ai-edge/mediapipe-samples/Opcjonalnie skonfiguruj instancję git do użycia skromnego sprawdzania, aby mieć tylko pliki przykładowej aplikacji Image Segmenter:
cd mediapipe-samples git sparse-checkout init --cone git sparse-checkout set examples/image_segmentation/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 Image Segmenter:
- ImageSegmenterService.swift: Inicjowanie narzędzia Image Segmenter, obsługa wyboru modelu i wykonywanie wnioskowania na danych wejściowych.
- CameraViewController.swift: implementuje interfejs użytkownika w trybie wejścia z obrazu na żywo z kamery i wizualizuje wyniki.
- MediaLibraryViewController.swift: implementuje interfejs użytkownika dla trybu wprowadzania statycznych obrazów i plików wideo oraz wizualizuje wyniki.
Konfiguracja
Ta sekcja zawiera opis kluczowych kroków konfiguracji środowiska programistycznego i projektów kodu, które umożliwiają korzystanie z narzędzia Image Segmenter. 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
Narzędzie do podziału obrazu 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 'MyImageSegmenterApp' 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 MediaPipe Image Segmenter wymaga wytrenowanego modelu, który jest zgodny z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach narzędzia Image Segmenter 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 segmentacji obrazu możesz utworzyć, wywołując jedną z jego funkcji inicjujących. Inicjalizator ImageSegmenter(options:) może przyjmować wartości opcji konfiguracji.
Jeśli nie potrzebujesz narzędzia ImageSegmenter zainicjowanego za pomocą niestandardowych opcji konfiguracji, możesz użyć funkcji inicjalizującej ImageSegmenter(modelPath:), aby utworzyć narzędzie ImageSegmenter z opcjami domyślnymi. Więcej informacji o opcjach konfiguracji znajdziesz w artykule Omówienie konfiguracji.
Zadanie segmentacji obrazu obsługuje 3 typy danych wejściowych: obrazy, pliki wideo i strumienie wideo na żywo. Domyślnie ImageSegmenter(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 ImageSegmenter(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 imageSegmenterLiveStreamDelegate, która umożliwia narzędziu Image Segmenter asynchroniczne przesyłanie wyników podziału obrazu do delegata.
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 = ImageSegmenterOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .image options.shouldOutputCategoryMask = true options.shouldOutputConfidenceMasks = false let imageSegmenter = try ImageSegmenter(options: options)
Wideo
import MediaPipeTasksVision let modelPath = Bundle.main.path(forResource: "model", ofType: "tflite") let options = ImageSegmenterOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .video options.shouldOutputCategoryMask = true options.shouldOutputConfidenceMasks = false let imageSegmenter = try ImageSegmenter(options: options)
Transmisja na żywo
import MediaPipeTasksVision // Class that conforms to the `imageSegmenterLiveStreamDelegate` protocol and // implements the method that the image segmenter calls once it finishes // performing segmentation of each input frame. class ImageSegmenterResultProcessor: NSObject, ImageSegmenterLiveStreamDelegate { func imageSegmenter( _ imageSegmenter: ImageSegmenter, didFinishSegmentation result: ImageSegmenterResult?, timestampInMilliseconds: Int, error: Error?) { // Process the image segmentation result or errors here. } } let modelPath = Bundle.main.path(forResource: "model", ofType: "tflite") let options = ImageSegmenterOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .liveStream options.shouldOutputCategoryMask = true options.shouldOutputConfidenceMasks = false // Set `imageSegmenterLiveStreamDelegate` to the object of the class that // confirms to the `ImageSegmenterLiveStreamDelegate` protocol. let processor = ImageSegmenterResultProcessor() options.imageSegmenterLiveStreamDelegate = processor let imageSegmenter = try ImageSegmenter(options: options)
Objective-C
Obraz
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model" ofType:@"tflite"]; MPPImageSegmenterOptions *options = [[MPPImageSegmenterOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeImage; options.shouldOutputCategoryMask = YES; options.shouldOutputConfidenceMasks = NO; MPPImageSegmenter *imageSegmenter = [[MPPImageSegmenter alloc] initWithOptions:options error:nil];
Wideo
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model" ofType:@"tflite"]; MPPImageSegmenterOptions *options = [[MPPImageSegmenterOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeVideo; options.shouldOutputCategoryMask = YES; options.shouldOutputConfidenceMasks = NO; MPPImageSegmenter *imageSegmenter = [[MPPImageSegmenter alloc] initWithOptions:options error:nil];
Transmisja na żywo
@import MediaPipeTasksVision; // Class that conforms to the `MPPImageSegmenterLiveStreamDelegate` protocol // and implements the method that the image segmenter calls once it finishes // performing segmentation of each input frame. @interface APPImageSegmenterResultProcessor : NSObject@end @implementation APPImageSegmenterResultProcessor - (void)imageSegmenter:(MPPImageSegmenter *)imageSegmenter didFinishSegmentationWithResult:(MPPImageSegmenterResult *)imageSegmenterResult timestampInMilliseconds:(NSInteger)timestampInMilliseconds error:(NSError *)error { // Process the image segmentation result or errors here. } @end NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model" ofType:@"tflite"]; MPPImageSegmenterOptions *options = [[MPPImageSegmenterOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeLiveStream; options.shouldOutputCategoryMask = YES; options.shouldOutputConfidenceMasks = NO; // Set `imageSegmenterLiveStreamDelegate` to the object of the class that // confirms to the `MPPImageSegmenterLiveStreamDelegate` protocol. APPImageSegmenterResultProcessor *processor = [APPImageSegmenterResultProcessor new]; options.imageSegmenterLiveStreamDelegate = processor; MPPImageSegmenter *imageSegmenter = [[MPPImageSegmenter alloc] initWithOptions:options error:nil];
Implementacja przykładowego kodu segmentacji obrazu umożliwia użytkownikowi przełączanie się między trybami przetwarzania. Takie podejście skomplikuje kod tworzący zadanie i może nie być odpowiednie w Twoim przypadku.
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 parametr ImageSegmenterLiveStreamDelegate musi być ustawiony na instancję klasy, która implementuje interfejs ImageSegmenterLiveStreamDelegate, aby asynchronicznie otrzymywać wyniki podziału na segmenty.
|
{RunningMode.image, RunningMode.video, RunningMode.liveStream} |
RunningMode.image |
shouldOutputCategoryMask |
Jeśli ustawisz tę opcję na True, dane wyjściowe będą zawierać maskę segmentacji w postaci obrazu uint8, w którym każda wartość piksela wskazuje zwycięską kategorię. |
{True, False} |
False |
shouldOutputConfidenceMasks |
Jeśli ustawisz tę opcję na True, dane wyjściowe będą zawierać maskę segmentacji w postaci obrazu z wartością zmiennoprzecinkową, gdzie każda wartość zmiennoprzecinkowa reprezentuje mapę współczynnika zaufania danej kategorii. |
{True, False} |
True |
displayNamesLocale |
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 |
result_callback |
Ustawia odbiornik wyników tak, aby asynchronicznie otrzymywał wyniki podziału na segmenty, gdy segmentator obrazu jest w trybie LIVE_STREAM.
Można go używać tylko wtedy, gdy tryb działania ma wartość LIVE_STREAM. |
Nie dotyczy | Nie dotyczy |
Gdy tryb działania jest ustawiony na LIVE_STREAM, narzędzie do segmentacji obrazu wymaga dodatkowej opcji konfiguracji imageSegmenterLiveStreamDelegate, która umożliwia asynchroniczne dostarczanie wyników segmentacji obrazu.
Delegat musi zaimplementować metodę imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:), którą ImageSegmenter wywołuje po przetworzeniu wyników podziału na segmenty w przypadku każdego kadru.
| Nazwa opcji | Opis | Zakres wartości | Wartość domyślna |
|---|---|---|---|
imageSegmenterLiveStreamDelegate |
Umożliwia narzędziu Image Segmenter asynchroniczne otrzymywanie wyników segmentacji obrazu w trybie transmisji na żywo. Klasa, której instancja jest ustawiona w tej właściwości, musi implementować metodę imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:). |
Nie dotyczy | Nie ustawiono |
Przygotuj dane
Przed przekazaniem do segmentatora obrazu musisz przekonwertować podany 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, CVPixelBuffer i CMSampleBuffer.
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
UIImagemożna przekształcić w obiektMPImage.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. Narzędzie do podziału obrazu 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
CVPixelBufferpo przetworzeniu ich za pomocą interfejsuCoreImagew iOS, mogą być wysyłane do narzędzia Image Segmenter w trybie uruchamiania obrazu.Filmy: ramki wideo można przekształcić w format
CVPixelBufferdo przetwarzania, a następnie wysłać do segmentacji obrazu w trybie wideo.transmisja na żywo: aplikacje korzystające z aparatu iOS do generowania klatek mogą zostać przekonwertowane do formatu
CVPixelBufferw celu przetwarzania, zanim zostaną wysłane do narzędzia Image Segmenter 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ć narzędzie do podziału obrazu, użyj metody segment() odpowiedniej dla przypisanego trybu działania:
- Statyczny obraz:
segment(image:) - Film:
segment(videoFrame:timestampInMilliseconds:) - Transmisja na żywo:
segmentAsync(image:timestampInMilliseconds:)
Poniższe przykłady kodu zawierają proste przykłady uruchamiania narzędzia Image Segmenter w różnych trybach:
Swift
Obraz
let result = try imageSegmenter.segment(image: image)
Wideo
let result = try imageSegmenter.segment(
videoFrame: image,
timestampInMilliseconds: timestamp)
Transmisja na żywo
try imageSegmenter.segmentAsync(
image: image,
timestampInMilliseconds: timestamp)
Objective-C
Obraz
MPPImageSegmenterResult *result = [imageSegmenter segmentImage:image error:nil];
Wideo
MPPImageSegmenterResult *result = [imageSegmenter segmentVideoFrame:image timestampInMilliseconds:timestamp error:nil];
Transmisja na żywo
BOOL success = [imageSegmenter segmentAsyncImage:image timestampInMilliseconds:timestamp error:nil];
Przykład kodu Image Segmenter pokazuje szczegółowo implementację każdego z tych trybów: segment(image:), segment(videoFrame:timestampInMilliseconds:) i segmentAsync(image:timestampInMilliseconds:).
Pamiętaj:
Podczas uruchamiania w trybie wideo lub transmisji na żywo musisz też podać zadaniu segmentacji obrazu sygnaturę czasową ramki wejściowej.
W trybie obrazu lub filmu zadanie segmentacji obrazu blokuje bieżący wątek, dopóki nie zakończy przetwarzania wejściowego obrazu 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 segmentacji obrazu zwraca wynik natychmiast i nie blokuje bieżącego wątku. Po przetworzeniu każdego wejściowego kadru wywołuje metodę
imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:)w segmencie obrazu. Narzędzie do dzielenia obrazu 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 funkcjasegmentAsynczostanie wywołana, gdy zadanie Image Segmenter jest zajęte przetwarzaniem innej klatki, Image Segmenter zignoruje nową klatkę wejściową.
Obsługa i wyświetlanie wyników
Po uruchomieniu wnioskowania zadanie segmentacji obrazu zwraca obiekt ImageSegmenterResult, który zawiera wyniki zadania segmentacji. Treść danych wyjściowych zależy od typu danych wyjściowych ustawionego podczas konfigurowania zadania.
Na poniższych obrazach widać wizualizację danych wyjściowych zadania w przypadku maski wartości kategorii. Zakres maski kategorii to [0, 255], a każda wartość piksela reprezentuje zwycięski indeks kategorii w wyniku modelu. Wybrany indeks kategorii ma najwyższą wartość spośród kategorii rozpoznawanych przez model.
Wyjście oryginalnej maski obrazu i kategorii. Obraz źródłowy z danych Pascal VOC 2012.
Przykładowy kod narzędzia do podziału obrazu pokazuje, jak wyświetlać wyniki tego narzędzia. Szczegółowe informacje znajdziesz w przykładowym kodzie.