Lựa chọn phân loại tư thế

Nhờ API Phát hiện tư thế của bộ công cụ học máy, bạn có thể lấy được những cách diễn giải phù hợp của tư thế bằng cách kiểm tra vị trí tương đối của các bộ phận cơ thể khác nhau. Trang này đưa ra một vài ví dụ.

Phân loại tư thế và đếm số lặp bằng thuật toán k-NN

Một trong những ứng dụng phổ biến nhất của tính năng phát hiện tư thế là theo dõi hoạt động thể dục. Xây dựng một thuật toán phân loại tư thế nhận dạng số lượng và tư thế tập thể dục cụ thể lặp lại có thể là một việc khó khăn đối với nhà phát triển.

Trong phần này, chúng tôi mô tả cách chúng tôi tạo một tư thế tuỳ chỉnh thuật toán phân loại bằng MediaPipe Colab và minh hoạ một thuật toán phân loại hoạt động trong ứng dụng mẫu Bộ công cụ học máy của chúng tôi.

Nếu bạn chưa hiểu rõ về Google Colaboratory, vui lòng xem hướng dẫn giới thiệu.

Để nhận biết tư thế, chúng ta sử dụng thuật toán hàng xóm gần nhất (k-NN) vì nó rất đơn giản và dễ dàng để bắt đầu. Thuật toán này xác định lớp của đối tượng dựa trên mẫu gần nhất trong tập huấn luyện.

Hãy làm theo các bước sau để xây dựng và huấn luyện trình nhận dạng:

1. Thu thập các mẫu hình ảnh

Chúng tôi đã thu thập các mẫu hình ảnh của các bài tập mục tiêu từ nhiều nguồn. T4 chọn vài trăm hình ảnh cho mỗi bài tập, chẳng hạn như "lên" và "giảm" vị trí chống đẩy. Bạn cần thu thập các mẫu bao gồm các camera khác nhau các góc, điều kiện môi trường, hình dạng cơ thể và các biến thể của bài tập thể dục.

Hình 1. Các tư thế chống đẩy lên và xuống

2. Chạy tính năng phát hiện tư thế trên hình ảnh mẫu

Thao tác này sẽ tạo ra một tập hợp các điểm mốc tư thế dùng để huấn luyện. Chúng tôi không quan tâm đến công nghệ phát hiện tư thế, vì chúng tôi sẽ đào tạo mô hình của riêng bạn trong bước tiếp theo.

Thuật toán k-NN mà chúng tôi đã chọn cho phân loại tư thế tuỳ chỉnh yêu cầu đại diện vectơ cho từng mẫu và số liệu để tính toán khoảng cách giữa hai vectơ để tìm mục tiêu gần nhất với mẫu tư thế. Điều này có nghĩa là chúng ta phải chuyển đổi các mốc tư thế vừa nhận được.

Để chuyển đổi vị trí các điểm mốc thành vectơ đối tượng, chúng ta sử dụng khoảng cách theo cặp giữa danh sách các khớp tư thế được xác định sẵn, chẳng hạn như khoảng cách giữa cổ tay và vai, mắt cá chân, hông, cổ tay trái và phải. Vì tỷ lệ hình ảnh có thể khác nhau, chúng tôi đã chuẩn hoá các tư thế để có cùng kích thước thân và thân dọc trước khi chuyển đổi các mốc.

3. Huấn luyện mô hình và đếm số lần lặp lại

Chúng tôi đã dùng MediaPipe Colab để truy cập vào mã cho thuật toán phân loại và huấn luyện mô hình.

Để đếm số lần lặp lại, chúng tôi đã sử dụng một thuật toán Colab khác để theo dõi xác suất ngưỡng của một vị trí tư thế mục tiêu. Ví dụ:

  • Khi xác suất "giảm" lớp tư thế vượt qua một ngưỡng nhất định cho lần đầu tiên, thuật toán đánh dấu rằng nút "giảm" đã nhập lớp tư thế.
  • Khi xác suất giảm xuống dưới ngưỡng, thuật toán sẽ đánh dấu rằng "down" (xuống) lớp tư thế đã được thoát và tăng bộ đếm.
