iOS でカスタムモデルを使用して画像にラベルを付ける

ML Kit を使用すると、画像内のエンティティを認識してラベルを付けることができます。 この API は、幅広いカスタム画像分類モデルをサポートしています。恐れ入りますが、 詳細については、ML Kit を使用したカスタムモデルをご覧ください。 モデルの互換性要件、事前トレーニング済みモデルの入手先 独自のモデルをトレーニングする方法を 見ていきます

カスタムモデルを統合するには、2 つの方法があります。モデルは、次の方法でバンドルできます。 アプリのアセット フォルダに配置するか、動的に 使用できます。次の表は、2 つのオプションを比較したものです。

バンドルされたモデル ホストされているモデル
このモデルはアプリの APK の一部であり、サイズが増大します。 モデルは APK の一部ではありません。アップロードすることでホストされます。 Firebase ML
Android デバイスがオフラインの場合でも、モデルをすぐに利用できます。 モデルはオンデマンドでダウンロードされる
Firebase プロジェクトは不要 Firebase プロジェクトが必要
モデルを更新するには、アプリを再公開する必要があります アプリを再公開せずにモデルの更新を push する
A/B Testing が組み込まれていない Firebase Remote Config で簡単に A/B テストを実施

試してみる

始める前に

  1. Podfile に ML Kit ライブラリを含めます。

    モデルをアプリにバンドルするには:

    pod 'GoogleMLKit/ImageLabelingCustom', '3.2.0'
    

    Firebase からモデルを動的にダウンロードする場合は、LinkFirebase を追加します。 :

    pod 'GoogleMLKit/ImageLabelingCustom', '3.2.0'
    pod 'GoogleMLKit/LinkFirebase', '3.2.0'
    
  2. プロジェクトの Pod をインストールまたは更新したら、Xcode プロジェクトを開きます。 .xcworkspace を使用します。ML Kit は Xcode バージョン 13.2.1 でサポートされています 以上です。

  3. モデルをダウンロードする場合は、 Firebase を iOS プロジェクトに追加する まだ実施していない場合は 追加してくださいこれは、 モデルです。

1. モデルを読み込む

ローカルモデルソースを構成する

モデルをアプリにバンドルするには:

  1. モデルファイル(通常は末尾が .tflite または .lite)を Xcode にコピーします。 その際は Copy bundle resources を選択してください。「 モデルファイルが App Bundle に含まれ、ML Kit で利用可能になります。

  2. モデルファイルのパスを指定して、LocalModel オブジェクトを作成します。

    Swift

    let localModel = LocalModel(path: localModelFilePath)

    Objective-C

    MLKLocalModel *localModel =
        [[MLKLocalModel alloc] initWithPath:localModelFilePath];
で確認できます。

Firebase でホストされているモデルソースを構成する

リモートでホストされるモデルを使用するには、RemoteModel オブジェクトを作成し、 モデルを公開したときに割り当てた名前です。

Swift

let firebaseModelSource = FirebaseModelSource(
    name: "your_remote_model") // The name you assigned in
                               // the Firebase console.
let remoteModel = CustomRemoteModel(remoteModelSource: firebaseModelSource)

Objective-C

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

次に、実行する条件を指定してモデルのダウンロード タスクを開始します。 ダウンロードを許可する対象のモデルがデバイスに搭載されていない場合や、 利用可能な場合、タスクは非同期でモデルの 構築する方法を紹介します。

Swift

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

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

Objective-C

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

NSProgress *downloadProgress =
    [[MLKModelManager modelManager] downloadModel:remoteModel
                                       conditions:downloadConditions];

多くのアプリは初期化コードでダウンロード タスクを開始しますが、 モデルを使用する必要がある前であれば、いつでも実行できます。

画像ラベラーを構成する

モデルソースを構成したら、モデルソースから ImageLabeler オブジェクトを作成します。 できます。

以下のオプションを使用できます。

オプション
confidenceThreshold

検出されたラベルの最小信頼スコア。設定しない場合、 モデルのメタデータで指定された分類器のしきい値が使用されます。 モデルにメタデータが含まれていないか、 指定しない場合、デフォルトのしきい値は 0.0 になります。 分析できます

maxResultCount

