Opsi klasifikasi pose

Dengan ML Kit Pose Detection API, Anda dapat memperoleh interpretasi yang bermakna dari sebuah pose dengan memeriksa posisi relatif dari berbagai bagian tubuh. Halaman ini menunjukkan beberapa contoh.

Klasifikasi pose dan penghitungan pengulangan dengan algoritma k-NN

Salah satu penerapan deteksi pose yang paling umum adalah pelacakan kebugaran. Membuat pengklasifikasi pose yang mengenali pose kebugaran tertentu dan menghitung pengulangan dapat menjadi pekerjaan yang menantang bagi developer.

Di bagian ini, kami menjelaskan cara kami membuat pengklasifikasi pose kustom menggunakan MediaPipe Colab, dan mendemonstrasikan pengklasifikasi yang berfungsi di aplikasi contoh ML Kit kami.

Jika Anda belum terbiasa dengan Google Colaboratory, lihat panduan pengantar.

Untuk mengenali pose, kami menggunakan algoritma k-nearestNeighbors (k-NN) karena sederhana dan mudah dimulai. Algoritma menentukan class objek berdasarkan sampel terdekat dalam set pelatihan.

Ikuti langkah-langkah berikut untuk membuat dan melatih pengenal:

1. Mengumpulkan contoh gambar

Kami mengumpulkan contoh gambar latihan target dari berbagai sumber. Kami memilih beberapa ratus gambar untuk setiap latihan, seperti posisi "atas" dan "bawah" untuk push-up. Penting untuk mengumpulkan sampel yang mencakup berbagai sudut kamera, kondisi lingkungan, bentuk tubuh, dan variasi olahraga.

Gambar 1. Posisi pose pushup atas dan bawah

2. Menjalankan deteksi pose pada gambar contoh

Ini menghasilkan serangkaian penanda pose yang akan digunakan untuk pelatihan. Kami tidak tertarik dengan deteksi pose itu sendiri, karena kami akan melatih model kami sendiri di langkah berikutnya.

Algoritma k-NN yang dipilih untuk klasifikasi pose kustom memerlukan representasi vektor fitur untuk setiap sampel, dan metrik untuk menghitung jarak antara dua vektor guna menemukan target yang paling dekat dengan sampel pose. Ini berarti kita harus mengonversi penanda pose yang baru saja diperoleh.

Untuk mengonversi tempat terkenal pose menjadi vektor fitur, kami menggunakan jarak berpasangan antara daftar sambungan pose yang telah ditentukan, seperti jarak antara pergelangan tangan dan bahu, pergelangan kaki dan pinggul, serta pergelangan tangan kiri dan kanan. Karena skala gambar dapat bervariasi, kami menormalisasi pose agar memiliki ukuran batang tubuh dan orientasi batang tubuh vertikal yang sama sebelum mengonversi tempat terkenal.

3. Melatih model dan menghitung pengulangan

Kami menggunakan MediaPipe Colab untuk mengakses kode pengklasifikasi dan melatih model.

Untuk menghitung pengulangan, kami menggunakan algoritma Colab lain untuk memantau batas probabilitas posisi pose target. Contoh:

  • Ketika probabilitas class pose "bawah" melewati batas tertentu untuk pertama kalinya, algoritme akan menandai bahwa class pose "bawah" dimasukkan.
  • Saat probabilitas turun di bawah nilai minimum, algoritme akan menandai bahwa class pose "bawah" telah keluar dan meningkatkan penghitung.
Gambar 2. Contoh penghitungan pengulangan

4. Berintegrasi dengan aplikasi panduan memulai ML Kit

Colab di atas menghasilkan file CSV yang dapat Anda isi dengan semua contoh pose. Di bagian ini, Anda akan mempelajari cara mengintegrasikan file CSV dengan aplikasi panduan memulai Android ML Kit untuk melihat klasifikasi pose kustom secara real time.