Hình 2. Ví dụ về cách tính số lần lặp lại

4. Tích hợp với ứng dụng bắt đầu nhanh với Bộ công cụ học máy

Colab ở trên sẽ tạo ra một tệp CSV để bạn có thể điền sẵn tất cả tư thế của mình mẫu. Trong phần này, bạn sẽ tìm hiểu cách tích hợp tệp CSV của mình với Ứng dụng bắt đầu nhanh của Android với Bộ công cụ học máy để xem cách phân loại tư thế tuỳ chỉnh theo thời gian thực.

Thử phân loại tư thế với các mẫu đi kèm trong ứng dụng bắt đầu nhanh

Thêm tệp CSV của riêng bạn

  • Thêm tệp CSV vào thư mục thành phần của ứng dụng.
  • Trong PoseClassifierProcessor, cập nhật các biến POSE_SAMPLES_FILEPOSE_CLASSES để khớp với CSV và các mẫu tư thế.
  • Tạo bản dựng và chạy ứng dụng

Lưu ý rằng việc phân loại có thể không hoạt động tốt nếu không có đủ mẫu. Thông thường, bạn cần khoảng 100 mẫu cho mỗi lớp tư thế.

Để tìm hiểu thêm và dùng thử tính năng này, hãy xem MediaPipe Colabhướng dẫn phân loại MediaPipe.

Nhận dạng các cử chỉ đơn giản bằng cách tính khoảng cách điểm mốc

Khi hai hoặc nhiều mốc gần nhau, chúng có thể được dùng để nhận dạng cử chỉ. Ví dụ: khi điểm mốc cho một hoặc nhiều ngón tay trên bàn tay ở gần điểm mốc ở mũi, bạn có thể suy luận người dùng có thể đang chạm vào khuôn mặt của mình.

Hình 3. Diễn giải tư thế

Nhận biết tư thế yoga bằng phương pháp suy đoán góc

Bạn có thể xác định tư thế yoga bằng cách tính toán góc của nhiều khớp. Cho ví dụ: Hình 2 bên dưới minh hoạ tư thế yoga của Warrior II. Các góc gần đúng xác định tư thế này được viết bằng:

Hình 4. Chia tư thế thành nhiều góc

Tư thế này có thể được mô tả là sự kết hợp của thân hình gần đúng sau góc toàn phần:

  • Góc 90 độ ở cả hai vai
  • 180 độ ở cả hai khuỷu tay
  • Góc 90 độ ở chân trước và eo
  • Đầu gối sau tạo góc 180 độ
  • Góc 135 độ ở eo

Bạn có thể sử dụng các điểm mốc đã đặt để tính các góc này. Ví dụ: góc ở chân trước bên phải và eo là góc giữa đường thẳng tính từ bên phải từ vai sang hông phải và đường thẳng từ hông phải sang đầu gối phải.

Sau khi tính toán tất cả các góc cần thiết để xác định tư thế, bạn có thể kiểm tra để xem có kiểu khớp nào không, trong trường hợp nào bạn đã nhận ra tư thế đó.

Đoạn mã dưới đây minh hoạ cách sử dụng toạ độ X và Y để tính góc giữa hai phần cơ thể. Phương pháp phân loại này có một số hạn chế. Khi chỉ kiểm tra X và Y, các góc được tính toán sẽ thay đổi theo góc giữa đối tượng và máy ảnh. Bạn sẽ nhận được kết quả tốt nhất bằng hình ảnh ngang, thẳng về phía trước. Bạn cũng có thể hãy thử mở rộng thuật toán này bằng cách tận dụng Toạ độ Z và xem liệu mô hình đó có mang lại hiệu quả cao hơn cho trường hợp sử dụng của bạn hay không.

