Firebase Summit에서 발표된 모든 내용을 살펴보고 Firebase로 앱을 빠르게 개발하고 안심하고 앱을 실행하는 방법을 알아보세요. 자세히 알아보기

iOS에서 AutoML 학습 모델로 이미지에 레이블 지정

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

AutoML Vision Edge를 사용하여 자체 모델을 학습 시킨 후 앱에서 이를 사용하여 이미지에 레이블을 지정할 수 있습니다.

시작하기 전에

  1. 아직 앱에 Firebase를 추가하지 않았다면 시작하기 가이드 의 단계에 따라 추가하세요.
  2. Podfile에 ML Kit 라이브러리 포함:
    pod 'Firebase/MLVision', '6.25.0'
    pod 'Firebase/MLVisionAutoML', '6.25.0'
    
    프로젝트의 Pod를 설치하거나 업데이트한 후 .xcworkspace 를 사용하여 Xcode 프로젝트를 열어야 합니다.
  3. 앱에서 Firebase를 가져옵니다.

    빠른

    import Firebase

    오브젝티브-C

    @import Firebase;

1. 모델 로드

ML Kit는 기기에서 AutoML 생성 모델을 실행합니다. 그러나 Firebase, 로컬 저장소 또는 둘 다에서 원격으로 모델을 로드하도록 ML Kit를 구성할 수 있습니다.

Firebase에서 모델을 호스팅하면 새 앱 버전을 출시하지 않고도 모델을 업데이트할 수 있으며 원격 구성 및 A/B 테스팅을 사용하여 다양한 사용자 집합에 다양한 모델을 동적으로 제공할 수 있습니다.

모델을 Firebase와 함께 호스팅하여 제공하기만 하고 앱과 번들로 묶지 않도록 선택한 경우 앱의 초기 다운로드 크기를 줄일 수 있습니다. 그러나 모델이 앱과 함께 번들로 제공되지 않으면 앱에서 모델을 처음 다운로드할 때까지 모델 관련 기능을 사용할 수 없습니다.

모델을 앱과 번들로 묶으면 Firebase 호스팅 모델을 사용할 수 없을 때 앱의 ML 기능이 계속 작동하도록 할 수 있습니다.

Firebase 호스팅 모델 소스 구성

원격으로 호스팅되는 모델을 사용하려면 모델을 게시할 때 할당한 이름을 지정하여 AutoMLRemoteModel 개체를 만듭니다.

빠른

let remoteModel = AutoMLRemoteModel(
    name: "your_remote_model"  // The name you assigned in the Firebase console.
)

오브젝티브-C

FIRAutoMLRemoteModel *remoteModel = [[FIRAutoMLRemoteModel alloc]
    initWithName:@"your_remote_model"];  // The name you assigned in the Firebase console.

그런 다음 다운로드를 허용할 조건을 지정하여 모델 다운로드 작업을 시작합니다. 모델이 기기에 없거나 최신 버전의 모델을 사용할 수 있는 경우 작업은 Firebase에서 모델을 비동기식으로 다운로드합니다.

빠른

let downloadConditions = ModelDownloadConditions(
  allowsCellularAccess: true,
  allowsBackgroundDownloading: true
)

let downloadProgress = ModelManager.modelManager().download(
  remoteModel,
  conditions: downloadConditions
)

오브젝티브-C

FIRModelDownloadConditions *downloadConditions =
    [[FIRModelDownloadConditions alloc] initWithAllowsCellularAccess:YES
                                         allowsBackgroundDownloading:YES];

NSProgress *downloadProgress =
    [[FIRModelManager modelManager] downloadRemoteModel:remoteModel
                                             conditions:downloadConditions];

많은 앱이 초기화 코드에서 다운로드 작업을 시작하지만 모델을 사용하기 전에 언제든지 시작할 수 있습니다.

로컬 모델 소스 구성

