Wykrywanie pozycji za pomocą ML Kit na iOS

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

Nazwa pakietu SDKPoseDetectionPoseDetectionAccurate
ImplementacjaZasoby dla podstawowego modułu wykrywającego są statycznie powiązane z aplikacją w momencie kompilacji.Komponenty dokładnego detektora są statycznie powiązane z aplikacją w momencie kompilacji.
Rozmiar aplikacjiDo 29,6 MBDo 33,2 MB
WynikiiPhone X: ok. 45 FPSiPhone X: około 29 FPS

Wypróbuj

Zanim zaczniesz

  1. Dodaj do pliku Podfile te pody ML Kit:

    # If you want to use the base implementation:
    pod 'GoogleMLKit/PoseDetection', '7.0.0'
    
    # If you want to use the accurate implementation:
    pod 'GoogleMLKit/PoseDetectionAccurate', '7.0.0'
    
  2. Po zainstalowaniu lub zaktualizowaniu modułów projektu otwórz projekt Xcode, używając jego xcworkspace. ML Kit jest obsługiwany w Xcode w wersji 13.2.1 lub nowszej.

1. Utwórz instancję PoseDetector

Aby wykryć pozę na zdjęciu, najpierw utwórz instancję funkcji PoseDetector i opcjonalnie określ ustawienia detektora.

Opcje: PoseDetector

Tryb wykrywania

Urządzenie PoseDetector działa w 2 trybach wykrywania. Pamiętaj, aby wybrać model, który odpowiada Twoim potrzebom.

stream (domyślnie)
Detektor pozy najpierw wykryje najbardziej widoczną osobę na zdjęciu, a potem przeprowadzi wykrywanie pozy. W kolejnych klatkach krok wykrywania osób nie będzie wykonywany, chyba że osoba zostanie zasłonięta lub nie będzie już wykrywana z wysoką pewnością. Detektor postawy będzie próbować śledzić najbardziej widoczną osobę i zwracać jej postawę w każdej prognozie. Pozwala to zmniejszyć opóźnienia i usprawnić wykrywanie. Użyj tego trybu, gdy chcesz wykrywać pozę w strumieniu wideo.
singleImage
Wykrywacz pozy wykryje osobę, a następnie przeprowadzi wykrywanie pozy. Etap wykrywania osób będzie wykonywany w przypadku każdego obrazu, więc opóźnienie będzie większe, a śledzenie osób nie będzie możliwe. Używaj tego trybu, gdy używasz wykrywania pozycji ciała na zdjęciach statycznych lub gdy śledzenie nie jest potrzebne.

Określ opcje detektora pozy:

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 instancję PoseDetector. Przekaż określone opcje:

Swift

let poseDetector = PoseDetector.poseDetector(options: options)

Objective-C

MLKPoseDetector *poseDetector =
    [MLKPoseDetector poseDetectorWithOptions:options];

2. Przygotuj obraz wejściowy

Aby wykryć pozy, wykonaj te czynności w przypadku każdego obrazu lub każdego kadru filmu. Jeśli masz włączony tryb strumieniowania, musisz utworzyć obiekty VisionImageCMSampleBuffer.

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

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

  • Utwórz obiekt VisionImage za pomocą funkcji UIImage. Pamiętaj, aby podać prawidłowy adres .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 obrazu zawartych w elemencie CMSampleBuffer.

    Aby uzyskać 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, używając obiektu CMSampleBuffer i jego 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 w detektorze pozy. Możesz użyć asynchronicznej metody process(image:) lub synchronicznej metody 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 wykrywać obiekty asynchronicznie:

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. Uzyskiwanie informacji o wykryciu pozy

Jeśli na obrazie zostanie wykryta osoba, interfejs API wykrywania pozycji ciała przekaże tablicę obiektów Pose do metody obsługi zakończenia lub zwróci tablicę, w zależności od tego, czy wywołano metodę asynchroniczną czy synchroniczną.

Jeśli osoba nie była w pełni widoczna na zdjęciu, model przypisuje brakujące współrzędne punktów orientacyjnych poza kadrem i przypisuje 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 zwiększania skuteczności

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

  • Aby ML Kit mógł dokładnie wykrywać pozę, osoba na zdjęciu powinna być reprezentowana przez wystarczającą ilość danych pikseli. Aby uzyskać najlepsze wyniki, obiekt powinien mieć co najmniej 256 × 256 pikseli.
  • Jeśli wykrywanie pozy odbywa się w aplikacji w czasie rzeczywistym, warto też wziąć pod uwagę ogólne wymiary obrazów wejściowych. Mniejsze obrazy można przetwarzać szybciej, więc aby zmniejszyć opóźnienie, rób zdjęcia w niższej rozdzielczości, pamiętając o wymienionych powyżej wymaganiach dotyczących rozdzielczości i upewnij się, że fotografowany obiekt zajmuje jak największą część obrazu.
  • Na dokładność może też wpływać niewłaściwe ustawienie ostrości. Jeśli nie uzyskasz zadowalających wyników, poproś użytkownika o ponowne zrobienie zdjęcia.

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

  • Użyj podstawowego pakietu SDK wykrywania pozycji i trybu wykrywania stream.
  • Rozważ robienie zdjęć w niższej rozdzielczości. Pamiętaj jednak o wymaganiach dotyczących wymiarów obrazu w tym interfejsie API.
  • Do przetwarzania klatek wideo użyj synchronicznego interfejsu API results(in:) do wykrywania. Wywołaj tę metodę z poziomu interfejsu AVCaptureVideoDataOutputSampleBufferDelegate, aby synchronicznie uzyskać wyniki z danego kadru wideo.captureOutput(_, didOutput:from:) Aby ograniczyć wywołania do detektora, ustaw parametr AVCaptureVideoDataOutput na alwaysDiscardsLateVideoFrames. Jeśli podczas działania detektora pojawi się nowa klatka wideo, zostanie ona odrzucona.
  • Jeśli używasz danych wyjściowych z detektora do nakładania grafiki na obraz wejściowy, najpierw uzyskaj wynik z ML Kit, a potem wyrenderuj obraz i nakładkę w jednym kroku. Dzięki temu renderowanie na powierzchni wyświetlacza odbywa się tylko raz dla każdego przetworzonego kadru wejściowego. Przykładem są klasy previewOverlayViewMLKDetectionOverlayView w przykładowej aplikacji pokazowej.

Dalsze kroki