ตัวเลือกการแยกประเภทท่าทาง

ML Kit Pose Detection API ช่วยให้คุณรับการตีความท่าทางที่มีความหมายได้ด้วยการตรวจสอบตำแหน่งสัมพัทธ์ของส่วนต่างๆ ของร่างกาย หน้านี้จะแสดงให้เห็นตัวอย่างบางส่วน

การแยกประเภทท่าทางและการนับการทำซ้ำด้วยอัลกอริทึม k-NN

หนึ่งในแอปพลิเคชันที่พบบ่อยที่สุดในการตรวจจับท่าทางคือการติดตามการออกกำลังกาย การสร้างตัวแยกประเภทที่รู้จำท่าออกกำลังและนับจำนวนการทำซ้ำอาจเป็นสิ่งที่ท้าทายสำหรับนักพัฒนาซอฟต์แวร์

ในส่วนนี้ เราจะอธิบายถึงวิธีที่เราสร้างตัวแยกประเภทท่าทางที่กำหนดเองโดยใช้ MediaPipe Colab และสาธิตการใช้ตัวแยกประเภทที่ใช้งานได้ในแอปตัวอย่าง ML Kit

หากไม่คุ้นเคยกับ Google Colaboratory โปรดดูคู่มือแนะนำ

ในการรู้จำท่าทาง เราใช้อัลกอริทึมเพื่อนบ้านที่อยู่ใกล้ที่สุด (k-NN) เพราะเรียบง่ายและเริ่มต้นได้ง่าย อัลกอริทึมจะกำหนดคลาสของออบเจ็กต์ตามตัวอย่างที่ใกล้เคียงที่สุดในชุดการฝึก

ทำตามขั้นตอนต่อไปนี้เพื่อสร้างและฝึกโปรแกรมรู้จำ

1. รวบรวมตัวอย่างรูปภาพ

เรารวบรวมตัวอย่างรูปภาพของแบบฝึกหัดเป้าหมายจากแหล่งที่มาต่างๆ เราจะเลือกรูปภาพ 200-300 รูปสำหรับการออกกำลังกายแต่ละครั้ง เช่น ท่า "ขึ้น" และ "ลง" สำหรับการวิดพื้น คุณต้องรวบรวมตัวอย่างที่ครอบคลุมมุมกล้อง สภาพสภาพแวดล้อม รูปร่าง และการออกกำลังกายรูปแบบต่างๆ

รูปที่ 1 ท่าวิดพื้นแบบขึ้นและลง

2. เรียกใช้การตรวจหาท่าทางในรูปภาพตัวอย่าง

ระบบจะสร้างชุดจุดสังเกตของท่าสำหรับฝึก เราไม่สนใจเกี่ยวกับการตรวจจับท่าทาง เนื่องจากเราจะฝึกโมเดลของเราเองในขั้นตอนถัดไป

อัลกอริทึม k-NN ที่เราเลือกสำหรับการแยกประเภทท่าทางที่กำหนดเองต้องใช้การแสดงเวกเตอร์ฟีเจอร์ของตัวอย่างแต่ละรายการและเมตริกในการคำนวณระยะห่างระหว่างเวกเตอร์ 2 เวกเตอร์เพื่อหาเป้าหมายที่ใกล้เคียงที่สุดกับตัวอย่างท่าทาง ซึ่งหมายความว่าเราต้องแปลงจุดสังเกตของท่าทางที่เพิ่งได้รับมา

ในการแปลงจุดสังเกตของท่าทางเป็นเวกเตอร์ของฟีเจอร์ เราใช้ระยะห่างแบบจับคู่ระหว่างรายการข้อต่อที่กำหนดไว้ล่วงหน้า เช่น ระยะห่างระหว่างข้อมือกับไหล่ ข้อเท้าและสะโพก และข้อมือซ้ายและขวา เนื่องจากขนาดรูปภาพอาจแตกต่างกันไป เราจึงปรับท่าทางให้มีขนาดลำตัวและแนวลำตัวแนวตั้งเท่ากันก่อนที่จะแปลงจุดสังเกต

3. ฝึกโมเดลและนับการทำซ้ำ

เราใช้ MediaPipe Colab เพื่อเข้าถึงโค้ดสำหรับตัวแยกประเภทและฝึกโมเดล

ในการนับจำนวนครั้งที่ทำซ้ำ เราใช้อัลกอริทึม Colab อื่นในการตรวจสอบเกณฑ์ความน่าจะเป็นของตำแหน่งท่าทาง เช่น

  • เมื่อความน่าจะเป็นของคลาสท่าทาง "ลง" ผ่านเกณฑ์ที่ระบุเป็นครั้งแรก อัลกอริทึมจะทำเครื่องหมายว่ามีการป้อนคลาสท่าทาง "ลง"
  • เมื่อความน่าจะเป็นลดลงต่ำกว่าเกณฑ์ อัลกอริทึมจะทำเครื่องหมายการออกจากคลาสท่าทาง "ลง" แล้วเพิ่มตัวนับ
รูปที่ 2 ตัวอย่างการนับซ้ำ

4. ผสานรวมกับแอปเริ่มต้นใช้งานอย่างรวดเร็วของ ML Kit

