Android के लिए, हाथ के लैंडमार्क का पता लगाने वाली गाइड

MediaPipe हैंड लैंडमार्क टास्क की मदद से, इमेज में मौजूद हाथों के लैंडमार्क का पता लगाया जा सकता है. इन निर्देशों में Android ऐप्लिकेशन के साथ हैंड लैंडमार्कर इस्तेमाल करने का तरीका बताया गया है. इन निर्देशों में बताया गया कोड सैंपल, GitHub पर उपलब्ध है.

इस टास्क की क्षमताओं, मॉडल, और कॉन्फ़िगरेशन विकल्पों के बारे में ज़्यादा जानकारी के लिए, खास जानकारी देखें.

कोड का उदाहरण

MediaPipe Tasks का उदाहरण कोड, Android के लिए हैंड लैंडमार्कर ऐप्लिकेशन को आसानी से लागू करने का एक आसान तरीका है. इस उदाहरण में, Android डिवाइस के कैमरे का इस्तेमाल करके, हाथ के लैंडमार्क का लगातार पता लगाया जा सकता है. साथ ही, डिवाइस की गैलरी से इमेज और वीडियो का इस्तेमाल किया जा सकता है, ताकि हाथ के लैंडमार्क का स्थिर रूप से पता लगाया जा सके.

इस ऐप्लिकेशन को, अपने Android ऐप्लिकेशन के लिए शुरुआती पॉइंट के तौर पर इस्तेमाल किया जा सकता है. इसके अलावा, किसी मौजूदा ऐप्लिकेशन में बदलाव करते समय इसका इस्तेमाल भी किया जा सकता है. हैंड लैंडमार्कर के उदाहरण वाले कोड को GitHub पर होस्ट किया जाता है.

कोड डाउनलोड करें

नीचे दिए गए निर्देशों में git कमांड लाइन टूल का इस्तेमाल करके, उदाहरण कोड की लोकल कॉपी बनाने का तरीका बताया गया है.

उदाहरण कोड डाउनलोड करने के लिए:

  1. नीचे दिए गए निर्देश का इस्तेमाल करके, गिट रिपॉज़िटरी का क्लोन बनाएं:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. इसके अलावा, स्पार्स चेकआउट का इस्तेमाल करने के लिए अपना गिट इंस्टेंस कॉन्फ़िगर करें, ताकि आपके पास सिर्फ़ हैंड लैंडमार्कर के उदाहरण वाले ऐप्लिकेशन की फ़ाइलें रहें:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/hand_landmarker/android
    

उदाहरण कोड का स्थानीय वर्शन बनाने के बाद, प्रोजेक्ट को Android Studio में इंपोर्ट किया जा सकता है. इसके बाद, ऐप्लिकेशन को चलाया जा सकता है. निर्देशों के लिए, Android के लिए सेटअप गाइड देखें.

मुख्य कॉम्पोनेंट

इन फ़ाइलों में हैंड लैंडमार्क की पहचान करने वाले ऐप्लिकेशन के लिए ज़रूरी कोड मौजूद है:

  • HandLandmarkerHelper.kt - हैंड लैंडमार्क की पहचान करने वाली सुविधा शुरू करता है. साथ ही, मॉडल और प्रतिनिधि चुनने का काम भी करता है.
  • MainActivity.kt - ऐप्लिकेशन को लागू करता है. इसमें HandLandmarkerHelper को कॉल करना भी शामिल है.

सेटअप

इस सेक्शन में, डेवलपमेंट एनवायरमेंट को सेट अप करने के मुख्य चरणों के बारे में बताया गया है. साथ ही, यह भी बताया गया है कि खास तौर पर हैंड लैंडमार्क का इस्तेमाल करने के लिए, कोड प्रोजेक्ट कैसे सेट अप किए जाते हैं. MediaPipe Tasks का इस्तेमाल करने और प्लैटफ़ॉर्म के वर्शन की ज़रूरी शर्तों के साथ-साथ अपना डेवलपमेंट एनवायरमेंट सेट अप करने से जुड़ी सामान्य जानकारी के लिए, Android के लिए सेटअप गाइड देखें.

डिपेंडेंसी

हैंड लैंडमार्क टास्क में com.google.mediapipe:tasks-vision लाइब्रेरी का इस्तेमाल होता है. अपने Android ऐप्लिकेशन की build.gradle फ़ाइल में यह डिपेंडेंसी जोड़ें:

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

मॉडल

