ML Kit udostępnia zoptymalizowany pakiet SDK do segmentacji selfie. Komponenty segmentatora selfie są statycznie połączone z aplikacją w czasie kompilacji. Zwiększy to rozmiar aplikacji o maksymalnie 24 MB, a opóźnienie interfejsu API może wynosić od ok. 7 ms do ok. 12 ms w zależności od rozmiaru obrazu wejściowego (pomiar na iPhonie X).
Wypróbuj
- Wypróbuj przykładową aplikację, aby zobaczyć, jak używać tego interfejsu API.
Zanim zaczniesz
W pliku Podfile uwzględnij te biblioteki ML Kit:
pod 'GoogleMLKit/SegmentationSelfie', '8.0.0'Po zainstalowaniu lub zaktualizowaniu podów projektu otwórz projekt Xcode za pomocą pliku .
xcworkspace. ML Kit jest obsługiwany w Xcode w wersji 13.2.1 lub nowszej.
1. Utwórz instancję 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 tryb, który pasuje do Twojego przypadku użycia.
STREAM_MODE (default)
Ten tryb jest przeznaczony do przesyłania strumieniowego klatek z filmu lub aparatu. W tym trybie segmentator wykorzystuje wyniki z poprzednich klatek, aby zwracać płynniejsze wyniki segmentacji.
SINGLE_IMAGE_MODE (default)
Ten tryb jest przeznaczony do pojedynczych, niezwiązanych ze sobą obrazów. W tym trybie segmentator przetwarza każdy obraz niezależnie, bez wygładzania klatek.
Włącz maskę o rozmiarze pierwotnym
Prosi segmentator o zwrócenie maski o rozmiarze pierwotnym, która odpowiada rozmiarowi danych wyjściowych modelu.
Rozmiar maski pierwotnej (np. 256 x 256) jest zwykle mniejszy niż rozmiar obrazu wejściowego.
Jeśli nie określisz tej opcji, segmentator przeskaluje maskę pierwotną, aby dopasować ją do rozmiaru obrazu wejściowego. Rozważ użycie tej opcji, jeśli chcesz zastosować niestandardową logikę skalowania lub jeśli skalowanie nie jest potrzebne w Twoim przypadku użycia.
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. Przygotuj obraz wejściowy
Aby segmentować selfie, wykonaj te czynności w przypadku każdego obrazu lub klatki filmu.
Jeśli włączysz tryb strumienia, musisz utworzyć obiekty VisionImage z CMSampleBuffer.
Utwórz obiekt VisionImage za pomocą UIImage lub
CMSampleBuffer.
Jeśli używasz UIImage, wykonaj te czynności:
- Utwórz obiekt
VisionImageza pomocąUIImage. Upewnij się, że określisz prawidłową wartość.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 CMSampleBuffer, wykonaj te czynności:
-
Określ orientację danych obrazu zawartych w
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
VisionImageza pomocą 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. Przetwórz obraz
Przekaż obiekt VisionImage do jednej z metod przetwarzania obrazu Segmenter. Możesz użyć asynchronicznej metody process(image:) lub synchronicznej metody results(in:).
Aby synchronicznie przeprowadzić segmentację obrazu selfie:
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 asynchronicznie przeprowadzić segmentację obrazu selfie:
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. Pobierz maskę 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 przewodniku Szybki start ML Kit.
Wskazówki dotyczące zwiększania skuteczności
Jakość wyników zależy od jakości obrazu wejściowego:
- Aby ML Kit mógł uzyskać dokładny wynik segmentacji, obraz powinien mieć rozmiar co najmniej 256 x 256 pikseli.
- Jeśli wykonujesz segmentację selfie w aplikacji działającej w czasie rzeczywistym, możesz też wziąć pod uwagę ogólne wymiary obrazów wejściowych. Mniejsze obrazy można przetwarzać szybciej, więc aby zmniejszyć opóźnienie, rób zdjęcia w niższej rozdzielczości. Pamiętaj jednak o powyższych wymaganiach dotyczących rozdzielczości i upewnij się, że obiekt zajmuje jak największą część obrazu.
- Niska jakość obrazu może też wpływać na dokładność. 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 na sekundę:
- Użyj trybu segmentatora
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 synchronicznego interfejsu API segmentatora
results(in:). Wywołaj tę metodę z funkcji AVCaptureVideoDataOutputSampleBufferDelegate's captureOutput(_, didOutput:from:), aby synchronicznie uzyskać wyniki z danej klatki wideo. Ustaw wartość alwaysDiscardsLateVideoFrames w AVCaptureVideoDataOutput na 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 potem w jednym kroku wyrenderuj obraz i nałóż na niego grafikę. Dzięki temu renderujesz na powierzchni wyświetlacza tylko raz dla każdej przetworzonej klatki wejściowej. Przykład znajdziesz w klasach previewOverlayView i CameraViewController w przewodniku Szybki start ML Kit.