১. শুরু করার আগে
কোড টাইপ করা স্মৃতিশক্তি বৃদ্ধি এবং উপাদান সম্পর্কে আপনার বোধগম্যতা গভীর করার একটি দুর্দান্ত উপায়। কপি-পেস্ট করা সময় সাশ্রয় করতে পারে, তবে এই অনুশীলনে বিনিয়োগ দীর্ঘমেয়াদে আরও দক্ষতা এবং শক্তিশালী কোডিং দক্ষতা অর্জন করতে পারে।
এই কোডল্যাবে, আপনি শিখবেন কিভাবে একটি অ্যান্ড্রয়েড অ্যাপ্লিকেশন তৈরি করবেন যা TensorFlow Lite এর জন্য Google এর নতুন রানটাইম, LiteRT ব্যবহার করে লাইভ ক্যামেরা ফিডে রিয়েল-টাইম ইমেজ সেগমেন্টেশন সম্পাদন করে। আপনি একটি স্টার্টার অ্যান্ড্রয়েড অ্যাপ্লিকেশন নেবেন এবং এতে ইমেজ সেগমেন্টেশন ক্ষমতা যুক্ত করবেন। আমরা প্রিপ্রসেসিং, ইনফারেন্স এবং পোস্টপ্রসেসিং ধাপগুলিও দেখব। আপনি যা করবেন:
- এমন একটি অ্যান্ড্রয়েড অ্যাপ তৈরি করুন যা রিয়েল-টাইমে ছবিগুলিকে ভাগ করে।
- একটি প্রাক-প্রশিক্ষিত LiterRT চিত্র বিভাজন মডেল একীভূত করুন।
- মডেলের জন্য ইনপুট ইমেজটি প্রিপ্রসেস করুন।
- CPU এবং GPU ত্বরণের জন্য LiterRT রানটাইম ব্যবহার করুন।
- সেগমেন্টেশন মাস্ক প্রদর্শনের জন্য মডেলের আউটপুট কীভাবে প্রক্রিয়া করতে হয় তা বুঝুন।
- সামনের ক্যামেরার জন্য কীভাবে সামঞ্জস্য করতে হয় তা বুঝুন।
শেষ পর্যন্ত, আপনি নীচের ছবির মতো কিছু তৈরি করবেন:

পূর্বশর্ত
এই কোডল্যাবটি অভিজ্ঞ মোবাইল ডেভেলপারদের জন্য ডিজাইন করা হয়েছে যারা মেশিন লার্নিং এর অভিজ্ঞতা অর্জন করতে চান। আপনার নিম্নলিখিত বিষয়গুলির সাথে পরিচিত হওয়া উচিত:
- কোটলিন এবং অ্যান্ড্রয়েড স্টুডিও ব্যবহার করে অ্যান্ড্রয়েড ডেভেলপমেন্ট
- চিত্র প্রক্রিয়াকরণের মৌলিক ধারণা
তুমি কি শিখবে
- একটি অ্যান্ড্রয়েড অ্যাপ্লিকেশনে LiterRT রানটাইম কীভাবে সংহত এবং ব্যবহার করবেন।
- একটি প্রাক-প্রশিক্ষিত LiterRT মডেল ব্যবহার করে কীভাবে চিত্র বিভাজন করবেন।
- মডেলের জন্য ইনপুট ইমেজটি কীভাবে প্রি-প্রসেস করবেন।
- মডেলটির জন্য অনুমান কীভাবে চালাবেন।
- ফলাফল কল্পনা করার জন্য একটি সেগমেন্টেশন মডেলের আউটপুট কীভাবে প্রক্রিয়া করা যায়।
- রিয়েল-টাইম ক্যামেরা ফিড প্রক্রিয়াকরণের জন্য ক্যামেরাএক্স কীভাবে ব্যবহার করবেন।
তোমার যা লাগবে
- অ্যান্ড্রয়েড স্টুডিওর একটি সাম্প্রতিক সংস্করণ (v2025.1.1 এ পরীক্ষিত)।
- একটি বাস্তব অ্যান্ড্রয়েড ডিভাইস। এটি গ্যালাক্সি এবং পিক্সেল ডিভাইসে সবচেয়ে ভালোভাবে পরীক্ষা করা হয়।
- নমুনা কোড (গিটহাব থেকে)।
- কোটলিনে অ্যান্ড্রয়েড ডেভেলপমেন্টের প্রাথমিক জ্ঞান।
2. চিত্র বিভাজন
ইমেজ সেগমেন্টেশন হল একটি কম্পিউটার ভিশন টাস্ক যার মধ্যে একটি ছবিকে একাধিক সেগমেন্ট বা অঞ্চলে ভাগ করা হয়। অবজেক্ট ডিটেকশনের বিপরীতে, যা একটি বস্তুর চারপাশে একটি বাউন্ডিং বক্স আঁকে, ইমেজ সেগমেন্টেশন ছবির প্রতিটি পিক্সেলের জন্য একটি নির্দিষ্ট ক্লাস বা লেবেল নির্ধারণ করে। এটি ছবির বিষয়বস্তু সম্পর্কে আরও বিস্তারিত এবং সূক্ষ্ম ধারণা প্রদান করে, যা আপনাকে প্রতিটি বস্তুর সঠিক আকৃতি এবং সীমানা জানতে সাহায্য করে।
উদাহরণস্বরূপ, কেবল একটি 'ব্যক্তি' একটি বাক্সে আছে তা জানার পরিবর্তে, আপনি ঠিক কোন পিক্সেলগুলি সেই ব্যক্তির তা জানতে পারবেন। এই টিউটোরিয়ালে দেখানো হয়েছে কিভাবে একটি পূর্ব-প্রশিক্ষিত মেশিন লার্নিং মডেল ব্যবহার করে একটি অ্যান্ড্রয়েড ডিভাইসে রিয়েল-টাইম ইমেজ সেগমেন্টেশন করা যায়।

