การสร้างรูปภาพในอุปกรณ์บน Android ด้วย MediaPipe

1. บทนำ

MediaPipe คืออะไร

โซลูชัน MediaPipe ช่วยให้คุณใช้โซลูชันแมชชีนเลิร์นนิง (ML) กับแอปได้ โดยมีเฟรมเวิร์กสำหรับการกำหนดค่าไปป์ไลน์การประมวลผลที่สร้างไว้ล่วงหน้า ซึ่งจะแสดงเอาต์พุตที่น่าสนใจและมีประโยชน์แก่ผู้ใช้ทันที คุณยังปรับแต่งโซลูชันเหล่านี้หลายรายการด้วย MediaPipe Model Maker เพื่ออัปเดตโมเดลเริ่มต้นได้ด้วย

การเปลี่ยนข้อความเป็นรูปภาพเป็นหนึ่งในงาน ML หลายอย่างที่โซลูชัน MediaPipe มีให้

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

สิ่งที่คุณจะได้เรียนรู้

  • วิธีใช้การเปลี่ยนข้อความเป็นรูปภาพที่ทำงานในเครื่องในแอป Android ด้วย MediaPipe Tasks

สิ่งที่คุณต้องมี

  • Android Studio เวอร์ชันที่ติดตั้งแล้ว (Codelab นี้เขียนและทดสอบด้วย Android Studio Giraffe)
  • อุปกรณ์ Android ที่มี RAM อย่างน้อย 8 GB
  • ความรู้พื้นฐานเกี่ยวกับการพัฒนา Android และความสามารถในการเรียกใช้สคริปต์ Python ที่เขียนไว้ล่วงหน้า

2. เพิ่ม MediaPipe Tasks ลงในแอป Android

ดาวน์โหลดแอปเริ่มต้นสำหรับ Android

Codelab นี้จะเริ่มต้นด้วยตัวอย่างที่สร้างไว้ล่วงหน้าซึ่งประกอบด้วย UI ที่จะใช้สำหรับการสร้างรูปภาพเวอร์ชันพื้นฐาน คุณสามารถดูแอปเริ่มต้นได้ในที่เก็บตัวอย่าง MediaPipe อย่างเป็นทางการ ที่นี่ โคลนที่เก็บหรือดาวน์โหลดไฟล์ ZIP โดยคลิก "โค้ด" > "ดาวน์โหลด ZIP"

นำเข้าแอปไปยัง Android Studio

  1. เปิด Android Studio
  2. จากหน้าจอ Welcome to Android Studio ให้เลือก Open ที่มุมขวาบน

a0b5b070b802e4ea.png

  1. ไปที่ตำแหน่งที่คุณโคลนหรือดาวน์โหลดที่เก็บ แล้วเปิด ไดเรกทอรี codelabs/image_generation_basic/android/start
  2. ในขั้นตอนนี้ แอปไม่ควรคอมไพล์ เนื่องจากคุณยังไม่ได้รวมทรัพยากร Dependency ของ MediaPipe Tasks

คุณจะแก้ไขแอปและทำให้แอปทำงานได้โดยไปที่ไฟล์ build.gradle แล้วเลื่อนลงไปที่ // Step 1 - Add dependency จากนั้นรวมบรรทัดต่อไปนี้ แล้วคลิกปุ่ม Sync Now ที่ปรากฏในแบนเนอร์ที่ด้านบนของ Android Studio

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

เมื่อการซิงค์เสร็จสมบูรณ์แล้ว ให้ตรวจสอบว่าทุกอย่างเปิดและติดตั้งอย่างถูกต้องโดยคลิกที่ลูกศรสีเขียว run ( 7e15a9c9e1620fe7.png) ที่ด้านขวาบนของ Android Studio คุณควรเห็นแอปเปิดขึ้นมาเป็นหน้าจอที่มีปุ่มตัวเลือก 2 ปุ่มและปุ่มที่มีป้ายกำกับว่า INITIALIZE หากคลิกปุ่มดังกล่าว ระบบจะนำคุณไปยัง UI แยกต่างหากซึ่งประกอบด้วยพรอมต์ข้อความและตัวเลือกอื่นๆ พร้อมกับปุ่มที่มีป้ายกำกับว่า GENERATE ทันที

83c31de8e8a320ee.png 78b8765e832024e3.png

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

3. การตั้งค่าเครื่องมือสร้างรูปภาพ

