ML Kit を使用すると、連続する動画フレームのオブジェクトを検出して追跡できます。
ML Kit に画像を渡すと、画像内の最大 5 つのオブジェクトと、画像内の各オブジェクトの位置が検出されます。動画ストリーム内のオブジェクトを検出する場合、各オブジェクトに一意の ID が割り当てられます。この ID を使用して、オブジェクトをフレーム間でトラッキングできます。必要に応じて、大まかなオブジェクト分類を有効にして、広範なカテゴリの説明でオブジェクトにラベル付けをします。
試してみる
- サンプルアプリを試してみると、この API の使用例を確認できます。
- この API のエンドツーエンドの実装については、マテリアル デザイン ショーケース アプリをご覧ください。
始める前に
- Podfile に次の ML Kit Pod を含めます。
pod 'GoogleMLKit/ObjectDetection', '3.2.0'
- プロジェクトの Pod をインストールまたは更新したら、
.xcworkspace
を使用して Xcode プロジェクトを開きます。ML Kit は Xcode バージョン 12.4 以降でサポートされています。
1. オブジェクト検出を構成する
オブジェクトを検出して追跡するには、まず ObjectDetector
のインスタンスを作成し、必要に応じてデフォルトから変更する検出設定を指定します。
ObjectDetectorOptions
オブジェクトを使用して、ユースケースのオブジェクト検出を構成します。次の設定を変更できます。オブジェクト検出の設定 検出モード .stream
(デフォルト)|.singleImage
ストリーム モード(デフォルト)では、オブジェクト検出は非常に低いレイテンシで実行されますが、最初の数回の検出呼び出しで不完全な結果(未指定の境界ボックスやカテゴリなど)が生成されることがあります。また、ストリーム モードでは、検出機能はオブジェクトにトラッキング ID を割り当てます。これにより、フレームをまたいでオブジェクトをトラッキングできます。このモードは、オブジェクトを追跡する場合、または動画ストリームをリアルタイムで処理する場合など、低レイテンシが重要な場合に使用します。
シングル画像モードでは、オブジェクトの境界ボックスが決定された後に、オブジェクト検出の結果が返されます。分類も有効にすると、境界ボックスとカテゴリラベルの両方が使用可能になった後に結果が返されます。その結果、検出のレイテンシが長くなる可能性があります。また、シングル画像モードでは、トラッキング ID は割り当てられません。レイテンシが重要ではなく、部分的な結果を処理しない場合は、このモードを使用します。
複数のオブジェクトを検出して追跡する false
(デフォルト)|true
最大 5 つのオブジェクトを検出して追跡するか、最も視認性の高いオブジェクトのみを追跡するか(デフォルト)。
オブジェクトを分類する false
(デフォルト)|true
検出されたオブジェクトを大まかなカテゴリに分類するかどうか。有効にすると、オブジェクト検出機能はファッション アイテム、食品、家庭用品、場所、植物のカテゴリにオブジェクトを分類します。
オブジェクト検出とトラッキングの API は、次の 2 つの主要なユースケース向けに最適化されています。
- カメラのビューファインダー内で最も目立つオブジェクトのライブ検出とトラッキング。
- 静止画像内の複数のオブジェクトの検出。
このようなユースケース向けに API を構成するには:
Swift
// Live detection and tracking let options = ObjectDetectorOptions() options.shouldEnableClassification = true // Multiple object detection in static images let options = ObjectDetectorOptions() options.detectorMode = .singleImage options.shouldEnableMultipleObjects = true options.shouldEnableClassification = true
Objective-C
// Live detection and tracking MLKObjectDetectorOptions *options = [[MLKObjectDetectorOptions alloc] init]; options.shouldEnableClassification = YES; // Multiple object detection in static images MLKObjectDetectorOptions *options = [[MLKOptions alloc] init]; options.detectorMode = MLKObjectDetectorModeSingleImage; options.shouldEnableMultipleObjects = YES; options.shouldEnableClassification = YES;
ObjectDetector
のインスタンスを取得します。
Swift
let objectDetector = ObjectDetector.objectDetector() // Or, to change the default settings: let objectDetector = ObjectDetector.objectDetector(options: options)
Objective-C
MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetector]; // Or, to change the default settings: MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions: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
をオブジェクト検出のいずれかの画像処理メソッドに渡します。非同期の process(image:)
メソッドまたは同期 results()
メソッドを使用できます。
オブジェクトを非同期で検出するには:
Swift
objectDetector.process(image) { objects, error in guard error == nil else { // Error. return } guard !objects.isEmpty else { // No objects detected. return } // Success. Get object info here. // ... }
Objective-C
[objectDetector processImage:image completion:^(NSArray* _Nullable objects, NSError * _Nullable error) { if (error == nil) { return; } if (objects.count == 0) { // No objects detected. return; } // Success. Get object info here. }];
オブジェクトを同期的に検出するには:
Swift
var objects: [Object] do { objects = try objectDetector.results(in: image) } catch let error { print("Failed to detect object with error: \(error.localizedDescription).") return } guard !objects.isEmpty else { print("Object detector returned no results.") return } // Success. Get object info here.
Objective-C
NSError *error; NSArray*objects = [objectDetector resultsInImage:image error:&error]; if (error == nil) { return; } if (objects.count == 0) { // No objects detected. return; } // Success. Get object info here.
4. 検出されたオブジェクトに関する情報を取得する
画像プロセッサの呼び出しが成功すると、非同期メソッドと同期メソッドのどちらを呼び出したかに応じて、Object
のリストが完了ハンドラに渡されるか、リストが返されます。
各 Object
には次のプロパティが含まれています。
frame |
画像内のオブジェクトの位置を示す CGRect 。 |
trackingID |
複数の画像でオブジェクトを識別する整数。シングル イメージ モードでは「nil」を指定します。 |
labels |
検出機能によって返されたオブジェクトを記述するラベルの配列。検出オプション shouldEnableClassification が false に設定されている場合、プロパティは空です。 |
Swift
// objects contains one item if multiple object detection wasn't enabled. for object in objects { let frame = object.frame let trackingID = object.trackingID // If classification was enabled: let description = object.labels.enumerated().map { (index, label) in "Label \(index): \(label.text), \(label.confidence)" }.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]; ... } }
ユーザビリティとパフォーマンスの向上
最適なユーザー エクスペリエンスを実現するには、アプリで次のガイドラインを遵守してください。
- オブジェクト検出が成功するかどうかは、オブジェクトの視覚的な複雑さによって異なります。これが検出されるには、視覚的特徴が少ないオブジェクトが画像の大部分を占めている必要があります。検出するオブジェクトの種類に適した入力をキャプチャするためのガイダンスをユーザーに提供する必要があります。
- 分類を使用するときに、サポートされているカテゴリに分類されないオブジェクトを検出するには、未知のオブジェクトに対する特別な処理を実装します。
また、マテリアル デザインの機械学習を利用した機能のパターン コレクションもご覧ください。
リアルタイムのアプリケーションでストリーミング モードを使用する場合は、最適なフレームレートを得るために次のガイドラインに従ってください。
- ストリーミング モードで複数オブジェクト検出を使用しないでください。ほとんどのデバイスは適切なフレームレートを生成できません。
- 分類が不要な場合は無効にしてください。
- 動画フレームの処理には、検出機能の
results(in:)
同期 API を使用します。このメソッドをAVCaptureVideoDataOutputSampleBufferDelegate
のcaptureOutput(_, didOutput:from:)
関数から呼び出して、指定された動画フレームから同期的に結果を取得します。AVCaptureVideoDataOutput
のalwaysDiscardsLateVideoFrames
をtrue
のままにして、検出機能の呼び出しをスロットリングします。検出機能の実行中に新しい動画フレームが使用可能になると、そのフレームは破棄されます。 - 検出機能の出力を使用して入力画像にグラフィックをオーバーレイする場合は、まず ML Kit から結果を取得してから、画像とオーバーレイを 1 つのステップでレンダリングします。これにより、ディスプレイ サーフェスへのレンダリングは、処理された入力フレームごとに 1 回だけ行います。例については、ML Kit クイックスタート サンプルの updatePreviewOverlayViewWithLastFrame をご覧ください。