Phát hiện và theo dõi đối tượng bằng Bộ công cụ học máy trên iOS

Bạn có thể dùng Bộ công cụ học máy để phát hiện và theo dõi các đối tượng trên nhiều khung hình của video.

Khi bạn truyền hình ảnh của Bộ công cụ học máy, Bộ công cụ học máy sẽ trả về một danh sách tối đa 5 đối tượng được phát hiện và vị trí của chúng trong hình ảnh. Khi phát hiện trong luồng video, mỗi đối tượng đều có một mã nhận dạng mà bạn có thể sử dụng để theo dõi trên các hình ảnh. Bạn cũng có thể tùy ý bật đối tượng tương đối Phân loại để gắn nhãn các đối tượng bằng mô tả danh mục rộng.

Trước khi bắt đầu

  1. Nếu bạn chưa thêm Firebase vào ứng dụng của mình, hãy thực hiện bằng cách làm theo hướng dẫn các bước trong hướng dẫn bắt đầu sử dụng.
  2. Thêm các thư viện Bộ công cụ học máy vào Podfile của bạn:
    pod 'Firebase/MLVision', '6.25.0'
    pod 'Firebase/MLVisionObjectDetection', '6.25.0'
    
    Sau khi cài đặt hoặc cập nhật Nhóm của dự án, hãy nhớ mở Xcode dự án bằng .xcworkspace của nó.
  3. Trong ứng dụng của bạn, hãy nhập Firebase:

    Swift

    import Firebase

    Objective-C

    @import Firebase;

1. Định cấu hình trình phát hiện đối tượng

Để bắt đầu phát hiện và theo dõi các đối tượng, trước tiên hãy tạo một thực thể của VisionObjectDetector, nếu muốn chỉ định bất kỳ chế độ cài đặt trình phát hiện nào bạn muốn thay đổi so với giá trị mặc định.

  1. Định cấu hình trình phát hiện đối tượng cho trường hợp sử dụng của bạn bằng Đối tượng VisionObjectDetectorOptions. Bạn có thể thay đổi các tuỳ chọn sau cài đặt:

    Cài đặt trình phát hiện đối tượng
    Chế độ phát hiện .stream (mặc định) | .singleImage

    Ở chế độ phát trực tuyến (mặc định), trình phát hiện đối tượng chạy với mức pin rất thấp nhưng có thể dẫn đến kết quả không đầy đủ (chẳng hạn như không được chỉ định hộp giới hạn hoặc danh mục) trên một số lệnh gọi đầu tiên của trình phát hiện. Ngoài ra, ở chế độ phát trực tuyến, trình phát hiện chỉ định tính năng theo dõi Mã nhận dạng của các đối tượng mà bạn có thể dùng để theo dõi đối tượng trên nhiều khung hình. Sử dụng chế độ này khi bạn muốn theo dõi các đối tượng hoặc khi có độ trễ thấp rất quan trọng, chẳng hạn như khi xử lý luồng video trong thực tế bất cứ lúc nào.

    Ở chế độ hình ảnh đơn, trình phát hiện đối tượng sẽ chờ cho đến khi một hộp giới hạn của đối tượng và danh mục (nếu bạn đã bật tính năng phân loại) có sẵn trước khi trả về kết quả. Do vậy, độ trễ phát hiện của bạn có thể cao hơn. Ngoài ra, trong một hình ảnh , mã theo dõi không được chỉ định. Sử dụng chế độ này nếu độ trễ không quan trọng và bạn không muốn giải quyết một phần kết quả.

    Phát hiện và theo dõi nhiều đối tượng false (mặc định) | true

    Phát hiện và theo dõi tối đa 5 đối tượng hay chỉ phát hiện tối đa đối tượng đối tượng nổi bật (mặc định).

    Phân loại đối tượng false (mặc định) | true

    Liệu có phân loại các đối tượng được phát hiện thành các danh mục tương đối hay không. Khi được bật, trình phát hiện đối tượng sẽ phân loại đối tượng thành các danh mục sau: hàng thời trang, thực phẩm, đồ gia dụng, địa điểm, thực vật và những điều chưa biết.

    API theo dõi và phát hiện đối tượng được tối ưu hoá cho hai mục đích sử dụng cốt lõi này trường hợp:

    • Phát hiện trực tiếp và theo dõi đối tượng nổi bật nhất trong máy ảnh kính ngắm
    • Phát hiện nhiều đối tượng trong ảnh tĩnh

    Cách định cấu hình API cho các trường hợp sử dụng này:

    Swift

    // 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. Nhận một thực thể của FirebaseVisionObjectDetector:

    Swift

    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. Chạy trình phát hiện đối tượng

