راهنمای طبقه بندی تصاویر برای اندروید

وظیفه MediaPipe Image Classifier به شما امکان می دهد تا روی تصاویر طبقه بندی کنید. شما می توانید از این کار برای شناسایی آنچه که یک تصویر در بین مجموعه ای از دسته بندی های تعریف شده در زمان آموزش نشان می دهد استفاده کنید. این دستورالعمل‌ها به شما نشان می‌دهند که چگونه از طبقه‌بندی کننده تصویر با برنامه‌های اندروید استفاده کنید. نمونه کد شرح داده شده در این دستورالعمل ها در GitHub موجود است.

می توانید با مشاهده نسخه نمایشی وب، این کار را در عمل مشاهده کنید. برای اطلاعات بیشتر در مورد قابلیت‌ها، مدل‌ها و گزینه‌های پیکربندی این کار، به نمای کلی مراجعه کنید.

نمونه کد

کد مثال MediaPipe Tasks یک پیاده سازی ساده از یک برنامه Image Classifier برای اندروید است. این مثال از دوربین یک دستگاه فیزیکی اندروید برای طبقه‌بندی مداوم اشیا استفاده می‌کند و همچنین می‌تواند از تصاویر و ویدیوهای گالری دستگاه برای طبقه‌بندی استاتیک اشیا استفاده کند.

می‌توانید از برنامه به‌عنوان نقطه شروع برای برنامه اندرویدی خود استفاده کنید یا هنگام تغییر برنامه موجود به آن مراجعه کنید. کد نمونه Image Classifier در GitHub میزبانی می شود.

کد را دانلود کنید

دستورالعمل های زیر به شما نشان می دهد که چگونه با استفاده از ابزار خط فرمان git یک کپی محلی از کد مثال ایجاد کنید.

برای دانلود کد نمونه:

  1. با استفاده از دستور زیر مخزن git را کلون کنید:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. به صورت اختیاری، نمونه git خود را برای استفاده از پرداخت پراکنده پیکربندی کنید، بنابراین فقط فایل‌های برنامه نمونه طبقه‌بندی کننده تصویر را داشته باشید:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_classification/android
    

پس از ایجاد یک نسخه محلی از کد نمونه، می توانید پروژه را به اندروید استودیو وارد کرده و برنامه را اجرا کنید. برای دستورالعمل‌ها، به راهنمای راه‌اندازی برای Android مراجعه کنید.

اجزای کلیدی

فایل های زیر حاوی کد حیاتی برای این برنامه نمونه طبقه بندی تصویر هستند:

  • ImageClassifierHelper.kt - طبقه بندی کننده تصویر را اولیه می کند و مدل و انتخاب نماینده را مدیریت می کند.
  • MainActivity.kt - برنامه را پیاده سازی می کند، از جمله فراخوانی ImageClassificationHelper و ClassificationResultsAdapter .
  • ClassificationResultsAdapter.kt - نتایج را کنترل و قالب بندی می کند.

راه اندازی

این بخش مراحل کلیدی را برای راه اندازی محیط توسعه و پروژه های کد برای استفاده از Image Classifier شرح می دهد. برای اطلاعات کلی در مورد تنظیم محیط توسعه خود برای استفاده از وظایف MediaPipe، از جمله الزامات نسخه پلت فرم، به راهنمای راه اندازی برای Android مراجعه کنید.

وابستگی ها

Image Classifier از کتابخانه com.google.mediapipe:tasks-vision استفاده می کند. این وابستگی را به فایل build.gradle پروژه توسعه برنامه اندروید خود اضافه کنید. وابستگی های مورد نیاز را با کد زیر وارد کنید:

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

مدل

وظیفه MediaPipe Image Classifier به یک مدل آموزش دیده نیاز دارد که با این کار سازگار باشد. برای اطلاعات بیشتر در مورد مدل‌های آموزش‌دیده موجود برای Image Classifier، بخش مدل‌های نمای کلی کار را ببینید.

مدل را انتخاب و دانلود کنید و سپس آن را در فهرست پروژه خود ذخیره کنید:

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