สำหรับตัวอย่างนี้ งานสร้างรูปภาพส่วนใหญ่จะเกิดขึ้นในไฟล์ ImageGenerationHelper.kt เมื่อเปิดไฟล์นี้ คุณจะเห็นตัวแปรที่ด้านบนของคลาสที่ชื่อว่า imageGenerator ซึ่งเป็นออบเจ็กต์ Task ที่จะทำงานหนักในแอปสร้างรูปภาพ

ใต้ออบเจ็กต์นั้น คุณจะเห็นฟังก์ชันที่ชื่อว่า initializeImageGenerator() พร้อมความคิดเห็นต่อไปนี้ // Step 2 - เริ่มต้นโปรแกรมสร้างรูปภาพ อย่างที่คุณอาจเดาได้ว่านี่คือตำแหน่งที่คุณจะเริ่มต้นออบเจ็กต์ ImageGenerator แทนที่เนื้อหาของฟังก์ชันนั้นด้วยโค้ดต่อไปนี้เพื่อตั้งค่าเส้นทางโมเดลการสร้างรูปภาพและเริ่มต้นออบเจ็กต์ ImageGenerator

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

imageGenerator = ImageGenerator.createFromOptions(context, options)

ด้านล่างนั้น คุณจะเห็นฟังก์ชันอื่นที่ชื่อว่า setInput() ซึ่งยอมรับพารามิเตอร์ 3 รายการ ได้แก่ สตริง prompt ที่จะใช้กำหนดรูปภาพที่สร้าง จำนวนการทำซ้ำ ที่ Task ควรดำเนินการขณะสร้างรูปภาพใหม่ และค่า seed ที่ใช้สร้างรูปภาพเวอร์ชันใหม่ตามพรอมต์เดียวกันได้ขณะสร้างรูปภาพ เดียวกัน เมื่อใช้ seed เดียวกัน จุดประสงค์ของฟังก์ชันนี้คือการตั้งค่าพารามิเตอร์เริ่มต้นเหล่านี้สำหรับโปรแกรมสร้างรูปภาพเมื่อคุณพยายามสร้างรูปภาพที่ แสดง ขั้นตอนระดับกลาง

ไปที่เนื้อหาของ setInput() (ตำแหน่งที่คุณจะเห็นความคิดเห็น // Step 3 - accept inputs) แล้วแทนที่ด้วยบรรทัดนี้

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

การสร้างจะเกิดขึ้นใน 2 ขั้นตอนถัดไป ฟังก์ชัน generate() ยอมรับอินพุตเดียวกันกับ setInput แต่จะสร้างรูปภาพเป็นการเรียกใช้แบบครั้งเดียวที่ไม่แสดงรูปภาพขั้นตอนระดับกลาง คุณสามารถแทนที่เนื้อหาของฟังก์ชันนี้ (ซึ่งรวมถึงความคิดเห็น // Step 4 - generate without showing iterations) ด้วยเนื้อหาต่อไปนี้

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

สิ่งสำคัญที่ควรทราบคือ Task นี้เกิดขึ้นแบบ ซิงโครนัส ดังนั้นคุณจะต้องเรียกใช้ฟังก์ชันจากเธรดเบื้องหลัง คุณจะได้เรียนรู้เพิ่มเติมเกี่ยวกับเรื่องนี้ในภายหลังใน Codelab นี้

ขั้นตอนสุดท้ายที่คุณจะทำในไฟล์นี้คือการกรอกฟังก์ชัน execute() (ติดป้ายกำกับว่า Step 5) ฟังก์ชันนี้จะยอมรับพารามิเตอร์ที่บอกว่าควรแสดงรูปภาพระดับกลางหรือไม่สำหรับ ขั้นตอนเดียว ของการสร้างที่จะดำเนินการด้วยฟังก์ชัน execute() ของ ImageGenerator แทนที่เนื้อหาของฟังก์ชันด้วยโค้ดนี้

// 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

และนี่คือทั้งหมดสำหรับไฟล์ Helper ในส่วนถัดไป คุณจะกรอกไฟล์ ViewModel ที่จัดการตรรกะสำหรับตัวอย่างนี้

4. การรวมแอป

ไฟล์ MainViewModel จะจัดการสถานะ UI และตรรกะอื่นๆ ที่เกี่ยวข้องกับแอปตัวอย่างนี้ เปิดไฟล์นี้เลย

ที่ด้านบนของไฟล์ คุณควรเห็นความคิดเห็น // Step 6 - set model path ซึ่งเป็นตำแหน่งที่คุณจะบอกแอปว่าแอปจะค้นหาไฟล์โมเดลที่จำเป็นสำหรับการสร้างรูปภาพได้ที่ใด สำหรับตัวอย่างนี้ คุณจะตั้งค่าเป็น /data/local/tmp/image_generator/bins/

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

จากนั้นเลื่อนลงไปที่ฟังก์ชัน generateImage() ที่ด้านล่างของฟังก์ชันนี้ คุณจะเห็นทั้ง Step 7 และ Step 8 ซึ่งจะใช้สร้างรูปภาพโดยมีการทำซ้ำที่แสดงหรือไม่แสดงตามลำดับ เนื่องจากทั้ง 2 การดำเนินการนี้เกิดขึ้นแบบ ซิงโครนัส คุณจะเห็นว่าการดำเนินการทั้ง 2 นี้อยู่ในโครูทีน คุณสามารถเริ่มต้นด้วยการแทนที่ // Step 7 - Generate without showing iterations ด้วยบล็อกโค้ดนี้เพื่อเรียกใช้ generate() จากไฟล์ ImageGenerationHelper จากนั้นอัปเดตสถานะ UI

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

Step 8 จะซับซ้อนขึ้นเล็กน้อย เนื่องจากฟังก์ชัน execute() จะดำเนินการเพียง ขั้นตอนเดียว แทนที่จะดำเนินการ ทุก ขั้นตอนสำหรับการสร้างรูปภาพ คุณจึงต้องเรียกใช้แต่ละขั้นตอนแยกกันผ่านลูป นอกจากนี้ คุณยังต้องกำหนดด้วยว่าควรแสดงขั้นตอนปัจจุบันให้ผู้ใช้เห็นหรือไม่ สุดท้าย คุณจะอัปเดตสถานะ UI หากควรแสดงการทำซ้ำปัจจุบัน คุณสามารถทำทั้งหมดนี้ได้แล้ว

// 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)",
            )
        }
    }
}

