ML Kit는 셀카 분할에 최적화된 SDK를 제공합니다. 셀카 분할기 애셋은 빌드 시 앱에 정적으로 연결됩니다. 이렇게 하면 앱 크기가 최대 24MB 증가하며 API 지연 시간은 입력 이미지 크기에 따라 iPhone X에서 측정한 대로 최대 7~12밀리초가 될 수 있습니다.
사용해 보기
- 샘플 앱을 살펴보고 이 API의 사용 예를 확인합니다.
시작하기 전에
Podfile에 다음 ML Kit 라이브러리를 포함합니다.
pod 'GoogleMLKit/SegmentationSelfie', '3.2.0'
프로젝트의 포드를 설치하거나 업데이트한 후 .
xcworkspace
을 사용하여 Xcode 프로젝트를 엽니다. ML Kit는 Xcode 버전 13.2.1 이상에서 지원됩니다.
1. Segmenter 인스턴스 만들기
셀카 이미지에 대해 분할을 실행하려면 먼저 SelfieSegmenterOptions
로 Segmenter
의 인스턴스를 만들고 원하는 경우 분할 설정을 지정합니다.
세그멘터 옵션
세그먼테이터 모드
Segmenter
는 두 가지 모드로 작동합니다. 사용 사례에 맞는 이름을 선택해야 합니다.
STREAM_MODE (default)
이 모드는 동영상 또는 카메라의 프레임을 스트리밍하기 위해 설계되었습니다. 이 모드에서 세그먼테이터는 이전 프레임의 결과를 활용하여 보다 원활한 세분화 결과를 반환합니다.
SINGLE_IMAGE_MODE (default)
이 모드는 관련이 없는 단일 이미지를 위해 설계되었습니다. 이 모드에서 분할기는 각 이미지를 독립적으로 처리하며, 프레임 위로 부드럽게 처리하지 않습니다.
원본 크기 마스크 사용 설정
세그먼테이터에 모델 출력 크기와 일치하는 원시 크기 마스크를 반환하도록 요청합니다.
원시 마스크 크기 (예: 256x256)는 일반적으로 입력 이미지 크기보다 작습니다.
이 옵션을 지정하지 않으면 세그먼트러가 입력 이미지 크기와 일치하도록 원시 마스크의 배율을 다시 조정합니다. 맞춤설정된 크기 조정 로직을 적용하고 싶거나 사용 사례에 크기 조정이 필요하지 않은 경우 이 옵션을 사용하는 것이 좋습니다.
분류기 옵션을 지정합니다.
Swift
let options = SelfieSegmenterOptions() options.segmenterMode = .singleImage options.shouldEnableRawSizeMask = true
Objective-C
MLKSelfieSegmenterOptions *options = [[MLKSelfieSegmenterOptions alloc] init]; options.segmenterMode = MLKSegmenterModeSingleImage; options.shouldEnableRawSizeMask = YES;
마지막으로 Segmenter
의 인스턴스를 가져옵니다. 지정한 옵션을 전달합니다.
Swift
let segmenter = Segmenter.segmenter(options: options)
Objective-C
MLKSegmenter *segmenter = [MLKSegmenter segmenterWithOptions:options];
2. 입력 이미지 준비
셀카를 분할하려면 각 이미지 또는 동영상 프레임에 대해 다음 단계를 따르세요.
스트림 모드를 사용 설정한 경우 CMSampleBuffer
에서 VisionImage
객체를 만들어야 합니다.
UIImage
또는 CMSampleBuffer
를 사용하여 VisionImage
객체를 만듭니다.
UIImage
를 사용하는 경우 다음 단계를 따르세요.
UIImage
를 사용하여VisionImage
객체를 만듭니다. 올바른.orientation
를 지정해야 합니다.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
CMSampleBuffer
를 사용하는 경우 다음 단계를 따르세요.
-
CMSampleBuffer
에 포함된 이미지 데이터의 방향을 지정합니다.이미지 방향을 가져오려면 다음 단계를 따르세요.
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; } }
CMSampleBuffer
객체와 방향을 사용하여VisionImage
객체를 만듭니다.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. 이미지 처리
VisionImage
객체를 Segmenter
의 이미지 처리 메서드 중 하나에 전달합니다. 비동기 process(image:)
메서드 또는 동기 results(in:)
메서드를 사용할 수 있습니다.
셀카 이미지에서 분할 작업을 동시에 수행하려면 다음 단계를 따르세요.
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.
셀카 이미지를 비동기식으로 분할하려면 다음 단계를 따르세요.
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. 세분화 마스크 가져오기
다음과 같이 세분화 결과를 얻을 수 있습니다.
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); }
세분화 결과를 사용하는 방법에 대한 전체 예시는 ML Kit 빠른 시작 샘플을 참조하세요.
실적 개선을 위한 팁
결과의 품질은 입력 이미지의 품질에 따라 달라집니다.
- ML Kit에서 정확한 세분화 결과를 얻으려면 이미지가 256x256픽셀 이상이어야 합니다.
- 실시간 애플리케이션에서 셀카 분할을 수행하는 경우 입력 이미지의 전체 크기도 고려해야 합니다. 이미지 크기가 작을수록 더 빠르게 처리될 수 있으므로 지연 시간을 줄이려면 더 낮은 해상도에서 이미지를 캡처하세요. 하지만 위의 해상도 요구사항을 염두에 두고 피사체가 이미지의 최대한 많은 부분을 차지하도록 하세요.
- 이미지 초점이 잘 맞지 않으면 정확도에 영향을 줄 수 있습니다. 허용 가능한 수준의 결과를 얻지 못하면 사용자에게 이미지를 다시 캡처하도록 요청합니다.
실시간 애플리케이션에서 세분화를 사용하려는 경우 최상의 프레임 속도를 얻으려면 다음 가이드라인을 따르세요.
stream
분류기 모드를 사용합니다.- 낮은 해상도에서 이미지를 캡처하는 것이 좋습니다. 단, 이 API의 이미지 크기 요구사항도 유의해야 합니다.
- 동영상 프레임을 처리하려면 세그먼테이션의
results(in:)
동기 API를 사용합니다. AVCaptureVideoDataOutputSampleBufferDelegate의 captureOutput(_, didOutput:from:) 함수에서 이 메서드를 호출하여 지정된 동영상 프레임에서 결과를 동기식으로 가져옵니다. 세그먼트러 호출을 제한하려면 AVCaptureVideoDataOutput의 alwaysDiscardsLateVideoFrames를 true로 유지합니다. 세그먼테이터가 실행 중일 때 새 동영상 프레임을 사용할 수 있게 되면 삭제됩니다. - 세그먼테이터의 출력을 사용하여 입력 이미지에서 그래픽을 오버레이하는 경우 먼저 ML Kit에서 결과를 가져온 후 이미지를 렌더링하고 단일 단계로 오버레이합니다. 이렇게 하면 처리된 입력 프레임마다 한 번만 디스플레이 표면에 렌더링됩니다. 예시는 ML Kit 빠른 시작 샘플의 previewOverlayView 및 CameraViewController 클래스를 참조하세요.