MediaPipe के साथ, Android पर डिवाइस पर इमेज जनरेट करना

1. परिचय

MediaPipe क्या है?

MediaPipe Solutions की मदद से, अपने ऐप्लिकेशन में मशीन लर्निंग (एमएल) के सलूशन लागू किए जा सकते हैं. यह पहले से तैयार प्रोसेसिंग पाइपलाइन को कॉन्फ़िगर करने के लिए एक फ़्रेमवर्क उपलब्ध कराता है. इससे, उपयोगकर्ताओं को तुरंत, दिलचस्प, और काम का आउटपुट मिलता है. डिफ़ॉल्ट मॉडल को अपडेट करने के लिए, MediaPipe मॉडल मेकर की मदद से, इनमें से कई समाधानों को अपनी पसंद के मुताबिक बनाया जा सकता है.

टेक्स्ट से इमेज जनरेट करना, एमएल के कई टास्क में से एक है. MediaPipe Solutions में यह सुविधा उपलब्ध है.

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

आपको क्या सीखने को मिलेगा

  • MediaPipe Tasks की मदद से, Android ऐप्लिकेशन में टेक्स्ट से इमेज जनरेट करने की सुविधा को स्थानीय तौर पर लागू करने का तरीका.

आपको किन चीज़ों की ज़रूरत होगी

  • Android Studio का इंस्टॉल किया गया वर्शन (इस कोडलैब को Android Studio Giraffe में लिखा और टेस्ट किया गया था).
  • ऐसा Android डिवाइस जिसकी रैम कम से कम 8 जीबी हो.
  • Android डेवलपमेंट की बुनियादी जानकारी और पहले से लिखी गई Python स्क्रिप्ट को चलाने की सुविधा.

2. Android ऐप्लिकेशन में MediaPipe Tasks जोड़ना

Android स्टार्टर ऐप्लिकेशन डाउनलोड करना

यह कोडलैब, पहले से तैयार किए गए सैंपल से शुरू होगा. इसमें यूज़र इंटरफ़ेस (यूआई) शामिल होगा, जिसका इस्तेमाल इमेज जनरेशन के बुनियादी वर्शन के लिए किया जाएगा. आपको वह शुरुआती ऐप्लिकेशन, MediaPipe के आधिकारिक सैंपल रेपो यहां मिलेगा. कोड > ZIP डाउनलोड करें पर क्लिक करके, रिपॉज़िटरी को क्लोन करें या ZIP फ़ाइल डाउनलोड करें.

ऐप्लिकेशन को Android Studio में इंपोर्ट करना

  1. Android Studio खोलें.
  2. Android Studio में आपका स्वागत है स्क्रीन पर, सबसे ऊपर दाएं कोने में मौजूद खोलें को चुनें.

a0b5b070b802e4ea.png

  1. उस जगह पर जाएं जहां आपने रिपॉज़िटरी को क्लोन किया है या डाउनलोड किया है. इसके बाद, codelabs/image_generation_basic/android/start डायरेक्ट्री खोलें.
  2. इस चरण में, ऐप्लिकेशन कंपाइल नहीं होना चाहिए, क्योंकि आपने अब तक MediaPipe Tasks की डिपेंडेंसी शामिल नहीं की है.

build.gradle फ़ाइल में जाकर और नीचे की ओर स्क्रोल करके // पहला चरण - डिपेंडेंसी जोड़ें पर जाकर, ऐप्लिकेशन को ठीक करें और उसे चलाएं. इसके बाद, यहां दी गई लाइन शामिल करें. इसके बाद, Android Studio में सबसे ऊपर मौजूद बैनर में दिखने वाले अभी सिंक करें बटन को दबाएं.

// Step 1 - Add dependency
implementation 'com.google.mediapipe:tasks-vision-image-generator:latest.release'

सिंक होने के बाद, Android Studio में सबसे ऊपर दाईं ओर मौजूद हरे रंग के रन ऐरो ( 7e15a9c9e1620fe7.png) पर क्लिक करके, पुष्टि करें कि सब कुछ सही तरीके से खुला और इंस्टॉल हुआ है. आपको ऐप्लिकेशन खुली हुई स्क्रीन पर दिखेगा. इसमें दो रेडियो बटन और शुरू करें लेबल वाला एक बटन होगा. उस बटन पर क्लिक करने पर, आपको तुरंत एक अलग यूज़र इंटरफ़ेस (यूआई) पर ले जाया जाएगा. इसमें, जनरेट करें लेबल वाले बटन के साथ-साथ एक टेक्स्ट प्रॉम्प्ट और अन्य विकल्प भी होंगे.

83c31de8e8a320ee.png 78b8765e832024e3.png

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

3. इमेज जनरेटर सेट अप करना