MediaPipe हैंड लैंडमार्कर टास्क के लिए एक प्रशिक्षित मॉडल बंडल की ज़रूरत होती है, जो इस टास्क के साथ काम कर सके. हैंड लैंडमार्कर के लिए उपलब्ध ट्रेनिंग मॉडल के बारे में ज़्यादा जानने के लिए, टास्क की खास जानकारी वाला मॉडल सेक्शन देखें.

मॉडल चुनें और डाउनलोड करें और इसे अपनी प्रोजेक्ट डायरेक्ट्री में स्टोर करें:

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

ModelAssetPath पैरामीटर में मॉडल का पाथ बताएं. उदाहरण कोड में, मॉडल की जानकारी HandLandmarkerHelper.kt फ़ाइल में दी गई है:

baseOptionBuilder.setModelAssetPath(MP_HAND_LANDMARKER_TASK)

टास्क बनाएं

MediaPipe हैंड लैंडमार्क टास्क, टास्क को सेट अप करने के लिए createFromOptions() फ़ंक्शन का इस्तेमाल करता है. createFromOptions() फ़ंक्शन, कॉन्फ़िगरेशन के विकल्पों के लिए वैल्यू स्वीकार करता है. कॉन्फ़िगरेशन के विकल्पों के बारे में ज़्यादा जानकारी के लिए, कॉन्फ़िगरेशन के विकल्प देखें.

हैंड लैंडमार्कर में तीन तरह के इनपुट डेटा टाइप काम करते हैं: स्टिल इमेज, वीडियो फ़ाइलें, और लाइव स्ट्रीम. टास्क बनाते समय, आपको अपने इनपुट डेटा टाइप के हिसाब से 'रनिंग मोड' तय करना होगा. टास्क बनाने और अनुमान लगाने का तरीका जानने के लिए, अपने इनपुट डेटा टाइप के हिसाब से टैब चुनें.

Image

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

val optionsBuilder =
    HandLandmarker.HandLandmarkerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setNumHands(maxNumHands)
        .setRunningMode(RunningMode.IMAGE)

val options = optionsBuilder.build()

handLandmarker =
    HandLandmarker.createFromOptions(context, options)
    

वीडियो

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

val optionsBuilder =
    HandLandmarker.HandLandmarkerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setNumHands(maxNumHands)
        .setRunningMode(RunningMode.VIDEO)

val options = optionsBuilder.build()

handLandmarker =
    HandLandmarker.createFromOptions(context, options)
    

लाइव स्ट्रीम

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

val optionsBuilder =
    HandLandmarker.HandLandmarkerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setNumHands(maxNumHands)
        .setResultListener(this::returnLivestreamResult)
        .setErrorListener(this::returnLivestreamError)
        .setRunningMode(RunningMode.VIDEO)

val options = optionsBuilder.build()

handLandmarker =
    HandLandmarker.createFromOptions(context, options)
    

हैंड लैंडमार्कर का उदाहरण कोड लागू करने पर, उपयोगकर्ता एक से दूसरे प्रोसेसिंग मोड पर स्विच कर सकता है. यह तरीका टास्क बनाने वाले कोड को ज़्यादा जटिल बना देता है. ऐसा भी हो सकता है कि वह आपके इस्तेमाल के उदाहरण के लिए सही न हो. आपके पास इस कोड को HandLandmarkerHelper.kt फ़ाइल में मौजूद setupHandLandmarker() फ़ंक्शन में देखने का विकल्प है.

कॉन्फ़िगरेशन विकल्प

इस टास्क में, Android ऐप्लिकेशन के कॉन्फ़िगरेशन के ये विकल्प मौजूद हैं:

विकल्प का नाम ब्यौरा वैल्यू रेंज डिफ़ॉल्ट मान
runningMode टास्क के लिए, रनिंग मोड सेट करता है. इसके तीन मोड होते हैं:

इमेज: सिंगल इमेज इनपुट के लिए मोड.

वीडियो: वीडियो के डिकोड किए गए फ़्रेम का मोड.

