नमस्ते! Android पर

परिचय

नमस्ते दुनिया! ट्यूटोरियल MediaPipe Framework का इस्तेमाल करके, ऐसा Android ऐप्लिकेशन डेवलप करता है जो Android पर MediaPipe ग्राफ़ चलाता है.

आपको क्या बनाना होगा

लाइव वीडियो में, रीयल-टाइम में सोबेल एज डिटेक्शन करने के लिए एक आसान कैमरा ऐप्लिकेशन किसी Android डिवाइस पर स्ट्रीम करना है.

edge_detection_android_gpu_gif

सेटअप

  1. अपने सिस्टम पर MediaPipe Framework इंस्टॉल करें, फ़्रेमवर्क इंस्टॉलेशन देखें गाइड पढ़ें.
  2. Android डेवलपमेंट SDK टूल और Android NDK इंस्टॉल करें. इसका तरीका जानें [फ़्रेमवर्क इंस्टॉलेशन गाइड].
  3. अपने Android डिवाइस पर डेवलपर के लिए सेटिंग और टूल चालू करें.
  4. Android ऐप्लिकेशन बनाने और डिप्लॉय करने के लिए, अपने सिस्टम पर Bazu सेट अप करें.

किनारे का पता लगाने के लिए ग्राफ़

हम इस ग्राफ़ का इस्तेमाल करेंगे, 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"
}

ग्राफ़ का विज़ुअलाइज़ेशन नीचे दिखाया गया है:

edge_detection_mobile_gpu

इस ग्राफ़ में, आने वाले सभी फ़्रेम के लिए input_video नाम की एक इनपुट स्ट्रीम मौजूद है जिसे आपके डिवाइस के कैमरे से मिलेगा.

ग्राफ़ के पहले नोड, LuminanceCalculator, में एक पैकेट (इमेज) होता है फ़्रेम) के आकार के साथ दिखाया जाता है और OpenGL शेडर का इस्तेमाल करके ल्यूमिनेंस में बदलाव लागू करता है. नतीजे के तौर पर मिला नतीजा इमेज फ़्रेम को luma_video आउटपुट स्ट्रीम पर भेजा जाता है.

दूसरा नोड, SobelEdgesCalculator किनारे की पहचान करने की सुविधा को इनकमिंग पर लागू करता है luma_video स्ट्रीम में पैकेट और आउटपुट के नतीजे में output_video आउटपुट मिलता है स्ट्रीम.

हमारा Android ऐप्लिकेशन इस output_video स्ट्रीम.

शुरुआती कम से कम ऐप्लिकेशन सेटअप

हम पहले एक आसान Android ऐप्लिकेशन से शुरुआत करते हैं, जो "हैलो वर्ल्ड!" स्क्रीन पर. अगर आपको Android डिवाइस बनाने की जानकारी है, तो इस चरण को छोड़ा जा सकता है bazel का इस्तेमाल करने वाले ऐप्लिकेशन.

नई डायरेक्ट्री बनाएं, जहां आप अपना Android ऐप्लिकेशन बनाएंगे. इसके लिए उदाहरण के लिए, इस ट्यूटोरियल का पूरा कोड यहां देखें: mediapipe/examples/android/src/java/com/google/mediapipe/apps/basic. हम करेंगे पूरे कोडलैब में इस पाथ को $APPLICATION_PATH के तौर पर दिखाएं.

ध्यान दें कि ऐप्लिकेशन के पाथ में:

  • ऐप्लिकेशन का नाम helloworld है.
  • ऐप्लिकेशन का $PACKAGE_PATH com.google.mediapipe.apps.basic है. इस ट्यूटोरियल में कोड स्निपेट में इसका इस्तेमाल किया गया है. इसलिए, कृपया कोड स्निपेट को कॉपी/इस्तेमाल करने पर, आपका अपना $PACKAGE_PATH.

activity_main.xml फ़ाइल को $APPLICATION_PATH/res/layout में जोड़ें. यह दिखाता है 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);
  }
}

AndroidManifest.xml को $APPLICATION_PATH में एक मेनिफ़ेस्ट फ़ाइल जोड़ें, जिसमें आवेदन शुरू होने पर 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 थीम का इस्तेमाल कर रहे हैं, इसलिए हमें इन ऐप्लिकेशन की ज़रूरत है में सही संदर्भ शामिल करें. colors.xml को इसमें जोड़ें $APPLICATION_PATH/res/values/:

<?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 नियम, इसके लिए जनरेट की गई basic_lib Android लाइब्रेरी का इस्तेमाल करता है अपने Android डिवाइस पर इंस्टॉल करने के लिए, बाइनरी APK बनाएं.

ऐप्लिकेशन बनाने के लिए, नीचे दिए गए निर्देश का इस्तेमाल करें:

bazel build -c opt --config=android_arm64 $APPLICATION_PATH:helloworld