모델을 앱과 번들로 묶으려면 다음 안내를 따르세요.

  1. Firebase 콘솔에서 다운로드한 zip 아카이브에서 모델과 해당 메타데이터를 폴더로 추출합니다.
    your_model_directory
      |____dict.txt
      |____manifest.json
      |____model.tflite
    
    세 파일은 모두 같은 폴더에 있어야 합니다. 다운로드 받은 파일을 수정(파일명 포함)하지 않고 그대로 사용하는 것을 권장합니다.
  2. 폴더를 Xcode 프로젝트에 복사하고 폴더 참조 생성 을 선택하도록 주의하십시오. 모델 파일과 메타데이터는 앱 번들에 포함되며 ML Kit에서 사용할 수 있습니다.
  3. 모델 매니페스트 파일의 경로를 지정하여 AutoMLLocalModel 객체를 생성합니다.

    빠른

    guard let manifestPath = Bundle.main.path(
        forResource: "manifest",
        ofType: "json",
        inDirectory: "your_model_directory"
    ) else { return true }
    let localModel = AutoMLLocalModel(manifestPath: manifestPath)
    

    오브젝티브-C

    NSString *manifestPath = [NSBundle.mainBundle pathForResource:@"manifest"
                                                           ofType:@"json"
                                                      inDirectory:@"your_model_directory"];
    FIRAutoMLLocalModel *localModel = [[FIRAutoMLLocalModel alloc] initWithManifestPath:manifestPath];
    

모델에서 이미지 라벨러 만들기

모델 소스를 구성한 후 그 중 하나에서 VisionImageLabeler 개체를 생성합니다.

로컬 번들 모델만 있는 경우 AutoMLLocalModel 객체에서 레이블러를 만들고 필요한 신뢰도 점수 임계값을 구성하기만 하면 됩니다( 모델 평가 참조).

빠른

let options = VisionOnDeviceAutoMLImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = 0  // Evaluate your model in the Firebase console
                                 // to determine an appropriate value.
let labeler = Vision.vision().onDeviceAutoMLImageLabeler(options: options)

오브젝티브-C