LIVE_STREAM: इनपुट डेटा की लाइव स्ट्रीम का मोड, जैसे कि कैमरे से स्ट्रीम किया जाने वाला मोड. इस मोड में, रिज़ल्ट पहचानकर्ता को लिसनर को सेट अप करने के लिए कॉल किया जाना चाहिए, ताकि वह एसिंक्रोनस तरीके से नतीजे पा सके.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
numHands हैंड लैंडमार्क डिटेक्टर की मदद से, ज़्यादा से ज़्यादा कितने हाथ पहचाने गए हैं. Any integer > 0 1
minHandDetectionConfidence हाथ की पहचान करने वाली सुविधा के लिए, पाम डिटेक्शन मॉडल में सबसे कम कॉन्फ़िडेंस स्कोर. 0.0 - 1.0 0.5
minHandPresenceConfidence हैंड लैंडमार्क डिटेक्शन मॉडल में हाथ की मौजूदगी के स्कोर के लिए कम से कम कॉन्फ़िडेंस स्कोर. वीडियो मोड और लाइव स्ट्रीम मोड में, अगर हैंड लैंडमार्क मॉडल के हाथ की मौजूदगी का कॉन्फ़िडेंस स्कोर इस थ्रेशोल्ड से कम है, तो हैंड लैंडमार्कर, हथेली की पहचान करने वाले मॉडल को ट्रिगर करता है. ऐसा न होने पर, लाइटवेट हैंड ट्रैकिंग एल्गोरिदम, लैंडमार्क की बाद में पहचान करने के लिए हाथों की जगह का पता लगाता है. 0.0 - 1.0 0.5
minTrackingConfidence हैंड ट्रैकिंग के लिए सबसे कम कॉन्फ़िडेंस स्कोर, जिसे कामयाब माना जाएगा. यह मौजूदा फ़्रेम और आखिरी फ़्रेम में मौजूद हाथों के बीच का बाउंडिंग बॉक्स IoU थ्रेशोल्ड है. अगर हैंड लैंडमार्कर के वीडियो मोड और स्ट्रीम मोड में ट्रैकिंग काम नहीं करती है, तो हैंड लैंडमार्कर हाथ की पहचान करने की सुविधा को ट्रिगर कर देता है. ऐसा न होने पर, हाथ की पहचान करने वाली सुविधा को छोड़ दें. 0.0 - 1.0 0.5
resultListener जब हैंड लैंडमार्कर लाइव स्ट्रीम मोड में होता है, तब नतीजे लिसनर को सेट करता है, ताकि इसे एसिंक्रोनस तरीके से, खोज के नतीजे पाए जा सकें. सिर्फ़ तब लागू होता है, जब रनिंग मोड को LIVE_STREAM पर सेट किया गया हो लागू नहीं लागू नहीं
errorListener गड़बड़ी की जानकारी देने वाला वैकल्पिक लिसनर सेट करता है. लागू नहीं लागू नहीं

डेटा तैयार करना

हैंड लैंडमार्कर, इमेज, वीडियो फ़ाइल, और लाइव स्ट्रीम वीडियो के साथ काम करता है. यह टास्क, डेटा इनपुट की प्री-प्रोसेसिंग को हैंडल करता है. इसमें साइज़ बदलना, घुमाना, और वैल्यू को सामान्य बनाना भी शामिल है.

इस कोड में बताया गया है कि डेटा को प्रोसेसिंग के लिए कैसे दें. यहां दिए गए सैंपल में, इमेज, वीडियो फ़ाइलों, और लाइव वीडियो स्ट्रीम के डेटा को मैनेज करने के तरीके के बारे में जानकारी शामिल है.

Image

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

'हैंड लैंडमार्कर' के उदाहरण वाले कोड में, डेटा तैयार करने की जानकारी HandLandmarkerHelper.kt फ़ाइल में दी गई है.

टास्क चलाएं

आपको किस तरह के डेटा के साथ काम करना है, इस आधार पर HandLandmarker.detect...() वाला तरीका इस्तेमाल करें. यह तरीका खास तौर पर उस डेटा टाइप के हिसाब से होना चाहिए. अलग-अलग इमेज के लिए detect(), वीडियो फ़ाइलों में फ़्रेम के लिए detectForVideo(), और वीडियो स्ट्रीम के लिए detectAsync() का इस्तेमाल करें. किसी वीडियो स्ट्रीम पर डिटेक्शन चलाते समय, यूज़र इंटरफ़ेस थ्रेड को ब्लॉक होने से बचाने के लिए, पक्का करें कि आप डिटेक्शन को किसी अलग थ्रेड पर चलाएं.

नीचे दिए गए कोड सैंपल, इन अलग-अलग डेटा मोड में हैंड लैंडमार्कर को चलाने के कुछ आसान उदाहरण दिखाते हैं:

Image

val result = handLandmarker?.detect(mpImage)
    

वीडियो

val timestampMs = i * inferenceIntervalMs

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

लाइव स्ट्रीम

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

handLandmarker?.detectAsync(mpImage, frameTime)
    

