您可以使用 ML Kit 跨視訊幀檢測和追蹤物件。
當您傳遞 ML Kit 映像時,ML Kit 會為每個影像傳回最多五個偵測到的物件及其在影像中的位置的清單。偵測視訊串流中的物件時,每個物件都有一個 ID,可用於跨影像追蹤物件。您也可以選擇啟用粗略物件分類,這會使用廣泛的類別描述來標記物件。
在你開始之前
- 如果您尚未將 Firebase 新增至您的應用程式中,請按照入門指南中的步驟進行操作。
- 在 Podfile 中包含 ML Kit 函式庫:
pod 'Firebase/MLVision', '6.25.0' pod 'Firebase/MLVisionObjectDetection', '6.25.0'
安裝或更新專案的 Pod 後,請務必使用其.xcworkspace
開啟 Xcode 專案。 - 在您的應用程式中,導入 Firebase:
迅速
import Firebase
Objective-C
@import Firebase;
1. 配置物體偵測器
若要開始偵測和追蹤對象,請先建立VisionObjectDetector
的實例,可以選擇指定要變更預設設定的任何偵測器設定。
使用
VisionObjectDetectorOptions
物件為您的用例配置物件偵測器。您可以更改以下設定:物體偵測器設定 檢測方式 .stream
(預設)|.singleImage
在流程模式(預設)下,物件偵測器以非常低的延遲運行,但在偵測器的前幾次呼叫時可能會產生不完整的結果(例如未指定的邊界框或類別)。此外,在串流模式下,偵測器會將追蹤 ID 指派給對象,您可以使用它來跨幀追蹤對象。當您想要追蹤物件或低延遲很重要時(例如即時處理視訊串流時),請使用此模式。
在單一影像模式下,物件偵測器會等待,直到偵測到的物件的邊界框和(如果啟用了分類)類別可用,然後才傳回結果。因此,檢測延遲可能會更高。此外,在單一影像模式下,不會指派追蹤 ID。如果延遲並不重要且您不想處理部分結果,請使用此模式。
偵測並追蹤多個物體 false
(預設)|true
是否檢測和追蹤最多五個物件或僅檢測和追蹤最突出的物件(預設)。
將物體分類 false
(預設)|true
是否將偵測到的物件分類為粗略類別。啟用後,物件偵測器會將物件分為以下類別:時尚商品、食品、家居用品、地點、植物和未知。
物件偵測和追蹤 API 針對這兩個核心用例進行了最佳化:
- 即時偵測並追蹤相機取景器中最突出的物體
- 偵測靜態影像中的多個對象
若要為這些用例配置 API:
迅速
// Live detection and tracking let options = VisionObjectDetectorOptions() options.detectorMode = .stream options.shouldEnableMultipleObjects = false options.shouldEnableClassification = true // Optional // Multiple object detection in static images let options = VisionObjectDetectorOptions() options.detectorMode = .singleImage options.shouldEnableMultipleObjects = true options.shouldEnableClassification = true // Optional
Objective-C
// Live detection and tracking FIRVisionObjectDetectorOptions *options = [[FIRVisionObjectDetectorOptions alloc] init]; options.detectorMode = FIRVisionObjectDetectorModeStream; options.shouldEnableMultipleObjects = NO; options.shouldEnableClassification = YES; // Optional // Multiple object detection in static images FIRVisionObjectDetectorOptions *options = [[FIRVisionObjectDetectorOptions alloc] init]; options.detectorMode = FIRVisionObjectDetectorModeSingleImage; options.shouldEnableMultipleObjects = YES; options.shouldEnableClassification = YES; // Optional
取得
FirebaseVisionObjectDetector
的實例:迅速
let objectDetector = Vision.vision().objectDetector() // Or, to change the default settings: let objectDetector = Vision.vision().objectDetector(options: options)
Objective-C
FIRVisionObjectDetector *objectDetector = [[FIRVision vision] objectDetector]; // Or, to change the default settings: FIRVisionObjectDetector *objectDetector = [[FIRVision vision] objectDetectorWithOptions:options];
2. 運行物體偵測器
若要偵測和追蹤對象,請對每個影像或視訊畫面執行以下操作。如果啟用了流模式,則必須從CMSampleBufferRef
建立VisionImage
物件。
使用
UIImage
或CMSampleBufferRef
建立VisionImage
物件。使用
UIImage
:- 如有必要,旋轉影像,使其
imageOrientation
屬性為.up
。 - 使用正確旋轉的
UIImage
建立VisionImage
物件。不要指定任何旋轉元資料 - 必須使用預設值.topLeft
。迅速
let image = VisionImage(image: uiImage)
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
使用
CMSampleBufferRef
:建立一個
VisionImageMetadata
對象,該對象指定CMSampleBufferRef
緩衝區中包含的圖像資料的方向。若要取得影像方向:
迅速
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 } }
Objective-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 )
Objective-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];
- 使用
CMSampleBufferRef
物件和旋轉元資料建立VisionImage
物件:迅速
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- 如有必要,旋轉影像,使其
將
VisionImage
傳遞給物件偵測器的影像處理方法之一。您可以使用非同步process(image:)
方法或同步results()
方法。非同步檢測對象:
迅速
objectDetector.process(image) { detectedObjects, error in guard error == nil else { // Error. return } guard let detectedObjects = detectedObjects, !detectedObjects.isEmpty else { // No objects detected. return } // Success. Get object info here. // ... }
Objective-C
[objectDetector processImage:image completion:^(NSArray<FIRVisionObject *> * _Nullable objects, NSError * _Nullable error) { if (error == nil) { return; } if (objects == nil | objects.count == 0) { // No objects detected. return; } // Success. Get object info here. // ... }];
同步檢測對象:
迅速
var results: [VisionObject]? = nil do { results = try objectDetector.results(in: image) } catch let error { print("Failed to detect object with error: \(error.localizedDescription).") return } guard let detectedObjects = results, !detectedObjects.isEmpty else { print("Object detector returned no results.") return } // ...
Objective-C
NSError *error; NSArray<FIRVisionObject *> *objects = [objectDetector resultsInImage:image error:&error]; if (error == nil) { return; } if (objects == nil | objects.count == 0) { // No objects detected. return; } // Success. Get object info here. // ...
如果對影像處理器的呼叫成功,它會將
VisionObject
列表傳遞給完成處理程序或傳回該列表,這取決於您呼叫的是非同步方法還是同步方法。每個
VisionObject
包含以下屬性:frame
指示影像中物件位置的 CGRect
。trackingID
一個整數,用於識別影像中的物件。單影像模式下為零。 classificationCategory
物件的粗略類別。如果物件偵測器未啟用分類,則始終為 .unknown
。confidence
物件分類的置信度值。如果物件偵測器未啟用分類,或物件被分類為未知,則值為 nil
。迅速
// detectedObjects contains one item if multiple object detection wasn't enabled. for obj in detectedObjects { let bounds = obj.frame let id = obj.trackingID // If classification was enabled: let category = obj.classificationCategory let confidence = obj.confidence }
Objective-C
// The list of detected objects contains one item if multiple // object detection wasn't enabled. for (FIRVisionObject *obj in objects) { CGRect bounds = obj.frame; if (obj.trackingID) { NSInteger id = obj.trackingID.integerValue; } // If classification was enabled: FIRVisionObjectCategory category = obj.classificationCategory; float confidence = obj.confidence.floatValue; }
提高可用性和效能
為了獲得最佳用戶體驗,請在您的應用程式中遵循以下準則:
- 成功的物件偵測取決於物件的視覺複雜性。具有少量視覺特徵的物件可能需要佔據影像的較大部分才能被偵測。您應該為使用者提供有關捕獲輸入的指導,該輸入與您想要檢測的物件類型配合良好。
- 使用分類時,如果您想要偵測未完全屬於支援類別的對象,請對未知對象實作特殊處理。
另外,請查看 [ML Kit Material Design 展示應用][showcase-link]{: .external } 和機器學習驅動功能集合的 Material Design 模式。
在即時應用程式中使用串流模式時,請遵循以下準則以獲得最佳幀速率:
不要在串流模式下使用多個物件偵測,因為大多數裝置無法產生足夠的幀速率。
如果不需要,請停用分類。
- 對檢測器的節流呼叫。如果偵測器運作時有新的視訊幀可用,則丟棄該幀。
- 如果您使用偵測器的輸出將圖形疊加在輸入影像上,請先從 ML Kit 取得結果,然後一步渲染影像並疊加。透過這樣做,每個輸入幀只需渲染到顯示表面一次。有關範例,請參閱展示範例應用程式中的PreviewOverlayView和FIRDetectionOverlayView類別。