ในตอนนี้ คุณ ควร ติดตั้งแอป เริ่มต้นโปรแกรมสร้างรูปภาพ แล้วสร้างรูปภาพใหม่ตามพรอมต์ข้อความได้

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

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

5. ทำให้แอปใช้งานได้และทดสอบแอป

หลังจากทำตามขั้นตอนทั้งหมดแล้ว คุณควรมีแอปที่ใช้งานได้ซึ่งสามารถรับพรอมต์ข้อความและสร้างรูปภาพใหม่ในอุปกรณ์ได้ทั้งหมด ลองทำให้แอปใช้งานได้ในอุปกรณ์ Android จริงเพื่อทดสอบแอป แต่โปรดทราบว่าคุณจะต้องลองใช้กับอุปกรณ์ที่มีหน่วยความจำอย่างน้อย 8 GB

  1. คลิก "เรียกใช้" ( 7e15a9c9e1620fe7.png) ในแถบเครื่องมือ Android Studio เพื่อเรียกใช้แอป
  2. เลือกประเภทขั้นตอนการสร้าง (ขั้นสุดท้ายหรือมีการทำซ้ำ) แล้วกดปุ่ม INITIALIZE
  3. ในหน้าจอถัดไป ให้ตั้งค่าพร็อพเพอร์ตี้ที่ต้องการ แล้วคลิกปุ่ม GENERATE เพื่อดูผลลัพธ์ของเครื่องมือ

e46cfaeb9d3fc235.gif

6. ยินดีด้วย

คุณทำได้แล้ว ใน Codelab นี้ คุณได้เรียนรู้วิธีเพิ่มการเปลี่ยนข้อความเป็นรูปภาพในอุปกรณ์ลงในแอป Android

ขั้นตอนถัดไป

คุณสามารถทำสิ่งต่างๆ ได้อีกมากมายด้วย Task การสร้างรูปภาพ ซึ่งรวมถึง

  • ใช้รูปภาพฐานเพื่อจัดโครงสร้างรูปภาพที่สร้างผ่านปลั๊กอิน หรือฝึกน้ำหนัก LoRA เพิ่มเติมของคุณเองผ่าน Vertex AI
  • ใช้พื้นที่เก็บข้อมูลของ Firebase เพื่อดึงไฟล์โมเดลในอุปกรณ์โดยไม่ต้องใช้เครื่องมือ adb

เราตั้งตารอที่จะได้เห็นสิ่งเจ๋งๆ ที่คุณสร้างขึ้นด้วย Task ทดลองนี้ และโปรดติดตาม Codelab และเนื้อหาอื่นๆ จากทีม MediaPipe!