iOS でカスタム分類モデルを使用してオブジェクトを検出、追跡、分類する

ML Kit を使用すると、連続する動画フレーム内のオブジェクトを検出して追跡できます。

ML Kit に画像を渡すと、画像内で最大 5 つのオブジェクトが検出されます。 画像内の各オブジェクトの位置を確認できます対象物の検知時に 各オブジェクトには、そのオブジェクトを追跡するために使用できる 同じです

カスタム画像分類モデルを使用すると、 検出されます。詳しくは、ML Kit を使用したカスタムモデルをご覧ください。 モデルの互換性要件に関するガイダンス、事前トレーニング済みモデルの入手先、 独自のモデルをトレーニングする方法を 見ていきます

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

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

試してみる

始める前に

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

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

    pod 'GoogleMLKit/ObjectDetectionCustom', '3.2.0'
    

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

    pod 'GoogleMLKit/ObjectDetectionCustom', '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 でホストされているモデルソースを構成する

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

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];

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

2. オブジェクト検出を構成する

モデルソースを設定したら、モデルのオブジェクト検出機能を CustomObjectDetectorOptions オブジェクトを使ってみましょう。[ 次の設定を行います。

オブジェクト検出の設定
検出モード STREAM_MODE(デフォルト)|SINGLE_IMAGE_MODE

STREAM_MODE(デフォルト)では、オブジェクト検出が実行されます。 レイテンシは短くなりますが、不完全な結果( 未指定の境界ボックスやカテゴリラベルなど)を最初の数行に配置 検出機能の呼び出し。また、STREAM_MODEには、 検出機能によってオブジェクトにトラッキング ID が割り当てられます。この ID を使用して、 フレーム間でオブジェクトを追跡できます。このモードは または低レイテンシが重要な場合(たとえばデータの処理や リアルタイムで分析できます

SINGLE_IMAGE_MODE では、オブジェクト検出によって以下が返されます。 オブジェクトの境界ボックスが決定した後の結果です。もし 分類を有効にすると、境界の後に結果が返されます。 ボックスとカテゴリラベルの両方を使用できます。その結果 レイテンシが高くなる可能性があります。また、 SINGLE_IMAGE_MODE、トラッキング ID は割り当てられていません。使用 このモードは、レイテンシが重要ではなく、 部分的な結果しか得られません。

複数のオブジェクトを検出して追跡する false(デフォルト)|true

最大 5 つのオブジェクトを検出して追跡するか、最も大きい 目立たせることができます(デフォルト)。

オブジェクトを分類する false(デフォルト)|true

検出されたオブジェクトを、指定された カスタム分類器モデルですカスタム分類を使用するには これを true に設定する必要があります。

分類信頼度のしきい値

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

オブジェクトあたりの最大ラベル数

検出機能によって適用される、オブジェクトあたりのラベルの最大数 戻ります。設定しない場合、デフォルト値の 10 が使用されます。

ローカルにバンドルされたモデルのみがある場合は、 LocalModel オブジェクトを使用します。

Swift

let options = CustomObjectDetectorOptions(localModel: localModel)
options.detectorMode = .singleImage
options.shouldEnableClassification = true
options.shouldEnableMultipleObjects = true
options.classificationConfidenceThreshold = NSNumber(value: 0.5)
options.maxPerObjectLabelCount = 3

Objective-C

MLKCustomObjectDetectorOptions *options =
    [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableClassification = YES;
options.shouldEnableMultipleObjects = YES;
options.classificationConfidenceThreshold = @(0.5);
options.maxPerObjectLabelCount = 3;

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

これを確認するには、オブジェクト検出を実行する前に行いますが、 リモートでホストされるモデルとローカルにバンドルされたモデルの両方を使用する場合、 ObjectDetector をインスタンス化する際にこのチェックを行うのが適切です。 ダウンロードされている場合にはリモートモデルから、またローカルモデルから できません。

Swift

var options: CustomObjectDetectorOptions!
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = CustomObjectDetectorOptions(remoteModel: remoteModel)
} else {
  options = CustomObjectDetectorOptions(localModel: localModel)
}
options.detectorMode = .singleImage
options.shouldEnableClassification = true
options.shouldEnableMultipleObjects = true
options.classificationConfidenceThreshold = NSNumber(value: 0.5)
options.maxPerObjectLabelCount = 3

Objective-C

MLKCustomObjectDetectorOptions *options;
if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) {
  options = [[MLKCustomObjectDetectorOptions alloc] initWithRemoteModel:remoteModel];
} else {
  options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
}
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableClassification = YES;
options.shouldEnableMultipleObjects = YES;
options.classificationConfidenceThreshold = @(0.5);
options.maxPerObjectLabelCount = 3;

リモートでホストされるモデルのみがある場合は、モデル関連 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];
            }];