adb install का इस्तेमाल करके जनरेट की गई APK फ़ाइल इंस्टॉल करें. उदाहरण के लिए:

adb install bazel-bin/$APPLICATION_PATH/helloworld.apk

अपने डिवाइस पर ऐप्लिकेशन खोलें. इस इमेज में टेक्स्ट के साथ स्क्रीन दिखनी चाहिए Hello World!.

bazel_hello_world_android

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" />

इससे यह पक्का होता है कि उपयोगकर्ता को कैमरा ऐक्सेस करने की अनुमति मांगने का अनुरोध किया जाएगा. इसके बाद, यह सुविधा चालू हो जाएगी हमें कैमरा ऐक्सेस करने के लिए CameraX लाइब्रेरी इस्तेमाल करनी है.

कैमरा ऐक्सेस करने की अनुमतियों का अनुरोध करने के लिए, हम MediaPipe Framework के ज़रिए उपलब्ध कराई गई सुविधा का इस्तेमाल कर सकते हैं कॉम्पोनेंट, जैसे कि PermissionHelper. इसका इस्तेमाल करने के लिए, कोई डिपेंडेंसी जोड़ें "//mediapipe/java/com/google/mediapipe/components:android_components" BUILD में mediapipe_lib नियम.

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 ऑब्जेक्ट में सेव किया जाएगा. इनका इस्तेमाल करने के लिए, हम पहले हमारे ऐप्लिकेशन का लेआउट बदलना होगा.

यहां से पूरा TextView कोड ब्लॉक हटाएं $APPLICATION_PATH/res/layout/activity_main.xml और यह कोड जोड़ें इसके बजाय:

<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>

इस कोड ब्लॉक में preview_display_layout नाम का एक नया FrameLayout और TextView इसके अंदर नेस्ट किया गया है, जिसका नाम no_camera_access_preview है. जब कैमरा ऐक्सेस की अनुमतियां नहीं दी गई हैं, तो हमारा ऐप्लिकेशन स्ट्रिंग मैसेज के साथ TextView, जिसे no_camera_access वैरिएबल में सेव किया गया है. $APPLICATION_PATH/res/values/strings.xml फ़ाइल में यह लाइन जोड़ें:

<string name="no_camera_access" translatable="false">Please grant camera permissions.</string>

जब उपयोगकर्ता कैमरा ऐक्सेस करने की अनुमति नहीं देता है, तो स्क्रीन अब ऐसी दिखेगी शामिल करें:

missing_camera_permission_android

अब हम SurfaceTexture और SurfaceView ऑब्जेक्ट को MainActivity:

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).

इस सुविधा का इस्तेमाल करने के लिए, BUILD फ़ाइल में बदलाव करें, ताकि इस पर निर्भरता जोड़ी जा सके "//mediapipe/java/com/google/mediapipe/components:android_camerax_helper".

अब 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 उपलब्ध है, हम समय बचाते हैं previewFrameTexture के तौर पर surfaceTexture और previewDisplayView बनाएं ताकि हमें previewFrameTexture से फ़्रेम दिखने लगें.

हालांकि, कैमरा शुरू करने से पहले, हमें यह तय करना होगा कि हमें कौनसा कैमरा इस्तेमाल करना है इस्तेमाल करें. CameraXPreviewHelper को CameraHelper से इनहेरिट किया जाता है, जो दो नतीजे देते हैं विकल्प, FRONT और BACK. हम BUILD फ़ाइल से फ़ैसला ले सकते हैं जैसे कि मेटाडेटा का दूसरा वर्शन बनाने के लिए किसी कोड में बदलाव की ज़रूरत नहीं होगी ऐप पर जाएं.

मान लीजिए कि हमें लाइव सीन के किनारे का पता लगाने के लिए, BACK कैमरा का इस्तेमाल करना है जिन्हें हम कैमरे से देखते हैं तो मेटाडेटा को AndroidManifest.xml में जोड़ें:

      ...
      <meta-data android:name="cameraFacingFront" android:value="${cameraFacingFront}"/>
  </application>
</manifest>

और helloworld Android बाइनरी नियम में BUILD में चुने गए विकल्प को तय करें manifest_values में एक नई प्रविष्टि के साथ:

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 ग्राफ़ में फ़्रेम का इस्तेमाल करना चाहते हैं, इसलिए हम इस ट्यूटोरियल में कैमरा आउटपुट देखें. इसके बजाय, हम यह देखते हैं कि हम MediaPipe ग्राफ़ पर प्रोसेस करने के लिए कैमरा फ़्रेम भेज सकते हैं. साथ ही, स्क्रीन पर ग्राफ़ का आउटपुट.

ExternalTextureConverter सेटअप

