คำแนะนำในการตรวจหาจุดสังเกตสำหรับ Android

งาน MediaPipe Pose Landinger จะช่วยให้คุณตรวจหาจุดสังเกตของร่างกายมนุษย์ในรูปภาพหรือวิดีโอได้ คุณสามารถใช้งานนี้เพื่อระบุตำแหน่งหลักของร่างกาย วิเคราะห์ท่าทาง และจัดหมวดหมู่การเคลื่อนไหว งานนี้ใช้โมเดลแมชชีนเลิร์นนิง (ML) ที่ใช้งานได้กับรูปภาพหรือวิดีโอรายการเดียว งานแสดงท่าทางร่างกายของจุดสังเกต ที่อยู่ในพิกัดรูปภาพและในพิกัดโลก 3 มิติ

ตัวอย่างโค้ดที่อธิบายในวิธีการเหล่านี้จะดูได้ใน GitHub ดูข้อมูลเพิ่มเติมเกี่ยวกับความสามารถ โมเดล และตัวเลือกการกำหนดค่าของงานนี้ได้ที่ภาพรวม

ตัวอย่างโค้ด

โค้ดตัวอย่างงาน MediaPipe Tasks เป็นการติดตั้งใช้งานแอป Pose Marker สำหรับ Android แบบง่ายๆ ตัวอย่างนี้ใช้กล้องบนอุปกรณ์ Android จริงเพื่อตรวจหาท่าทางในสตรีมวิดีโอแบบต่อเนื่อง แอปยังสามารถตรวจจับท่าทาง ในรูปภาพและวิดีโอจากแกลเลอรีของอุปกรณ์

คุณสามารถใช้แอปนี้เป็นจุดเริ่มต้นสำหรับแอป Android ของคุณเองหรือใช้อ้างอิงเมื่อแก้ไขแอปที่มีอยู่ โค้ดตัวอย่างของ Pose Marker นั้นโฮสต์อยู่ใน GitHub

ดาวน์โหลดโค้ด

วิธีการต่อไปนี้แสดงวิธีสร้างสำเนาโค้ดตัวอย่างในเครื่องโดยใช้เครื่องมือบรรทัดคำสั่ง git

วิธีดาวน์โหลดโค้ดตัวอย่าง

  1. โคลนที่เก็บ Git โดยใช้คำสั่งต่อไปนี้
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. (ไม่บังคับ) กำหนดค่าอินสแตนซ์ Git เพื่อใช้การชำระเงินแบบกะทัดรัด เพื่อให้คุณมีเพียงไฟล์สำหรับแอปตัวอย่าง Poseจุดสังเกต ดังนี้
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/pose_landmarker/android
    

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

องค์ประกอบหลัก

ไฟล์ต่อไปนี้มีโค้ดสำคัญสำหรับแอปพลิเคชันตัวอย่างการกำหนดจุดสังเกตนี้

  • PoseLandmarkerHelper.kt - เริ่มต้นตัวทำเครื่องหมายท่าทาง และจัดการโมเดลและมอบสิทธิ์การเลือก
  • CameraFragment.kt - จัดการกล้องของอุปกรณ์และประมวลผลข้อมูลอินพุตรูปภาพและวิดีโอ
  • GalleryFragment.kt - โต้ตอบกับ OverlayView เพื่อแสดงรูปภาพหรือวิดีโอเอาต์พุต
  • OverlayView.kt - ใช้การแสดงผลสำหรับท่าทางที่ตรวจพบ

ตั้งค่า

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

การอ้างอิง

งาน Pose Marker ใช้ไลบรารี com.google.mediapipe:tasks-vision เพิ่มทรัพยากร Dependency นี้ไปยังไฟล์ build.gradle ของแอป Android

dependencies {
    implementation 'com.google.mediapipe:tasks-vision:latest.release'
}

รุ่น

งาน MediaPipe Pose Marker ต้องมีแพ็กเกจโมเดลที่ผ่านการฝึกแล้วซึ่งเข้ากันได้กับงานนี้ ดูข้อมูลเพิ่มเติมเกี่ยวกับโมเดลที่ฝึกแล้วที่พร้อมใช้งานสำหรับจุดสังเกตของ Pose ได้ที่ภาพรวมงานส่วนโมเดล