FIRVisionOnDeviceAutoMLImageLabelerOptions *options =
    [[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = 0;  // Evaluate your model in the Firebase console
                                  // to determine an appropriate value.
FIRVisionImageLabeler *labeler =
    [[FIRVision vision] onDeviceAutoMLImageLabelerWithOptions:options];

원격으로 호스트되는 모델이 있는 경우 실행하기 전에 다운로드되었는지 확인해야 합니다. 모델 관리자의 isModelDownloaded(remoteModel:) 메소드를 사용하여 모델 다운로드 작업의 상태를 확인할 수 있습니다.

레이블러를 실행하기 전에 이것을 확인하기만 하면 되지만, 원격 호스팅 모델과 로컬 번들 모델이 모두 있는 경우 VisionImageLabeler 를 인스턴스화할 때 이 검사를 수행하는 것이 합리적일 수 있습니다. 다운로드되고 그렇지 않은 경우 로컬 모델에서 다운로드됩니다.

빠른

var options: VisionOnDeviceAutoMLImageLabelerOptions?
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = VisionOnDeviceAutoMLImageLabelerOptions(remoteModel: remoteModel)
} else {
  options = VisionOnDeviceAutoMLImageLabelerOptions(localModel: localModel)
}
options.confidenceThreshold = 0  // Evaluate your model in the Firebase console
                                 // to determine an appropriate value.
let labeler = Vision.vision().onDeviceAutoMLImageLabeler(options: options)

오브젝티브-C

VisionOnDeviceAutoMLImageLabelerOptions *options;
if ([[FIRModelManager modelManager] isModelDownloaded:remoteModel]) {
  options = [[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithRemoteModel:remoteModel];
} else {
  options = [[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
}
options.confidenceThreshold = 0.0f;  // Evaluate your model in the Firebase console
                                     // to determine an appropriate value.
FIRVisionImageLabeler *labeler = [[FIRVision vision] onDeviceAutoMLImageLabelerWithOptions:options];

원격으로 호스팅되는 모델만 있는 경우 모델이 다운로드되었음을 확인할 때까지 모델 관련 기능(예: UI의 일부를 회색으로 표시하거나 숨기기)을 비활성화해야 합니다.

기본 알림 센터에 관찰자를 연결하여 모델 다운로드 상태를 얻을 수 있습니다. 다운로드에 시간이 걸릴 수 있고 다운로드가 완료될 때 원래 개체가 해제될 수 있으므로 관찰자 블록에서 self 에 대한 약한 참조를 사용해야 합니다. 예를 들어:

빠른

NotificationCenter.default.addObserver(
    forName: .firebaseMLModelDownloadDidSucceed,
    object: nil,
    queue: nil
) { [weak self] notification in
    guard let strongSelf = self,
        let userInfo = notification.userInfo,
        let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue]
            as? RemoteModel,
        model.name == "your_remote_model"
        else { return }
    // The model was downloaded and is available on the device
}

NotificationCenter.default.addObserver(
    forName: .firebaseMLModelDownloadDidFail,
    object: nil,
    queue: nil
) { [weak self] notification in
    guard let strongSelf = self,
        let userInfo = notification.userInfo,
        let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue]
            as? RemoteModel
        else { return }
    let error = userInfo[ModelDownloadUserInfoKey.error.rawValue]
    // ...
}

오브젝티브-C

__weak typeof(self) weakSelf = self;

[NSNotificationCenter.defaultCenter
    addObserverForName:FIRModelDownloadDidSucceedNotification
                object:nil
                 queue:nil
            usingBlock:^(NSNotification *_Nonnull note) {
              if (weakSelf == nil | note.userInfo == nil) {
                return;
              }
              __strong typeof(self) strongSelf = weakSelf;

              FIRRemoteModel *model = note.userInfo[FIRModelDownloadUserInfoKeyRemoteModel];
              if ([model.name isEqualToString:@"your_remote_model"]) {
                // The model was downloaded and is available on the device
              }
            }];

[NSNotificationCenter.defaultCenter
    addObserverForName:FIRModelDownloadDidFailNotification
                object:nil
                 queue:nil
            usingBlock:^(NSNotification *_Nonnull note) {
              if (weakSelf == nil | note.userInfo == nil) {
                return;
              }
              __strong typeof(self) strongSelf = weakSelf;

              NSError *error = note.userInfo[FIRModelDownloadUserInfoKeyError];
            }];

2. 입력 이미지 준비

그런 다음 레이블을 지정하려는 각 이미지에 대해 이 섹션에 설명된 옵션 중 하나를 사용하여 VisionImage 개체를 만들고 이를 VisionImageLabeler 의 인스턴스에 전달합니다(다음 섹션에 설명됨).

UIImage 또는 CMSampleBufferRef 를 사용하여 VisionImage 개체를 만듭니다.

UIImage 를 사용하려면:

  1. 필요한 경우 imageOrientation 속성이 .up 이 되도록 이미지를 회전합니다.
  2. 올바르게 회전된 UIImage 를 사용하여 VisionImage 객체를 만듭니다. 회전 메타데이터를 지정하지 마십시오. 기본값인 .topLeft 를 사용해야 합니다.

    빠른

    let image = VisionImage(image: uiImage)

    오브젝티브-C

    FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

CMSampleBufferRef 를 사용하려면:

  1. CMSampleBufferRef 버퍼에 포함된 이미지 데이터의 방향을 지정하는 VisionImageMetadata 개체를 만듭니다.

    이미지 방향을 얻으려면:

    빠른

    func imageOrientation(
        deviceOrientation: UIDeviceOrientation,
        cameraPosition: AVCaptureDevice.Position
        ) -> VisionDetectorImageOrientation {
        switch deviceOrientation {
        case .portrait:
            return cameraPosition == .front ? .leftTop : .rightTop
        case .landscapeLeft:
            return cameraPosition == .front ? .bottomLeft : .topLeft
        case .portraitUpsideDown:
            return cameraPosition == .front ? .rightBottom : .leftBottom
        case .landscapeRight:
            return cameraPosition == .front ? .topRight : .bottomRight
        case .faceDown, .faceUp, .unknown:
            return .leftTop
        }
    }

    오브젝티브-C

    - (FIRVisionDetectorImageOrientation)
        imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                               cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          if (cameraPosition == AVCaptureDevicePositionFront) {
            return FIRVisionDetectorImageOrientationLeftTop;
          } else {
            return FIRVisionDetectorImageOrientationRightTop;
          }
        case UIDeviceOrientationLandscapeLeft:
          if (cameraPosition == AVCaptureDevicePositionFront) {
            return FIRVisionDetectorImageOrientationBottomLeft;
          } else {
            return FIRVisionDetectorImageOrientationTopLeft;
          }
        case UIDeviceOrientationPortraitUpsideDown:
          if (cameraPosition == AVCaptureDevicePositionFront) {
            return FIRVisionDetectorImageOrientationRightBottom;
          } else {
            return FIRVisionDetectorImageOrientationLeftBottom;
          }
        case UIDeviceOrientationLandscapeRight:
          if (cameraPosition == AVCaptureDevicePositionFront) {
            return FIRVisionDetectorImageOrientationTopRight;
          } else {
            return FIRVisionDetectorImageOrientationBottomRight;
          }
        default:
          return FIRVisionDetectorImageOrientationTopLeft;
      }
    }

    그런 다음 메타데이터 개체를 만듭니다.

    빠른

    let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
    let metadata = VisionImageMetadata()
    metadata.orientation = imageOrientation(
        deviceOrientation: UIDevice.current.orientation,
        cameraPosition: cameraPosition
    )

    오브젝티브-C

    FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init];
    AVCaptureDevicePosition cameraPosition =
        AVCaptureDevicePositionBack;  // Set to the capture device you used.
    metadata.orientation =
        [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                     cameraPosition:cameraPosition];
  2. CMSampleBufferRef 개체와 회전 메타데이터를 사용하여 VisionImage 개체를 만듭니다.

    빠른

    let image = VisionImage(buffer: sampleBuffer)
    image.metadata = metadata

    오브젝티브-C

    FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
    image.metadata = metadata;

