Phát hiện tư thế bằng Bộ công cụ học máy trên iOS

Bộ công cụ học máy cung cấp 2 SDK được tối ưu hoá để phát hiện tư thế.

Tên SDKPoseDetectionPoseDetectionAccurate
Triển khaiCác thành phần cho bộ nhận diện cơ bản được liên kết tĩnh với ứng dụng của bạn tại thời điểm tạo.Các thành phần cho bộ nhận diện chính xác được liên kết tĩnh với ứng dụng của bạn tại thời điểm tạo.
Kích thước ứng dụngTối đa 29,6 MBTối đa 33,2 MB
Hiệu suấtiPhone X: ~45 khung hình/giâyiPhone X: ~29 khung hình/giây

Dùng thử

Trước khi bắt đầu

  1. Thêm các nhóm ML Kit sau vào Podfile:

    # If you want to use the base implementation:
    pod 'GoogleMLKit/PoseDetection', '8.0.0'
    
    # If you want to use the accurate implementation:
    pod 'GoogleMLKit/PoseDetectionAccurate', '8.0.0'
    
  2. Sau khi bạn cài đặt hoặc cập nhật các pod của dự án, hãy mở dự án Xcode bằng xcworkspace. Bộ công cụ học máy được hỗ trợ trong Xcode phiên bản 13.2.1 trở lên.

1. Tạo một thực thể của PoseDetector

Để phát hiện tư thế trong hình ảnh, trước tiên, hãy tạo một thực thể PoseDetector và tuỳ ý chỉ định chế độ cài đặt của bộ nhận diện.

PoseDetector lựa chọn

Chế độ phát hiện

PoseDetector hoạt động ở 2 chế độ phát hiện. Hãy nhớ chọn một trong những lựa chọn phù hợp với trường hợp sử dụng của bạn.

stream (mặc định)
Đầu tiên, bộ nhận diện tư thế sẽ phát hiện người nổi bật nhất trong hình ảnh, sau đó chạy quy trình phát hiện tư thế. Trong các khung hình tiếp theo, bước phát hiện người sẽ không được thực hiện trừ phi người đó bị che khuất hoặc không còn được phát hiện với độ tin cậy cao. Trình phát hiện tư thế sẽ cố gắng theo dõi người nổi bật nhất và trả về tư thế của họ trong mỗi lần suy luận. Điều này giúp giảm độ trễ và phát hiện mượt mà hơn. Sử dụng chế độ này khi bạn muốn phát hiện tư thế trong một luồng video.
singleImage
Trình phát hiện tư thế sẽ phát hiện một người rồi chạy tính năng phát hiện tư thế. Bước phát hiện người sẽ chạy cho mọi hình ảnh, vì vậy độ trễ sẽ cao hơn và không có tính năng theo dõi người. Sử dụng chế độ này khi dùng tính năng phát hiện tư thế trên hình ảnh tĩnh hoặc khi bạn không muốn theo dõi.

Chỉ định các lựa chọn của trình phát hiện tư thế:

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;

Cuối cùng, hãy lấy một thực thể PoseDetector. Truyền các lựa chọn mà bạn đã chỉ định:

Swift

let poseDetector = PoseDetector.poseDetector(options: options)

Objective-C

MLKPoseDetector *poseDetector =
    [MLKPoseDetector poseDetectorWithOptions:options];

2. Chuẩn bị hình ảnh đầu vào

Để phát hiện tư thế, hãy làm như sau cho mỗi hình ảnh hoặc khung hình của video. Nếu đã bật chế độ truyền phát trực tiếp, bạn phải tạo các đối tượng VisionImage từ CMSampleBuffer.

Tạo đối tượng VisionImage bằng cách sử dụng UIImage hoặc CMSampleBuffer.

Nếu bạn sử dụng UIImage, hãy làm theo các bước sau:

  • Tạo một đối tượng VisionImage bằng UIImage. Hãy nhớ chỉ định .orientation chính xác.

    Swift

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

    Objective-C

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

