Catch up on everthing we announced at this year's Firebase Summit. Learn more

在 iOS 上使用 ML Kit 檢測和跟踪對象

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

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

在你開始之前

  1. 如果您尚未添加火力地堡到您的應用程序,通過遵循的步驟做這樣的入門指南
  2. :在您的Podfile的ML套件庫
    pod 'Firebase/MLVision', '6.25.0'
    pod 'Firebase/MLVisionObjectDetection', '6.25.0'
    
    您安裝或更新項目的吊艙後,一定要使用它的打開你的Xcode項目.xcworkspace
  3. 在您的應用中,導入 Firebase:

    迅速

    import Firebase

    目標-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
    

    目標-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)
    

    目標-C

    FIRVisionObjectDetector *objectDetector = [[FIRVision vision] objectDetector];
    
    // Or, to change the default settings:
    FIRVisionObjectDetector *objectDetector = [[FIRVision vision] objectDetectorWithOptions:options];
    

2. 運行物體檢測器

要檢測和跟踪對象,請對每個圖像或視頻幀執行以下操作。如果啟用了流模式,你必須創建VisionImage從對象CMSampleBufferRef秒。

  1. 創建VisionImage使用對象UIImageCMSampleBufferRef

    要使用UIImage

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

      迅速

      let image = VisionImage(image: uiImage)

      目標-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
          }
      }

      目標-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
      )

      目標-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. 創建VisionImage使用對象CMSampleBufferRef對象和旋轉元數據:

      迅速

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

      目標-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.
      // ...
    }
    

    目標-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
    }
    
    // ...
    

    目標-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 s到完成處理或返回列表,這取決於您是否稱為異步或同步方法。

    每個VisionObject包含以下屬性:

    frameCGRect指示圖像中的對象的位置。
    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
    }
    

    目標-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套件材料設計展示應用] [展示鏈接] {:.external}和材料設計模式的學習機供電的功能集合。

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

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

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

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