ছবি বিশ্লেষণ

ইমেজ বিশ্লেষণ ব্যবহারের ক্ষেত্রে আপনার অ্যাপকে একটি সিপিইউ-অ্যাক্সেসযোগ্য ছবি প্রদান করে যার উপর আপনি ইমেজ প্রসেসিং, কম্পিউটার ভিশন বা মেশিন লার্নিং ইনফারেন্স পারফর্ম করতে পারবেন। অ্যাপ্লিকেশনটি একটি analyze() পদ্ধতি প্রয়োগ করে যা প্রতিটি ফ্রেমে চালানো হয়।

আপনার CameraX অ্যাপের সাথে Google-এর ML Kit কীভাবে ইন্টিগ্রেট করবেন তা জানতে, ML Kit Analyzer দেখুন।

অপারেটিং মোড

অ্যাপ্লিকেশনের বিশ্লেষণ পাইপলাইন CameraX-এর ফ্রেম রেট সংক্রান্ত প্রয়োজনীয়তা পূরণ করতে না পারলে, নিম্নলিখিত যেকোনও উপায়ে ফ্রেম ড্রপ করার জন্য CameraX কনফিগার করা যেতে পারে:

  • নন-ব্লকিং (ডিফল্ট): এই মোডে, এক্সিকিউটর সবসময় লেটেস্ট ছবিকে ইমেজ বাফারে (এক গভীরতার সারি) ক্যাশে করে, যখন অ্যাপ্লিকেশন আগের ছবি বিশ্লেষণ করে। অ্যাপ্লিকেশন প্রসেসিং শেষ করার আগে CameraX নতুন ছবি পেলে, নতুন ছবিটি একই বাফারে সেভ করা হয়, আগের ছবিটি ওভাররাইট করে। মনে রাখবেন যে এই পরিস্থিতিতে ImageAnalysis.Builder.setImageQueueDepth()-এর কোনও প্রভাব নেই এবং বাফার কন্টেন্ট সবসময় ওভাররাইট করা হয়। আপনি STRATEGY_KEEP_ONLY_LATEST-এর সাথে setBackpressureStrategy()-কে কল করে এই নন-ব্লকিং মোড চালু করতে পারবেন। এক্সিকিউটর ইমপ্লিকেশন সম্পর্কে আরও তথ্যের জন্য, STRATEGY_KEEP_ONLY_LATEST-এর রেফারেন্স ডকুমেন্টেশন দেখুন।

  • ব্লকিং: এই মোডে, ইন্টার্নাল এক্সিকিউটর ইন্টার্নাল ইমেজ কিউতে একাধিক ছবি যোগ করতে পারে এবং কিউ সম্পূর্ণ হয়ে গেলে তবেই ফ্রেম ড্রপ করা শুরু করে। ব্লক করার ঘটনাটি পুরো ক্যামেরা ডিভাইসের স্কোপ জুড়ে ঘটে: যদি ক্যামেরা ডিভাইসে একাধিক বাউন্ড ব্যবহারের কেস থাকে, তাহলে CameraX এই ছবিগুলি প্রসেস করার সময় সেই সমস্ত ব্যবহারের কেস ব্লক করা হবে। যেমন, প্রিভিউ ও ছবি বিশ্লেষণ, দুটিই ক্যামেরা ডিভাইসের সাথে যুক্ত থাকলে, CameraX ছবি প্রসেস করার সময় প্রিভিউও ব্লক হয়ে যাবে। আপনি STRATEGY_BLOCK_PRODUCER থেকে setBackpressureStrategy()-এ পাস করার মাধ্যমে ব্লকিং মোড চালু করতে পারবেন। এছাড়াও, আপনি ImageAnalysis.Builder.setImageQueueDepth() ব্যবহার করে ইমেজ কিউ ডেপথ কনফিগার করতে পারবেন।

