পোজ শ্রেণীবিভাগের বিকল্প

ML Kit Pose Detection API এর সাহায্যে, আপনি শরীরের বিভিন্ন অংশের আপেক্ষিক অবস্থান পরীক্ষা করে একটি ভঙ্গির অর্থপূর্ণ ব্যাখ্যা পেতে পারেন। এই পৃষ্ঠাটি কয়েকটি উদাহরণ দেখায়।

k-NN অ্যালগরিদমের সাথে পোজ শ্রেণীবিভাগ এবং পুনরাবৃত্তি গণনা

পোজ সনাক্তকরণের সবচেয়ে সাধারণ অ্যাপ্লিকেশনগুলির মধ্যে একটি হল ফিটনেস ট্র্যাকিং। একটি পোজ ক্লাসিফায়ার তৈরি করা যা নির্দিষ্ট ফিটনেস পোজকে স্বীকৃতি দেয় এবং পুনরাবৃত্তি গণনা করে ডেভেলপারদের জন্য একটি চ্যালেঞ্জিং কৃতিত্ব হতে পারে।

এই বিভাগে আমরা MediaPipe Colab ব্যবহার করে কীভাবে একটি কাস্টম পোজ ক্লাসিফায়ার তৈরি করেছি এবং আমাদের ML কিট নমুনা অ্যাপে একটি কার্যকরী শ্রেণীবদ্ধকারী প্রদর্শন করেছি তা বর্ণনা করি।

আপনি যদি Google Colaboratory এর সাথে অপরিচিত হন তবে অনুগ্রহ করে পরিচিতি নির্দেশিকাটি দেখুন।

ভঙ্গি চিনতে আমরা কে-নিকটবর্তী প্রতিবেশী অ্যালগরিদম (k-NN) ব্যবহার করি কারণ এটি সহজ এবং শুরু করা সহজ। প্রশিক্ষণ সেটের নিকটতম নমুনার উপর ভিত্তি করে অ্যালগরিদম বস্তুর শ্রেণী নির্ধারণ করে।

সনাক্তকারী তৈরি এবং প্রশিক্ষণের জন্য এই পদক্ষেপগুলি অনুসরণ করুন:

1. ছবির নমুনা সংগ্রহ করুন

আমরা বিভিন্ন উত্স থেকে লক্ষ্য অনুশীলনের চিত্র নমুনা সংগ্রহ করেছি। আমরা প্রতিটি ব্যায়ামের জন্য কয়েকশো ছবি বেছে নিয়েছি, যেমন পুশ-আপের জন্য "আপ" এবং "নিচে" অবস্থান। নমুনা সংগ্রহ করা গুরুত্বপূর্ণ যা ক্যামেরার বিভিন্ন কোণ, পরিবেশের অবস্থা, শরীরের আকার এবং ব্যায়ামের বিভিন্নতা কভার করে।

চিত্র 1. উপরে এবং নীচে পুশআপ পোজ পজিশন

2. নমুনা চিত্রগুলিতে ভঙ্গি সনাক্তকরণ চালান

এটি প্রশিক্ষণের জন্য ব্যবহার করার জন্য পোজ ল্যান্ডমার্কের একটি সেট তৈরি করে। আমরা ভঙ্গি সনাক্তকরণে আগ্রহী নই, যেহেতু আমরা পরবর্তী ধাপে আমাদের নিজস্ব মডেলকে প্রশিক্ষণ দেব।

কাস্টম পোজ শ্রেণীবিভাগের জন্য আমরা যে কে-এনএন অ্যালগরিদম বেছে নিয়েছি তাতে প্রতিটি নমুনার জন্য একটি বৈশিষ্ট্য ভেক্টর উপস্থাপনা এবং পোজ নমুনার কাছাকাছি লক্ষ্য খুঁজে পেতে দুটি ভেক্টরের মধ্যে দূরত্ব গণনা করার জন্য একটি মেট্রিকের প্রয়োজন। এর অর্থ হল আমরা এইমাত্র প্রাপ্ত পোজ ল্যান্ডমার্কগুলিকে রূপান্তর করতে হবে৷

পোজ ল্যান্ডমার্কগুলিকে একটি বৈশিষ্ট্য ভেক্টরে রূপান্তর করতে, আমরা পোজ জয়েন্টগুলির পূর্বনির্ধারিত তালিকার মধ্যে যুগলভাবে দূরত্ব ব্যবহার করি, যেমন কব্জি এবং কাঁধ, গোড়ালি এবং নিতম্ব এবং বাম এবং ডান কব্জির মধ্যে দূরত্ব। যেহেতু চিত্রের স্কেল পরিবর্তিত হতে পারে, তাই আমরা ল্যান্ডমার্কগুলিকে রূপান্তর করার আগে একই ধড়ের আকার এবং উল্লম্ব ধড়ের অভিযোজন থাকার জন্য ভঙ্গিগুলিকে স্বাভাবিক করেছি৷