Coba klasifikasi pose dengan contoh yang dipaketkan di aplikasi panduan memulai

  • Dapatkan project aplikasi panduan memulai Android ML Kit dari GitHub dan pastikan aplikasi tersebut dibangun dan berjalan dengan baik.
  • Buka LivePreviewActivity dan aktifkan Deteksi Pose Run classification dari halaman Setelan. Sekarang Anda seharusnya sudah bisa mengklasifikasikan {i>pushup<i} dan {i>squat<i}.

Tambahkan CSV Anda sendiri

  • Tambahkan file CSV ke folder aset aplikasi.
  • Di PoseClassifierProcessor, perbarui variabel POSE_SAMPLES_FILE dan POSE_CLASSES agar sesuai dengan file CSV dan contoh pose.
  • Bangun dan jalankan aplikasi.

Perhatikan bahwa klasifikasi mungkin tidak berfungsi dengan baik jika sampel tidak cukup. Umumnya, Anda memerlukan sekitar 100 sampel per class pose.

Untuk mempelajari lebih lanjut dan mencobanya sendiri, lihat MediaPipe Colab dan panduan klasifikasi MediaPipe.

Mengenali gestur sederhana dengan menghitung jarak penanda

Jika dua atau beberapa tempat terkenal saling berdekatan, keduanya dapat digunakan untuk mengenali gestur. Misalnya, jika penanda untuk satu atau beberapa jari di tangan dekat dengan penanda untuk hidung, Anda dapat menyimpulkan bahwa pengguna kemungkinan besar menyentuh wajahnya.

Gambar 3. Menafsirkan pose

Mengenali pose yoga dengan heuristik sudut

Anda dapat mengidentifikasi pose yoga dengan menghitung sudut berbagai sendi. Misalnya, Gambar 2 di bawah menunjukkan pose yoga Warrior II. Perkiraan sudut yang mengidentifikasi pose ini ditulis dalam:

Gambar 4. Memecah pose menjadi beberapa sudut

Pose ini dapat dijelaskan sebagai kombinasi perkiraan sudut bagian tubuh berikut:

  • sudut 90 derajat di kedua bahu
  • 180 derajat di kedua siku
  • Sudut 90 derajat di kaki depan dan pinggang
  • Sudut 180 derajat di bagian belakang lutut
  • Sudut 135 derajat di bagian pinggang

Anda dapat menggunakan penanda pose untuk menghitung sudut-sudut ini. Misalnya, sudut di kaki depan kanan dan pinggang adalah sudut antara garis dari bahu kanan ke pinggul kanan, dan garis dari pinggul kanan ke lutut kanan.

Setelah menghitung semua sudut yang diperlukan untuk mengidentifikasi pose, Anda dapat memeriksa apakah ada kecocokan, dan dalam hal ini Anda telah mengenali pose tersebut.

Cuplikan kode di bawah menunjukkan cara menggunakan koordinat X dan Y untuk menghitung sudut antara dua bagian tubuh. Pendekatan klasifikasi ini memiliki beberapa batasan. Dengan hanya memeriksa X dan Y, sudut yang dihitung bervariasi sesuai dengan sudut antara subjek dan kamera. Anda akan mendapatkan hasil terbaik dengan gambar langsung yang lurus ke depan. Anda juga dapat mencoba memperluas algoritme ini dengan menggunakan koordinat Z dan melihat apakah performanya lebih baik untuk kasus penggunaan Anda.

Menghitung sudut tempat terkenal di Android

Metode berikut menghitung sudut antara tiga landmark. Hal ini memastikan sudut yang ditampilkan antara 0 dan 180 derajat.

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

Berikut cara menghitung sudut di pinggul kanan:

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

Menghitung sudut tempat terkenal di iOS

Metode berikut menghitung sudut antara tiga landmark. Hal ini memastikan sudut yang ditampilkan antara 0 dan 180 derajat.

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

Berikut cara menghitung sudut di pinggul kanan:

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