LiterRT: অন-ডিভাইস ML-এর সীমানা ঠেলে দেওয়া
মোবাইল ডিভাইসে রিয়েল-টাইম, হাই-ফিডেলিটি সেগমেন্টেশন সক্ষম করার জন্য একটি মূল প্রযুক্তি হল LiteRT । TensorFlow Lite-এর জন্য Google-এর পরবর্তী প্রজন্মের, উচ্চ-কার্যক্ষমতা সম্পন্ন রানটাইম হিসেবে, LiteRT-কে অন্তর্নিহিত হার্ডওয়্যার থেকে সর্বোত্তম কর্মক্ষমতা পাওয়ার জন্য তৈরি করা হয়েছে।
এটি GPU (গ্রাফিক্স প্রসেসিং ইউনিট) এবং NPU (নিউরাল প্রসেসিং ইউনিট) এর মতো হার্ডওয়্যার অ্যাক্সিলারেটরগুলির বুদ্ধিমান এবং অপ্টিমাইজড ব্যবহারের মাধ্যমে এটি অর্জন করে। সাধারণ-উদ্দেশ্য CPU থেকে এই বিশেষায়িত প্রসেসরগুলিতে সেগমেন্টেশন মডেলের তীব্র কম্পিউটেশনাল ওয়ার্কলোড অফলোড করে, LiteRT নাটকীয়ভাবে ইনফারেন্স সময় হ্রাস করে। এই ত্বরণই জটিল মডেলগুলিকে লাইভ ক্যামেরা ফিডে মসৃণভাবে চালানো সম্ভব করে তোলে, যা আপনার ফোনে সরাসরি মেশিন লার্নিংয়ের মাধ্যমে আমরা যা অর্জন করতে পারি তার প্রান্তকে প্রসারিত করে। এই স্তরের কর্মক্ষমতা ছাড়া, রিয়েল-টাইম সেগমেন্টেশন একটি ভাল ব্যবহারকারীর অভিজ্ঞতার জন্য খুব ধীর এবং বিশৃঙ্খল হবে।
৩. সেট আপ করুন
সংগ্রহস্থলটি ক্লোন করুন
প্রথমে, LiterRT এর জন্য সংগ্রহস্থলটি ক্লোন করুন:
git clone https://github.com/google-ai-edge/litert-samples.git
litert-samples/v2/image_segmentation হল সেই ডিরেক্টরি যেখানে আপনার প্রয়োজনীয় সমস্ত রিসোর্স থাকবে। এই কোডল্যাবের জন্য, আপনার কেবল kotlin_cpu_gpu/android_starter প্রকল্পটি প্রয়োজন। যদি আপনি আটকে যান তবে আপনি সমাপ্ত প্রকল্পটি পর্যালোচনা করতে চাইতে পারেন: kotlin_cpu_gpu/android
ফাইল পাথ সম্পর্কে একটি নোট
এই টিউটোরিয়ালটি Linux/macOS ফর্ম্যাটে ফাইল পাথ নির্দিষ্ট করে। যদি আপনি Windows ব্যবহার করেন, তাহলে আপনাকে সেই অনুযায়ী পাথগুলি সামঞ্জস্য করতে হবে।
অ্যান্ড্রয়েড স্টুডিও প্রজেক্ট ভিউ এবং একটি স্ট্যান্ডার্ড ফাইল সিস্টেম ভিউয়ের মধ্যে পার্থক্যটি লক্ষ্য করাও গুরুত্বপূর্ণ। অ্যান্ড্রয়েড স্টুডিও প্রজেক্ট ভিউ হল আপনার প্রোজেক্টের ফাইলগুলির একটি কাঠামোগত উপস্থাপনা, যা অ্যান্ড্রয়েড ডেভেলপমেন্টের জন্য সংগঠিত। এই টিউটোরিয়ালে ফাইল পাথগুলি ফাইল সিস্টেম পাথগুলিকে নির্দেশ করে, অ্যান্ড্রয়েড স্টুডিও প্রজেক্ট ভিউয়ের পাথগুলিকে নয়।
স্টার্টার অ্যাপটি আমদানি করুন
চলুন শুরু করা যাক অ্যান্ড্রয়েড স্টুডিওতে স্টার্টার অ্যাপটি আমদানি করে।
- অ্যান্ড্রয়েড স্টুডিও খুলুন এবং খুলুন নির্বাচন করুন।

