با ML Kit Pose Detection API، میتوانید با بررسی موقعیتهای نسبی قسمتهای مختلف بدن، تفاسیر معنیداری از یک ژست دریافت کنید. این صفحه چند نمونه را نشان می دهد.
طبقه بندی پوزها و شمارش تکرار با الگوریتم k-NN
یکی از رایج ترین کاربردهای تشخیص پوس، ردیابی تناسب اندام است. ساختن یک طبقهبندی پوز که ژستهای تناسب اندام خاص را تشخیص میدهد و تکرارها را میشمارد، میتواند یک شاهکار چالش برانگیز برای توسعهدهندگان باشد.
در این بخش توضیح میدهیم که چگونه با استفاده از MediaPipe Colab یک طبقهبندیکننده حالت سفارشی ساختیم و یک طبقهبندیکننده فعال را در برنامه نمونه ML Kit خود نشان میدهیم.
اگر با Google Colaboratory آشنا نیستید، لطفاً راهنمای معرفی را بررسی کنید.
برای تشخیص پوزیشنها، از الگوریتم k-نزدیکترین همسایه (k-NN) استفاده میکنیم، زیرا شروع با آن ساده و آسان است. الگوریتم کلاس شی را بر اساس نزدیکترین نمونه ها در مجموعه آموزشی تعیین می کند.
برای ساختن و آموزش شناساگر مراحل زیر را دنبال کنید:
1. نمونه های تصویر را جمع آوری کنید
ما نمونه های تصویری تمرینات هدف را از منابع مختلف جمع آوری کردیم. ما چند صد تصویر را برای هر تمرین انتخاب کردیم، مانند موقعیت های "بالا" و "پایین" برای فشار دادن. جمع آوری نمونه هایی که زوایای مختلف دوربین، شرایط محیطی، شکل بدن و تغییرات ورزشی را پوشش می دهند، مهم است.
2. تشخیص پوس را روی تصاویر نمونه اجرا کنید
این مجموعه ای از نقاط عطف ژست را تولید می کند که برای آموزش استفاده می شود. ما علاقه ای به تشخیص پوس نداریم، زیرا در مرحله بعدی مدل خود را آموزش خواهیم داد.
الگوریتم k-NN که ما برای طبقهبندی حالت سفارشی انتخاب کردهایم، به یک نمایش بردار ویژگی برای هر نمونه و یک متریک برای محاسبه فاصله بین دو بردار برای یافتن نزدیکترین هدف به نمونه حالت نیاز دارد. این بدان معنی است که ما باید نشانه های پوزی را که به تازگی به دست آورده ایم تبدیل کنیم.
برای تبدیل نشانههای حالت به بردار ویژگی، از فواصل زوجی بین لیستهای از پیش تعریفشده مفاصل حالت، مانند فاصله بین مچ دست و شانه، مچ پا و لگن، و مچ دست چپ و راست استفاده میکنیم. از آنجایی که مقیاس تصاویر میتواند متفاوت باشد، قبل از تبدیل نشانهها، ژستها را به گونهای عادی کردیم که اندازه تنه و جهت عمودی تنه یکسان داشته باشند.
3. مدل را آموزش دهید و تکرارها را بشمارید
ما از MediaPipe Colab برای دسترسی به کد طبقهبندیکننده و آموزش مدل استفاده کردیم.
برای شمارش تکرارها، از الگوریتم کولب دیگری برای نظارت بر آستانه احتمال یک موقعیت هدف استفاده کردیم. به عنوان مثال:
- هنگامی که احتمال کلاس پوز "پایین" برای اولین بار از آستانه معینی عبور می کند، الگوریتم نشان می دهد که کلاس پوز "پایین" وارد شده است.
- وقتی احتمال به زیر آستانه میرسد، الگوریتم نشان میدهد که کلاس پوز «پایین» خارج شده است و شمارنده را افزایش میدهد.
4. با برنامه راه اندازی سریع ML Kit یکپارچه شوید
Colab بالا یک فایل CSV تولید می کند که می توانید با تمام نمونه های ژست خود پر کنید. در این بخش، یاد می گیرید که چگونه فایل CSV خود را با برنامه ML Kit اندروید سریع ادغام کنید تا طبقه بندی ژست های سفارشی را در زمان واقعی مشاهده کنید.
طبقه بندی ژست را با نمونه های همراه در برنامه شروع سریع امتحان کنید
- پروژه برنامه راه اندازی سریع اندروید ML Kit را از Github دریافت کنید و مطمئن شوید که به خوبی ساخته و اجرا می شود.
- به
LivePreviewActivity
بروید وRun classification
تشخیص پوس را از صفحه تنظیمات فعال کنید. اکنون باید بتوانید اسکات و اسکات را طبقه بندی کنید.
CSV خود را اضافه کنید
- فایل CSV خود را به پوشه دارایی برنامه اضافه کنید.
- در PoseClassifierProcessor ، متغیرهای
POSE_SAMPLES_FILE
وPOSE_CLASSES
را برای مطابقت با فایل CSV و نمونههای ژست بهروزرسانی کنید. - برنامه را بسازید و اجرا کنید.
توجه داشته باشید که اگر نمونه های کافی وجود نداشته باشد، ممکن است طبقه بندی به خوبی کار نکند. به طور کلی، شما به حدود 100 نمونه در هر کلاس پوز نیاز دارید.
برای کسب اطلاعات بیشتر و امتحان کردن این موضوع، راهنمای طبقه بندی MediaPipe Colab و MediaPipe را بررسی کنید.
تشخیص حرکات ساده با محاسبه فاصله نقطه عطف
هنگامی که دو یا چند نشانه نزدیک به یکدیگر هستند، می توان از آنها برای تشخیص حرکات استفاده کرد. به عنوان مثال، هنگامی که نقطه عطف یک یا چند انگشت روی دست نزدیک به نقطه عطف بینی است، می توانید استنباط کنید که کاربر به احتمال زیاد صورت خود را لمس می کند.
تشخیص ژست یوگا با اکتشافی زاویه
شما می توانید با محاسبه زوایای مفاصل مختلف، وضعیت یوگا را شناسایی کنید. به عنوان مثال، شکل 2 زیر ژست یوگا Warrior II را نشان می دهد. زوایای تقریبی که این ژست را مشخص می کند به صورت زیر نوشته شده است:
این حالت را می توان به عنوان ترکیب زیر از زوایای تقریبی اعضای بدن توصیف کرد:
- زاویه 90 درجه در هر دو شانه
- 180 درجه در هر دو آرنج
- زاویه 90 درجه در پا و کمر جلو
- زاویه 180 درجه در زانوی عقب
- زاویه 135 درجه در کمر
برای محاسبه این زوایا می توانید از نشانه های پوز استفاده کنید. به عنوان مثال، زاویه در پای راست جلو و کمر، زاویه بین خط از شانه راست تا باسن راست، و خط از باسن راست تا زانوی راست است.
هنگامی که تمام زوایای مورد نیاز برای شناسایی ژست را محاسبه کردید، می توانید بررسی کنید که آیا مطابقت دارد یا خیر، در این صورت شما ژست را تشخیص داده اید.
قطعه کد زیر نحوه استفاده از مختصات X و Y را برای محاسبه زاویه بین دو قسمت بدن نشان می دهد. این رویکرد به طبقه بندی محدودیت هایی دارد. تنها با بررسی X و Y، زوایای محاسبه شده با توجه به زاویه بین سوژه و دوربین متفاوت است. بهترین نتایج را با یک تصویر سطح، مستقیم و رو به جلو دریافت خواهید کرد. همچنین میتوانید این الگوریتم را با استفاده از مختصات Z گسترش دهید و ببینید آیا این الگوریتم برای مورد استفاده شما بهتر عمل میکند یا خیر.
محاسبه زوایای برجسته در اندروید
روش زیر زاویه بین هر سه نشانه را محاسبه می کند. این تضمین می کند که زاویه برگشت بین 0 تا 180 درجه است.
کاتلین
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 }
جاوا
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; }
در اینجا نحوه محاسبه زاویه در لگن راست آمده است:
کاتلین
val rightHipAngle = getAngle( pose.getPoseLandmark(PoseLandmark.Type.RIGHT_SHOULDER), pose.getPoseLandmark(PoseLandmark.Type.RIGHT_HIP), pose.getPoseLandmark(PoseLandmark.Type.RIGHT_KNEE))
جاوا
double rightHipAngle = getAngle( pose.getPoseLandmark(PoseLandmark.Type.RIGHT_SHOULDER), pose.getPoseLandmark(PoseLandmark.Type.RIGHT_HIP), pose.getPoseLandmark(PoseLandmark.Type.RIGHT_KNEE));
محاسبه زوایای برجسته در iOS
روش زیر زاویه بین هر سه نشانه را محاسبه می کند. این تضمین می کند که زاویه برگشت بین 0 تا 180 درجه است.
سویفت
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 }
هدف-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; }
در اینجا نحوه محاسبه زاویه در لگن راست آمده است:
سویفت
let rightHipAngle = angle( firstLandmark: pose.landmark(ofType: .rightShoulder), midLandmark: pose.landmark(ofType: .rightHip), lastLandmark: pose.landmark(ofType: .rightKnee))
هدف-C
CGFloat rightHipAngle = [self angleFromFirstLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightShoulder] midLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightHip] lastLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightKnee]];