SurfaceTexture किसी स्ट्रीम से OpenGL ES के तौर पर इमेज फ़्रेम कैप्चर करता है बनावट. MediaPipe ग्राफ़ का इस्तेमाल करने के लिए, कैमरे से कैप्चर किए गए फ़्रेम ऐसे होने चाहिए: को किसी सामान्य Open GL टेक्सचर ऑब्जेक्ट में सेव किया जाता है. यह फ़्रेमवर्क एक क्लास, SurfaceTexture में सेव की गई इमेज को बदलने के लिए ExternalTextureConverter ऑब्जेक्ट को सामान्य OpenGL टेक्स्चर ऑब्जेक्ट पर ले जाता है.

ExternalTextureConverter का इस्तेमाल करने के लिए, हमें EGLContext की भी ज़रूरत होगी, जो EglManager ऑब्जेक्ट से बनाया और मैनेज किया जाता है. BUILD पर डिपेंडेंसी जोड़ें EglManager, "//mediapipe/java/com/google/mediapipe/glutil" इस्तेमाल करने के लिए फ़ाइल.

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, GLContext का इस्तेमाल करता है, जिसे eglManager मैनेज करता है.

हमें MainActivity में onPause() फ़ंक्शन को भी बदलना होगा, ताकि अगर ऐप्लिकेशन रुका हुआ है, तो हम converter को ठीक से बंद कर देते हैं:

@Override
protected void onPause() {
  super.onPause();
  converter.close();
}

previewFrameTexture के आउटपुट को converter से जोड़ने के लिए, जोड़ें 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 को जोड़ने के लिए ऑब्जेक्ट सबमिट करें और परिकलित displaySize के फ़्रेम converter पर भेजें.

अब हम MediaPipe ग्राफ़ में कैमरा फ़्रेम का इस्तेमाल करने के लिए तैयार हैं.

Android में MediaPipe ग्राफ़ का इस्तेमाल करना

काम की डिपेंडेंसी जोड़ें

MediaPipe ग्राफ़ का इस्तेमाल करने के लिए, हमें MediaPipe फ़्रेमवर्क में डिपेंडेंसी जोड़नी होगी Android पर देखें. हम सबसे पहले जेएनआई कोड का इस्तेमाल करके 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,
)

mediapipe_lib बिल्ड नियम में डिपेंडेंसी ":mediapipe_jni_lib" जोड़ें BUILD फ़ाइल.

इसके बाद, आपको जिस MediaPipe ग्राफ़ का इस्तेमाल करना है उसकी डिपेंडेंसी जोड़नी होगी ऐप्लिकेशन में.

सबसे पहले, libmediapipe_jni.so में मौजूद सभी कैलकुलेटर कोड पर डिपेंडेंसी जोड़ें बिल्ड नियम:

"//mediapipe/graphs/edge_detection:mobile_calculators",

MediaPipe ग्राफ़ .pbtxt फ़ाइलें हैं, लेकिन ऐप्लिकेशन में उनका उपयोग करने के लिए हमें ताकि .binarypb फ़ाइल जनरेट करने के लिए mediapipe_binary_graph बिल्ड नियम का इस्तेमाल किया जा सके.

helloworld Android बाइनरी बिल्ड के नियम में, 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 में ग्राफ़ का इस्तेमाल करें

सबसे पहले, हमें उस ऐसेट को लोड करना होगा जिसमें इनसे इकट्ठा किया गया .binarypb शामिल है ग्राफ़ की .pbtxt फ़ाइल. ऐसा करने के लिए, हम MediaPipe उपयोगिता का उपयोग कर सकते हैं, AndroidAssetUtil.

शुरू करने से पहले, onCreate(Bundle) में ऐसेट मैनेजर को शुरू करें eglManager:

// Initialize asset manager so that MediaPipe native libraries can access the app assets, e.g.,
// binary graphs.
AndroidAssetUtil.initializeNativeAssetManager(this);

अब हमें एक ऐसा FrameProcessor ऑब्जेक्ट सेट अप करना होगा जो कैमरे के फ़्रेम भेज सके को converter के ज़रिए MediaPipe ग्राफ़ के लिए तैयार किया जाता है और ग्राफ़ को चलाया जाता है, आउटपुट, और फिर आउटपुट दिखाने के लिए 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 से बदले गए फ़्रेम का इस्तेमाल करना होगा प्रोसेस चल रही है. शुरू करने के बाद, नीचे दी गई लाइन को onResume() में जोड़ें converter:

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 बनाने पर, हमने Surface को processor में से VideoSurfaceOutput. इसे खत्म कर दिए जाने पर, हम इसे यहां से हटा देते हैं processor के VideoSurfaceOutput.

यह बहुत आसान है! अब आप इसे बनाने और चलाने में सक्षम होना चाहिए डिवाइस में मौजूद ऐप्लिकेशन को लॉक किया गया है और सॉबेल एज डिटेक्शन को लाइव कैमरे में चलते हुए देखा गया है फ़ीड! बधाई हो!

edge_detection_android_gpu_gif

अगर आपको कोई समस्या हुई है, तो कृपया ट्यूटोरियल का पूरा कोड देखें यहां पढ़ें.