iOS에서 ML Kit를 사용한 셀카 세분화

<ph type="x-smartling-placeholder">

ML Kit는 셀카 세분화에 최적화된 SDK를 제공합니다. 셀카 세분화 도구 애셋은 빌드 시 앱에 정적으로 연결됩니다. 이렇게 하면 앱 크기가 최대 24MB까지 늘어나며, iPhone X에서 측정된 바와 같이 API 지연 시간은 입력 이미지 크기에 따라 최대 7ms~12ms가 될 수 있습니다.

사용해 보기

  • 샘플 앱을 사용하여 이 API의 사용 예를 참조하세요.

시작하기 전에

  1. Podfile에 다음 ML Kit 라이브러리를 포함합니다.

    pod 'GoogleMLKit/SegmentationSelfie', '3.2.0'
    
  2. 프로젝트의 포드를 설치하거나 업데이트한 후 .xcworkspace를 사용하여 Xcode 프로젝트를 엽니다. ML Kit는 Xcode 버전 13.2.1 이상에서 지원됩니다.

1. 세그먼터의 인스턴스 만들기

셀카 이미지에서 세분화를 실행하려면 먼저 SelfieSegmenterOptionsSegmenter 인스턴스를 만들고 선택적으로 세분화 설정을 지정합니다.

분류 기준 옵션

세그먼터 모드

Segmenter는 두 가지 모드로 작동합니다. 사용 사례에 맞는 태그를 선택해야 합니다.

STREAM_MODE (default)

이 모드는 동영상 또는 카메라의 프레임을 스트리밍하도록 설계되었습니다. 이 모드에서는 세그먼트 도구가 이전 프레임의 결과를 활용하여 더 원활한 세분화 결과를 반환합니다.

SINGLE_IMAGE_MODE (default)

이 모드는 관련되지 않은 단일 이미지를 위해 설계되었습니다. 이 모드에서는 세그먼트 도구가 각 이미지를 독립적으로 처리하며 프레임에 평활화를 적용하지 않습니다.

원시 크기 마스크 사용 설정

세그먼트 작성자에게 모델 출력 크기와 일치하는 원시 크기 마스크를 반환하도록 요청합니다.

RAW 마스크 크기 (예: 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. 입력 이미지 준비

셀카를 분류하려면 각 이미지 또는 동영상 프레임에 대해 다음을 수행합니다. 스트림 모드를 사용 설정한 경우 VisionImage 객체를 CMSampleBuffer

VisionImage 객체를 UIImage 또는 CMSampleBuffer입니다.

UIImage를 사용하는 경우 다음 단계를 따르세요.

  • UIImageVisionImage 객체를 만듭니다. 올바른 .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;
      }
    }
          
  • 다음을 사용하여 VisionImage 객체를 만듭니다. CMSampleBuffer 객체 및 방향:

    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를 사용하세요. 지정된 동영상 프레임에서 동기식으로 결과를 가져오려면 AVCaptureVideoDataOutputSampleBufferDelegatecaptureOutput(_, didOutput:from:) 함수에서 이 메서드를 호출합니다. AVCaptureVideoDataOutputalwaysDiscardsLateVideoFrames를 true로 유지하여 분류기에 대한 호출을 제한합니다. 세그먼트 도구가 실행 중일 때 새 동영상 프레임이 제공되는 경우 삭제됩니다.
  • 세그먼트 도구의 출력을 사용하여 입력 이미지에서 그래픽을 오버레이하는 경우 먼저 ML Kit에서 결과를 가져온 후 이미지를 렌더링하고 단일 단계로 오버레이합니다. 이렇게 하면 처리된 입력 프레임마다 한 번만 디스플레이 표면에 렌더링됩니다. 예는 ML Kit 빠른 시작 샘플previewOverlayViewCameraViewController 클래스를 참조하세요.