3. 이미지 라벨러 실행

이미지의 객체에 레이블을 지정하려면 VisionImage 객체를 VisionImageLabelerprocess() 메서드에 전달합니다.

빠른

labeler.process(image) { labels, error in
    guard error == nil, let labels = labels else { return }

    // Task succeeded.
    // ...
}

오브젝티브-C

[labeler
    processImage:image
      completion:^(NSArray<FIRVisionImageLabel *> *_Nullable labels, NSError *_Nullable error) {
        if (error != nil || labels == nil) {
          return;
        }

        // Task succeeded.
        // ...
      }];

이미지 라벨링이 성공하면 VisionImageLabel 객체의 배열이 완료 핸들러에 전달됩니다. 각 객체에서 이미지에서 인식된 특징에 대한 정보를 얻을 수 있습니다.

예를 들어:

빠른

for label in labels {
    let labelText = label.text
    let confidence = label.confidence
}

오브젝티브-C

for (FIRVisionImageLabel *label in labels) {
  NSString *labelText = label.text;
  NSNumber *confidence = label.confidence;
}

실시간 성능 향상을 위한 팁

  • 감지기에 대한 호출을 조절합니다. 감지기가 실행되는 동안 새 비디오 프레임을 사용할 수 있게 되면 프레임을 삭제합니다.
  • 감지기의 출력을 사용하여 입력 이미지에 그래픽을 오버레이하는 경우 먼저 ML Kit에서 결과를 가져온 다음 단일 단계로 이미지와 오버레이를 렌더링합니다. 이렇게 하면 각 입력 프레임에 대해 한 번만 디스플레이 표면에 렌더링됩니다. 예제는 쇼케이스 샘플 앱의 previewOverlayViewFIRDetectionOverlayView 클래스를 참조하세요.