Colab ด้านบนจะสร้างไฟล์ CSV ที่คุณนำไปเติมข้อมูลด้วยตัวอย่างท่าทางทั้งหมดของคุณได้ ในส่วนนี้ คุณจะได้เรียนรู้วิธีผสานรวมไฟล์ CSV กับแอปเริ่มใช้งาน Android ของ ML Kit อย่างรวดเร็วเพื่อดูการจัดประเภทท่าทางที่กำหนดเองแบบเรียลไทม์

ลองจัดประเภทท่าทางด้วยตัวอย่างที่รวมอยู่ในแอป Quickstart

เพิ่ม CSV ของคุณเอง

  • เพิ่มไฟล์ CSV ลงในโฟลเดอร์ชิ้นงานของแอป
  • ใน PoseClassifierProcessor ให้อัปเดตตัวแปร POSE_SAMPLES_FILE และ POSE_CLASSES ให้ตรงกับไฟล์ CSV และวางตัวอย่าง
  • สร้างและเรียกใช้แอป

โปรดทราบว่าการจัดประเภทอาจทำงานได้ไม่ดีหากมีตัวอย่างไม่เพียงพอ โดยทั่วไป คุณต้องการประมาณ 100 ตัวอย่างต่อคลาสท่าทาง

ดูข้อมูลเพิ่มเติมและลองใช้งานด้วยตัวเองได้ใน MediaPipe Colab และคู่มือการแยกประเภท MediaPipe

การจดจำท่าทางสัมผัสง่ายๆ โดยการคำนวณระยะห่างของจุดสังเกต

เมื่อจุดสังเกต 2 รายการขึ้นไปอยู่ใกล้กัน สามารถใช้เพื่อจดจำท่าทางสัมผัสได้ เช่น เมื่อจุดสังเกตสำหรับนิ้วมือ 1 นิ้วหรือมากกว่าอยู่ใกล้กับจุดสังเกตสำหรับจมูก คุณจะอนุมานได้ว่าผู้ใช้มีแนวโน้มที่จะสัมผัสใบหน้าของตนมากที่สุด

รูปที่ 3 การตีความท่าทาง

การจดจำท่าโยคะที่มีการเรียนรู้มุม

คุณสามารถระบุท่าโยคะได้โดยการคำนวณมุมของข้อต่อต่างๆ ตัวอย่างเช่น รูปที่ 2 ด้านล่างแสดงท่าโยคะ Warrior II มุมโดยประมาณที่ระบุท่าทางนี้เขียนว่า

รูปที่ 4 จัดท่าให้เป็นมุมฉาก

ท่าทางนี้อาจอธิบายได้จากการรวมมุมส่วนต่างๆ ของร่างกายโดยประมาณดังต่อไปนี้

  • ทำมุม 90 องศาที่ไหล่ทั้ง 2 ข้าง
  • 180 องศาที่ข้อศอกทั้ง 2 ข้าง
  • ทำมุม 90 องศาที่ขาหน้าและเอว
  • ทำมุม 180 องศาที่เข่าด้านหลัง
  • ทำมุม 135 องศาที่เอว

คุณใช้จุดสังเกตของท่าทางเพื่อคำนวณมุมเหล่านี้ได้ ตัวอย่างเช่น มุมที่ขาหน้าและเอวด้านขวาคือมุมระหว่างเส้นจากไหล่ด้านขวาไปยังสะโพกด้านขวา และเส้นจากสะโพกด้านขวาไปยังเข่าด้านขวา

เมื่อคุณคำนวณมุมทั้งหมดที่ต้องใช้ในการระบุท่าทางแล้ว คุณก็ดูว่ามีภาพที่ตรงกันไหม ซึ่งในกรณีนี้คุณรู้ท่าโพสแล้ว

ข้อมูลโค้ดด้านล่างสาธิตวิธีใช้พิกัด X และ Y เพื่อคำนวณมุมระหว่างส่วนต่างๆ ของร่างกาย วิธีการแยกประเภทนี้ มีข้อจำกัดบางประการ ถ้าเลือกเฉพาะ X และ Y มุมที่คำนวณได้ จะแตกต่างกันไปตามมุมระหว่างวัตถุและกล้อง คุณจะได้ผลลัพธ์ที่ดีที่สุดเมื่อ เห็นภาพชัดเจนตรงไปตรงมา คุณยังสามารถลองขยายอัลกอริทึมนี้โดยใช้พิกัด Z และดูว่ามีประสิทธิภาพดีกว่าสำหรับกรณีการใช้งานของคุณไหม

คำนวณมุมของจุดสังเกตบน Android

เมธอดต่อไปนี้จะคำนวณมุมระหว่างจุดสังเกต 3 อย่าง เพื่อให้แน่ใจว่ามุมที่แสดงผลอยู่ระหว่าง 0 ถึง 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;
}

วิธีคำนวณมุมด้านขวาสะโพกมีดังนี้

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

คำนวณมุมของจุดสังเกตบน iOS

เมธอดต่อไปนี้จะคำนวณมุมระหว่างจุดสังเกต 3 อย่าง เพื่อให้แน่ใจว่ามุมที่แสดงผลอยู่ระหว่าง 0 ถึง 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;
}

วิธีคำนวณมุมด้านขวาสะโพกมีดังนี้

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