Để phát hiện và theo dõi các đối tượng, hãy làm như sau cho từng hình ảnh hoặc khung video. Nếu đã bật chế độ phát trực tuyến, bạn phải tạo các đối tượng VisionImage từ CMSampleBufferRef giây.

  1. Tạo đối tượng VisionImage bằng UIImage hoặc CMSampleBufferRef.

    Cách sử dụng UIImage:

    1. Nếu cần, hãy xoay hình ảnh để imageOrientation.up.
    2. Tạo đối tượng VisionImage bằng chế độ xoay chính xác UIImage Không chỉ định bất kỳ siêu dữ liệu xoay vòng nào—mặc định bạn phải sử dụng giá trị .topLeft.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

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

    Cách sử dụng CMSampleBufferRef:

    1. Tạo đối tượng VisionImageMetadata chỉ định của dữ liệu hình ảnh chứa trong Vùng đệm CMSampleBufferRef.

      Cách lấy hướng ảnh:

      Swift

      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;
        }
      }

      Sau đó, hãy tạo đối tượng siêu dữ liệu:

      Swift

      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. Tạo đối tượng VisionImage bằng Đối tượng CMSampleBufferRef và siêu dữ liệu xoay:

      Swift

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

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  2. Truyền VisionImage đến một trong các trình xử lý hình ảnh của trình phát hiện đối tượng . Bạn có thể sử dụng phương thức process(image:) không đồng bộ hoặc results() đồng bộ.

    Cách phát hiện đối tượng không đồng bộ:

    Swift

    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.
                        // ...
                      }];
    

    Cách phát hiện đối tượng một cách đồng bộ:

    Swift

    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. Nếu lệnh gọi đến bộ xử lý hình ảnh thành công, lệnh gọi đó sẽ chuyển danh sách VisionObject cho trình xử lý hoàn thành hoặc trả về danh sách, tuỳ thuộc vào cho dù bạn đã gọi phương thức không đồng bộ hay đồng bộ.

    Mỗi VisionObject chứa các thuộc tính sau:

    frame CGRect cho biết vị trí của đối tượng trong hình ảnh.
    trackingID Số nguyên xác định đối tượng trên các hình ảnh. Nil trong một chế độ hình ảnh.
    classificationCategory Danh mục tương đối của đối tượng. Nếu trình phát hiện vật thể không đã bật tính năng phân loại, giá trị này luôn là .unknown.
    confidence Giá trị tin cậy của việc phân loại đối tượng. Nếu đối tượng trình phát hiện không bật tính năng phân loại hoặc đối tượng được phân loại là không xác định, đây là nil.

    Swift

    // 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;
    }
    

Cải thiện khả năng hữu dụng và hiệu suất

Để có trải nghiệm người dùng tốt nhất, hãy làm theo các nguyên tắc sau trong ứng dụng của bạn:

  • Việc phát hiện được đối tượng có thành công hay không còn phụ thuộc vào độ phức tạp trực quan của đối tượng. Đồ vật nhưng có một số ít các tính năng trực quan có thể cần chiếm phần lớn hơn hình ảnh cần phát hiện. Bạn cần cung cấp cho người dùng hướng dẫn về cách chụp đầu vào phù hợp với loại đối tượng bạn muốn phát hiện.
  • Khi sử dụng tính năng phân loại, nếu bạn muốn phát hiện các đối tượng không nằm trong rõ ràng vào các danh mục được hỗ trợ, triển khai cách xử lý đặc biệt đối với các trường hợp .

Ngoài ra, hãy xem [Ứng dụng giới thiệu Material Design của bộ công cụ học máy][đường liên kết giới thiệu]{: .external } và Thiết kế Material Design Bộ sưu tập Mẫu cho các tính năng dựa trên công nghệ học máy.

Khi sử dụng chế độ truyền trực tuyến trong một ứng dụng theo thời gian thực, hãy làm theo các nguyên tắc sau để đạt được tốc độ khung hình tốt nhất:

  • Đừng dùng tính năng phát hiện nhiều vật thể ở chế độ phát trực tuyến, vì hầu hết các thiết bị sẽ không dùng được có thể tạo đủ tốc độ khung hình.

  • Hãy tắt tính năng phân loại nếu bạn không cần.

  • Điều tiết lệnh gọi đến trình phát hiện. Nếu một khung video mới trong khi trình phát hiện đang chạy, hãy thả khung hình.
  • Nếu bạn đang sử dụng đầu ra của trình phát hiện để phủ đồ hoạ lên hình ảnh đầu vào, trước tiên hãy lấy kết quả từ Bộ công cụ học máy, sau đó kết xuất hình ảnh và phủ lên trên trong một bước duy nhất. Khi làm vậy, bạn sẽ kết xuất lên giao diện màn hình một lần cho mỗi khung đầu vào. Xem previewOverlayViewFIRDetectionOverlayView trong ứng dụng mẫu Showcase.