งานตัวแยกประเภทรูปภาพ MediaPipe ให้คุณแยกประเภทรูปภาพได้ คุณใช้งานนี้เพื่อระบุว่ารูปภาพแสดงถึงอะไรในชุดหมวดหมู่ที่กำหนดไว้ในเวลาฝึกได้ คำแนะนำเหล่านี้จะแสดงวิธีใช้ตัวแยกประเภทรูปภาพ กับแอป Android ตัวอย่างโค้ดที่อธิบายไว้ในวิธีการเหล่านี้มีอยู่ใน GitHub
คุณสามารถดูการใช้งานจริงของงานนี้ได้โดยดูการสาธิตเว็บ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับความสามารถ โมเดล และตัวเลือกการกำหนดค่าของงานนี้ โปรดดูที่ภาพรวม
ตัวอย่างโค้ด
โค้ดตัวอย่าง MediaPipe Tasks คือการใช้งานแบบง่ายๆ ของแอปตัวแยกประเภทรูปภาพสำหรับ Android ตัวอย่างนี้ใช้กล้องบนอุปกรณ์ Android ที่จับต้องได้เพื่อจำแนกวัตถุอย่างต่อเนื่อง และยังใช้รูปภาพและวิดีโอจากแกลเลอรีของอุปกรณ์เพื่อจำแนกวัตถุแบบคงที่ได้อีกด้วย
คุณสามารถใช้แอปเป็นจุดเริ่มต้นสำหรับแอป Android ของคุณเอง หรือใช้อ้างอิงเมื่อแก้ไขแอปที่มีอยู่ โค้ดตัวอย่างตัวแยกประเภทรูปภาพจะโฮสต์อยู่ใน GitHub
ดาวน์โหลดโค้ด
วิธีการต่อไปนี้แสดงวิธีสร้างสำเนาโค้ดตัวอย่างในเครื่องโดยใช้เครื่องมือบรรทัดคำสั่ง git
วิธีดาวน์โหลดโค้ดตัวอย่าง
- โคลนที่เก็บ Git โดยใช้คำสั่งต่อไปนี้
git clone https://github.com/google-ai-edge/mediapipe-samples
- เลือกกำหนดค่าอินสแตนซ์ git เพื่อใช้การชำระเงินแบบกระจัดกระจายเพื่อให้มีเพียงไฟล์สำหรับแอปตัวอย่างตัวแยกประเภทรูปภาพเท่านั้น ดังนี้
cd mediapipe git sparse-checkout init --cone git sparse-checkout set examples/image_classification/android
หลังจากสร้างโค้ดตัวอย่างในเวอร์ชันในเครื่องแล้ว คุณสามารถนำเข้าโปรเจ็กต์ลงใน Android Studio และเรียกใช้แอป ดูวิธีการได้ในคู่มือการตั้งค่าสำหรับ Android
องค์ประกอบหลัก
ไฟล์ต่อไปนี้มีโค้ดที่สำคัญสำหรับแอปพลิเคชันตัวอย่างการจัดประเภทรูปภาพนี้
- ImageClassifierHelper.kt - เริ่มต้นตัวแยกประเภทรูปภาพและจัดการโมเดลและมอบสิทธิ์การเลือก
- MainActivity.kt -
ใช้แอปพลิเคชัน รวมถึงการเรียกใช้
ImageClassificationHelper
และClassificationResultsAdapter
- ClassificationResultsAdapter.kt - จัดการและจัดรูปแบบผลลัพธ์
ตั้งค่า
ส่วนนี้จะอธิบายขั้นตอนสำคัญในการตั้งค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์และโปรเจ็กต์โค้ดเพื่อใช้ตัวแยกประเภทรูปภาพ สำหรับข้อมูลทั่วไปเกี่ยวกับการตั้งค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์เพื่อใช้งาน MediaPipe รวมถึงข้อกำหนดเวอร์ชันของแพลตฟอร์ม โปรดดูคู่มือการตั้งค่าสำหรับ Android
การอ้างอิง
ตัวแยกประเภทรูปภาพใช้ไลบรารี com.google.mediapipe:tasks-vision
เพิ่มการอ้างอิงนี้ลงในไฟล์ build.gradle
ของโปรเจ็กต์การพัฒนาแอป Android นำเข้าทรัพยากร Dependency ที่จำเป็นด้วยโค้ดต่อไปนี้
dependencies {
...
implementation 'com.google.mediapipe:tasks-vision:latest.release'
}
รุ่น
งานตัวแยกประเภทรูปภาพ MediaPipe ต้องใช้โมเดลที่ผ่านการฝึกและเข้ากันได้กับงานนี้ ดูข้อมูลเพิ่มเติมเกี่ยวกับโมเดลที่ผ่านการฝึกที่ใช้ได้สําหรับตัวแยกประเภทรูปภาพได้ที่ภาพรวมงานส่วนโมเดล
เลือกและดาวน์โหลดโมเดล จากนั้นเก็บโมเดลไว้ในไดเรกทอรีโปรเจ็กต์ของคุณ:
<dev-project-root>/src/main/assets
ใช้เมธอด BaseOptions.Builder.setModelAssetPath()
เพื่อระบุเส้นทางที่โมเดลใช้ วิธีการนี้จะอ้างถึงในตัวอย่างโค้ดในส่วนถัดไป
ในโค้ดตัวอย่างตัวแยกประเภทรูปภาพ
โมเดลจะได้รับการกำหนดในไฟล์ ImageClassifierHelper.kt
สร้างงาน
คุณใช้ฟังก์ชัน createFromOptions
เพื่อสร้างงานได้ ฟังก์ชัน createFromOptions
จะยอมรับตัวเลือกการกำหนดค่าต่างๆ เช่น โหมดการวิ่ง ภาษาของชื่อที่แสดง จำนวนผลลัพธ์สูงสุด เกณฑ์ความเชื่อมั่น และรายการอนุญาตหมวดหมู่หรือรายการปฏิเสธ ดูข้อมูลเพิ่มเติมเกี่ยวกับตัวเลือกการกำหนดค่าได้ที่ภาพรวมการกำหนดค่า
งานตัวแยกประเภทรูปภาพรองรับอินพุต 3 ประเภท ได้แก่ ภาพนิ่ง ไฟล์วิดีโอ และสตรีมวิดีโอสด คุณต้องระบุโหมดการทำงานให้สอดคล้องกับประเภทข้อมูลอินพุตของคุณเมื่อสร้างงาน เลือกแท็บที่สอดคล้องกับประเภทข้อมูลอินพุตเพื่อดูวิธีสร้างงานและเรียกใช้การอนุมาน
รูปภาพ
ImageClassifierOptions options = ImageClassifierOptions.builder() .setBaseOptions( BaseOptions.builder().setModelAssetPath("model.tflite").build()) .setRunningMode(RunningMode.IMAGE) .setMaxResults(5) .build(); imageClassifier = ImageClassifier.createFromOptions(context, options);
วิดีโอ
ImageClassifierOptions options = ImageClassifierOptions.builder() .setBaseOptions( BaseOptions.builder().setModelAssetPath("model.tflite").build()) .setRunningMode(RunningMode.VIDEO) .setMaxResults(5) .build(); imageClassifier = ImageClassifier.createFromOptions(context, options);
สตรีมแบบสด
ImageClassifierOptions options = ImageClassifierOptions.builder() .setBaseOptions( BaseOptions.builder().setModelAssetPath("model.tflite").build()) .setRunningMode(RunningMode.LIVE_STREAM) .setMaxResults(5) .setResultListener((result, inputImage) -> { // Process the classification result here. }) .setErrorListener((result, inputImage) -> { // Process the classification errors here. }) .build() imageClassifier = ImageClassifier.createFromOptions(context, options)
การใช้โค้ดตัวอย่างของตัวแยกประเภทรูปภาพช่วยให้ผู้ใช้สลับระหว่างโหมดการประมวลผลได้ วิธีนี้ทำให้โค้ดการสร้างงานซับซ้อนขึ้นและอาจไม่เหมาะกับกรณีการใช้งานของคุณ คุณดูโค้ดนี้ได้ในฟังก์ชัน setupImageClassifier()
ของไฟล์ ImageClassifierHelper.kt
ตัวเลือกการกำหนดค่า
งานนี้มีตัวเลือกการกำหนดค่าต่อไปนี้สำหรับแอป Android
ชื่อตัวเลือก | คำอธิบาย | ช่วงค่า | ค่าเริ่มต้น |
---|---|---|---|
runningMode |
ตั้งค่าโหมดการทำงานสำหรับงาน มี 3 โหมด ได้แก่ รูปภาพ: โหมดสำหรับอินพุตรูปภาพเดียว วิดีโอ: โหมดสำหรับเฟรมที่ถอดรหัสของวิดีโอ LIVE_STREAM: โหมดสำหรับสตรีมแบบสดของข้อมูลอินพุต เช่น จากกล้อง ในโหมดนี้ ต้องเรียกใช้ resultsListener เพื่อตั้งค่า Listener ให้รับผลลัพธ์ แบบไม่พร้อมกัน |
{IMAGE, VIDEO, LIVE_STREAM } |
IMAGE |
displayNamesLocale |
ตั้งค่าภาษาของป้ายกำกับที่จะใช้กับชื่อที่แสดงซึ่งระบุไว้ในข้อมูลเมตาของโมเดลงาน หากมี ค่าเริ่มต้นคือ en สำหรับภาษาอังกฤษ คุณเพิ่มป้ายกำกับที่แปลแล้วไปยังข้อมูลเมตาของโมเดลที่กำหนดเองได้โดยใช้ TensorFlow Lite Metadata Writer API |
รหัสภาษา | en |
maxResults |
ตั้งค่าจำนวนผลลัพธ์การจัดประเภทที่มีคะแนนสูงสุด (ไม่บังคับ) ที่จะแสดง หาก < 0 ระบบจะแสดงผลลัพธ์ที่ใช้ได้ทั้งหมด | จำนวนบวกใดก็ได้ | -1 |
scoreThreshold |
ตั้งค่าเกณฑ์คะแนนการคาดการณ์ที่ลบล้างเกณฑ์ที่ระบุไว้ในข้อมูลเมตาของโมเดล (หากมี) ผลลัพธ์ที่ต่ำกว่าค่านี้ถูกปฏิเสธ | ทศนิยมใดก็ได้ | ไม่ได้ตั้งค่า |
categoryAllowlist |
ตั้งค่ารายการชื่อหมวดหมู่ที่อนุญาตซึ่งไม่บังคับ หากไม่ว่างเปล่า ระบบจะกรองผลลัพธ์การจัดประเภทที่มีชื่อหมวดหมู่ที่ไม่ได้อยู่ในชุดนี้ออก ระบบจะไม่สนใจชื่อหมวดหมู่ที่ซ้ำกันหรือไม่รู้จัก
ตัวเลือกนี้จะใช้กับ categoryDenylist ไม่ได้ และการใช้ทั้ง 2 อย่างจะทำให้เกิดข้อผิดพลาด |
สตริงใดก็ได้ | ไม่ได้ตั้งค่า |
categoryDenylist |
ตั้งค่ารายการตัวเลือกชื่อหมวดหมู่ที่ไม่ได้รับอนุญาต หากไม่ว่างเปล่า ผลการจัดประเภทที่มีชื่อหมวดหมู่อยู่ในชุดนี้จะถูกกรองออก ระบบจะไม่สนใจชื่อหมวดหมู่ที่ซ้ำกันหรือไม่รู้จัก ตัวเลือกนี้ใช้ร่วมกับ categoryAllowlist ไม่ได้ และการใช้ทั้ง 2 อย่างจะทําให้เกิดข้อผิดพลาด |
สตริงใดก็ได้ | ไม่ได้ตั้งค่า |
resultListener |
ตั้งค่า Listener ผลลัพธ์เพื่อรับผลลัพธ์การจัดประเภทแบบไม่พร้อมกันเมื่อตัวแยกประเภทรูปภาพอยู่ในโหมดสตรีมแบบสด ใช้ได้เมื่อตั้งค่าโหมดวิ่งเป็น LIVE_STREAM เท่านั้น |
ไม่มีข้อมูล | ไม่ได้ตั้งค่า |
errorListener |
ตั้งค่า Listener ข้อผิดพลาดที่ไม่บังคับ | ไม่มีข้อมูล | ไม่ได้ตั้งค่า |
เตรียมข้อมูล
ตัวแยกประเภทรูปภาพใช้งานได้กับรูปภาพ ไฟล์วิดีโอ และวิดีโอสตรีมแบบสด งานนี้จะจัดการกับการประมวลผลอินพุตข้อมูลล่วงหน้า รวมถึงการปรับขนาด การหมุน และการปรับค่าให้เป็นมาตรฐาน
คุณต้องแปลงรูปภาพหรือเฟรมอินพุตเป็นออบเจ็กต์ com.google.mediapipe.framework.image.MPImage
ก่อนที่จะส่งไปยังตัวแยกประเภทรูปภาพ
รูปภาพ
import com.google.mediapipe.framework.image.BitmapImageBuilder; import com.google.mediapipe.framework.image.MPImage; // Load an image on the user’s device as a Bitmap object using BitmapFactory. // Convert an Android’s Bitmap object to a MediaPipe’s Image object. Image mpImage = new BitmapImageBuilder(bitmap).build();
วิดีโอ
import com.google.mediapipe.framework.image.BitmapImageBuilder; import com.google.mediapipe.framework.image.MPImage; // Load a video file on the user's device using MediaMetadataRetriever // From the video’s metadata, load the METADATA_KEY_DURATION and // METADATA_KEY_VIDEO_FRAME_COUNT value. You’ll need them // to calculate the timestamp of each frame later. // Loop through the video and load each frame as a Bitmap object. // Convert the Android’s Bitmap object to a MediaPipe’s Image object. Image mpImage = new BitmapImageBuilder(frame).build();
สตรีมแบบสด
import com.google.mediapipe.framework.image.MediaImageBuilder; import com.google.mediapipe.framework.image.MPImage; // Create a CameraX’s ImageAnalysis to continuously receive frames // from the device’s camera. Configure it to output frames in RGBA_8888 // format to match with what is required by the model. // For each Android’s ImageProxy object received from the ImageAnalysis, // extract the encapsulated Android’s Image object and convert it to // a MediaPipe’s Image object. android.media.Image mediaImage = imageProxy.getImage() Image mpImage = new MediaImageBuilder(mediaImage).build();
ในโค้ดตัวอย่างของตัวแยกประเภทรูปภาพ การจัดเตรียมข้อมูลจะจัดการในไฟล์ ImageClassifierHelper.kt
เรียกใช้งาน
คุณสามารถเรียกใช้ฟังก์ชัน classify
ที่สอดคล้องกับโหมดการวิ่งเพื่อทริกเกอร์การอนุมานได้ Image Classifier API จะแสดงผลหมวดหมู่ที่เป็นไปได้สำหรับวัตถุภายในรูปภาพหรือเฟรมอินพุต
รูปภาพ
ImageClassifierResult classifierResult = imageClassifier.classify(image);
วิดีโอ
// Calculate the timestamp in milliseconds of the current frame. long frame_timestamp_ms = 1000 * video_duration * frame_index / frame_count; // Run inference on the frame. ImageClassifierResult classifierResult = imageClassifier.classifyForVideo(image, frameTimestampMs);
สตรีมแบบสด
// Run inference on the frame. The classifications results will be available // via the `resultListener` provided in the `ImageClassifierOptions` when // the image classifier was created. imageClassifier.classifyAsync(image, frameTimestampMs);
โปรดทราบดังต่อไปนี้
- เมื่อทำงานในโหมดวิดีโอหรือโหมดสตรีมแบบสด คุณต้องระบุการประทับเวลาของเฟรมอินพุตในงานเครื่องมือแยกประเภทรูปภาพด้วย
- เมื่อทำงานในโหมดรูปภาพหรือวิดีโอ งานตัวแยกประเภทรูปภาพจะบล็อกชุดข้อความปัจจุบันจนกว่าการประมวลผลรูปภาพหรือเฟรมอินพุตจะเสร็จสิ้น หากต้องการหลีกเลี่ยงการบล็อกอินเทอร์เฟซผู้ใช้ ให้เรียกใช้การประมวลผลในเทรดเบื้องหลัง
- เมื่อทำงานในโหมดสตรีมแบบสด งานตัวแยกประเภทรูปภาพจะไม่บล็อกชุดข้อความปัจจุบัน แต่จะกลับมาทำงานทันที โดยจะเรียกใช้เครื่องมือฟังผลลัพธ์พร้อมผลลัพธ์การตรวจจับทุกครั้งที่ประมวลผลเฟรมอินพุตเสร็จแล้ว หากมีการเรียกฟังก์ชัน
classifyAsync
เมื่องานตัวแยกประเภทรูปภาพไม่ว่างในการประมวลผลเฟรมอื่น งานจะไม่สนใจเฟรมอินพุตใหม่
ในโค้ดตัวอย่างของตัวแยกประเภทรูปภาพ ฟังก์ชัน classify
ได้รับการกำหนดไว้ในไฟล์
ImageClassifierHelper.kt
จัดการและแสดงผลลัพธ์
เมื่อใช้การอนุมาน งานตัวแยกประเภทรูปภาพจะแสดงผลออบเจ็กต์ ImageClassifierResult
ซึ่งมีรายการหมวดหมู่ที่เป็นไปได้สำหรับวัตถุภายในรูปภาพหรือเฟรมอินพุต
ตัวอย่างต่อไปนี้แสดงตัวอย่างข้อมูลเอาต์พุตจากงานนี้
ImageClassifierResult:
Classifications #0 (single classification head):
head index: 0
category #0:
category name: "/m/01bwb9"
display name: "Passer domesticus"
score: 0.91406
index: 671
category #1:
category name: "/m/01bwbt"
display name: "Passer montanus"
score: 0.00391
index: 670
ผลลัพธ์นี้มาจากการเรียกใช้ Bird Classifier ใน:
ในโค้ดตัวอย่างตัวแยกประเภทรูปภาพ คลาส ClassificationResultsAdapter
ในไฟล์ ClassificationResultsAdapter.kt
จะจัดการผลลัพธ์ดังต่อไปนี้
fun updateResults(imageClassifierResult: ImageClassifierResult? = null) {
categories = MutableList(adapterSize) { null }
if (imageClassifierResult != null) {
val sortedCategories = imageClassifierResult.classificationResult()
.classifications()[0].categories().sortedBy { it.index() }
val min = kotlin.math.min(sortedCategories.size, categories.size)
for (i in 0 until min) {
categories[i] = sortedCategories[i]
}
}
}