Wykrywanie pozycji za pomocą ML Kit na iOS

ML Kit udostępnia 2 zoptymalizowane pakiety SDK do wykrywania pozycji.

Nazwa pakietu SDKPoseDetectionPoseDetectionAccurate
ImplementacjaZasoby podstawowego wzorca do wykrywania treści są statycznie połączone z aplikacją w czasie kompilacji.Zasoby zapewniające dokładny detektor są statycznie połączone z aplikacją w czasie kompilacji.
Rozmiar aplikacjiDo 29,6 MBDo 33,2 MB
WystępyiPhone X: ~45 kl./siPhone X: ~29 kl./s

Wypróbuj

Zanim zaczniesz

  1. W pliku Podfile umieść te pody ML Kit:

    # If you want to use the base implementation:
    pod 'GoogleMLKit/PoseDetection', '3.2.0'
    
    # If you want to use the accurate implementation:
    pod 'GoogleMLKit/PoseDetectionAccurate', '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 13.2.1 lub nowszej.

1. Utwórz instancję PoseDetector

Aby wykryć pozę na obrazie, najpierw utwórz instancję PoseDetector i opcjonalnie określ ustawienia wzorca do wykrywania treści.

Opcje: PoseDetector

Tryb wykrywania

PoseDetector działa w 2 trybach wykrywania. Wybierz taki, który pasuje do Twojego przypadku użycia.

stream (domyślnie)
Wykrywanie pozycji najpierw wykryje najwyższą osobę na zdjęciu, a potem uruchomi wykrywanie pozycji. W kolejnych klatkach etap wykrywania osoby nie zostanie przeprowadzony, chyba że osoba ta pojawi się w cieniu lub nie będzie już wykryta z dużym prawdopodobieństwem. Wykrywanie pozycji spróbuje śledzić najbardziej widoczną osobę i przy każdym wnioskowaniu określać pozycję. Pozwala to skrócić czas oczekiwania i płynnie wykrywać wykrywanie. Użyj tego trybu, gdy chcesz wykryć pozę w strumieniu wideo.
singleImage
Wykrywanie pozycji wykryje osobę, a następnie uruchomi wykrywanie pozycji. Etap wykrywania osób będzie przeprowadzany dla każdego obrazu, więc opóźnienia będą większe i nie będzie funkcji śledzenia osób. Użyj tego trybu, gdy wykrywasz pozycję na obrazach statycznych lub gdy śledzenie nie jest pożądane.

Określ opcje wykrywania pozycji:

Swift

// Base pose detector with streaming, when depending on the PoseDetection SDK
let options = PoseDetectorOptions()
options.detectorMode = .stream

// Accurate pose detector on static images, when depending on the
// PoseDetectionAccurate SDK
let options = AccuratePoseDetectorOptions()
options.detectorMode = .singleImage

Objective-C

// Base pose detector with streaming, when depending on the PoseDetection SDK
MLKPoseDetectorOptions *options = [[MLKPoseDetectorOptions alloc] init];
options.detectorMode = MLKPoseDetectorModeStream;

// Accurate pose detector on static images, when depending on the
// PoseDetectionAccurate SDK
MLKAccuratePoseDetectorOptions *options =
    [[MLKAccuratePoseDetectorOptions alloc] init];
options.detectorMode = MLKPoseDetectorModeSingleImage;

Na koniec pobierz wystąpienie PoseDetector. Przekaż określone opcje:

Swift

let poseDetector = PoseDetector.poseDetector(options: options)

Objective-C

MLKPoseDetector *poseDetector =
    [MLKPoseDetector poseDetectorWithOptions:options];

2. Przygotowywanie obrazu wejściowego

Aby wykryć pozycje, 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 konta UIImage, wykonaj te czynności:

  • Utwórz obiekt VisionImage z UIImage. Pamiętaj, aby podać prawidłowy atrybut .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 konta CMSampleBuffer, wykonaj te czynności:

  • Określ orientację danych obrazu zawartych w pliku CMSampleBuffer.

    Aby określić orientację zdjęcia:

    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, używając obiektu CMSampleBuffer i orientacji:

    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 obrazu

Przekaż VisionImage do jednej z metod przetwarzania obrazu stosowanych przez detektor pozycji. Możesz użyć asynchronicznej metody process(image:) lub synchronicznej results().

Aby wykrywać obiekty synchronicznie:

Swift

var results: [Pose]
do {
  results = try poseDetector.results(in: image)
} catch let error {
  print("Failed to detect pose with error: \(error.localizedDescription).")
  return
}
guard let detectedPoses = results, !detectedPoses.isEmpty else {
  print("Pose detector returned no results.")
  return
}

// Success. Get pose landmarks here.

Objective-C