Tính toán các góc mốc trên Android

Phương thức sau đây tính góc giữa 3 giá trị bất kỳ mốc. Đảm bảo góc được trả về nằm trong khoảng 0 và 180 độ.

Kotlin

fun getAngle(firstPoint: PoseLandmark, midPoint: PoseLandmark, lastPoint: PoseLandmark): Double {
        var result = Math.toDegrees(atan2(lastPoint.getPosition().y - midPoint.getPosition().y,
                lastPoint.getPosition().x - midPoint.getPosition().x)
                - atan2(firstPoint.getPosition().y - midPoint.getPosition().y,
                firstPoint.getPosition().x - midPoint.getPosition().x))
        result = Math.abs(result) // Angle should never be negative
        if (result > 180) {
            result = 360.0 - result // Always get the acute representation of the angle
        }
        return result
    }

Java

static double getAngle(PoseLandmark firstPoint, PoseLandmark midPoint, PoseLandmark lastPoint) {
  double result =
        Math.toDegrees(
            atan2(lastPoint.getPosition().y - midPoint.getPosition().y,
                      lastPoint.getPosition().x - midPoint.getPosition().x)
                - atan2(firstPoint.getPosition().y - midPoint.getPosition().y,
                      firstPoint.getPosition().x - midPoint.getPosition().x));
  result = Math.abs(result); // Angle should never be negative
  if (result > 180) {
      result = (360.0 - result); // Always get the acute representation of the angle
  }
  return result;
}

Sau đây là cách tính góc ở hông phải:

Kotlin

val rightHipAngle = getAngle(
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_SHOULDER),
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_HIP),
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_KNEE))

Java

double rightHipAngle = getAngle(
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_SHOULDER),
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_HIP),
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_KNEE));

Tính toán các góc mốc trên iOS

Phương thức sau đây tính góc giữa 3 giá trị bất kỳ mốc. Đảm bảo góc được trả về nằm trong khoảng 0 và 180 độ.

Swift

func angle(
      firstLandmark: PoseLandmark,
      midLandmark: PoseLandmark,
      lastLandmark: PoseLandmark
  ) -> CGFloat {
      let radians: CGFloat =
          atan2(lastLandmark.position.y - midLandmark.position.y,
                    lastLandmark.position.x - midLandmark.position.x) -
            atan2(firstLandmark.position.y - midLandmark.position.y,
                    firstLandmark.position.x - midLandmark.position.x)
      var degrees = radians * 180.0 / .pi
      degrees = abs(degrees) // Angle should never be negative
      if degrees > 180.0 {
          degrees = 360.0 - degrees // Always get the acute representation of the angle
      }
      return degrees
  }

Objective-C

(CGFloat)angleFromFirstLandmark:(MLKPoseLandmark *)firstLandmark
                      midLandmark:(MLKPoseLandmark *)midLandmark
                     lastLandmark:(MLKPoseLandmark *)lastLandmark {
    CGFloat radians = atan2(lastLandmark.position.y - midLandmark.position.y,
                            lastLandmark.position.x - midLandmark.position.x) -
                      atan2(firstLandmark.position.y - midLandmark.position.y,
                            firstLandmark.position.x - midLandmark.position.x);
    CGFloat degrees = radians * 180.0 / M_PI;
    degrees = fabs(degrees); // Angle should never be negative
    if (degrees > 180.0) {
        degrees = 360.0 - degrees; // Always get the acute representation of the angle
    }
    return degrees;
}

Sau đây là cách tính góc ở hông phải:

Swift

let rightHipAngle = angle(
      firstLandmark: pose.landmark(ofType: .rightShoulder),
      midLandmark: pose.landmark(ofType: .rightHip),
      lastLandmark: pose.landmark(ofType: .rightKnee))

Objective-C

CGFloat rightHipAngle =
    [self angleFromFirstLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightShoulder]
                     midLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightHip]
                    lastLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightKnee]];