ML Kit を使用すると、連続する動画フレーム内のオブジェクトを検出してトラックできます。
ML Kit に画像を渡すと、画像内の最大 5 つのオブジェクトと、画像内の各オブジェクトの位置が検出されます。動画ストリーム内のオブジェクトを検出する場合、各オブジェクトには一意の 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 をご覧ください。