Wykrywanie i śledzenie obiektów za pomocą ML Kit na iOS

Za pomocą ML Kit możesz wykrywać i śledzić obiekty w kolejnych klatkach wideo.

Gdy przekazujesz obraz do ML Kit, wykrywa on maksymalnie 5 obiektów. wraz z położeniem każdego obiektu na obrazie. Podczas wykrywania obiektów w strumieni wideo, każdy obiekt ma unikalny identyfikator, którego możesz użyć do śledzenia od klatki do klatki. Możesz też opcjonalnie włączyć obiekt przybliżony klasyfikację, która oznacza etykietami obiekty o szerokim opisie kategorii.

Wypróbuj

Zanim zaczniesz

  1. W pliku Podfile umieść te pody ML Kit:
    pod 'GoogleMLKit/ObjectDetection', '3.2.0'
    
  2. Po zainstalowaniu lub zaktualizowaniu podów projektu otwórz projekt Xcode za pomocą .xcworkspace ML Kit jest obsługiwany w Xcode w wersji 12.4 lub nowszej.

1. Konfigurowanie detektora obiektów

Aby wykrywać i śledzić obiekty, najpierw utwórz instancję ObjectDetector i opcjonalnie wybierz ustawienia wzorca do wykrywania treści, które chcesz niż domyślna.

  1. Skonfiguruj detektor obiektów na potrzeby swojego przypadku użycia za pomocą ObjectDetectorOptions obiekt. Możesz zmienić te ustawienia: ustawienia:

    Ustawienia wykrywania obiektów
    Tryb wykrywania .stream (domyślna) | .singleImage

    W trybie strumienia (domyślny) detektor obiektów działa z bardzo niską wydajnością czas oczekiwania, ale może dawać niepełne wyniki (np. nieokreślone) ramki ograniczające lub kategorie) na kilku pierwszych wywołaniach wzorca. Ponadto w trybie strumienia detektor przypisuje śledzenie Identyfikatory obiektów, które mogą służyć do śledzenia obiektów w ramkach. Użyj tego trybu, jeśli chcesz śledzić obiekty lub gdy małe opóźnienie ma duże znaczenie, np. podczas przetwarzania strumieni wideo w czasie rzeczywistym, obecnie się znajdujesz.

    W trybie pojedynczego obrazu detektor obiektów zwraca wynik. po określeniu ramki ograniczającej obiektu. Jeśli włączysz też klasyfikacja zwraca wynik po ramce ograniczającej i . W związku z tym wykrywanie czas oczekiwania jest potencjalnie większy. Ponadto w trybie pojedynczego obrazu śledzenie Identyfikatory nie są przypisywane. Użyj tego trybu, jeśli czas oczekiwania nie jest krytyczny bo nie chcesz mieć do czynienia z częściowymi wynikami.

    Wykrywanie i śledzenie wielu obiektów false (domyślna) | true

    Określa, czy można wykryć i śledzić do pięciu obiektów, czy tylko najbardziej. widoczny obiekt (domyślnie).

    Klasyfikowanie obiektów false (domyślna) | true

    Określa, czy należy sklasyfikować wykryte obiekty w przybliżonych kategoriach. Gdy ta opcja jest włączona, detektor obiektów klasyfikuje obiekty w następujące kategorie: artykuły modowe, żywność, artykuły wyposażenia domu, miejsc i roślin.

    Interfejs API wykrywania i śledzenia obiektów jest zoptymalizowany pod kątem tych dwóch podstawowych zastosowań przypadki:

    • Wykrywanie na żywo i śledzenie najbardziej widocznego obiektu w kamerze wizjer.
    • Wykrywanie wielu obiektów na obrazie statycznym.

    Aby skonfigurować interfejs API pod kątem tych przypadków użycia:

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;
  1. Pobierz instancję 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. Przygotowywanie obrazu wejściowego

Aby wykrywać i śledzić obiekty, wykonaj te czynności w przypadku każdego obrazu lub klatki filmu. Jeśli masz włączony tryb strumieniowania, musisz utworzyć obiekty VisionImage z CMSampleBuffer.