इस उदाहरण में, इमेज जनरेट करने का ज़्यादातर काम ImageGenerationHelper.kt फ़ाइल में होगा. इस फ़ाइल को खोलने पर, आपको क्लास के सबसे ऊपर imageGenerator नाम का वैरिएबल दिखेगा. यह वह टास्क ऑब्जेक्ट है जो आपके इमेज जनरेशन ऐप्लिकेशन में ज़्यादा काम करेगा.

उस ऑब्जेक्ट के ठीक नीचे, आपको initializeImageGenerator() नाम का फ़ंक्शन दिखेगा. साथ ही, इस फ़ंक्शन के नीचे यह टिप्पणी होगी: // Step 2 - initialize the image generator. जैसा कि आपको पता है, यहां ImageGenerator ऑब्जेक्ट को शुरू किया जाएगा. इमेज जनरेशन मॉडल का पाथ सेट करने और ImageGenerator ऑब्जेक्ट को शुरू करने के लिए, फ़ंक्शन के बॉडी को इस कोड से बदलें:

// Step 2 - initialize the image generator
val options = ImageGeneratorOptions.builder()
    .setImageGeneratorModelDirectory(modelPath)
    .build()

imageGenerator = ImageGenerator.createFromOptions(context, options)

इसके नीचे, आपको setInput() नाम का एक और फ़ंक्शन दिखेगा. यह तीन पैरामीटर स्वीकार करता है: प्रॉम्प्ट स्ट्रिंग, जिसका इस्तेमाल जनरेट की गई इमेज को तय करने के लिए किया जाएगा, नई इमेज जनरेट करते समय टास्क को पूरा करने के लिए ज़रूरी इटरेशन की संख्या, और सीड वैल्यू. इसका इस्तेमाल, उसी प्रॉम्प्ट के आधार पर इमेज के नए वर्शन बनाने के लिए किया जा सकता है. साथ ही, एक ही सीड का इस्तेमाल करके एक जैसी इमेज जनरेट की जा सकती है. इस फ़ंक्शन का मकसद, इमेज जनरेटर के लिए इन शुरुआती पैरामीटर को सेट करना है. ऐसा तब किया जाता है, जब आपको ऐसी इमेज बनानी हो जिसमें बीच के चरण दिखते हों.