เลือกและดาวน์โหลดโมเดล แล้วจัดเก็บไว้ในไดเรกทอรีโปรเจ็กต์ของคุณ ดังนี้

<dev-project-root>/src/main/assets

ระบุเส้นทางของโมเดลภายในพารามิเตอร์ ModelAssetPath ในโค้ดตัวอย่าง โมเดลจะได้รับการกำหนดในไฟล์ PoseLandmarkerHelper.kt ดังนี้

val modelName = "pose_landmarker_lite.task"
baseOptionsBuilder.setModelAssetPath(modelName)

สร้างงาน

งาน MediaPipe Pose Marker จะใช้ฟังก์ชัน createFromOptions() เพื่อตั้งค่างาน ฟังก์ชัน createFromOptions() จะยอมรับค่าสำหรับตัวเลือกการกำหนดค่า ดูข้อมูลเพิ่มเติมเกี่ยวกับตัวเลือกการกำหนดค่าได้ที่ตัวเลือกการกำหนดค่า

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

รูปภาพ

val baseOptionsBuilder = BaseOptions.builder().setModelAssetPath(modelName)
val baseOptions = baseOptionBuilder.build()

val optionsBuilder = 
    poseLandmarker.poseLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinPoseDetectionConfidence(minPoseDetectionConfidence)
        .setMinTrackingConfidence(minPoseTrackingConfidence)
        .setMinPosePresenceConfidence(minposePresenceConfidence)
        .setNumPoses(maxNumPoses)
        .setRunningMode(RunningMode.IMAGE)

val options = optionsBuilder.build()
poseLandmarker = poseLandmarker.createFromOptions(context, options)
    

วิดีโอ

val baseOptionsBuilder = BaseOptions.builder().setModelAssetPath(modelName)
val baseOptions = baseOptionBuilder.build()

val optionsBuilder = 
    poseLandmarker.poseLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinPoseDetectionConfidence(minPoseDetectionConfidence)
        .setMinTrackingConfidence(minPoseTrackingConfidence)
        .setMinPosePresenceConfidence(minposePresenceConfidence)
        .setNumPoses(maxNumPoses)
        .setRunningMode(RunningMode.VIDEO)

val options = optionsBuilder.build()
poseLandmarker = poseLandmarker.createFromOptions(context, options)
    

สตรีมแบบสด

val baseOptionsBuilder = BaseOptions.builder().setModelAssetPath(modelName)
val baseOptions = baseOptionBuilder.build()

val optionsBuilder = 
    poseLandmarker.poseLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinPoseDetectionConfidence(minPoseDetectionConfidence)
        .setMinTrackingConfidence(minPoseTrackingConfidence)
        .setMinPosePresenceConfidence(minposePresenceConfidence)
        .setNumPoses(maxNumPoses)
        .setResultListener(this::returnLivestreamResult)
        .setErrorListener(this::returnLivestreamError)
        .setRunningMode(RunningMode.LIVE_STREAM)

val options = optionsBuilder.build()
poseLandmarker = poseLandmarker.createFromOptions(context, options)
    

ตัวอย่างการใช้โค้ด Pose Marker ช่วยให้ผู้ใช้เปลี่ยนโหมดการประมวลผลได้ วิธีนี้ทำให้โค้ดการสร้างงานซับซ้อนขึ้นและอาจไม่เหมาะกับกรณีการใช้งานของคุณ คุณดูโค้ดนี้ได้ในฟังก์ชัน setupPoseLandmarker() ในไฟล์ PoseLandmarkerHelper.kt

ตัวเลือกการกำหนดค่า

งานมีตัวเลือกการกำหนดค่าต่อไปนี้สำหรับแอป Android

ชื่อตัวเลือก คำอธิบาย ช่วงของค่า ค่าเริ่มต้น
runningMode ตั้งค่าโหมดการทำงาน มี 3 โหมดดังนี้

IMAGE: โหมดสำหรับการป้อนข้อมูลรูปภาพเดียว

วิดีโอ: โหมดสำหรับเฟรมที่ถอดรหัสของวิดีโอ