কম লেটেন্সি ও উচ্চ পারফর্ম্যান্স অ্যানালাইজারের মাধ্যমে, যেখানে কোনও ছবি বিশ্লেষণ করার মোট সময় CameraX ফ্রেমের সময়সীমার চেয়ে কম (যেমন, ৬০fps-এর জন্য ১৬ms), সেখানে যেকোনও অপারেটিং মোড সামগ্রিকভাবে মসৃণ অভিজ্ঞতা প্রদান করে। ব্লকিং মোড এখনও কিছু পরিস্থিতিতে সহায়ক হতে পারে, যেমন খুব সংক্ষিপ্ত সিস্টেম জিটার নিয়ে কাজ করার সময়।

হাই লেটেন্সি ও হাই পারফর্ম্যান্স অ্যানালাইজারের ক্ষেত্রে, লেটেন্সি কমানোর জন্য আরও দীর্ঘ কিউ সহ ব্লকিং মোড প্রয়োজন। তবে মনে রাখবেন, অ্যাপ্লিকেশনটি এখনও সমস্ত ফ্রেম প্রসেস করতে পারে।

অধিক লেটেন্সি ও সময়সাপেক্ষ অ্যানালাইজার (অ্যানালাইজার সব ফ্রেম প্রসেস করতে পারে না) সহ, নন-ব্লকিং মোড আরও উপযুক্ত বিকল্প হতে পারে, কারণ অ্যানালিসিস পাথের জন্য ফ্রেম ড্রপ করতে হয়, তবে অন্যান্য কনকারেন্ট বাউন্ড ব্যবহারের ক্ষেত্রে এখনও সব ফ্রেম দেখা যেতে পারে।

প্রয়োগ

আপনার অ্যাপ্লিকেশনে ইমেজ অ্যানালিসিস ব্যবহার করতে, এইসব ধাপ অনুসরণ করুন:

বাইন্ডিংয়ের ঠিক পরেই, CameraX আপনার রেজিস্টার করা অ্যানালাইজারে ছবি পাঠায়। বিশ্লেষণ সম্পূর্ণ করার পরে, ImageAnalysis.clearAnalyzer() কল করুন অথবা বিশ্লেষণ বন্ধ করতে ImageAnalysis ব্যবহারের কেস আনবাইন্ড করুন।

ImageAnalysis ব্যবহারের উদাহরণ তৈরি করুন

ImageAnalysis আপনার অ্যানালাইজারকে (একটি ইমেজ কনজিউমার) CameraX-এর সাথে কানেক্ট করে, যা একটি ইমেজ প্রোডিউসার। অ্যাপ্লিকেশন ImageAnalysis.Builder ব্যবহার করে ImageAnalysis অবজেক্ট তৈরি করতে পারে। ImageAnalysis.Builder-এর মাধ্যমে, অ্যাপ্লিকেশন নিম্নলিখিতগুলি কনফিগার করতে পারে:

অ্যাপ্লিকেশন রেজোলিউশন বা অ্যাস্পেক্ট রেশিওর মধ্যে যেকোনও একটি সেট করতে পারে, কিন্তু দুটিই নয়। আউটপুটের সঠিক রেজোলিউশন নির্ভর করে অ্যাপ্লিকেশনের অনুরোধ করা সাইজ (বা অ্যাস্পেক্ট রেশিও) এবং হার্ডওয়্যার ক্ষমতার উপর এবং অনুরোধ করা সাইজ বা রেশিওর থেকে আলাদা হতে পারে। রেজোলিউশন ম্যাচিং অ্যালগরিদম সম্পর্কে তথ্যের জন্য, setTargetResolution()-এর ডকুমেন্টেশন দেখুন

কোনও অ্যাপ্লিকেশন আউটপুট ইমেজ পিক্সেলকে YUV (ডিফল্ট) বা RGBA কালার স্পেসে কনফিগার করতে পারে। RGBA আউটপুট ফর্ম্যাট সেট করার সময়, CameraX ইন্টার্নালি YUV থেকে RGBA কালার স্পেসে ছবি কনভার্ট করে এবং ছবির বিট ImageProxy-এর প্রথম প্লেনের ByteBuffer-এ নিম্নলিখিত ক্রমে প্যাক করে (অন্য দুটি প্লেন ব্যবহার করা হয় না):

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।

কালার স্পেস কনফিগারেশন এবং পিক্সেল বাইট কোথা থেকে ফিরিয়ে আনা যাবে তা জানতে ImageAnalysis ব্যবহারের কেস তৈরি করুন দেখুন।