Object Detection and Tracking API は、この 2 つの主な用途のために最適化されています。 ケース:

  • カメラで最も目立つオブジェクトをライブ検出してトラッキング ビューファインダーです。
  • 静止画像からの複数のオブジェクトの検出。

このようなユースケース向けに API を構成するには:

Swift

// Live detection and tracking
let options = CustomObjectDetectorOptions(localModel: localModel)
options.shouldEnableClassification = true
options.maxPerObjectLabelCount = 3

// Multiple object detection in static images
let options = CustomObjectDetectorOptions(localModel: localModel)
options.detectorMode = .singleImage
options.shouldEnableMultipleObjects = true
options.shouldEnableClassification = true
options.maxPerObjectLabelCount = 3

Objective-C

// Live detection and tracking
MLKCustomObjectDetectorOptions *options =
    [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
options.shouldEnableClassification = YES;
options.maxPerObjectLabelCount = 3;

// Multiple object detection in static images
MLKCustomObjectDetectorOptions *options =
    [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableMultipleObjects = YES;
options.shouldEnableClassification = YES;
options.maxPerObjectLabelCount = 3;

3. 入力画像を準備する

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];

4. オブジェクト検出を作成して実行する

  1. 新しいオブジェクト検出を作成します。

    Swift

    let objectDetector = ObjectDetector.objectDetector(options: options)

    Objective-C

    MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions:options];
  2. 次に、検出機能を使用します。

    非同期:

    Swift

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

    Objective-C

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

    同期:

    Swift

    var objects: [Object]
    do {
        objects = try objectDetector.results(in: image)
    } catch let error {
        // Handle the error.
        return
    }
    // Show results.

    Objective-C

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

5. ラベル付きオブジェクトに関する情報を取得する

画像プロセッサへの呼び出しが成功すると、画像処理装置は 以下に応じて、完了ハンドラに Object を渡すか、リストを返します。 非同期メソッドと同期メソッドのどちらを呼び出してもかまいません。

Object には次のプロパティが含まれています。

frame 境界内でのオブジェクトの位置を示す CGRect 説明します。
trackingID 画像全体でオブジェクトを識別する整数、または SINGLE_IMAGE_MODE。
labels
label.text ラベルのテキストの説明。TensorFlow Data Validation の Lite モデルのメタデータには、ラベルの説明が含まれています。
label.index 分類器です。
label.confidence オブジェクト分類の信頼値。

Swift

// objects contains one item if multiple object detection wasn't enabled.
for object in objects {
  let frame = object.frame
  let trackingID = object.trackingID
  let description = object.labels.enumerated().map { (index, label) in
    "Label \(index): \(label.text), \(label.confidence), \(label.index)"
  }.joined(separator: "\n")
}

Objective-C

// The list of detected objects contains one item if multiple object detection
// wasn't enabled.
for (MLKObject *object in objects) {
  CGRect frame = object.frame;
  NSNumber *trackingID = object.trackingID;
  for (MLKObjectLabel *label in object.labels) {
    NSString *labelString =
        [NSString stringWithFormat:@"%@, %f, %lu",
                                   label.text,
                                   label.confidence,
                                   (unsigned long)label.index];
  }
}

優れたユーザー エクスペリエンスの確保

最適なユーザー エクスペリエンスを実現するには、アプリで次のガイドラインを遵守してください。

  • オブジェクトの検出が成功するかどうかは、オブジェクトの視覚的な複雑さによって決まります。イン 検出するには、対象物の視覚的な特徴の数が少ない場合、 大きな部分を占めるようにしますユーザーに 検出したい種類のオブジェクトに適した入力をキャプチャします。
  • 分類を使用するときに、落下しないオブジェクトを検出したい場合 サポートされているカテゴリに明確に分類し、不明点に対する特別な処理を実装 説明します。

また、 [ML Kit マテリアル デザイン ショーケース アプリ][showcase-link]{: .external } マテリアル デザイン ML を利用した特徴のパターン コレクション。

パフォーマンスの向上

リアルタイム アプリケーションでオブジェクト検出を使用する場合は、 実現するためのガイドラインは次のとおりです。