LIVE_Stream: โหมดสำหรับสตรีมแบบสดของข้อมูลอินพุต เช่น จากกล้อง ในโหมดนี้ ต้องมีการเรียกใช้ resultsListener เพื่อตั้งค่า Listener เพื่อรับผลลัพธ์แบบไม่พร้อมกัน
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
numposes จำนวนสูงสุดของท่าทางที่ตัวระบุตำแหน่ง จะตรวจจับได้ Integer > 0 1
minPoseDetectionConfidence คะแนนความเชื่อมั่นขั้นต่ำสำหรับการตรวจจับท่าทางจะถือว่าประสบความสำเร็จ Float [0.0,1.0] 0.5
minPosePresenceConfidence คะแนนความเชื่อมั่นขั้นต่ำของคะแนนการตรวจหาบุคคลในบ้าน ในการตรวจจับจุดสังเกต Float [0.0,1.0] 0.5
minTrackingConfidence คะแนนความเชื่อมั่นขั้นต่ำสำหรับการติดตามท่าทางจะถือว่าประสบความสำเร็จ Float [0.0,1.0] 0.5
outputSegmentationMasks Poseจุดสังเกตแสดงมาสก์การแบ่งกลุ่มสำหรับท่าทางที่ตรวจพบหรือไม่ Boolean False
resultListener ตั้งค่า Listener ผลลัพธ์ให้รับผลลัพธ์ของจุดสังเกต แบบไม่พร้อมกันเมื่อ Pose Marker อยู่ในโหมดสตรีมแบบสด ใช้ได้เมื่อตั้งค่าโหมดการทำงานเป็น LIVE_STREAM เท่านั้น ResultListener N/A
errorListener ตั้งค่า Listener ข้อผิดพลาดที่ไม่บังคับ ErrorListener N/A

เตรียมข้อมูล

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

โค้ดต่อไปนี้แสดงวิธีส่งต่อข้อมูลเพื่อการประมวลผล ตัวอย่างเหล่านี้มีรายละเอียดเกี่ยวกับวิธีจัดการข้อมูลจากรูปภาพ ไฟล์วิดีโอ และสตรีมวิดีโอสด

รูปภาพ

import com.google.mediapipe.framework.image.BitmapImageBuilder
import com.google.mediapipe.framework.image.MPImage

// Convert the input Bitmap object to an MPImage object to run inference
val mpImage = BitmapImageBuilder(image).build()
    

วิดีโอ

import com.google.mediapipe.framework.image.BitmapImageBuilder
import com.google.mediapipe.framework.image.MPImage

val argb8888Frame =
    if (frame.config == Bitmap.Config.ARGB_8888) frame
    else frame.copy(Bitmap.Config.ARGB_8888, false)

// Convert the input Bitmap object to an MPImage object to run inference
val mpImage = BitmapImageBuilder(argb8888Frame).build()
    

สตรีมแบบสด

import com.google.mediapipe.framework.image.BitmapImageBuilder
import com.google.mediapipe.framework.image.MPImage

// Convert the input Bitmap object to an MPImage object to run inference
val mpImage = BitmapImageBuilder(rotatedBitmap).build()
    

ในโค้ดตัวอย่าง Pose Marker ระบบจะจัดการการเตรียมข้อมูลในไฟล์ PoseLandmarkerHelper.kt

เรียกใช้งาน

ใช้เมธอด poseLandmarker.detect...() ที่เจาะจงสำหรับประเภทข้อมูลนั้น ทั้งนี้ขึ้นอยู่กับประเภทข้อมูลที่ใช้งานอยู่ ใช้ detect() สำหรับรูปภาพแต่ละรูป ใช้ detectForVideo() สำหรับเฟรมในไฟล์วิดีโอ และใช้ detectAsync() สำหรับสตรีมวิดีโอ เมื่อตรวจหาสตรีมวิดีโอ ให้เรียกใช้การตรวจจับในเทรดแยกต่างหากเพื่อหลีกเลี่ยงการบล็อกชุดข้อความที่ผู้ใช้แทรกเข้ามา

ตัวอย่างโค้ดต่อไปนี้แสดงตัวอย่างง่ายๆ ของวิธีเรียกใช้จุดวางจุดสังเกตในโหมดข้อมูลต่างๆ เหล่านี้