setInput() बॉडी (जहां आपको टिप्पणी // तीसरा चरण - इनपुट स्वीकार करें दिखेगा) को इस लाइन से बदलें:

// Step 3 - accept inputs
imageGenerator.setInputs(prompt, iteration, seed)

अगले दो चरणों में, डेटा जनरेट होता है. generate() फ़ंक्शन, setInput फ़ंक्शन के जैसे ही इनपुट स्वीकार करता है. हालांकि, यह एक बार में इमेज जनरेट करता है और बीच के किसी भी चरण की इमेज नहीं दिखाता. इस फ़ंक्शन के मुख्य हिस्से (जिसमें टिप्पणी // चौथा चरण - दोहराव दिखाए बिना जनरेट करें शामिल है) को इनके साथ बदला जा सकता है:

// Step 4 - generate without showing iterations
val result = imageGenerator.generate(prompt, iteration, seed)
val bitmap = BitmapExtractor.extract(result?.generatedImage())
return bitmap

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

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

// Step 5 - generate with iterations
val result = imageGenerator.execute(showResult)

if (result == null || result.generatedImage() == null) {
    return Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888)
        .apply {
            val canvas = Canvas(this)
            val paint = Paint()
            paint.color = Color.WHITE
            canvas.drawPaint(paint)
        }
}

val bitmap =
    BitmapExtractor.extract(result.generatedImage())

return bitmap

हेल्पर फ़ाइल के लिए बस इतना ही. अगले सेक्शन में, आपको ViewModel फ़ाइल भरनी होगी, जो इस उदाहरण के लिए लॉजिक को मैनेज करती है.

4. ऐप्लिकेशन को एक साथ लाना

MainViewModel फ़ाइल, इस उदाहरण वाले ऐप्लिकेशन से जुड़े यूज़र इंटरफ़ेस (यूआई) के स्टेटस और अन्य लॉजिक को मैनेज करेगी. अब इसे खोलें.

फ़ाइल में सबसे ऊपर, आपको // छठा चरण - मॉडल का पाथ सेट करें टिप्पणी दिखेगी. यहां आपको अपने ऐप्लिकेशन को यह बताना होगा कि इमेज जनरेट करने के लिए ज़रूरी मॉडल फ़ाइलें कहां मिल सकती हैं. इस उदाहरण के लिए, आपको वैल्यू को /data/local/tmp/image_generator/bins/ पर सेट करना होगा.

// Step 6 - set model path
private val MODEL_PATH = "/data/local/tmp/image_generator/bins/"

वहां से, नीचे की ओर स्क्रोल करके generateImage() फ़ंक्शन पर जाएं. इस फ़ंक्शन के सबसे नीचे, आपको सातवां और आठवां चरण दिखेगा. इनका इस्तेमाल, क्रमशः नतीजों के तौर पर मिले आइटम या बिना किसी आइटम के इमेज जनरेट करने के लिए किया जाएगा. ये दोनों ऑपरेशन एक साथ होते हैं. इसलिए, आपको पता चलेगा कि इन्हें कोरुटाइन में रैप किया गया है. ImageGenerationHelper फ़ाइल से generate() को कॉल करने के लिए, // Step 7 - Generate without showing iterations को इस कोड ब्लॉक से बदलकर शुरू किया जा सकता है. इसके बाद, यूज़र इंटरफ़ेस (यूआई) की स्थिति अपडेट करें.

// Step 7 - Generate without showing iterations
val result = helper?.generate(prompt, iteration, seed)
_uiState.update {
    it.copy(outputBitmap = result)
}

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

// Step 8 - Generate with showing iterations
helper?.setInput(prompt, iteration, seed)
for (step in 0 until iteration) {
    isDisplayStep =
        (displayIteration > 0 && ((step + 1) % displayIteration == 0))
    val result = helper?.execute(isDisplayStep)

    if (isDisplayStep) {
        _uiState.update {
            it.copy(
                outputBitmap = result,
                generatingMessage = "Generating... (${step + 1}/$iteration)",
            )
        }
    }
}

अब आपके पास ऐप्लिकेशन इंस्टॉल करने, इमेज जनरेटर को शुरू करने, और टेक्स्ट प्रॉम्प्ट के आधार पर नई इमेज बनाने का विकल्प होगा

... हालांकि, अब इमेज जनरेटर को शुरू करने पर ऐप्लिकेशन क्रैश हो जाता है. ऐसा इसलिए होता है, क्योंकि आपको अपने डिवाइस पर मॉडल फ़ाइलें कॉपी करनी होती हैं. तीसरे पक्ष के उन मॉडल के बारे में अप-टू-डेट जानकारी पाने के लिए जिन्हें MediaPipe के टास्क के लिए इस्तेमाल किया जा सकता है, उन्हें अपने डिवाइस पर कॉपी करने के लिए, आधिकारिक दस्तावेज़ के इस सेक्शन को पढ़ें.

फ़ाइलों को सीधे अपने डेवलपमेंट डिवाइस पर कॉपी करने के साथ-साथ, Firebase Storage को भी सेट अप किया जा सकता है. इससे, रन टाइम पर ज़रूरी फ़ाइलों को सीधे उपयोगकर्ता के डिवाइस पर डाउनलोड किया जा सकता है.

5. ऐप्लिकेशन को डिप्लॉय और टेस्ट करना

इन सभी चरणों को पूरा करने के बाद, आपके पास एक ऐसा ऐप्लिकेशन होगा जो टेक्स्ट प्रॉम्प्ट स्वीकार कर सकता है और पूरी तरह से डिवाइस पर नई इमेज जनरेट कर सकता है! ऐप्लिकेशन की जांच करने के लिए, उसे किसी Android डिवाइस पर डिप्लॉय करें. हालांकि, याद रखें कि आपको इसे कम से कम 8 जीबी मेमोरी वाले डिवाइस पर आज़माना होगा.

  1. ऐप्लिकेशन चलाने के लिए, Android Studio टूलबार में मौजूद 'चालू करें' ( 7e15a9c9e1620fe7.png) पर क्लिक करें.
  2. जनरेशन के चरणों का टाइप चुनें (फ़ाइनल या दोहराव के साथ). इसके बाद, शुरू करें बटन दबाएं.
  3. अगली स्क्रीन पर, अपनी पसंद की कोई भी प्रॉपर्टी सेट करें. इसके बाद, जनरेट करें बटन पर क्लिक करके देखें कि टूल क्या दिखाता है.

e46cfaeb9d3fc235.gif

6. बधाई हो!

आपने कर दिखाया! इस कोडलैब में, आपको Android ऐप्लिकेशन में डिवाइस पर टेक्स्ट से इमेज जनरेट करने की सुविधा जोड़ने का तरीका पता चला है.

अगले चरण

इमेज जनरेट करने के टास्क की मदद से, और भी काम किए जा सकते हैं. जैसे:

  • प्लग इन की मदद से जनरेट की गई इमेज को स्ट्रक्चर करने के लिए, किसी बेस इमेज का इस्तेमाल करना या Vertex AI की मदद से, अपने अतिरिक्त LoRA वेट को ट्रेन करना.
  • अपने डिवाइस पर मॉडल फ़ाइलें वापस पाने के लिए, ADB टूल का इस्तेमाल किए बिना Firebase स्टोरेज का इस्तेमाल करें.

हमें यह देखने का इंतज़ार रहेगा कि इस एक्सपेरिमेंट के ज़रिए आपने कौन-कौनसी शानदार चीज़ें बनाई हैं. साथ ही, MediaPipe टीम के ज़्यादा कोडलैब और कॉन्टेंट पर नज़र बनाए रखें!