在 iOS 上使用 ML Kit 來偵測和追蹤對象

您可以使用 ML Kit 跨視頻幀檢測和跟踪對象。

當您傳遞 ML Kit 圖像時,ML Kit 會為每張圖像返回一個列表,其中包含最多五個檢測到的對象及其在圖像中的位置。在視頻流中檢測對象時,每個對像都有一個 ID,您可以使用該 ID 跨圖像跟踪對象。您還可以選擇啟用粗略的對象分類,用廣泛的類別描述標記對象。

在你開始之前

  1. 如果您尚未將 Firebase 添加到您的應用,請按照入門指南中的步驟進行操作。
  2. 在您的 Podfile 中包含 ML Kit 庫:
    pod 'Firebase/MLVision', '6.25.0'
    pod 'Firebase/MLVisionObjectDetection', '6.25.0'
    
    安裝或更新項目的 Pod 後,請務必使用其.xcworkspace打開您的 Xcode 項目。
  3. 在您的應用中,導入 Firebase:

    迅速

    import Firebase

    Objective-C

    @import Firebase;

1.配置物體檢測器

要開始檢測和跟踪對象,首先創建一個VisionObjectDetector實例,可選擇指定要更改默認設置的任何檢測器設置。

  1. 使用VisionObjectDetectorOptions對象為您的用例配置對象檢測器。您可以更改以下設置:

    物體檢測器設置
    檢測方式.stream (默認) | .singleImage

    在流模式(默認)下,對象檢測器以非常低的延遲運行,但在檢測器的前幾次調用中可能會產生不完整的結果(例如未指定的邊界框或類別)。此外,在流模式下,檢測器會為對象分配跟踪 ID,您可以使用這些 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
    
  2. 獲取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對象。

  1. 使用UIImageCMSampleBufferRef創建VisionImage對象。

    要使用UIImage

    1. 如有必要,旋轉圖像,使其imageOrientation屬性為.up
    2. 使用正確旋轉的UIImage創建一個VisionImage對象。不要指定任何旋轉元數據——必須使用默認值.topLeft

      迅速

      let image = VisionImage(image: uiImage)

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

    要使用CMSampleBufferRef

    1. 創建一個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];
    2. 使用CMSampleBufferRef對象和旋轉元數據創建一個VisionImage對象:

      迅速

      let image = VisionImage(buffer: sampleBuffer)
      image.metadata = metadata

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  2. 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.
    // ...
    
  3. 如果對圖像處理器的調用成功,它要么將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 Patterns for machine learning-driven features collection。

在實時應用程序中使用流媒體模式時,請遵循以下準則以實現最佳幀速率:

  • 不要在流模式下使用多對象檢測,因為大多數設備無法產生足夠的幀速率。

  • 如果不需要,請禁用分類。

  • 限制對檢測器的調用。如果在檢測器運行時有新的視頻幀可用,請丟棄該幀。
  • 如果您使用檢測器的輸出在輸入圖像上疊加圖形,首先從 ML Kit 中獲取結果,然後在一個步驟中渲染圖像並疊加。通過這樣做,您只為每個輸入幀渲染到顯示表面一次。有關示例,請參閱展示示例應用程序中的previewOverlayViewFIRDetectionOverlayView類。