ভূমিকা
এই হ্যালো ওয়ার্ল্ড! টিউটোরিয়াল মিডিয়াপাইপ ফ্রেমওয়ার্ক ব্যবহার করে একটি অ্যান্ড্রয়েড অ্যাপ্লিকেশন তৈরি করতে যা অ্যান্ড্রয়েডে মিডিয়াপাইপ গ্রাফ চালায়।
যা আপনি নির্মাণ করবেন
একটি অ্যান্ড্রয়েড ডিভাইসে একটি লাইভ ভিডিও স্ট্রিমে প্রয়োগ করা রিয়েল-টাইম সোবেল প্রান্ত সনাক্তকরণের জন্য একটি সাধারণ ক্যামেরা অ্যাপ।
সেটআপ
- আপনার সিস্টেমে MediaPipe ফ্রেমওয়ার্ক ইনস্টল করুন, বিস্তারিত জানার জন্য ফ্রেমওয়ার্ক ইনস্টলেশন গাইড দেখুন।
- Android ডেভেলপমেন্ট SDK এবং Android NDK ইনস্টল করুন। [ফ্রেমওয়ার্ক ইনস্টলেশন গাইড] এ কীভাবে তা করবেন তা দেখুন।
- আপনার অ্যান্ড্রয়েড ডিভাইসে বিকাশকারী বিকল্পগুলি সক্ষম করুন৷
- অ্যান্ড্রয়েড অ্যাপ তৈরি এবং স্থাপন করতে আপনার সিস্টেমে Bazel সেটআপ করুন।
প্রান্ত সনাক্তকরণের জন্য গ্রাফ
আমরা নিম্নলিখিত গ্রাফটি ব্যবহার করব, edge_detection_mobile_gpu.pbtxt
:
# MediaPipe graph that performs GPU Sobel edge detection on a live video stream.
# Used in the examples in
# mediapipe/examples/android/src/java/com/mediapipe/apps/basic and
# mediapipe/examples/ios/edgedetectiongpu.
# Images coming into and out of the graph.
input_stream: "input_video"
output_stream: "output_video"
# Converts RGB images into luminance images, still stored in RGB format.
node: {
calculator: "LuminanceCalculator"
input_stream: "input_video"
output_stream: "luma_video"
}
# Applies the Sobel filter to luminance images stored in RGB format.
node: {
calculator: "SobelEdgesCalculator"
input_stream: "luma_video"
output_stream: "output_video"
}
গ্রাফের একটি ভিজ্যুয়ালাইজেশন নীচে দেখানো হয়েছে:
এই গ্রাফটিতে একটি একক ইনপুট স্ট্রীম রয়েছে যার নাম input_video
সমস্ত আগত ফ্রেমের জন্য যা আপনার ডিভাইসের ক্যামেরা দ্বারা সরবরাহ করা হবে৷
গ্রাফের প্রথম নোড, LuminanceCalculator
, একটি একক প্যাকেট (ইমেজ ফ্রেম) নেয় এবং একটি OpenGL শেডার ব্যবহার করে লুমিন্যান্সে পরিবর্তন প্রয়োগ করে। ফলস্বরূপ ইমেজ ফ্রেম luma_video
আউটপুট স্ট্রীমে পাঠানো হয়।
দ্বিতীয় নোড, SobelEdgesCalculator
luma_video
স্ট্রিমে ইনকামিং প্যাকেটগুলিতে প্রান্ত সনাক্তকরণ প্রয়োগ করে এবং output_video
আউটপুট স্ট্রীমে ফলাফল দেয়।
আমাদের অ্যান্ড্রয়েড অ্যাপ্লিকেশন output_video
স্ট্রিমের আউটপুট ইমেজ ফ্রেম প্রদর্শন করবে।
প্রাথমিক ন্যূনতম অ্যাপ্লিকেশন সেটআপ
আমরা প্রথমে একটি সাধারণ অ্যান্ড্রয়েড অ্যাপ্লিকেশন দিয়ে শুরু করি যা প্রদর্শন করে "হ্যালো ওয়ার্ল্ড!" পর্দায় আপনি যদি bazel
ব্যবহার করে অ্যান্ড্রয়েড অ্যাপ্লিকেশন তৈরির সাথে পরিচিত হন তবে আপনি এই পদক্ষেপটি এড়িয়ে যেতে পারেন৷
একটি নতুন ডিরেক্টরি তৈরি করুন যেখানে আপনি আপনার অ্যান্ড্রয়েড অ্যাপ্লিকেশন তৈরি করবেন। উদাহরণস্বরূপ, এই টিউটোরিয়ালের সম্পূর্ণ কোডটি mediapipe/examples/android/src/java/com/google/mediapipe/apps/basic
এ পাওয়া যাবে। আমরা কোডল্যাব জুড়ে এই পথটিকে $APPLICATION_PATH
হিসাবে উল্লেখ করব।
নোট করুন যে অ্যাপ্লিকেশনের পথে:
- অ্যাপ্লিকেশনটির নাম
helloworld
। - অ্যাপ্লিকেশনটির
$PACKAGE_PATH
হলcom.google.mediapipe.apps.basic
। এই টিউটোরিয়ালের কোড স্নিপেটে এটি ব্যবহার করা হয়েছে, তাই অনুগ্রহ করে মনে রাখবেন আপনার নিজের$PACKAGE_PATH
যখন আপনি কোড স্নিপেটগুলি কপি/ব্যবহার করবেন।
$APPLICATION_PATH/res/layout
এ activity_main.xml
ফাইল যোগ করুন। এটি Hello World!
TextView
:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
$APPLICATION_PATH
এ একটি সাধারণ MainActivity.java
যোগ করুন যা নিচে দেখানো হিসাবে activity_main.xml
লেআউটের বিষয়বস্তু লোড করে:
package com.google.mediapipe.apps.basic;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
/** Bare-bones main activity. */
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
$APPLICATION_PATH
এ AndroidManifest.xml
নামের একটি ম্যানিফেস্ট ফাইল যোগ করুন, যা অ্যাপ্লিকেশন শুরু হলে MainActivity
চালু করে:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.mediapipe.apps.basic">
<uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:label="${appName}"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name="${mainActivity}"
android:exported="true"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
আমাদের অ্যাপ্লিকেশনে আমরা অ্যাপে একটি Theme.AppCompat
থিম ব্যবহার করছি, তাই আমাদের উপযুক্ত থিমের উল্লেখ প্রয়োজন। $APPLICATION_PATH/res/values/
এ colors.xml
যোগ করুন :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>
</resources>
$APPLICATION_PATH/res/values/
styles.xml
যোগ করুন :
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
অ্যাপ্লিকেশানটি তৈরি করতে, $APPLICATION_PATH
এ একটি BUILD
ফাইল যোগ করুন এবং ম্যানিফেস্টে ${appName}
এবং ${mainActivity}
নীচে দেখানো হিসাবে BUILD
এ নির্দিষ্ট করা স্ট্রিং দ্বারা প্রতিস্থাপিত হবে৷
android_library(
name = "basic_lib",
srcs = glob(["*.java"]),
manifest = "AndroidManifest.xml",
resource_files = glob(["res/**"]),
deps = [
"//third_party:android_constraint_layout",
"//third_party:androidx_appcompat",
],
)
android_binary(
name = "helloworld",
manifest = "AndroidManifest.xml",
manifest_values = {
"applicationId": "com.google.mediapipe.apps.basic",
"appName": "Hello World",
"mainActivity": ".MainActivity",
},
multidex = "native",
deps = [
":basic_lib",
],
)
android_library
নিয়ম MainActivity
, রিসোর্স ফাইল এবং AndroidManifest.xml
এর জন্য নির্ভরতা যোগ করে।
android_binary
নিয়ম, আপনার অ্যান্ড্রয়েড ডিভাইসে ইনস্টলেশনের জন্য একটি বাইনারি APK তৈরি করতে তৈরি করা basic_lib
অ্যান্ড্রয়েড লাইব্রেরি ব্যবহার করে।
অ্যাপটি তৈরি করতে, নিম্নলিখিত কমান্ডটি ব্যবহার করুন:
bazel build -c opt --config=android_arm64 $APPLICATION_PATH:helloworld
adb install
ব্যবহার করে জেনারেট করা APK ফাইলটি ইনস্টল করুন। যেমন:
adb install bazel-bin/$APPLICATION_PATH/helloworld.apk
আপনার ডিভাইসে অ্যাপ্লিকেশন খুলুন. এটি Hello World!
.
CameraX
এর মাধ্যমে ক্যামেরা ব্যবহার করা
ক্যামেরা অনুমতি
আমাদের অ্যাপ্লিকেশনে ক্যামেরা ব্যবহার করার জন্য, আমাদের ব্যবহারকারীকে ক্যামেরায় অ্যাক্সেস দেওয়ার জন্য অনুরোধ করতে হবে। ক্যামেরা অনুমতির অনুরোধ করতে, AndroidManifest.xml
এ নিম্নলিখিত যোগ করুন:
<!-- For using the camera -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
একই ফাইলে ন্যূনতম SDK সংস্করণ 21
এবং লক্ষ্য SDK সংস্করণ 27
এ পরিবর্তন করুন:
<uses-sdk
android:minSdkVersion="21"
android:targetSdkVersion="27" />
এটি নিশ্চিত করে যে ব্যবহারকারীকে ক্যামেরা অনুমতির অনুরোধ করতে বলা হয়েছে এবং ক্যামেরা অ্যাক্সেসের জন্য ক্যামেরাএক্স লাইব্রেরি ব্যবহার করতে আমাদের সক্ষম করে।
ক্যামেরা অনুমতির অনুরোধ করার জন্য, আমরা MediaPipe ফ্রেমওয়ার্ক উপাদানগুলির দ্বারা প্রদত্ত একটি ইউটিলিটি ব্যবহার করতে পারি, যথা PermissionHelper
৷ এটি ব্যবহার করতে, BUILD
এ mediapipe_lib
নিয়মে একটি নির্ভরতা "//mediapipe/java/com/google/mediapipe/components:android_components"
যোগ করুন।
MainActivity
এ PermissionHelper
ব্যবহার করতে, onCreate
ফাংশনে নিম্নলিখিত লাইন যোগ করুন:
PermissionHelper.checkAndRequestCameraPermissions(this);
এটি স্ক্রিনে একটি ডায়ালগ সহ ব্যবহারকারীকে এই অ্যাপ্লিকেশনটিতে ক্যামেরা ব্যবহার করার অনুমতির জন্য অনুরোধ করে।
ব্যবহারকারীর প্রতিক্রিয়া পরিচালনা করতে নিম্নলিখিত কোড যোগ করুন:
@Override
public void onRequestPermissionsResult(
int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
PermissionHelper.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
protected void onResume() {
super.onResume();
if (PermissionHelper.cameraPermissionsGranted(this)) {
startCamera();
}
}
public void startCamera() {}
আমরা startCamera()
পদ্ধতিটি আপাতত খালি রাখব। ব্যবহারকারী যখন প্রম্পটে সাড়া দেয়, তখন MainActivity
পুনরায় শুরু হবে এবং onResume()
কল করা হবে। কোডটি নিশ্চিত করবে যে ক্যামেরা ব্যবহার করার অনুমতি দেওয়া হয়েছে এবং তারপর ক্যামেরা চালু হবে।
অ্যাপ্লিকেশনটি পুনর্নির্মাণ এবং ইনস্টল করুন। আপনি এখন অ্যাপ্লিকেশনটির জন্য ক্যামেরায় অ্যাক্সেসের অনুরোধ করে একটি প্রম্পট দেখতে পাবেন।
ক্যামেরা অ্যাক্সেস
উপলব্ধ ক্যামেরা অনুমতির সাথে, আমরা ক্যামেরা থেকে ফ্রেমগুলি শুরু করতে এবং আনতে পারি৷
ক্যামেরা থেকে ফ্রেম দেখতে আমরা একটি SurfaceView
ব্যবহার করব। ক্যামেরার প্রতিটি ফ্রেম একটি SurfaceTexture
অবজেক্টে সংরক্ষণ করা হবে। এগুলি ব্যবহার করার জন্য, আমাদের প্রথমে আমাদের অ্যাপ্লিকেশনটির বিন্যাস পরিবর্তন করতে হবে।
$APPLICATION_PATH/res/layout/activity_main.xml
থেকে সম্পূর্ণ TextView
কোড ব্লকটি সরান এবং পরিবর্তে নিম্নলিখিত কোড যোগ করুন:
<FrameLayout
android:id="@+id/preview_display_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1">
<TextView
android:id="@+id/no_camera_access_view"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:gravity="center"
android:text="@string/no_camera_access" />
</FrameLayout>
এই কোড ব্লকটিতে একটি নতুন FrameLayout
রয়েছে যার নাম preview_display_layout
এবং এর ভিতরে একটি TextView
নেস্ট করা হয়েছে, যার নাম no_camera_access_preview
। যখন ক্যামেরা অ্যাক্সেসের অনুমতি দেওয়া হয় না, তখন আমাদের অ্যাপ্লিকেশনটি no_camera_access
ভেরিয়েবলে সংরক্ষিত একটি স্ট্রিং বার্তা সহ TextView
প্রদর্শন করবে। $APPLICATION_PATH/res/values/strings.xml
ফাইলে নিম্নলিখিত লাইন যোগ করুন:
<string name="no_camera_access" translatable="false">Please grant camera permissions.</string>
যখন ব্যবহারকারী ক্যামেরার অনুমতি দেয় না, তখন স্ক্রীনটি এইরকম দেখাবে:
এখন, আমরা MainActivity
এ SurfaceTexture
এবং SurfaceView
অবজেক্ট যোগ করব:
private SurfaceTexture previewFrameTexture;
private SurfaceView previewDisplayView;
onCreate(Bundle)
ফাংশনে, ক্যামেরা অনুমতির অনুরোধ করার আগে নিম্নলিখিত দুটি লাইন যোগ করুন:
previewDisplayView = new SurfaceView(this);
setupPreviewDisplayView();
এবং এখন setupPreviewDisplayView()
সংজ্ঞায়িত কোড যোগ করুন :
private void setupPreviewDisplayView() {
previewDisplayView.setVisibility(View.GONE);
ViewGroup viewGroup = findViewById(R.id.preview_display_layout);
viewGroup.addView(previewDisplayView);
}
আমরা একটি নতুন SurfaceView
অবজেক্ট সংজ্ঞায়িত করি এবং এটিকে preview_display_layout
FrameLayout
অবজেক্টে যুক্ত করি যাতে আমরা previewFrameTexture
নামে একটি SurfaceTexture
অবজেক্ট ব্যবহার করে ক্যামেরা ফ্রেমগুলি প্রদর্শন করতে এটি ব্যবহার করতে পারি।
ক্যামেরা ফ্রেম পাওয়ার জন্য previewFrameTexture
ব্যবহার করতে, আমরা CameraX ব্যবহার করব। CameraX ব্যবহার করার জন্য ফ্রেমওয়ার্ক CameraXPreviewHelper
নামে একটি ইউটিলিটি প্রদান করে। onCameraStarted(@Nullable SurfaceTexture)
এর মাধ্যমে ক্যামেরা চালু হলে এই ক্লাসটি একজন শ্রোতাকে আপডেট করে।
এই ইউটিলিটি ব্যবহার করতে, "//mediapipe/java/com/google/mediapipe/components:android_camerax_helper"
এ নির্ভরতা যোগ করতে BUILD
ফাইলটি পরিবর্তন করুন।
এখন CameraXPreviewHelper
আমদানি করুন এবং MainActivity
তে নিম্নলিখিত লাইন যোগ করুন:
private CameraXPreviewHelper cameraHelper;
এখন, আমরা startCamera()
এ আমাদের বাস্তবায়ন যোগ করতে পারি:
public void startCamera() {
cameraHelper = new CameraXPreviewHelper();
cameraHelper.setOnCameraStartedListener(
surfaceTexture -> {
previewFrameTexture = surfaceTexture;
// Make the display view visible to start showing the preview.
previewDisplayView.setVisibility(View.VISIBLE);
});
}
এটি একটি নতুন CameraXPreviewHelper
অবজেক্ট তৈরি করে এবং অবজেক্টে একটি বেনামী শ্রোতা যোগ করে। cameraHelper
যখন সংকেত দেয় যে ক্যামেরা শুরু হয়েছে এবং ফ্রেমগুলি দখল করার জন্য একটি surfaceTexture
উপলব্ধ আছে, তখন আমরা সেই surfaceTexture
previewFrameTexture
হিসাবে সংরক্ষণ করি এবং previewDisplayView
দৃশ্যমান করি যাতে আমরা previewFrameTexture
থেকে ফ্রেম দেখা শুরু করতে পারি।
যাইহোক, ক্যামেরা শুরু করার আগে, আমাদের সিদ্ধান্ত নিতে হবে যে আমরা কোন ক্যামেরাটি ব্যবহার করতে চাই। CameraXPreviewHelper
CameraHelper
থেকে উত্তরাধিকার সূত্রে প্রাপ্ত যা দুটি বিকল্প প্রদান করে, FRONT
এবং BACK
। আমরা BUILD
ফাইল থেকে সিদ্ধান্তটি মেটাডেটা হিসাবে পাস করতে পারি যাতে একটি ভিন্ন ক্যামেরা ব্যবহার করে অ্যাপের অন্য সংস্করণ তৈরি করতে কোনও কোড পরিবর্তনের প্রয়োজন হয় না।
ধরে নিই যে আমরা ক্যামেরা থেকে দেখি এমন একটি লাইভ দৃশ্যে প্রান্ত সনাক্তকরণ সম্পাদন করতে BACK
ক্যামেরা ব্যবহার করতে চাই, AndroidManifest.xml
এ মেটাডেটা যোগ করুন :
...
<meta-data android:name="cameraFacingFront" android:value="${cameraFacingFront}"/>
</application>
</manifest>
এবং manifest_values
এ একটি নতুন এন্ট্রি সহ helloworld
অ্যান্ড্রয়েড বাইনারি নিয়মে BUILD
এ নির্বাচন নির্দিষ্ট করুন:
manifest_values = {
"applicationId": "com.google.mediapipe.apps.basic",
"appName": "Hello World",
"mainActivity": ".MainActivity",
"cameraFacingFront": "False",
},
এখন, manifest_values
এ নির্দিষ্ট করা মেটাডেটা পুনরুদ্ধার করতে MainActivity
তে, একটি ApplicationInfo
অবজেক্ট যোগ করুন:
private ApplicationInfo applicationInfo;
onCreate()
ফাংশনে, যোগ করুন:
try {
applicationInfo =
getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
} catch (NameNotFoundException e) {
Log.e(TAG, "Cannot find application info: " + e);
}
এখন startCamera()
ফাংশনের শেষে নিম্নলিখিত লাইন যোগ করুন:
CameraHelper.CameraFacing cameraFacing =
applicationInfo.metaData.getBoolean("cameraFacingFront", false)
? CameraHelper.CameraFacing.FRONT
: CameraHelper.CameraFacing.BACK;
cameraHelper.startCamera(this, cameraFacing, /*unusedSurfaceTexture=*/ null);
এই মুহুর্তে, অ্যাপ্লিকেশনটি সফলভাবে তৈরি করা উচিত। যাইহোক, আপনি যখন আপনার ডিভাইসে অ্যাপ্লিকেশনটি চালাবেন, আপনি একটি কালো পর্দা দেখতে পাবেন (যদিও ক্যামেরা অনুমতি দেওয়া হয়েছে)। এর কারণ হল যদিও আমরা CameraXPreviewHelper
দ্বারা প্রদত্ত surfaceTexture
ভেরিয়েবল সংরক্ষণ করি, তবুও previewSurfaceView
তার আউটপুট ব্যবহার করে না এবং এটি এখনও স্ক্রিনে প্রদর্শন করে না।
যেহেতু আমরা একটি MediaPipe গ্রাফে ফ্রেমগুলি ব্যবহার করতে চাই, তাই এই টিউটোরিয়ালে আমরা সরাসরি ক্যামেরা আউটপুট দেখার জন্য কোড যোগ করব না। পরিবর্তে, আমরা কীভাবে মিডিয়াপাইপ গ্রাফে প্রক্রিয়াকরণের জন্য ক্যামেরা ফ্রেম পাঠাতে পারি এবং স্ক্রিনে গ্রাফের আউটপুট প্রদর্শন করতে পারি সেদিকে এগিয়ে যাই।
ExternalTextureConverter
সেটআপ
একটি SurfaceTexture
একটি OpenGL ES টেক্সচার হিসাবে একটি স্ট্রীম থেকে ইমেজ ফ্রেম ক্যাপচার করে। একটি MediaPipe গ্রাফ ব্যবহার করতে, ক্যামেরা থেকে ক্যাপচার করা ফ্রেমগুলিকে একটি নিয়মিত ওপেন GL টেক্সচার অবজেক্টে সংরক্ষণ করা উচিত। একটি SurfaceTexture
অবজেক্টে সঞ্চিত ইমেজকে একটি নিয়মিত OpenGL টেক্সচার অবজেক্টে রূপান্তর করতে ফ্রেমওয়ার্ক একটি ক্লাস, ExternalTextureConverter
প্রদান করে।
ExternalTextureConverter
ব্যবহার করার জন্য, আমাদের একটি EGLContext
প্রয়োজন, যা একটি EglManager
অবজেক্ট দ্বারা তৈরি এবং পরিচালিত হয়। EglManager
, "//mediapipe/java/com/google/mediapipe/glutil"
ব্যবহার করতে BUILD
ফাইলে একটি নির্ভরতা যোগ করুন।
MainActivity
এ, নিম্নলিখিত ঘোষণা যোগ করুন:
private EglManager eglManager;
private ExternalTextureConverter converter;
onCreate(Bundle)
ফাংশনে, ক্যামেরা অনুমতির অনুরোধ করার আগে eglManager
অবজেক্ট শুরু করার জন্য একটি বিবৃতি যোগ করুন:
eglManager = new EglManager(null);
মনে রাখবেন যে ক্যামেরা অনুমতি দেওয়া হয়েছে তা নিশ্চিত করতে আমরা MainActivity
onResume()
ফাংশনটি সংজ্ঞায়িত করেছি এবং startCamera()
কল করি। এই চেক করার আগে, converter
অবজেক্ট শুরু করতে onResume()
এ নিম্নলিখিত লাইন যোগ করুন:
converter = new ExternalTextureConverter(eglManager.getContext());
এই converter
এখন eglManager
দ্বারা পরিচালিত GLContext
ব্যবহার করে।
আমাদের MainActivity
onPause()
ফাংশনটিকে ওভাররাইড করতে হবে যাতে অ্যাপ্লিকেশনটি যদি বিরতিযুক্ত অবস্থায় যায়, আমরা converter
সঠিকভাবে বন্ধ করে দিই:
@Override
protected void onPause() {
super.onPause();
converter.close();
}
converter
previewFrameTexture
এর আউটপুট পাইপ করতে, setupPreviewDisplayView()
:
previewDisplayView
.getHolder()
.addCallback(
new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// (Re-)Compute the ideal size of the camera-preview display (the area that the
// camera-preview frames get rendered onto, potentially with scaling and rotation)
// based on the size of the SurfaceView that contains the display.
Size viewSize = new Size(width, height);
Size displaySize = cameraHelper.computeDisplaySizeFromViewSize(viewSize);
// Connect the converter to the camera-preview frames as its input (via
// previewFrameTexture), and configure the output width and height as the computed
// display size.
converter.setSurfaceTextureAndAttachToGLContext(
previewFrameTexture, displaySize.getWidth(), displaySize.getHeight());
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {}
});
এই কোড ব্লকে, আমরা একটি কাস্টম SurfaceHolder.Callback
যোগ করি। previewDisplayView
দেখতে কলব্যাক করি এবং ডিভাইসের স্ক্রিনে ক্যামেরা ফ্রেমের উপযুক্ত ডিসপ্লে সাইজ গণনা করার জন্য surfaceChanged(SurfaceHolder holder, int format, int width, int height)
ফাংশন প্রয়োগ করি। previewFrameTexture
অবজেক্ট এবং converter
গণনা করা displaySize
ফ্রেম পাঠান।
আমরা এখন মিডিয়াপাইপ গ্রাফে ক্যামেরা ফ্রেম ব্যবহার করার জন্য প্রস্তুত।
অ্যান্ড্রয়েডে মিডিয়াপাইপ গ্রাফ ব্যবহার করা
প্রাসঙ্গিক নির্ভরতা যোগ করুন
একটি MediaPipe গ্রাফ ব্যবহার করার জন্য, আমাদের Android-এ MediaPipe ফ্রেমওয়ার্কে নির্ভরতা যোগ করতে হবে। আমরা প্রথমে মিডিয়াপাইপ ফ্রেমওয়ার্কের JNI কোড ব্যবহার করে একটি cc_binary
তৈরি করতে একটি বিল্ড নিয়ম যোগ করব এবং তারপর আমাদের অ্যাপ্লিকেশনে এই বাইনারিটি ব্যবহার করার জন্য একটি cc_library
নিয়ম তৈরি করব। আপনার BUILD
ফাইলে নিম্নলিখিত কোড ব্লক যোগ করুন:
cc_binary(
name = "libmediapipe_jni.so",
linkshared = 1,
linkstatic = 1,
deps = [
"//mediapipe/java/com/google/mediapipe/framework/jni:mediapipe_framework_jni",
],
)
cc_library(
name = "mediapipe_jni_lib",
srcs = [":libmediapipe_jni.so"],
alwayslink = 1,
)
BUILD
ফাইলে mediapipe_lib
বিল্ড নিয়মে ":mediapipe_jni_lib"
নির্ভরতা যোগ করুন।
এরপরে, আমরা যে মিডিয়াপাইপ গ্রাফটি অ্যাপ্লিকেশনটিতে ব্যবহার করতে চাই তার সাথে আমাদের নির্দিষ্ট নির্ভরতা যোগ করতে হবে।
প্রথমত, libmediapipe_jni.so
এর সমস্ত ক্যালকুলেটর কোডে নির্ভরতা যোগ করুন তাই নিয়ম তৈরি করুন:
"//mediapipe/graphs/edge_detection:mobile_calculators",
MediaPipe গ্রাফগুলি হল .pbtxt
ফাইল, কিন্তু এগুলিকে অ্যাপ্লিকেশনে ব্যবহার করার জন্য, একটি .binarypb
ফাইল তৈরি করতে আমাদের mediapipe_binary_graph
বিল্ড নিয়ম ব্যবহার করতে হবে।
helloworld
অ্যান্ড্রয়েড বাইনারি বিল্ড নিয়মে, একটি সম্পদ হিসাবে গ্রাফে নির্দিষ্ট mediapipe_binary_graph
লক্ষ্য যোগ করুন:
assets = [
"//mediapipe/graphs/edge_detection:mobile_gpu_binary_graph",
],
assets_dir = "",
assets
তৈরির নিয়মে, আপনি আপনার গ্রাফে ব্যবহৃত TensorFlowLite মডেলের মতো অন্যান্য সম্পদও যোগ করতে পারেন।
উপরন্তু, গ্রাফের নির্দিষ্ট বৈশিষ্ট্যগুলির জন্য অতিরিক্ত manifest_values
যোগ করুন, যা পরে MainActivity
এ পুনরুদ্ধার করা হবে:
manifest_values = {
"applicationId": "com.google.mediapipe.apps.basic",
"appName": "Hello World",
"mainActivity": ".MainActivity",
"cameraFacingFront": "False",
"binaryGraphName": "mobile_gpu.binarypb",
"inputVideoStreamName": "input_video",
"outputVideoStreamName": "output_video",
},
মনে রাখবেন যে binaryGraphName
বাইনারি গ্রাফের ফাইলের নাম নির্দেশ করে, যা mediapipe_binary_graph
লক্ষ্যে output_name
ক্ষেত্র দ্বারা নির্ধারিত হয়। inputVideoStreamName
এবং outputVideoStreamName
হল যথাক্রমে গ্রাফে নির্দিষ্ট করা ইনপুট এবং আউটপুট ভিডিও স্ট্রিম নাম।
এখন, MainActivity
MediaPipe ফ্রেমওয়ার্ক লোড করতে হবে। এছাড়াও, ফ্রেমওয়ার্ক OpenCV ব্যবহার করে, তাই MainActvity
OpenCV
ও লোড করা উচিত। উভয় নির্ভরতা লোড করতে MainActivity
নিম্নলিখিত কোডটি ব্যবহার করুন (ক্লাসের ভিতরে, তবে কোনও ফাংশনের ভিতরে নয়):
static {
// Load all native libraries needed by the app.
System.loadLibrary("mediapipe_jni");
System.loadLibrary("opencv_java3");
}
MainActivity
এ গ্রাফ ব্যবহার করুন
প্রথমত, আমাদের গ্রাফের .pbtxt
ফাইল থেকে সংকলিত .binarypb
ধারণ করা সম্পদ লোড করতে হবে। এটি করার জন্য, আমরা একটি MediaPipe ইউটিলিটি, AndroidAssetUtil
ব্যবহার করতে পারি।
eglManager
শুরু করার আগে onCreate(Bundle)
এ অ্যাসেট ম্যানেজার শুরু করুন:
// Initialize asset manager so that MediaPipe native libraries can access the app assets, e.g.,
// binary graphs.
AndroidAssetUtil.initializeNativeAssetManager(this);
এখন, আমাদের একটি FrameProcessor
অবজেক্ট সেটআপ করতে হবে যা converter
দ্বারা প্রস্তুত ক্যামেরা ফ্রেমগুলিকে মিডিয়াপিপ গ্রাফে পাঠায় এবং গ্রাফটি চালায়, আউটপুট প্রস্তুত করে এবং আউটপুট প্রদর্শনের জন্য previewDisplayView
আপডেট করে। FrameProcessor
ঘোষণা করতে নিম্নলিখিত কোড যোগ করুন:
private FrameProcessor processor;
এবং eglManager
আরম্ভ করার পরে onCreate(Bundle)
এ আরম্ভ করুন:
processor =
new FrameProcessor(
this,
eglManager.getNativeContext(),
applicationInfo.metaData.getString("binaryGraphName"),
applicationInfo.metaData.getString("inputVideoStreamName"),
applicationInfo.metaData.getString("outputVideoStreamName"));
processor
প্রসেসিংয়ের জন্য converter
থেকে রূপান্তরিত ফ্রেমগুলি গ্রাস করতে হবে। converter
শুরু করার পরে onResume()
এ নিম্নলিখিত লাইন যোগ করুন:
converter.setConsumer(processor);
processor
তার আউটপুট previewDisplayView
পাঠাতে হবে এটি করার জন্য, আমাদের কাস্টম SurfaceHolder.Callback
নিম্নলিখিত ফাংশন সংজ্ঞা যোগ করুন। কলব্যাক:
@Override
public void surfaceCreated(SurfaceHolder holder) {
processor.getVideoSurfaceOutput().setSurface(holder.getSurface());
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
processor.getVideoSurfaceOutput().setSurface(null);
}
যখন SurfaceHolder
তৈরি হয়, তখন আমাদের কাছে processor
Surface
টু VideoSurfaceOutput
ছিল। এটি ধ্বংস হয়ে গেলে, আমরা processor
VideoSurfaceOutput
থেকে এটি সরিয়ে ফেলি।
আর এটাই! আপনি এখন ডিভাইসে অ্যাপ্লিকেশনটি সফলভাবে তৈরি করতে এবং চালাতে সক্ষম হবেন এবং একটি লাইভ ক্যামেরা ফিডে সোবেল প্রান্ত সনাক্তকরণ চলমান দেখতে পাবেন! অভিনন্দন!
আপনি যদি কোনো সমস্যায় পড়ে থাকেন, অনুগ্রহ করে টিউটোরিয়ালের সম্পূর্ণ কোডটি এখানে দেখুন।