Utwórz obiekt VisionImage za pomocą UIImage lub CMSampleBuffer.

Jeśli używasz UIImage, wykonaj te czynności:

  • Utwórz obiekt VisionImage za pomocą UIImage. Pamiętaj, by określić prawidłowy .orientation.

    Swift

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    Objective-C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

Jeśli używasz CMSampleBuffer, wykonaj te czynności:

  • Określ orientację danych zdjęć zawartych w pliku CMSampleBuffer

    Aby sprawdzić orientację obrazu:

    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;
      }
    }
          
  • Utwórz obiekt VisionImage za pomocą CMSampleBuffer obiekt i orientacja:

    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. Przetwarzanie zdjęcia

Przekaż VisionImage do jednego z procesów przetwarzania obrazu detektora obiektów . Możesz użyć asynchronicznej metody process(image:) lub synchroniczną metodę results().

Aby asynchronicznie wykrywać obiekty:

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

Aby synchronicznie wykrywać obiekty:

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. Uzyskiwanie informacji o wykrytych obiektach

Jeśli wywołanie procesora zdjęć się powiedzie, przekazywana jest lista Objects do modułu obsługi uzupełniania lub zwraca listę, w zależności od niezależnie od tego, czy została użyta metoda asynchroniczna czy synchroniczna.

Każdy element Object zawiera te właściwości:

frame CGRect wskazujący położenie obiektu w .
trackingID Liczba całkowita, która identyfikuje obiekt na obrazach, lub „nil” w w trybie pojedynczego obrazu.
labels Tablica etykiet opisujących obiekt zwrócony przez detektor. Właściwość jest pusta, jeśli opcja detektora jest pusta shouldEnableClassification ma wartość 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];
    ...
  }
}

Poprawa łatwości obsługi i wydajności

Aby zadbać o wygodę użytkowników, przestrzegaj tych wytycznych:

  • Pomyślne wykrycie obiektu zależy od jego złożoności wizualnej. W są wykrywane, obiekty z niewielką liczbą funkcji wizualnych mogą wymagać aby zająć większą część obrazu. Należy dostarczyć użytkownikom wskazówki na temat tego, przechwytywanie danych wejściowych, które dobrze działają z rodzajami obiektów, które chcesz wykrywać.
  • Gdy używasz klasyfikacji, aby wykrywać obiekty, które nie wypadają do obsługiwanych kategorii, zastosować specjalną obsługę nieznanych obiektów.

Zwróć też uwagę na interfejs Material Design, Kolekcja Wzorce funkcji opartych na systemach uczących się.

Jeśli używasz trybu strumieniowania w aplikacji działającej w czasie rzeczywistym, postępuj zgodnie z tymi wskazówkami, aby: aby uzyskać najlepszą liczbę klatek:

  • Nie używaj wykrywania wielu obiektów w trybie strumieniowania, ponieważ większość urządzeń którzy są w stanie wygenerować odpowiednią liczbę klatek na sekundę.
  • Wyłącz klasyfikację, jeśli jej nie potrzebujesz.
  • Do przetwarzania klatek wideo używaj synchronicznego interfejsu API results(in:) detektora. Zadzwoń do nas tę metodę z AVCaptureVideoDataOutputSampleBufferDelegate . captureOutput(_, didOutput:from:), aby synchronicznie pobierać wyniki dotyczące danego filmu ramki. Zachowaj AVCaptureVideoDataOutput: alwaysDiscardsLateVideoFrames jako true, aby ograniczyć wywołania detektora. Jeśli nowy gdy klatka wideo jest dostępna, gdy jest uruchomiony detektor, zostanie usunięta.
  • Jeśli użyjesz danych wyjściowych detektora do nakładania grafiki na obrazu wejściowego, najpierw pobierz wynik z ML Kit, a następnie wyrenderuj obraz i nakładanie nakładek w jednym kroku. W ten sposób renderowanie na powierzchni tylko raz na każdą przetworzoną ramkę wejściową. Zobacz updatePreviewOverlayViewWithLastFrame. znajdziesz na przykład w krótkim wprowadzeniu do korzystania z ML Kit.