返されるラベルの最大数。設定しない場合、 10 が使用されます。

ローカルにバンドルされたモデルのみがある場合は、 LocalModel オブジェクト:

Swift

let options = CustomImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = NSNumber(value: 0.0)
let imageLabeler = ImageLabeler.imageLabeler(options: options)

Objective-C

MLKCustomImageLabelerOptions *options =
    [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = @(0.0);
MLKImageLabeler *imageLabeler =
    [MLKImageLabeler imageLabelerWithOptions:options];

リモートでホストされるモデルがある場合は、 ダウンロードされます。モデルのダウンロードのステータスを確認できます モデル マネージャーの isModelDownloaded(remoteModel:) メソッドを使用して、タスクを実行できます。

ラベラーを実行する前に確認する必要があるだけですが、 リモートでホストされているモデルとローカルにバンドルされたモデルの両方がある場合は、 ImageLabeler をインスタンス化する際にこのチェックを行うのが適切です。 ダウンロードされている場合はリモートモデルから、またローカルモデルから できません。

Swift

var options: CustomImageLabelerOptions!
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = CustomImageLabelerOptions(remoteModel: remoteModel)
} else {
  options = CustomImageLabelerOptions(localModel: localModel)
}
options.confidenceThreshold = NSNumber(value: 0.0)
let imageLabeler = ImageLabeler.imageLabeler(options: options)

Objective-C

MLKCustomImageLabelerOptions *options;
if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) {
  options = [[MLKCustomImageLabelerOptions alloc] initWithRemoteModel:remoteModel];
} else {
  options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];
}
options.confidenceThreshold = @(0.0);
MLKImageLabeler *imageLabeler =
    [MLKImageLabeler imageLabelerWithOptions:options];

リモートでホストされるモデルのみがある場合は、モデル関連 UI の一部をグレー表示したり非表示にしたりする モデルがダウンロードされたことを確認します

モデルのダウンロード ステータスを取得するには、オブザーバーをデフォルト 通知センター。オブザーバーでは、必ず self への弱い参照を使用してください。 ブロックします。これは、ダウンロードに時間がかかり、元のオブジェクトが 解放されます。例:

Swift

NotificationCenter.default.addObserver(
    forName: .mlkitModelDownloadDidSucceed,
    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: .mlkitModelDownloadDidFail,
    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]
    // ...
}

Objective-C

__weak typeof(self) weakSelf = self;

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

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

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

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

2. 入力画像を準備する

VisionImageオブジェクトを作成するには、UIImage または CMSampleBuffer

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;
      }
    }
          
  • 次のコマンドを使用して、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. 画像ラベラーを実行する

画像内のオブジェクトにラベルを付けるには、image オブジェクトを ImageLabelerprocess() メソッドを使用します。

非同期:

Swift

imageLabeler.process(image) { labels, error in
    guard error == nil, let labels = labels, !labels.isEmpty else {
        // Handle the error.
        return
    }
    // Show results.
}

Objective-C

[imageLabeler
    processImage:image
      completion:^(NSArray *_Nullable labels,
                   NSError *_Nullable error) {
        if (label.count == 0) {
            // Handle the error.
            return;
        }
        // Show results.
     }];

同期:

Swift

var labels: [ImageLabel]
do {
    labels = try imageLabeler.results(in: image)
} catch let error {
    // Handle the error.
    return
}
// Show results.

Objective-C

NSError *error;
NSArray *labels =
    [imageLabeler resultsInImage:image error:&error];
// Show results or handle the error.

4. ラベル付きエンティティに関する情報を取得する

画像のラベル付けオペレーションが成功すると、 ImageLabel。各 ImageLabel は、発生したものを表します。 画像内のラベルが付けられています。各ラベルのテキストの説明を取得できます( TensorFlow Lite モデルファイルのメタデータ)、信頼スコア、インデックスが含まれます。 例:

Swift

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

Objective-C

for (MLKImageLabel *label in labels) {
  NSString *labelText = label.text;
  float confidence = label.confidence;
  NSInteger index = label.index;
}

リアルタイムのパフォーマンスを改善するためのヒント

リアルタイム アプリケーションで画像にラベルを付ける場合は、 実現するためのガイドラインは次のとおりです。