از متد BaseOptions.Builder.setModelAssetPath() برای تعیین مسیر استفاده شده توسط مدل استفاده کنید. به این روش در مثال کد در قسمت بعدی اشاره شده است.

در کد نمونه Image Classifier، مدل در فایل 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 حالت اجرا را برای کار تنظیم می کند. سه حالت وجود دارد:

IMAGE: حالت برای ورودی های تک تصویر.

VIDEO: حالت برای فریم های رمزگشایی شده یک ویدیو.

LIVE_STREAM: حالت پخش زنده داده های ورودی، مانند دوربین. در این حالت، resultListener باید فراخوانی شود تا شنونده ای را برای دریافت نتایج به صورت ناهمزمان تنظیم کند.
{ IMAGE, VIDEO, LIVE_STREAM } IMAGE
displayNamesLocale زبان برچسب‌ها را برای استفاده برای نام‌های نمایشی ارائه شده در فراداده مدل کار، در صورت وجود، تنظیم می‌کند. پیش فرض برای انگلیسی en است. با استفاده از TensorFlow Lite Metadata Writer API می‌توانید برچسب‌های محلی را به ابرداده یک مدل سفارشی اضافه کنید. کد محلی en
maxResults حداکثر تعداد اختیاری نتایج طبقه بندی با امتیاز بالا را برای بازگشت تنظیم می کند. اگر < 0 باشد، تمام نتایج موجود برگردانده خواهند شد. هر عدد مثبت -1
scoreThreshold آستانه امتیاز پیش‌بینی را تنظیم می‌کند که بر آستانه ارائه‌شده در فراداده مدل (در صورت وجود) لغو می‌شود. نتایج زیر این مقدار رد می شوند. هر شناور تنظیم نشده است
categoryAllowlist فهرست اختیاری نام‌های دسته‌بندی مجاز را تنظیم می‌کند. در صورت خالی نبودن، نتایج طبقه بندی که نام دسته آنها در این مجموعه نیست فیلتر می شود. نام‌های دسته‌بندی تکراری یا ناشناخته نادیده گرفته می‌شوند. این گزینه با categoryDenylist منحصر به فرد است و از هر دو نتیجه در یک خطا استفاده می کند. هر رشته تنظیم نشده است
categoryDenylist فهرست اختیاری نام‌های دسته‌هایی را که مجاز نیستند را تنظیم می‌کند. در صورت خالی نبودن، نتایج طبقه بندی که نام دسته آنها در این مجموعه است فیلتر می شود. نام‌های دسته‌بندی تکراری یا ناشناخته نادیده گرفته می‌شوند. این گزینه با categoryAllowlist منحصر به فرد است و از هر دو نتیجه در خطا استفاده می کند. هر رشته تنظیم نشده است
resultListener شنونده نتیجه را طوری تنظیم می‌کند که وقتی طبقه‌بندی کننده تصویر در حالت پخش زنده است، نتایج طبقه‌بندی را به صورت ناهمزمان دریافت کند. فقط زمانی قابل استفاده است که حالت اجرا روی LIVE_STREAM تنظیم شده باشد N/A تنظیم نشده است
errorListener یک شنونده خطای اختیاری را تنظیم می کند. N/A تنظیم نشده است

داده ها را آماده کنید

Image Classifier با تصاویر، فایل ویدیویی و پخش زنده ویدیو کار می کند. این وظیفه، پیش پردازش ورودی داده، از جمله تغییر اندازه، چرخش و نرمال سازی مقدار را انجام می دهد.

شما باید تصویر یا فریم ورودی را به یک شی 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();
    

در کد نمونه Image Classifier، آماده سازی داده ها در فایل 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 زمانی فراخوانی شود که وظیفه طبقه‌بندی کننده تصویر مشغول پردازش فریم دیگری است، کار فریم ورودی جدید را نادیده می‌گیرد.

در کد نمونه Image Classifier، توابع classify در فایل ImageClassifierHelper.kt تعریف شده اند.

کنترل و نمایش نتایج

پس از اجرای استنتاج، وظیفه Image Classifier یک شی 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 در موارد زیر به دست آمده است:

در کد نمونه Image 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]
        }
    }
}