تجزیه و تحلیل تصویر

مورد استفاده تجزیه و تحلیل تصویر تصویری قابل دسترسی به CPU را به برنامه شما ارائه می دهد که می توانید پردازش تصویر، بینایی کامپیوتر یا استنتاج یادگیری ماشین را روی آن انجام دهید. این برنامه یک متد analyze() پیاده سازی می کند که روی هر فریم اجرا می شود.

برای یادگیری نحوه ادغام کیت ML Google با برنامه CameraX، به ML Kit Analyzer مراجعه کنید.

حالت های عملیاتی

هنگامی که خط لوله تجزیه و تحلیل برنامه نمی تواند با الزامات نرخ فریم CameraX مطابقت داشته باشد، CameraX را می توان برای رها کردن فریم ها به یکی از روش های زیر پیکربندی کرد:

  • non-blocking (پیش‌فرض): در این حالت، مجری همیشه آخرین تصویر را در بافر تصویر (مشابه یک صف با عمق یک) ذخیره می‌کند در حالی که برنامه تصویر قبلی را تجزیه و تحلیل می‌کند. اگر CameraX قبل از اتمام پردازش برنامه یک تصویر جدید دریافت کند، تصویر جدید در همان بافر ذخیره می‌شود و تصویر قبلی را بازنویسی می‌کند. توجه داشته باشید که ImageAnalysis.Builder.setImageQueueDepth() هیچ تاثیری در این سناریو ندارد و محتوای بافر همیشه رونویسی می شود. می‌توانید با فراخوانی setBackpressureStrategy() با STRATEGY_KEEP_ONLY_LATEST ، این حالت غیر مسدود را فعال کنید. برای اطلاعات بیشتر در مورد پیامدهای اجرایی، به مستندات مرجع STRATEGY_KEEP_ONLY_LATEST مراجعه کنید.

  • مسدود کردن : در این حالت، مجری داخلی می‌تواند چندین تصویر را به صف تصویر داخلی اضافه کند و تنها زمانی که صف پر است شروع به رها کردن فریم می‌کند. مسدود کردن در کل محدوده دستگاه دوربین اتفاق می‌افتد: اگر دستگاه دوربین دارای چندین مورد استفاده محدود باشد، وقتی CameraX در حال پردازش این تصاویر است، همه موارد استفاده مسدود می‌شوند. به عنوان مثال، زمانی که پیش‌نمایش و تجزیه و تحلیل تصویر هر دو به یک دستگاه دوربین متصل می‌شوند، در حالی که CameraX در حال پردازش تصاویر است، پیش‌نمایش نیز مسدود می‌شود. می‌توانید حالت مسدود کردن را با عبور STRATEGY_BLOCK_PRODUCER به setBackpressureStrategy() فعال کنید. همچنین می توانید عمق صف تصویر را با استفاده از ImageAnalysis.Builder.setImageQueueDepth() پیکربندی کنید.

با تأخیر کم و آنالایزر با کارایی بالا که در آن کل زمان تجزیه و تحلیل یک تصویر کمتر از مدت زمان یک فریم CameraX است (مثلاً 16 میلی‌ثانیه برای 60 فریم در ثانیه)، هر یک از حالت‌های عملیاتی تجربه کلی نرمی را ارائه می‌دهند. حالت مسدود کردن همچنان می‌تواند در برخی سناریوها مفید باشد، مانند زمانی که با لرزش‌های بسیار مختصر سیستم سروکار دارید.

با یک تحلیلگر تأخیر بالا و عملکرد بالا، حالت مسدود کردن با صف طولانی‌تر برای جبران تأخیر ضروری است. البته توجه داشته باشید که برنامه همچنان می‌تواند همه فریم‌ها را پردازش کند.

