Zestaw ML Kit zawiera zoptymalizowany pakiet SDK do segmentacji selfie. Zasoby Selfie Segmenter są statycznie połączone z aplikacją podczas jej tworzenia. Zwiększy to rozmiar aplikacji o maksymalnie 24 MB, a czas oczekiwania interfejsu API może wynosić od ok. 7 ms do ok. 12 ms w zależności od rozmiaru obrazu wejściowego (pomiary wykonane na iPhonie X).
Wypróbuj
- Wypróbuj przykładową aplikację, aby zobaczyć, jak można używać tego interfejsu API.
Zanim zaczniesz
Uwzględnij w pliku Podfile te biblioteki ML Kit:
pod 'GoogleMLKit/SegmentationSelfie', '8.0.0'Po zainstalowaniu lub zaktualizowaniu Pods projektu otwórz projekt Xcode za pomocą pliku .
xcworkspace. Zestaw ML Kit jest obsługiwany w Xcode w wersji 13.2.1 lub nowszej.
1. Tworzenie instancji segmentatora
Aby przeprowadzić segmentację obrazu selfie, najpierw utwórz instancję Segmenter z SelfieSegmenterOptions i opcjonalnie określ ustawienia segmentacji.
Opcje segmentatora
Tryb segmentatora
Segmenter działa w 2 trybach. Wybierz model, który najlepiej odpowiada Twojemu zastosowaniu.
STREAM_MODE (default)
Ten tryb jest przeznaczony do strumieniowego przesyłania klatek z filmu lub aparatu. W tym trybie segmentator będzie wykorzystywać wyniki z poprzednich klatek, aby zwracać płynniejsze wyniki segmentacji.
SINGLE_IMAGE_MODE (default)
Ten tryb jest przeznaczony do pojedynczych obrazów, które nie są ze sobą powiązane. W tym trybie segmentator przetwarza każdy obraz niezależnie, bez wygładzania klatek.
Włącz maskę rozmiaru nieprzetworzonego
Prosi segmentator o zwrócenie maski o rozmiarze nieprzetworzonym, który odpowiada rozmiarowi danych wyjściowych modelu.
Rozmiar nieprzetworzonej maski (np. 256 x 256) jest zwykle mniejszy niż rozmiar obrazu wejściowego.
Jeśli nie określisz tej opcji, segmentator przeskaluje nieprzetworzoną maskę, aby dopasować ją do rozmiaru obrazu wejściowego. Rozważ użycie tej opcji, jeśli chcesz zastosować niestandardową logikę zmiany skali lub jeśli zmiana skali nie jest potrzebna w Twoim przypadku.
Określ opcje segmentatora:
Swift
let options = SelfieSegmenterOptions() options.segmenterMode = .singleImage options.shouldEnableRawSizeMask = true
Objective-C
MLKSelfieSegmenterOptions *options = [[MLKSelfieSegmenterOptions alloc] init]; options.segmenterMode = MLKSegmenterModeSingleImage; options.shouldEnableRawSizeMask = YES;
Na koniec pobierz instancję Segmenter. Przekaż określone opcje:
Swift
let segmenter = Segmenter.segmenter(options: options)
Objective-C
MLKSegmenter *segmenter = [MLKSegmenter segmenterWithOptions:options];
2. Przygotowywanie obrazu wejściowego
Aby posegmentować selfie, wykonaj te czynności w przypadku każdego obrazu lub klatki filmu.
Jeśli masz włączony tryb strumieniowy, musisz utworzyć obiekty VisionImage z obiektów CMSampleBuffer.
Utwórz obiekt VisionImage, używając UIImage lub CMSampleBuffer.
Jeśli używasz urządzenia UIImage, wykonaj te czynności:
- Utwórz obiekt
VisionImagezUIImage. Upewnij się, że podajesz prawidłowy parametr.orientation.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Jeśli używasz urządzenia CMSampleBuffer, wykonaj te czynności:
-
Określ orientację danych obrazu zawartych w elemencie
CMSampleBuffer.Aby uzyskać orientację obrazu:
Swift
func imageOrientation( deviceOrientation: UIDeviceOrientation, cameraPosition: AVCaptureDevice.Position ) -> UIImage.Orientation { switch deviceOrientation { case .portrait: return cameraPosition == .front ? .leftMirrored : .right case .landscapeLeft: return cameraPosition == .front ? .downMirrored : .up case .portraitUpsideDown: return cameraPosition == .front ? .rightMirrored : .left case .landscapeRight: return cameraPosition == .front ? .upMirrored : .down case .faceDown, .faceUp, .unknown: return .up } }
Objective-C
- (UIImageOrientation) imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation cameraPosition:(AVCaptureDevicePosition)cameraPosition { switch (deviceOrientation) { case UIDeviceOrientationPortrait: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored : UIImageOrientationRight; case UIDeviceOrientationLandscapeLeft: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored : UIImageOrientationUp; case UIDeviceOrientationPortraitUpsideDown: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored : UIImageOrientationLeft; case UIDeviceOrientationLandscapeRight: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored : UIImageOrientationDown; case UIDeviceOrientationUnknown: case UIDeviceOrientationFaceUp: case UIDeviceOrientationFaceDown: return UIImageOrientationUp; } }
- Utwórz obiekt
VisionImage, używając obiektuCMSampleBufferi orientacji:Swift
let image = VisionImage(buffer: sampleBuffer) image.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition)
Objective-C
MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer]; image.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
3. Przetwarzanie obrazu
Przekaż obiekt VisionImage do jednej z metod przetwarzania obrazu Segmenter. Możesz użyć metody asynchronicznej process(image:) lub metody synchronicznej results(in:).
Aby przeprowadzić segmentację zdjęcia selfie synchronicznie:
Swift
var mask: [SegmentationMask] do { mask = try segmenter.results(in: image) } catch let error { print("Failed to perform segmentation with error: \(error.localizedDescription).") return } // Success. Get a segmentation mask here.
Objective-C
NSError *error; MLKSegmentationMask *mask = [segmenter resultsInImage:image error:&error]; if (error != nil) { // Error. return; } // Success. Get a segmentation mask here.
Aby przeprowadzić segmentację obrazu selfie asynchronicznie:
Swift
segmenter.process(image) { mask, error in guard error == nil else { // Error. return } // Success. Get a segmentation mask here.
Objective-C
[segmenter processImage:image completion:^(MLKSegmentationMask * _Nullable mask, NSError * _Nullable error) { if (error != nil) { // Error. return; } // Success. Get a segmentation mask here. }];
4. Pobieranie maski segmentacji
Wynik segmentacji możesz uzyskać w ten sposób:
Swift
let maskWidth = CVPixelBufferGetWidth(mask.buffer) let maskHeight = CVPixelBufferGetHeight(mask.buffer) CVPixelBufferLockBaseAddress(mask.buffer, CVPixelBufferLockFlags.readOnly) let maskBytesPerRow = CVPixelBufferGetBytesPerRow(mask.buffer) var maskAddress = CVPixelBufferGetBaseAddress(mask.buffer)!.bindMemory( to: Float32.self, capacity: maskBytesPerRow * maskHeight) for _ in 0...(maskHeight - 1) { for col in 0...(maskWidth - 1) { // Gets the confidence of the pixel in the mask being in the foreground. let foregroundConfidence: Float32 = maskAddress[col] } maskAddress += maskBytesPerRow / MemoryLayout<Float32>.size }
Objective-C
size_t width = CVPixelBufferGetWidth(mask.buffer); size_t height = CVPixelBufferGetHeight(mask.buffer); CVPixelBufferLockBaseAddress(mask.buffer, kCVPixelBufferLock_ReadOnly); size_t maskBytesPerRow = CVPixelBufferGetBytesPerRow(mask.buffer); float *maskAddress = (float *)CVPixelBufferGetBaseAddress(mask.buffer); for (int row = 0; row < height; ++row) { for (int col = 0; col < width; ++col) { // Gets the confidence of the pixel in the mask being in the foreground. float foregroundConfidence = maskAddress[col]; } maskAddress += maskBytesPerRow / sizeof(float); }
Pełny przykład użycia wyników segmentacji znajdziesz w przykładowym krótkim wprowadzeniu do ML Kit.
Wskazówki dotyczące zwiększania skuteczności
Jakość wyników zależy od jakości obrazu wejściowego:
- Aby zestaw ML Kit mógł uzyskać dokładny wynik segmentacji, obraz powinien mieć co najmniej 256 x 256 pikseli.
- Jeśli przeprowadzasz segmentację selfie w aplikacji działającej w czasie rzeczywistym, weź pod uwagę ogólne wymiary obrazów wejściowych. Mniejsze obrazy mogą być przetwarzane szybciej, więc aby zmniejszyć opóźnienie, rób zdjęcia w niższej rozdzielczości, ale pamiętaj o powyższych wymaganiach dotyczących rozdzielczości i upewnij się, że obiekt zajmuje jak największą część obrazu.
- Na dokładność może też wpływać słaba ostrość obrazu. Jeśli nie uzyskasz zadowalających wyników, poproś użytkownika o ponowne zrobienie zdjęcia.
Jeśli chcesz używać segmentacji w aplikacji działającej w czasie rzeczywistym, postępuj zgodnie z tymi wskazówkami, aby uzyskać najlepszą liczbę klatek:
- Użyj trybu segmentacji
stream. - Rozważ robienie zdjęć w niższej rozdzielczości. Pamiętaj jednak o wymaganiach tego interfejsu API dotyczących wymiarów obrazu.
- Do przetwarzania klatek wideo użyj interfejsu API
results(in:)segmentera. Wywołaj tę metodę z funkcji captureOutput(_, didOutput:from:) interfejsu AVCaptureVideoDataOutputSampleBufferDelegate, aby synchronicznie uzyskiwać wyniki z danej klatki wideo. Ustaw właściwość alwaysDiscardsLateVideoFrames klasy AVCaptureVideoDataOutput na wartość „true”, aby ograniczyć wywołania segmentatora. Jeśli podczas działania segmentatora pojawi się nowa klatka wideo, zostanie ona odrzucona. - Jeśli używasz danych wyjściowych segmentatora do nakładania grafiki na obraz wejściowy, najpierw pobierz wynik z ML Kit, a następnie wyrenderuj obraz i nakładkę w jednym kroku. Dzięki temu renderowanie na powierzchni wyświetlacza odbywa się tylko raz dla każdej przetworzonej klatki wejściowej. Przykład znajdziesz w klasach previewOverlayView i CameraViewController w przykładowym krótkim wprowadzeniu do ML Kit.