Nếu bạn sử dụng CMSampleBuffer, hãy làm theo các bước sau:

  • Chỉ định hướng của dữ liệu hình ảnh có trong CMSampleBuffer.

    Cách lấy hướng của hình ảnh:

    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;
      }
    }
          
  • Tạo một đối tượng VisionImage bằng đối tượng CMSampleBuffer và hướng:

    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. Xử lý hình ảnh

Truyền VisionImage đến một trong các phương thức xử lý hình ảnh của trình phát hiện tư thế. Bạn có thể sử dụng phương thức process(image:) không đồng bộ hoặc phương thức results() đồng bộ.

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

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.

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

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. Nhận thông tin về tư thế được phát hiện

Nếu phát hiện thấy một người trong hình ảnh, API phát hiện tư thế sẽ truyền một mảng các đối tượng Pose đến trình xử lý hoàn thành hoặc trả về mảng đó, tuỳ thuộc vào việc bạn đã gọi phương thức không đồng bộ hay đồng bộ.

Nếu người đó không hoàn toàn nằm trong hình ảnh, mô hình sẽ chỉ định toạ độ các điểm mốc bị thiếu bên ngoài khung hình và gán cho các điểm mốc đó giá trị InFrameConfidence thấp.

Nếu không phát hiện thấy người nào, mảng sẽ trống.

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

Mẹo cải thiện hiệu suất

Chất lượng của kết quả phụ thuộc vào chất lượng của hình ảnh đầu vào:

  • Để ML Kit phát hiện tư thế một cách chính xác, người trong ảnh phải được biểu thị bằng đủ dữ liệu pixel; để có hiệu suất tốt nhất, đối tượng phải có kích thước tối thiểu là 256x256 pixel.
  • Nếu phát hiện tư thế trong một ứng dụng theo thời gian thực, bạn cũng có thể cân nhắc kích thước tổng thể của hình ảnh đầu vào. Hình ảnh nhỏ hơn có thể được xử lý nhanh hơn, vì vậy, để giảm độ trễ, hãy chụp ảnh ở độ phân giải thấp hơn, nhưng hãy lưu ý các yêu cầu về độ phân giải nêu trên và đảm bảo rằng đối tượng chiếm phần lớn hình ảnh có thể.
  • Hình ảnh không rõ nét cũng có thể ảnh hưởng đến độ chính xác. Nếu bạn không nhận được kết quả chấp nhận được, hãy yêu cầu người dùng chụp lại hình ảnh.

Nếu bạn muốn sử dụng tính năng phát hiện tư thế 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:

  • Sử dụng PoseDetection SDK cơ bản và chế độ phát hiện stream.
  • Hãy cân nhắc chụp ảnh ở độ phân giải thấp hơn. Tuy nhiên, bạn cũng cần lưu ý các yêu cầu về kích thước hình ảnh của API này.
  • Để xử lý các khung hình video, hãy dùng API đồng bộ results(in:) của bộ nhận diện. Gọi phương thức này từ hàm captureOutput(_, didOutput:from:) của AVCaptureVideoDataOutputSampleBufferDelegate để nhận kết quả đồng bộ từ khung hình video đã cho. Luôn giữ AVCaptureVideoDataOutput's alwaysDiscardsLateVideoFrames ở trạng thái true để điều chỉnh tốc độ các lệnh gọi đến trình phát hiện. Nếu có một khung hình video mới trong khi bộ phát hiện đang chạy, khung hình đó sẽ bị loại bỏ.
  • Nếu bạn dùng đầu ra của bộ nhận diện để phủ đồ hoạ lên hình ảnh đầu vào, trước tiên, hãy lấy kết quả từ ML Kit, sau đó kết xuất hình ảnh và lớp phủ trong một bước. Bằng cách này, bạn chỉ kết xuất vào bề mặt hiển thị một lần cho mỗi khung hình đầu vào đã xử lý. Hãy xem các lớp previewOverlayViewMLKDetectionOverlayView trong ứng dụng mẫu giới thiệu để biết ví dụ.

Các bước tiếp theo