निम्न पर ध्यान दें:

  • वीडियो मोड या लाइव स्ट्रीम मोड में चलाते समय, आपको हैंड लैंडमार्कर टास्क को इनपुट फ़्रेम का टाइमस्टैंप भी देना होगा.
  • इमेज या वीडियो मोड में चलाते समय, 'हैंड लैंडमार्कर' टास्क मौजूदा थ्रेड को तब तक ब्लॉक रखेगा, जब तक कि वह इनपुट इमेज या फ़्रेम की प्रोसेसिंग पूरी नहीं कर लेता. यूज़र इंटरफ़ेस को ब्लॉक होने से बचाने के लिए, प्रोसेसिंग को बैकग्राउंड थ्रेड में चलाएं.
  • लाइव स्ट्रीम मोड में चलाते समय, 'हैंड लैंडमार्कर टास्क' मौजूदा थ्रेड को ब्लॉक नहीं करता. हालांकि, वह तुरंत वापस आ जाता है. यह जब भी इनपुट फ़्रेम की प्रोसेसिंग पूरी करेगा, तब यह खोज के नतीजे के साथ अपने रिज़ल्ट लिसनर को शुरू करेगा. अगर हैंड लैंडमार्कर टास्क किसी दूसरे फ़्रेम को प्रोसेस करने में व्यस्त होने पर पहचान फ़ंक्शन कॉल किया जाता है, तो यह टास्क नए इनपुट फ़्रेम को अनदेखा कर देगा.

हैंड लैंडमार्कर के उदाहरण कोड में, detect, detectForVideo, और detectAsync फ़ंक्शन के बारे में HandLandmarkerHelper.kt फ़ाइल में बताया गया है.

नतीजे मैनेज करें और दिखाएं

हैंड लैंडमार्कर, जांच के बाद चलाए जाने वाले हर नतीजे के लिए, हैंड लैंडमार्कर नतीजे के लिए एक ऑब्जेक्ट जनरेट करता है. नतीजे के ऑब्जेक्ट में, इमेज के निर्देशांकों में हैंड लैंडमार्क, दुनिया के निर्देशांकों में हैंडमार्क, और पहचाने गए हाथों की हैंडराइटिंग(बायां/दाएं हाथ) होती है.

इस टास्क के आउटपुट डेटा का एक उदाहरण यहां दिया गया है:

HandLandmarkerResult आउटपुट में तीन कॉम्पोनेंट होते हैं. हर कॉम्पोनेंट एक कलेक्शन है. इसमें किसी एक हाथ की पहचान करने वाले हर एलिमेंट के लिए ये नतीजे शामिल होते हैं:

  • हाथ का इस्तेमाल

    हाथ का इस्तेमाल यह बताता है कि पहचाने गए हाथ बाएं हाथ हैं या दाएं.

  • लैंडमार्क

    यहां 21 हैंड लैंडमार्क हैं, जिनमें से हर एक में x, y, और z निर्देशांक हैं. x और y कोऑर्डिनेट को इमेज की चौड़ाई और ऊंचाई के हिसाब से [0.0, 1.0] नॉर्मलाइज़ किया जाता है. z निर्देशांक, लैंडमार्क की गहराई दिखाता है. इसमें, कलाई पर मौजूद गहराई का मतलब, शुरुआत की जगह होता है. वैल्यू जितनी छोटी होगी, लैंडमार्क कैमरे के उतना ही करीब होगा. z की तीव्रता x के बराबर तीव्रता का इस्तेमाल करती है.

  • विश्व भू-स्थल

    दुनिया के निर्देशांकों में भी इन 21 हाथ की मशहूर जगहों को दिखाया गया है. हर लैंडमार्क x, y, और z से मिलकर बना है. यह असल दुनिया के 3D निर्देशांक को मीटर में दिखाता है और इन निर्देशांकों को हाथ के ज्यामितीय केंद्र में रखा गया है.

HandLandmarkerResult:
  Handedness:
    Categories #0:
      index        : 0
      score        : 0.98396
      categoryName : Left
  Landmarks:
    Landmark #0:
      x            : 0.638852
      y            : 0.671197
      z            : -3.41E-7
    Landmark #1:
      x            : 0.634599
      y            : 0.536441
      z            : -0.06984
    ... (21 landmarks for a hand)
  WorldLandmarks:
    Landmark #0:
      x            : 0.067485
      y            : 0.031084
      z            : 0.055223
    Landmark #1:
      x            : 0.063209
      y            : -0.00382
      z            : 0.020920
    ... (21 world landmarks for a hand)

इस इमेज में, टास्क के आउटपुट का विज़ुअलाइज़ेशन दिखाया गया है:

हैंड लैंडमार्क के उदाहरण वाले कोड से, टास्क से दिखाए गए नतीजों को दिखाने का तरीका पता चलता है. ज़्यादा जानकारी के लिए, OverlayView क्लास देखें.