-
kotlin_cpu_gpu/android_starterডিরেক্টরিতে যান এবং এটি খুলুন।

আপনার অ্যাপে সমস্ত নির্ভরতা উপলব্ধ আছে কিনা তা নিশ্চিত করার জন্য, আমদানি প্রক্রিয়া শেষ হয়ে গেলে আপনার প্রকল্পটি gradle ফাইলগুলির সাথে সিঙ্ক করা উচিত।
- অ্যান্ড্রয়েড স্টুডিও টুলবার থেকে "সিঙ্ক প্রজেক্ট উইথ গ্রেডল ফাইলস" নির্বাচন করুন।

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

অ্যাপটি আপনার ডিভাইসে চালু হওয়া উচিত। আপনি একটি লাইভ ক্যামেরা ফিড দেখতে পাবেন, কিন্তু এখনও কোনও সেগমেন্টেশন ঘটবে না। এই টিউটোরিয়ালে আপনি যে সমস্ত ফাইল সম্পাদনা করবেন litert-samples/v2/image_segmentation/kotlin_cpu_gpu/android_starter/app/src/main/java/com/google/ai/edge/examples/image_segmentation ডিরেক্টরির অধীনে থাকবে (এখন আপনি জানেন কেন Android Studio এটি পুনর্গঠন করে 😃)।

আপনি ImageSegmentationHelper.kt , MainViewModel.kt , এবং view/SegmentationOverlay.kt ফাইলগুলিতেও TODO মন্তব্য দেখতে পাবেন। নিম্নলিখিত ধাপগুলিতে, আপনি এই TODO গুলি পূরণ করে চিত্র বিভাজন কার্যকারিতা বাস্তবায়ন করবেন।
৪. স্টার্টার অ্যাপটি বুঝুন
স্টার্টার অ্যাপটিতে ইতিমধ্যেই একটি মৌলিক UI এবং ক্যামেরা হ্যান্ডলিং লজিক রয়েছে। এখানে মূল ফাইলগুলির একটি সংক্ষিপ্ত সারসংক্ষেপ দেওয়া হল:
-
app/src/main/java/com/google/ai/edge/examples/image_segmentation/MainActivity.kt: এটি অ্যাপ্লিকেশনের প্রধান এন্ট্রি পয়েন্ট। এটি Jetpack Compose ব্যবহার করে UI সেট আপ করে এবং ক্যামেরার অনুমতিগুলি পরিচালনা করে। -
app/src/main/java/com/google/ai/edge/examples/image_segmentation/MainViewModel.kt: এই ViewModel UI অবস্থা পরিচালনা করে এবং চিত্র বিভাজন প্রক্রিয়াটি পরিচালনা করে। -
app/src/main/java/com/google/ai/edge/examples/image_segmentation/ImageSegmentationHelper.kt: এখানে আমরা ইমেজ সেগমেন্টেশনের জন্য মূল লজিক যোগ করব। এটি মডেল লোড করা, ক্যামেরা ফ্রেম প্রক্রিয়াকরণ এবং ইনফারেন্স চালানোর কাজ করবে। -
app/src/main/java/com/google/ai/edge/examples/image_segmentation/view/CameraScreen.kt: এই কম্পোজেবল ফাংশনটি ক্যামেরা প্রিভিউ এবং সেগমেন্টেশন ওভারলে প্রদর্শন করে। -
app/download_model.gradle: এই স্ক্রিপ্টটিselfie_multiclass.tfliteডাউনলোড করে। এটি হল পূর্ব-প্রশিক্ষিত TensorFlow Lite ইমেজ সেগমেন্টেশন মডেল যা আমরা ব্যবহার করব।
৫. LiterRT বোঝা এবং নির্ভরতা যোগ করা
এখন, স্টার্টার অ্যাপে ইমেজ সেগমেন্টেশন কার্যকারিতা যোগ করা যাক।
১. LiterRT নির্ভরতা যোগ করুন
প্রথমে, আপনার প্রোজেক্টে LiterRT লাইব্রেরি যোগ করতে হবে। গুগলের অপ্টিমাইজড রানটাইম ব্যবহার করে ডিভাইসে মেশিন লার্নিং সক্ষম করার জন্য এটি গুরুত্বপূর্ণ প্রথম পদক্ষেপ।
app/build.gradle.kts ফাইলটি খুলুন এবং dependencies ব্লকে নিম্নলিখিত লাইনটি যোগ করুন:
// LiteRT for on-device ML
implementation(libs.litert)
নির্ভরতা যোগ করার পরে, Android Studio-এর উপরের ডানদিকের কোণায় প্রদর্শিত Sync Now বোতামে ক্লিক করে আপনার প্রকল্পটি Gradle ফাইলগুলির সাথে সিঙ্ক করুন।

