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
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)
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)
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
@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];
@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];
@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
UIImage
moż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
.
// 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)
// 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
CVPixelBuffer
po przetworzeniu ich za pomocą interfejsuCoreImage
w iOS, mogą być wysyłane do narzędzia Image Segmenter w trybie uruchamiania obrazu.Filmy: ramki wideo można przekształcić w format
CVPixelBuffer
do 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
CVPixelBuffer
w celu przetwarzania, zanim zostaną wysłane do narzędzia Image Segmenter w trybie transmisji na żywo.
// 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)
// 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.
// 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)
// 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
let result = try imageSegmenter.segment(image: image)
let result = try imageSegmenter.segment( videoFrame: image, timestampInMilliseconds: timestamp)
try imageSegmenter.segmentAsync( image: image, timestampInMilliseconds: timestamp)
Objective-C
MPPImageSegmenterResult *result = [imageSegmenter segmentImage:image error:nil];
MPPImageSegmenterResult *result = [imageSegmenter segmentVideoFrame:image timestampInMilliseconds:timestamp error:nil];
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 funkcjasegmentAsync
zostanie 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.