با تأخیر بالا و تحلیلگر وقت گیر (آنالیزور قادر به پردازش همه فریم ها نیست)، حالت غیر مسدود کننده ممکن است انتخاب مناسب تری باشد، زیرا فریم ها باید برای مسیر تجزیه و تحلیل حذف شوند، اما سایر موارد استفاده محدود همزمان همچنان می توانند مشاهده شوند. تمام قاب ها

پیاده سازی

برای استفاده از تجزیه و تحلیل تصویر در برنامه خود، این مراحل را دنبال کنید:

بلافاصله پس از صحافی، CameraX تصاویر را به آنالایزر ثبت شده شما ارسال می کند. پس از تکمیل تجزیه و تحلیل، ImageAnalysis.clearAnalyzer() را فراخوانی کنید یا مورد استفاده ImageAnalysis را برای توقف تجزیه و تحلیل لغو پیوند کنید.

استفاده از ImageAnalysis را بسازید

ImageAnalysis آنالایزر شما (یک مصرف کننده تصویر) را به CameraX که یک تولید کننده تصویر است متصل می کند. برنامه ها می توانند از ImageAnalysis.Builder برای ساخت یک شی ImageAnalysis استفاده کنند. با ImageAnalysis.Builder ، برنامه می تواند موارد زیر را پیکربندی کند:

برنامه ها می توانند وضوح یا نسبت تصویر را تنظیم کنند، اما نه هر دو را. وضوح خروجی دقیق به اندازه درخواستی (یا نسبت ابعاد) و قابلیت های سخت افزاری برنامه بستگی دارد و ممکن است با اندازه یا نسبت درخواستی متفاوت باشد. برای اطلاعات در مورد الگوریتم تطبیق وضوح، به مستندات setTargetResolution() مراجعه کنید.

یک برنامه کاربردی می‌تواند پیکسل‌های تصویر خروجی را در فضاهای رنگی YUV (پیش‌فرض) یا RGBA پیکربندی کند. هنگام تنظیم یک فرمت خروجی RGBA، CameraX به صورت داخلی تصاویر را از فضای رنگی YUV به فضای رنگی RGBA تبدیل می‌کند و بیت‌های تصویر را در ByteBuffer اولین صفحه ImageProxy (دو صفحه دیگر استفاده نمی‌شوند) با ترتیب زیر بسته‌بندی می‌کند:

ImageProxy.getPlanes()[0].buffer[0]: alpha
ImageProxy.getPlanes()[0].buffer[1]: red
ImageProxy.getPlanes()[0].buffer[2]: green
ImageProxy.getPlanes()[0].buffer[3]: blue
...

هنگام انجام تجزیه و تحلیل تصویر پیچیده در جایی که دستگاه نمی تواند با نرخ فریم مطابقت داشته باشد، می توانید CameraX را برای رها کردن فریم ها با استراتژی های توضیح داده شده در بخش حالت های عملیاتی این مبحث پیکربندی کنید.

تحلیلگر خود را بسازید

برنامه‌ها می‌توانند با پیاده‌سازی رابط ImageAnalysis.Analyzer و نادیده گرفتن analyze(ImageProxy image) تحلیلگر ایجاد کنند. در هر تحلیلگر، برنامه ها یک ImageProxy دریافت می کنند که پوششی برای Media.Image است. فرمت تصویر را می توان با ImageProxy.getFormat() جستجو کرد. قالب یکی از مقادیر زیر است که برنامه با ImageAnalysis.Builder ارائه می کند:

  • اگر برنامه OUTPUT_IMAGE_FORMAT_RGBA_8888 را درخواست کرد ImageFormat.RGBA_8888 .
  • اگر برنامه OUTPUT_IMAGE_FORMAT_YUV_420_888 را درخواست کند، ImageFormat.YUV_420_888 .

مورد استفاده Build ImageAnalysis را برای تنظیمات فضای رنگی و جایی که بایت های پیکسل را می توان بازیابی کرد، ببینید.