NSError *error;
NSArray *poses = [poseDetector resultsInImage:image error:&error];
if (error != nil) {
  // Error.
  return;
}
if (poses.count == 0) {
  // No pose detected.
  return;
}

// Success. Get pose landmarks here.

Aby asynchronicznie wykrywać obiekty:

Swift

poseDetector.process(image) { detectedPoses, error in
  guard error == nil else {
    // Error.
    return
  }
  guard !detectedPoses.isEmpty else {
    // No pose detected.
    return
  }

  // Success. Get pose landmarks here.
}

Objective-C

[poseDetector processImage:image
                completion:^(NSArray * _Nullable poses,
                             NSError * _Nullable error) {
                    if (error != nil) {
                      // Error.
                      return;
                    }
                    if (poses.count == 0) {
                      // No pose detected.
                      return;
                    }

                    // Success. Get pose landmarks here.
                  }];

4. Uzyskaj informacje o wykrytej pozycji

Jeśli na obrazie zostanie wykryta osoba, interfejs API wykrywania pozycji przekazuje tablicę obiektów Pose do modułu obsługi ukończenia lub zwraca tablicę w zależności od tego, czy wywołano metodę asynchroniczną czy synchroniczną.

Jeśli dana osoba nie była w pełni widoczna na zdjęciu, model przypisuje brakujące współrzędne punktów orientacyjnych poza ramką i nadaje im niskie wartości InFrameConfidence.

Jeśli nie wykryto żadnej osoby, tablica jest pusta.

Swift

for pose in detectedPoses {
  let leftAnkleLandmark = pose.landmark(ofType: .leftAnkle)
  if leftAnkleLandmark.inFrameLikelihood > 0.5 {
    let position = leftAnkleLandmark.position
  }
}

Objective-C

for (MLKPose *pose in detectedPoses) {
  MLKPoseLandmark *leftAnkleLandmark =
      [pose landmarkOfType:MLKPoseLandmarkTypeLeftAnkle];
  if (leftAnkleLandmark.inFrameLikelihood > 0.5) {
    MLKVision3DPoint *position = leftAnkleLandmark.position;
  }
}

Wskazówki dotyczące poprawy skuteczności

Jakość wyników zależy od jakości obrazu wejściowego:

  • Aby narzędzie ML Kit mogło dokładnie wykryć pozycję osoby, osoba na obrazie powinna być reprezentowana przez wystarczającą ilość danych pikseli. Najlepsze wyniki uzyskasz, jeśli osoba zdjęcia będzie mieć rozmiar co najmniej 256 x 256 pikseli.
  • Jeśli wykryjesz pozycję w aplikacji przesyłających dane w czasie rzeczywistym, możesz też wziąć pod uwagę ogólne wymiary obrazów wejściowych. Mniejsze obrazy mogą być przetwarzane szybciej. Aby zmniejszyć opóźnienie, zrób zdjęcia w niższej rozdzielczości, pamiętaj przy tym o powyższych wymaganiach dotyczących rozdzielczości i upewnij się, że obiekt zajmuje jak największą część obrazu.
  • Słaba ostrość obrazu może również wpływać na dokładność. Jeśli nie uzyskasz zadowalających wyników, poproś użytkownika o ponowne zrobienie zdjęcia.

Jeśli chcesz używać wykrywania pozycji w aplikacji korzystającej z danych w czasie rzeczywistym, postępuj zgodnie z tymi wskazówkami, aby uzyskać najlepszą liczbę klatek na sekundę:

  • Użyj podstawowego pakietu PoseDetection SDK i trybu wykrywania stream.
  • Rozważ robienie zdjęć w niższej rozdzielczości. Pamiętaj jednak o wymaganiach dotyczących wymiarów obrazów w tym interfejsie API.
  • Do przetwarzania klatek wideo użyj synchronicznego interfejsu API results(in:) wzorca. Wywołaj tę metodę z funkcji AVCaptureVideoDataOutputSampleBufferDelegate w funkcji captureOutput(_, didOutput:from:), aby synchronicznie pobierać wyniki z danej klatki wideo. Aby ograniczać wywołania do wzorca, ustaw opcję AVCaptureVideoDataOutput na wartość alwaysDiscardsLateVideoFrames na wartość true (prawda). Jeśli w działaniu czujnika pojawi się nowa klatka wideo, zostanie usunięta.
  • Jeśli używasz danych wyjściowych detektora do nakładania grafiki na obraz wejściowy, najpierw pobierz wynik z ML Kit, a następnie w jednym kroku wyrenderuj obraz i nakładkę. Dzięki temu renderujesz na wyświetlaczu tylko raz dla każdej przetworzonej ramki wejściowej. Przykład znajdziesz w klasach previewOverlayView i MLKDetectionOverlayView w przykładowej aplikacji z prezentacją.

Dalsze kroki