รูปภาพ

val result = poseLandmarker.detect(mpImage)
    

วิดีโอ

val timestampMs = i * inferenceIntervalMs

poseLandmarker.detectForVideo(mpImage, timestampMs)
    .let { detectionResult ->
        resultList.add(detectionResult)
    }
    

สตรีมแบบสด

val mpImage = BitmapImageBuilder(rotatedBitmap).build()
val frameTime = SystemClock.uptimeMillis()

poseLandmarker.detectAsync(mpImage, frameTime)
    

โปรดทราบดังต่อไปนี้

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

ในโค้ดตัวอย่าง Pose Marker ได้มีการระบุฟังก์ชัน detect, detectForVideo และ detectAsync ไว้ในไฟล์ PoseLandmarkerHelper.kt

แฮนเดิลและแสดงผลลัพธ์

Pose Landinger จะแสดงผลออบเจ็กต์ poseLandmarkerResult สำหรับการตรวจจับแต่ละครั้ง วัตถุผลลัพธ์มีพิกัดสำหรับจุดสังเกตของท่าโพสแต่ละรายการ

ตัวอย่างต่อไปนี้แสดงตัวอย่างข้อมูลเอาต์พุตจากงานนี้

PoseLandmarkerResult:
  Landmarks:
    Landmark #0:
      x            : 0.638852
      y            : 0.671197
      z            : 0.129959
      visibility   : 0.9999997615814209
      presence     : 0.9999984502792358
    Landmark #1:
      x            : 0.634599
      y            : 0.536441
      z            : -0.06984
      visibility   : 0.999909
      presence     : 0.999958
    ... (33 landmarks per pose)
  WorldLandmarks:
    Landmark #0:
      x            : 0.067485
      y            : 0.031084
      z            : 0.055223
      visibility   : 0.9999997615814209
      presence     : 0.9999984502792358
    Landmark #1:
      x            : 0.063209
      y            : -0.00382
      z            : 0.020920
      visibility   : 0.999976
      presence     : 0.999998
    ... (33 world landmarks per pose)
  SegmentationMasks:
    ... (pictured below)

ผลลัพธ์จะมีทั้งพิกัดปกติ (Landmarks) และพิกัดโลก (WorldLandmarks) สำหรับจุดสังเกตแต่ละแห่ง

เอาต์พุตมีพิกัดมาตรฐานต่อไปนี้ (Landmarks)

  • x และ y: พิกัดของจุดสังเกตที่เป็นค่ามาตรฐานระหว่าง 0.0 ถึง 1.0 ตามความกว้างของรูปภาพ (x) และความสูง (y)

  • z: ความลึกของจุดสังเกต โดยมีความลึกอยู่ที่จุดกึ่งกลางของสะโพกเป็นต้นกำเนิด ค่ายิ่งน้อยเท่าใด จุดสังเกตก็จะยิ่งอยู่ใกล้กับกล้อง ขนาดของ z ใช้สเกลใกล้เคียงกับ x

  • visibility: แนวโน้มที่จุดสังเกตจะปรากฏให้เห็นภายในรูปภาพ

ผลลัพธ์จะมีพิกัดโลกต่อไปนี้ (WorldLandmarks)

  • x, y และ z: พิกัด 3 มิติในชีวิตจริงในหน่วยเมตร โดยมีจุดกึ่งกลางของสะโพกเป็นต้นทาง

  • visibility: แนวโน้มที่จุดสังเกตจะปรากฏให้เห็นภายในรูปภาพ

รูปภาพต่อไปนี้แสดงภาพเอาต์พุตของงาน

มาสก์การแบ่งกลุ่ม (ไม่บังคับ) แสดงถึงความเป็นไปได้ที่พิกเซลแต่ละพิกเซลจะเป็นของบุคคลที่ตรวจพบ รูปภาพต่อไปนี้คือมาสก์การแบ่งกลุ่มของเอาต์พุตงาน

โค้ดตัวอย่าง Pose Marker จะสาธิตวิธีแสดงผลลัพธ์ที่ได้จากงาน ดูรายละเอียดเพิ่มเติมได้จากคลาส OverlayView