در داخل یک آنالایزر، برنامه باید موارد زیر را انجام دهد:

  1. یک فریم معین را با بیشترین سرعت ممکن، ترجیحاً در محدوده زمانی تعیین شده نرخ فریم (مثلاً کمتر از 32 میلی‌ثانیه برای 30 فریم در ثانیه) تجزیه و تحلیل کنید. اگر برنامه نمی تواند یک فریم را به اندازه کافی سریع تجزیه و تحلیل کند، یکی از مکانیسم های افت فریم پشتیبانی شده را در نظر بگیرید.
  2. با فراخوانی ImageProxy.close() ImageProxy در CameraX رها کنید. توجه داشته باشید که نباید تابع بستن Media.Image را فراخوانی کنید ( Media.Image.close() ).

برنامه‌ها می‌توانند مستقیماً از Media.Image در داخل ImageProxy استفاده کنند. فقط Media.Image.close() روی تصویر پیچیده شده صدا نکنید زیرا این کار مکانیسم اشتراک گذاری تصویر در CameraX را خراب می کند. در عوض، از ImageProxy.close() برای انتشار Media.Image زیرین به CameraX استفاده کنید.

آنالایزر خود را برای ImageAnalysis پیکربندی کنید

هنگامی که یک تحلیلگر ایجاد کردید، از ImageAnalysis.setAnalyzer() برای ثبت آن برای شروع تجزیه و تحلیل استفاده کنید. پس از پایان تجزیه و تحلیل، از ImageAnalysis.clearAnalyzer() برای حذف تحلیلگر ثبت شده استفاده کنید.

فقط یک تحلیلگر فعال را می توان برای تجزیه و تحلیل تصویر پیکربندی کرد. فراخوانی ImageAnalysis.setAnalyzer() جایگزین آنالایزر ثبت شده در صورت وجود آن می شود. برنامه‌ها می‌توانند در هر زمان، قبل یا بعد از اتصال مورد استفاده، یک آنالایزر جدید تنظیم کنند.

Image Analysis را به یک چرخه زندگی متصل کنید

به شدت توصیه می شود که ImageAnalysis خود را با تابع ProcessCameraProvider.bindToLifecycle() به چرخه حیات AndroidX موجود متصل کنید. توجه داشته باشید که تابع bindToLifecycle() دستگاه Camera انتخاب شده را برمی گرداند، که می تواند برای تنظیم دقیق تنظیمات پیشرفته مانند نوردهی و موارد دیگر استفاده شود. برای اطلاعات بیشتر در مورد کنترل خروجی دوربین به این راهنما مراجعه کنید.

مثال زیر همه چیز را از مراحل قبلی ترکیب می کند، موارد استفاده CameraX ImageAnalysis و Preview را به مالک lifeCycle متصل می کند:

کاتلین

val imageAnalysis = ImageAnalysis.Builder()
    // enable the following line if RGBA output is needed.
    // .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
    .setTargetResolution(Size(1280, 720))
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
    .build()
imageAnalysis.setAnalyzer(executor, ImageAnalysis.Analyzer { imageProxy ->
    val rotationDegrees = imageProxy.imageInfo.rotationDegrees
    // insert your code here.
    ...
    // after done, release the ImageProxy object
    imageProxy.close()
})

cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, imageAnalysis, preview)

جاوا

ImageAnalysis imageAnalysis =
    new ImageAnalysis.Builder()
        // enable the following line if RGBA output is needed.
        //.setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
        .setTargetResolution(new Size(1280, 720))
        .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
        .build();

imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {
    @Override
    public void analyze(@NonNull ImageProxy imageProxy) {
        int rotationDegrees = imageProxy.getImageInfo().getRotationDegrees();
            // insert your code here.
            ...
            // after done, release the ImageProxy object
            imageProxy.close();
        }
    });

cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, imageAnalysis, preview);

منابع اضافی

برای کسب اطلاعات بیشتر در مورد CameraX، به منابع اضافی زیر مراجعه کنید.

Codelab

  • شروع کار با CameraX
  • نمونه کد

  • نمونه برنامه های CameraX