অ্যানালাইজারের মধ্যে, অ্যাপ্লিকেশনটিকে নিম্নলিখিতগুলি করতে হবে:

  1. যত দ্রুত সম্ভব প্রদত্ত ফ্রেম বিশ্লেষণ করুন, বিশেষত প্রদত্ত ফ্রেম রেটের সময়সীমার মধ্যে (যেমন, ৩০ fps-এর ক্ষেত্রে ৩২ মিলিসেকেন্ডের কম)। অ্যাপ্লিকেশনটি যদি যথেষ্ট দ্রুত ফ্রেম বিশ্লেষণ করতে না পারে, তাহলে ফ্রেম ড্রপ করার জন্য কাজ করে এমন মেকানিজম-এর মধ্যে একটি ব্যবহার করার কথা বিবেচনা করুন।
  2. ImageProxy.close() কল করে ImageProxy-কে CameraX-এ রিলিজ করুন। মনে রাখবেন, আপনার Media.Image-এর ক্লোজ ফাংশন (Media.Image.close()) কল করা উচিত নয়।

অ্যাপ্লিকেশন সরাসরি ImageProxy-এর মধ্যে র‍্যাপ করা Media.Image ব্যবহার করতে পারে। র‍্যাপ করা ছবিতে Media.Image.close() কল করবেন না, কারণ এটি CameraX-এর মধ্যে ছবি শেয়ার করার মেকানিজমকে ভেঙে দেবে; এর পরিবর্তে, CameraX-এ অন্তর্নিহিত Media.Image রিলিজ করতে ImageProxy.close() ব্যবহার করুন।

ImageAnalysis-এর জন্য আপনার অ্যানালাইজার কনফিগার করুন

আপনি অ্যানালাইজার তৈরি করার পরে, বিশ্লেষণ শুরু করার জন্য এটি রেজিস্টার করতে ImageAnalysis.setAnalyzer() ব্যবহার করুন। বিশ্লেষণ করা হয়ে গেলে, রেজিস্টার করা বিশ্লেষক সরাতে ImageAnalysis.clearAnalyzer() ব্যবহার করুন।

ছবি বিশ্লেষণের জন্য শুধুমাত্র একটি অ্যাক্টিভ বিশ্লেষক কনফিগার করা যেতে পারে। ImageAnalysis.setAnalyzer() কল করা, আগে থেকেই রেজিস্টার করা অ্যানালাইজার থাকলে তা পরিবর্তন করে। অ্যাপ্লিকেশন যেকোনও সময় নতুন বিশ্লেষক সেট করতে পারে, ব্যবহারের কেস বাইন্ডিং করার আগে বা পরে।

ImageAnalysis-কে একটি লাইফসাইকেলের সাথে বাইন্ড করুন

ProcessCameraProvider.bindToLifecycle() ফাংশনের মাধ্যমে আপনার ImageAnalysis-কে আগে থেকে থাকা AndroidX লাইফসাইকেলের সাথে বাইন্ড করার জন্য বিশেষভাবে সাজেস্ট করা হয়। মনে রাখবেন যে bindToLifecycle() ফাংশন বেছে নেওয়া Camera ডিভাইস ফিরিয়ে দেয়, যা এক্সপোজার ও অন্যান্য উন্নত সেটিংস ফাইন টিউন করতে ব্যবহার করা যেতে পারে। ক্যামেরা আউটপুট নিয়ন্ত্রণ করা সম্পর্কে আরও তথ্যের জন্য এই নির্দেশিকা দেখুন।

নিম্নলিখিত উদাহরণটি আগের ধাপের সবকিছু একত্রিত করে, CameraX ImageAnalysis এবং Preview ব্যবহারের কেসকে lifeCycle মালিকের সাথে বাইন্ড করে:

Kotlin

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 সম্পর্কে আরও জানতে, নিম্নলিখিত অতিরিক্ত রিসোর্স দেখুন।

কোডল্যাব

  • CameraX ব্যবহার শুরু করা
  • কোডের স্যাম্পেল

  • CameraX স্যাম্পেল অ্যাপ