3. মডেলকে প্রশিক্ষণ দিন এবং পুনরাবৃত্তি গণনা করুন

ক্লাসিফায়ারের কোড অ্যাক্সেস করতে এবং মডেলটিকে প্রশিক্ষণ দিতে আমরা MediaPipe Colab ব্যবহার করেছি।

পুনরাবৃত্তি গণনা করার জন্য, আমরা একটি টার্গেট পোজ অবস্থানের সম্ভাব্যতা থ্রেশহোল্ড নিরীক্ষণ করতে আরেকটি Colab অ্যালগরিদম ব্যবহার করেছি। যেমন:

  • যখন "ডাউন" পোজ ক্লাসের সম্ভাব্যতা প্রথমবারের জন্য একটি প্রদত্ত থ্রেশহোল্ড অতিক্রম করে, তখন অ্যালগরিদম চিহ্নিত করে যে "ডাউন" পোজ ক্লাসটি প্রবেশ করা হয়েছে।
  • যখন সম্ভাবনা থ্রেশহোল্ডের নীচে নেমে যায়, তখন অ্যালগরিদম চিহ্নিত করে যে "ডাউন" পোজ ক্লাস থেকে প্রস্থান করা হয়েছে এবং কাউন্টারকে বাড়িয়ে দেয়।
চিত্র 2. পুনরাবৃত্তি গণনার উদাহরণ

4. ML Kit quickstart অ্যাপের সাথে একীভূত করুন

উপরের Colab একটি CSV ফাইল তৈরি করে যা আপনি আপনার সমস্ত পোজ নমুনা দিয়ে তৈরি করতে পারেন। এই বিভাগে, আপনি রিয়েল টাইমে কাস্টম পোজ শ্রেণীবিভাগ দেখতে এমএল কিট অ্যান্ড্রয়েড কুইকস্টার্ট অ্যাপের সাথে কীভাবে আপনার CSV ফাইলকে একীভূত করবেন তা শিখবেন।

কুইকস্টার্ট অ্যাপে বান্ডিল করা নমুনা সহ পোজ ক্লাসিফিকেশন চেষ্টা করুন

আপনার নিজের CSV যোগ করুন

  • অ্যাপের সম্পদ ফোল্ডারে আপনার CSV ফাইল যোগ করুন।
  • PoseClassifierProcessor- এ, POSE_SAMPLES_FILE এবং POSE_CLASSES ভেরিয়েবল আপডেট করুন আপনার CSV ফাইলের সাথে মেলে এবং নমুনা পোজ করুন।
  • অ্যাপটি তৈরি করুন এবং চালান।

মনে রাখবেন যে পর্যাপ্ত নমুনা না থাকলে শ্রেণীবিভাগ ভালভাবে কাজ নাও করতে পারে। সাধারণত, আপনার পোজ ক্লাস প্রতি প্রায় 100 টি নমুনা প্রয়োজন।

আরও জানতে এবং নিজে এটি চেষ্টা করে দেখতে, MediaPipe Colab এবং MediaPipe শ্রেণিবিন্যাস নির্দেশিকা দেখুন।

ল্যান্ডমার্ক দূরত্ব গণনা করে সহজ অঙ্গভঙ্গি স্বীকৃতি

যখন দুই বা ততোধিক ল্যান্ডমার্ক একে অপরের কাছাকাছি থাকে, তখন সেগুলি অঙ্গভঙ্গি চিনতে ব্যবহার করা যেতে পারে। উদাহরণস্বরূপ, যখন একটি হাতের এক বা একাধিক আঙ্গুলের জন্য ল্যান্ডমার্ক নাকের জন্য ল্যান্ডমার্কের কাছাকাছি থাকে, আপনি অনুমান করতে পারেন যে ব্যবহারকারী সম্ভবত তাদের মুখ স্পর্শ করছে।

চিত্র 3. একটি ভঙ্গি ব্যাখ্যা করা

অ্যাঙ্গেল হিউরিস্টিকস সহ একটি যোগব্যায়াম ভঙ্গি সনাক্ত করা

আপনি বিভিন্ন জয়েন্টের কোণ গণনা করে একটি যোগ ভঙ্গি সনাক্ত করতে পারেন। উদাহরণস্বরূপ, চিত্র 2 নীচে ওয়ারিয়র II যোগ পোজ দেখায়। আনুমানিক কোণগুলি যা এই ভঙ্গিটিকে চিহ্নিত করে তা লেখা হয়েছে:

চিত্র 4. একটি ভঙ্গি কোণে ভাঙা

এই ভঙ্গিটিকে শরীরের আনুমানিক অংশ কোণের নিম্নলিখিত সংমিশ্রণ হিসাবে বর্ণনা করা যেতে পারে:

  • উভয় কাঁধে 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]];