2. Key LiterRT API গুলি বুঝুন
ImageSegmentationHelper.kt খুলুন
বাস্তবায়ন কোড লেখার আগে, LiterRT API-এর মূল উপাদানগুলি বোঝা গুরুত্বপূর্ণ যা আপনি ব্যবহার করবেন। নিশ্চিত করুন যে আপনি com.google.ai.edge.litert প্যাকেজ থেকে আমদানি করছেন, ImageSegmentationHelper.kt এর উপরে নিম্নলিখিত আমদানিগুলি যোগ করুন:
import com.google.ai.edge.litert.Accelerator
import com.google.ai.edge.litert.CompiledModel
-
CompiledModel: এটি আপনার TFLite মডেলের সাথে ইন্টারঅ্যাক্ট করার জন্য কেন্দ্রীয় ক্লাস। এটি এমন একটি মডেলকে প্রতিনিধিত্ব করে যা একটি নির্দিষ্ট হার্ডওয়্যার অ্যাক্সিলারেটরের (যেমন CPU বা GPU) জন্য পূর্বে কম্পাইল এবং অপ্টিমাইজ করা হয়েছে। এই প্রাক-সংকলন LiteRT-এর একটি মূল বৈশিষ্ট্য যা দ্রুত এবং আরও দক্ষ ইনফারেন্সের দিকে পরিচালিত করে। -
CompiledModel.Options:CompiledModelকনফিগার করার জন্য আপনি এই বিল্ডার ক্লাসটি ব্যবহার করেন। সবচেয়ে গুরুত্বপূর্ণ সেটিং হল আপনার মডেলটি চালানোর জন্য আপনি যে হার্ডওয়্যার অ্যাক্সিলারেটর ব্যবহার করতে চান তা নির্দিষ্ট করা। -
Accelerator: এই enum আপনাকে অনুমানের জন্য হার্ডওয়্যার নির্বাচন করতে দেয়। স্টার্টার প্রকল্পটি ইতিমধ্যেই এই বিকল্পগুলি পরিচালনা করার জন্য কনফিগার করা আছে:-
Accelerator.CPU: ডিভাইসের CPU তে মডেলটি চালানোর জন্য। এটি সর্বজনীনভাবে সামঞ্জস্যপূর্ণ সবচেয়ে বিকল্প। -
Accelerator.GPU: ডিভাইসের GPU তে মডেল চালানোর জন্য। এটি প্রায়শই চিত্র-ভিত্তিক মডেলের CPU এর তুলনায় উল্লেখযোগ্যভাবে দ্রুত।
-
- ইনপুট এবং আউটপুট বাফার (
TensorBuffer) : LiteRT মডেল ইনপুট এবং আউটপুটগুলির জন্যTensorBufferব্যবহার করে। এটি আপনাকে মেমরির উপর সূক্ষ্ম নিয়ন্ত্রণ দেয় এবং অপ্রয়োজনীয় ডেটা কপি এড়ায়। আপনিmodel.createInputBuffers()এবংmodel.createOutputBuffers()ব্যবহার করে আপনারCompiledModelইনস্ট্যান্স থেকে সরাসরি এই বাফারগুলি পাবেন এবং তারপরে আপনার ইনপুট ডেটা তাদের কাছে লিখুন এবং তাদের থেকে ফলাফল পড়ুন। -
model.run(): এটি হল সেই ফাংশন যা অনুমান কার্যকর করে। আপনি এতে ইনপুট এবং আউটপুট বাফারগুলি পাস করেন এবং LiterRT নির্বাচিত হার্ডওয়্যার অ্যাক্সিলারেটরে মডেলটি চালানোর জটিল কাজটি পরিচালনা করে।
৬. প্রাথমিক ImageSegmentationHelper বাস্তবায়ন সম্পন্ন করুন
এখন কিছু কোড লেখার সময়। আপনি ImageSegmentationHelper.kt এর প্রাথমিক বাস্তবায়ন সম্পন্ন করবেন। এর মধ্যে রয়েছে LiterRT মডেল ধরে রাখার জন্য Segmenter private ক্লাস সেট আপ করা এবং এটি সঠিকভাবে প্রকাশ করার জন্য cleanup() ফাংশন বাস্তবায়ন করা।
-
Segmenterক্লাস এবংcleanup()ফাংশনটি সম্পূর্ণ করুন :ImageSegmentationHelper.ktফাইলে, আপনিSegmenterনামক একটি প্রাইভেট ক্লাসের জন্য একটি স্কেলিটন এবংcleanup()নামক একটি ফাংশন পাবেন। প্রথমে, মডেলটি ধরে রাখার জন্য এর কনস্ট্রাক্টর নির্ধারণ করে, ইনপুট/আউটপুট বাফারের জন্য বৈশিষ্ট্য তৈরি করে এবং মডেলটি প্রকাশ করার জন্য একটিclose()পদ্ধতি যোগ করেSegmenterক্লাসটি সম্পূর্ণ করুন। তারপর, এই নতুনclose()cleanup()) ফাংশনটি বাস্তবায়ন করুন। বিদ্যমানSegmenterক্লাস এবংcleanup()ফাংশনটি নিম্নলিখিত দিয়ে প্রতিস্থাপন করুন: (~লাইন 83)private class Segmenter( // Add this argument private val model: CompiledModel, private val coloredLabels: List<ColoredLabel>, ) { // Add these private vals private val inputBuffers = model.createInputBuffers() private val outputBuffers = model.createOutputBuffers() fun cleanup() { // cleanup buffers inputBuffers.forEach { it.close() } outputBuffers.forEach { it.close() } // cleanup model model.close() } } - toAccelerator পদ্ধতি নির্ধারণ করুন : এই পদ্ধতিটি অ্যাক্সিলারেটর মেনু থেকে আমদানি করা LiterRT মডিউলের জন্য নির্দিষ্ট অ্যাক্সিলারেটর এনামগুলিতে সংজ্ঞায়িত অ্যাক্সিলারেটর এনামগুলিকে ম্যাপ করে (~লাইন 225):
fun toAccelerator(acceleratorEnum: AcceleratorEnum): Accelerator { return when (acceleratorEnum) { AcceleratorEnum.CPU -> Accelerator.CPU AcceleratorEnum.GPU -> Accelerator.GPU } } CompiledModelআরম্ভ করুন : এখনinitSegmenterফাংশনটি খুঁজুন। এখানেই আপনিCompiledModelইনস্ট্যান্স তৈরি করবেন এবং এটি ব্যবহার করে আপনার এখন সংজ্ঞায়িতSegmenterক্লাসটি ইন্সট্যান্ট করবেন। এই কোডটি নির্দিষ্ট অ্যাক্সিলারেটর (CPU বা GPU) দিয়ে মডেলটি সেট আপ করে এবং এটিকে অনুমানের জন্য প্রস্তুত করে।initSegmenterএTODOনিম্নলিখিত বাস্তবায়ন (Cmd/Ctrl+f 'initSegmenter` অথবা ~লাইন 62) দিয়ে প্রতিস্থাপন করুন:cleanup() try { withContext(singleThreadDispatcher) { val model = CompiledModel.create( context.assets, "selfie_multiclass.tflite", CompiledModel.Options(toAccelerator(acceleratorEnum)), null, ) segmenter = Segmenter(model, coloredLabels) Log.d(TAG, "Created an image segmenter") } } catch (e: Exception) { Log.i(TAG, "Create LiteRT from selfie_multiclass is failed: ${e.message}") _error.emit(e) }
৭. সেগমেন্টেশন এবং প্রিপ্রসেসিং শুরু করুন
এখন যেহেতু আমাদের একটি মডেল আছে, আমাদের সেগমেন্টেশন প্রক্রিয়াটি শুরু করতে হবে এবং মডেলটির জন্য ইনপুট ডেটা প্রস্তুত করতে হবে।
ট্রিগার সেগমেন্টেশন
সেগমেন্টেশন প্রক্রিয়াটি MainViewModel.kt এ শুরু হয়, যা ক্যামেরা থেকে ফ্রেম গ্রহণ করে।
MainViewModel.kt খুলুন
- ক্যামেরা ফ্রেম থেকে সেগমেন্টেশন ট্রিগার করুন :
MainViewModelএsegmentফাংশনগুলি আমাদের সেগমেন্টেশন টাস্কের এন্ট্রি পয়েন্ট। ক্যামেরা থেকে নতুন ছবি পাওয়া গেলে বা গ্যালারি থেকে নির্বাচিত হলেই এগুলি কল করা হয়। এই ফাংশনগুলি তখন আমাদেরImageSegmentationHelperএsegmentপদ্ধতিকে কল করে। উভয়segmentফাংশনেরTODOগুলি নিম্নলিখিত (লাইন ~107) দিয়ে প্রতিস্থাপন করুন:// For ImageProxy (from CameraX) fun segment(imageProxy: ImageProxy) { segmentJob = viewModelScope.launch { imageSegmentationHelper.segment(imageProxy.toBitmap(), imageProxy.imageInfo.rotationDegrees) imageProxy.close() } } // For Bitmaps (from gallery) fun segment(bitmap: Bitmap, rotationDegrees: Int) { segmentJob = viewModelScope.launch { val argbBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true) imageSegmentationHelper.segment(argbBitmap, rotationDegrees) } }
ছবিটি প্রিপ্রসেস করুন
এবার ইমেজ প্রিপ্রসেসিং পরিচালনা করার জন্য ImageSegmentationHelper.kt এ ফিরে যাওয়া যাক।
ImageSegmentationHelper.kt খুলুন
- পাবলিক
segmentফাংশনটি বাস্তবায়ন করুন: এই ফাংশনটি একটি র্যাপার হিসেবে কাজ করে যাSegmenterক্লাসের মধ্যে প্রাইভেটsegmentফাংশনকে কল করে।TODOএর পরিবর্তে (~লাইন 95) ব্যবহার করুন:try { withContext(singleThreadDispatcher) { segmenter?.segment(bitmap, rotationDegrees)?.let { if (isActive) _segmentation.emit(it) } } } catch (e: Exception) { Log.i(TAG, "Image segment error occurred: ${e.message}") _error.emit(e) } - প্রি-প্রসেসিং বাস্তবায়ন করুন :
Segmenterক্লাসের ভিতরে প্রাইভেটsegmentফাংশন হল যেখানে আমরা মডেলের জন্য প্রস্তুত করার জন্য ইনপুট ইমেজে প্রয়োজনীয় রূপান্তরগুলি সম্পাদন করব। এর মধ্যে রয়েছে স্কেলিং, ঘূর্ণন এবং ইমেজটিকে স্বাভাবিককরণ। এই ফাংশনটি তারপর ইনফারেন্স সম্পাদনের জন্য আরেকটি প্রাইভেটsegmentফাংশন কল করবে।segment(bitmap: Bitmap, ...)ফাংশনেরTODO(~line 121) দিয়ে প্রতিস্থাপন করুন:val totalStartTime = SystemClock.uptimeMillis() val rotation = -rotationDegrees / 90 val (h, w) = Pair(256, 256) // Preprocessing val preprocessStartTime = SystemClock.uptimeMillis() var image = bitmap.scale(w, h, true) image = rot90Clockwise(image, rotation) val inputFloatArray = normalize(image, 127.5f, 127.5f) Log.d(TAG, "Preprocessing time: ${SystemClock.uptimeMillis() - preprocessStartTime} ms") // Inference val inferenceStartTime = SystemClock.uptimeMillis() val segmentResult = segment(inputFloatArray) Log.d(TAG, "Inference time: ${SystemClock.uptimeMillis() - inferenceStartTime} ms") Log.d(TAG, "Total segmentation time: ${SystemClock.uptimeMillis() - totalStartTime} ms") return SegmentationResult(segmentResult, SystemClock.uptimeMillis() - inferenceStartTime)
৮. LiterRT এর মাধ্যমে প্রাথমিক অনুমান
ইনপুট ডেটা প্রি-প্রসেসড করে, আমরা এখন LiterRT ব্যবহার করে মূল অনুমান চালাতে পারি।
ImageSegmentationHelper.kt খুলুন
- মডেল এক্সিকিউশন বাস্তবায়ন : private
segment(inputFloatArray: FloatArray)ফাংশন হল সেই ফাংশন যেখানে আমরা সরাসরি LiterTrun()পদ্ধতির সাথে ইন্টারঅ্যাক্ট করি। আমরা আমাদের প্রি-প্রসেসড ডেটা ইনপুট বাফারে লিখি, মডেলটি রান করি এবং আউটপুট বাফার থেকে ফলাফল পড়ি। এই ফাংশনেTODO(~line 188) দিয়ে প্রতিস্থাপন করি:val (h, w, c) = Triple(256, 256, 6) // MODEL EXECUTION PHASE val modelExecStartTime = SystemClock.uptimeMillis() // Write input data - measure time val bufferWriteStartTime = SystemClock.uptimeMillis() inputBuffers[0].writeFloat(inputFloatArray) val bufferWriteTime = SystemClock.uptimeMillis() - bufferWriteStartTime Log.d(TAG, "Buffer write time: $bufferWriteTime ms") // Optional tensor inspection logTensorStats("Input tensor", inputFloatArray) // Run model inference - measure time val modelRunStartTime = SystemClock.uptimeMillis() model.run(inputBuffers, outputBuffers) val modelRunTime = SystemClock.uptimeMillis() - modelRunStartTime Log.d(TAG, "Model.run() time: $modelRunTime ms") // Read output data - measure time val bufferReadStartTime = SystemClock.uptimeMillis() val outputFloatArray = outputBuffers[0].readFloat() val outputBuffer = FloatBuffer.wrap(outputFloatArray) val bufferReadTime = SystemClock.uptimeMillis() - bufferReadStartTime Log.d(TAG, "Buffer read time: $bufferReadTime ms") val modelExecTime = SystemClock.uptimeMillis() - modelExecStartTime Log.d(TAG, "Total model execution time: $modelExecTime ms") // Optional tensor inspection logTensorStats("Output tensor", outputFloatArray) // POSTPROCESSING PHASE val postprocessStartTime = SystemClock.uptimeMillis() // Process mask from model output val inferenceData = InferenceData(width = w, height = h, channels = c, buffer = outputBuffer) val mask = processImage(inferenceData) val postprocessTime = SystemClock.uptimeMillis() - postprocessStartTime Log.d(TAG, "Postprocessing time (mask creation): $postprocessTime ms") return Segmentation( listOf(Mask(mask, inferenceData.width, inferenceData.height)), coloredLabels, )
৯. ওভারলে প্রক্রিয়াকরণের পরে এবং প্রদর্শন
ইনফারেন্স চালানোর পর, আমরা মডেল থেকে একটি কাঁচা আউটপুট পাই। আমাদের এই আউটপুটটি প্রক্রিয়া করে একটি ভিজ্যুয়াল সেগমেন্টেশন মাস্ক তৈরি করতে হবে এবং তারপর এটি স্ক্রিনে প্রদর্শন করতে হবে।
ImageSegmentationHelper.kt খুলুন
- আউটপুট প্রসেসিং বাস্তবায়ন করুন :
processImageফাংশনটি মডেল থেকে raw floating-point আউটপুটকে একটিByteBufferএ রূপান্তর করে যা সেগমেন্টেশন মাস্ককে উপস্থাপন করে। এটি প্রতিটি পিক্সেলের জন্য সর্বোচ্চ সম্ভাব্যতা সহ ক্লাসটি খুঁজে বের করে এটি করে। এরTODO(~line 238) দিয়ে প্রতিস্থাপন করুন:val mask = ByteBuffer.allocateDirect(inferenceData.width * inferenceData.height) for (i in 0 until inferenceData.height) { for (j in 0 until inferenceData.width) { val offset = inferenceData.channels * (i * inferenceData.width + j) var maxIndex = 0 var maxValue = inferenceData.buffer.get(offset) for (index in 1 until inferenceData.channels) { if (inferenceData.buffer.get(offset + index) > maxValue) { maxValue = inferenceData.buffer.get(offset + index) maxIndex = index } } mask.put(i * inferenceData.width + j, maxIndex.toByte()) } } return mask
MainViewModel.kt খুলুন
- সেগমেন্টেশন ফলাফল সংগ্রহ এবং প্রক্রিয়াকরণ : এখন আমরা
ImageSegmentationHelperথেকে সেগমেন্টেশন ফলাফল প্রক্রিয়াকরণ করতেMainViewModelএ ফিরে যাই।segmentationUiShareFlowSegmentationResultসংগ্রহ করে, মাস্কটিকে একটি রঙিনBitmapরূপান্তর করে এবং UI-তে সরবরাহ করে।segmentationUiShareFlowপ্রোপার্টিতেTODO(~line 63) দিয়ে প্রতিস্থাপন করুন - ইতিমধ্যেই সেখানে থাকা কোডটি প্রতিস্থাপন করবেন না, কেবল বডিটি পূরণ করুন:viewModelScope.launch { imageSegmentationHelper.segmentation .filter { it.segmentation.masks.isNotEmpty() } .map { val segmentation = it.segmentation val mask = segmentation.masks[0] val maskArray = mask.data val width = mask.width val height = mask.height val pixelSize = width * height val pixels = IntArray(pixelSize) val colorLabels = segmentation.coloredLabels.mapIndexed { index, coloredLabel -> ColorLabel(index, coloredLabel.label, coloredLabel.argb) } // Set color for pixels for (i in 0 until pixelSize) { val colorLabel = colorLabels[maskArray[i].toInt()] val color = colorLabel.getColor() pixels[i] = color } // Get image info val overlayInfo = OverlayInfo(pixels = pixels, width = width, height = height) val inferenceTime = it.inferenceTime Pair(overlayInfo, inferenceTime) } .collect { flow.emit(it) } }
view/SegmentationOverlay.kt খুলুন
শেষ কাজটি হল ব্যবহারকারী যখন সামনের ক্যামেরায় ফ্লিপ করে তখন সেগমেন্টেশন ওভারলেটিকে সঠিকভাবে ওরিয়েন্ট করা। ক্যামেরা ফিডটি স্বাভাবিকভাবেই সামনের ক্যামেরার জন্য মিরর করা হয়, তাই আমাদের ওভারলে Bitmap একই অনুভূমিক ফ্লিপ প্রয়োগ করতে হবে যাতে এটি ক্যামেরা প্রিভিউয়ের সাথে সঠিকভাবে সারিবদ্ধ হয়।
- হ্যান্ডেল ওভারলে ওরিয়েন্টেশন :
SegmentationOverlay.ktফাইলেTODOখুঁজুন এবং নিম্নলিখিত কোড দিয়ে এটি প্রতিস্থাপন করুন। এই কোডটি সামনের দিকের ক্যামেরাটি সক্রিয় কিনা তা পরীক্ষা করে এবং যদি তাই হয়,Canvasআঁকার আগে ওভারলেBitmapএকটি অনুভূমিক ফ্লিপ প্রয়োগ করে। (~লাইন 42):val orientedBitmap = if (lensFacing == CameraSelector.LENS_FACING_FRONT) { // Create a matrix for horizontal flipping val matrix = Matrix().apply { preScale(-1f, 1f) } Bitmap.createBitmap(image, 0, 0, image.width, image.height, matrix, false).also { image.recycle() } } else { image }
১০. ফাইনাল অ্যাপটি চালান এবং ব্যবহার করুন
আপনি এখন সমস্ত প্রয়োজনীয় কোড পরিবর্তন সম্পন্ন করেছেন। অ্যাপটি চালানোর এবং আপনার কাজটি কীভাবে কার্যকর হয় তা দেখার সময় এসেছে!
- অ্যাপটি চালান : আপনার অ্যান্ড্রয়েড ডিভাইসটি সংযুক্ত করুন এবং অ্যান্ড্রয়েড স্টুডিও টুলবারে রান ক্লিক করুন।

- বৈশিষ্ট্যগুলি পরীক্ষা করুন : অ্যাপটি চালু হয়ে গেলে, আপনি একটি রঙিন সেগমেন্টেশন ওভারলে সহ লাইভ ক্যামেরা ফিড দেখতে পাবেন।
- ক্যামেরা পরিবর্তন করুন : সামনের এবং পিছনের ক্যামেরাগুলির মধ্যে স্যুইচ করতে উপরের ক্যামেরা ফ্লিপ আইকনে ট্যাপ করুন। লক্ষ্য করুন কিভাবে ওভারলে সঠিকভাবে নিজেকে অভিমুখী করে।
- অ্যাক্সিলারেটর পরিবর্তন করুন : হার্ডওয়্যার অ্যাক্সিলারেটর পরিবর্তন করতে নীচের "CPU" বা "GPU" বোতামটি আলতো চাপুন। স্ক্রিনের নীচে প্রদর্শিত ইনফারেন্স টাইমের পরিবর্তন লক্ষ্য করুন। GPU উল্লেখযোগ্যভাবে দ্রুত হওয়া উচিত।
- একটি গ্যালারি ছবি ব্যবহার করুন : আপনার ডিভাইসের ফটো গ্যালারি থেকে একটি ছবি নির্বাচন করতে উপরের "গ্যালারি" ট্যাবে ট্যাপ করুন। অ্যাপটি নির্বাচিত স্ট্যাটিক ছবিতে সেগমেন্টেশন চালাবে।

আপনার কাছে এখন LiterRT দ্বারা চালিত একটি সম্পূর্ণ কার্যকরী, রিয়েল-টাইম ইমেজ সেগমেন্টেশন অ্যাপ রয়েছে!
১১. উন্নত (ঐচ্ছিক): NPU ব্যবহার করা
এই সংগ্রহস্থলে অ্যাপটির একটি সংস্করণও রয়েছে যা নিউরাল প্রসেসিং ইউনিট (NPU) এর জন্য অপ্টিমাইজ করা হয়েছে। NPU সংস্করণটি সামঞ্জস্যপূর্ণ NPU আছে এমন ডিভাইসগুলিতে উল্লেখযোগ্য কর্মক্ষমতা বৃদ্ধি করতে পারে।
NPU ভার্সনটি চেষ্টা করার জন্য, Android Studio তে kotlin_npu/android প্রজেক্টটি খুলুন। কোডটি CPU/GPU ভার্সনের সাথে খুব মিল এবং NPU ডেলিগেট ব্যবহারের জন্য কনফিগার করা হয়েছে।
NPU প্রতিনিধি ব্যবহার করার জন্য, আপনাকে আর্লি অ্যাক্সেস প্রোগ্রামে নথিভুক্ত হতে হবে।
১২. অভিনন্দন!
আপনি সফলভাবে একটি অ্যান্ড্রয়েড অ্যাপ তৈরি করেছেন যা LiterRT ব্যবহার করে রিয়েল-টাইম ইমেজ সেগমেন্টেশন করে। আপনি শিখেছেন কিভাবে:
- LiterRT রানটাইমকে একটি অ্যান্ড্রয়েড অ্যাপের সাথে একীভূত করুন।
- একটি TFLite ইমেজ সেগমেন্টেশন মডেল লোড করুন এবং চালান।
- মডেলের ইনপুট প্রিপ্রসেস করুন।
- একটি সেগমেন্টেশন মাস্ক তৈরি করতে মডেলের আউটপুট প্রক্রিয়া করুন।
- রিয়েল-টাইম ক্যামেরা অ্যাপের জন্য CameraX ব্যবহার করুন।
পরবর্তী পদক্ষেপ
- একটি ভিন্ন চিত্র বিভাজন মডেল চেষ্টা করুন।
- বিভিন্ন LiterRT প্রতিনিধিদের (CPU, GPU, NPU) নিয়ে পরীক্ষা-নিরীক্ষা করুন।