Einführung
Dies ist Hello World! im Tutorial mithilfe des MediaPipe-Frameworks eine Android-App entwickeln, die ein MediaPipe-Diagramm unter Android ausführt.
Umfang
Eine einfache Kamera-App für die Sobel-Kantenerkennung in Echtzeit, die auf ein Live-Video angewendet wird auf einem Android-Gerät streamen.
Einrichtung
- MediaPipe Framework auf Ihrem System installieren (siehe Framework-Installation) .
- Installieren Sie das Android Development SDK und das Android NDK. Eine Anleitung dazu finden Sie auch unter [Framework-Installationsanleitung].
- Aktivieren Sie die Entwickleroptionen auf Ihrem Android-Gerät.
- Richten Sie Bazel auf Ihrem System ein, um die Android-App zu erstellen und bereitzustellen.
Grafik für die Kantenerkennung
Wir verwenden die folgende Grafik, 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"
}
Im Folgenden sehen Sie eine Visualisierung des Diagramms:
Dieses Diagramm enthält einen einzelnen Eingabestream namens input_video
für alle eingehenden Frames
die von der Kamera Ihres Geräts bereitgestellt wird.
Der erste Knoten im Diagramm, LuminanceCalculator
, verwendet ein einzelnes Paket (Bild
Frame) und wendet eine Änderung der Leuchtdichte mithilfe eines OpenGL-Shaders an. Das Ergebnis
Bildframe an den luma_video
-Ausgabestream gesendet.
Der zweite Knoten, SobelEdgesCalculator
, wendet die Edge-Erkennung auf eingehende Anfragen an
Pakete im luma_video
-Stream und Ausgaben führen zu einer output_video
-Ausgabe
.
Unsere Android-App zeigt die Ausgabe-Bildframes der
Stream "output_video
".
Minimale anfängliche Einrichtung der Anwendung
Wir beginnen mit einer einfachen Android-Anwendung, in der „Hello World!“
auf dem Bildschirm. Sie können diesen Schritt überspringen, wenn Sie mit der Erstellung von Android-Apps vertraut sind.
Anwendungen, die bazel
verwenden.
Erstellen Sie ein neues Verzeichnis, in dem Sie Ihre Android-App erstellen. Für
den vollständigen Code dieser Anleitung unter
mediapipe/examples/android/src/java/com/google/mediapipe/apps/basic
Wir werden
im gesamten Codelab als $APPLICATION_PATH
.
Beachten Sie im Pfad zur Anwendung Folgendes:
- Die Anwendung heißt
helloworld
. - Die
$PACKAGE_PATH
der Anwendung istcom.google.mediapipe.apps.basic
. Dies wird in Code-Snippets in diesem Tutorial verwendet. Denken Sie daher daran, Ihre eigene$PACKAGE_PATH
, wenn Sie die Code-Snippets kopieren/verwenden.
Fügen Sie die Datei activity_main.xml
zu $APPLICATION_PATH/res/layout
hinzu. Dadurch wird Folgendes angezeigt:
ein TextView
im Vollbildmodus der Anwendung mit dem String Hello
World!
:
<?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>
Fügen Sie eine einfache MainActivity.java
zu $APPLICATION_PATH
hinzu, die den Inhalt lädt.
des activity_main.xml
-Layouts wie unten gezeigt:
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);
}
}
Fügen Sie die Manifestdatei AndroidManifest.xml
zu $APPLICATION_PATH
hinzu, die
startet MainActivity
beim Start der App:
<?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>
In unserer Anwendung verwenden wir ein Theme.AppCompat
-Design. Deshalb müssen wir
angemessene Themenreferenzen. colors.xml
hinzufügen zu
$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>
styles.xml
zu $APPLICATION_PATH/res/values/
hinzufügen:
<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>
Fügen Sie zum Erstellen der Anwendung eine BUILD
-Datei zu $APPLICATION_PATH
hinzu.
${appName}
und ${mainActivity}
im Manifest werden durch Strings ersetzt
wie unten in BUILD
angegeben.
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",
],
)
Die Regel android_library
fügt Abhängigkeiten für die Ressourcendateien MainActivity
hinzu
und AndroidManifest.xml
.
Die Regel „android_binary
“ verwendet die Android-Bibliothek basic_lib
, die generiert wurde, um
Erstelle ein binäres APK zur Installation auf deinem Android-Gerät.
Verwenden Sie den folgenden Befehl, um die App zu erstellen:
bazel build -c opt --config=android_arm64 $APPLICATION_PATH:helloworld
Installiere die generierte APK-Datei mit adb install
. Beispiel:
adb install bazel-bin/$APPLICATION_PATH/helloworld.apk
Öffnen Sie die App auf Ihrem Gerät. Nun sollte ein Bildschirm mit dem Text
Hello World!
Kamera über CameraX
verwenden
Kameraberechtigungen
Um die Kamera in unserer App verwenden zu können, müssen wir den Nutzer
auf die Kamera zugreifen. Füge Folgendes hinzu, um Kameraberechtigungen anzufordern:
AndroidManifest.xml
:
<!-- For using the camera -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
Ändern Sie die SDK-Mindestversion in 21
und die SDK-Zielversion in 27
Dieselbe Datei:
<uses-sdk
android:minSdkVersion="21"
android:targetSdkVersion="27" />
So wird sichergestellt, dass der Nutzer aufgefordert wird, die Kameraberechtigung anzufordern, und aktiviert die CameraX-Bibliothek für den Kamerazugriff zu verwenden.
Zum Anfordern von Kameraberechtigungen können wir ein von MediaPipe Framework bereitgestelltes Dienstprogramm verwenden
Komponenten, nämlich PermissionHelper
. Fügen Sie eine Abhängigkeit hinzu, um sie zu verwenden
"//mediapipe/java/com/google/mediapipe/components:android_components"
in der
mediapipe_lib
-Regel in BUILD
.
Um die PermissionHelper
in MainActivity
zu verwenden, fügen Sie die folgende Zeile zum
onCreate
-Funktion:
PermissionHelper.checkAndRequestCameraPermissions(this);
Dadurch wird der Nutzer in einem Dialogfeld aufgefordert, die Berechtigungen für die Kamera in dieser App verwenden.
Fügen Sie den folgenden Code hinzu, um die Nutzerantwort zu verarbeiten:
@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() {}
Lassen Sie die Methode startCamera()
vorerst leer. Wenn der Nutzer antwortet
wird MainActivity
fortgesetzt und onResume()
aufgerufen.
Der Code bestätigt, dass die Berechtigungen zur Verwendung der Kamera erteilt wurden.
und startet dann die Kamera.
Erstellen Sie die Anwendung neu und installieren Sie sie. Sie sollten nun eine Aufforderung sehen, für die App Zugriff auf die Kamera gewähren.
Kamerazugriff
Wenn Kameraberechtigungen verfügbar sind, können wir Frames aus der Kamera.
Um die Bilder von der Kamera zu sehen, verwenden wir ein SurfaceView
. Jeder Frame
von der Kamera werden in einem SurfaceTexture
-Objekt gespeichert. Um sie zu verwenden,
müssen wir zuerst das Layout
unserer App ändern.
Entfernen Sie den gesamten Codeblock TextView
aus
$APPLICATION_PATH/res/layout/activity_main.xml
und fügen Sie den folgenden Code hinzu:
stattdessen:
<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>
Dieser Codeblock hat ein neues FrameLayout
mit dem Namen preview_display_layout
und einen
TextView
ist darin verschachtelt und heißt no_camera_access_preview
. Wenn Kamera
Zugriffsberechtigungen nicht gewährt haben, zeigt die Anwendung die
TextView
durch eine Stringnachricht, gespeichert in der Variablen no_camera_access
.
Fügen Sie die folgende Zeile in die Datei $APPLICATION_PATH/res/values/strings.xml
ein:
<string name="no_camera_access" translatable="false">Please grant camera permissions.</string>
Wenn der Nutzer keine Kameraberechtigung erteilt, sieht der Bildschirm jetzt so aus: dies:
Jetzt fügen wir die Objekte SurfaceTexture
und SurfaceView
MainActivity
:
private SurfaceTexture previewFrameTexture;
private SurfaceView previewDisplayView;
Fügen Sie in der Funktion onCreate(Bundle)
die folgenden zwei Zeilen vor
Kameraberechtigungen anfordern:
previewDisplayView = new SurfaceView(this);
setupPreviewDisplayView();
Fügen Sie jetzt den Code hinzu, mit dem setupPreviewDisplayView()
definiert wird:
private void setupPreviewDisplayView() {
previewDisplayView.setVisibility(View.GONE);
ViewGroup viewGroup = findViewById(R.id.preview_display_layout);
viewGroup.addView(previewDisplayView);
}
Wir definieren ein neues SurfaceView
-Objekt und fügen es zum
preview_display_layout
-FrameLayout
-Objekt, damit wir es zum Anzeigen
ein SurfaceTexture
-Objekt namens previewFrameTexture
ein.
Um previewFrameTexture
zum Abrufen von Kamerarahmen zu verwenden, nutzen wir CameraX.
Framework stellt ein Dienstprogramm namens CameraXPreviewHelper
zur Verwendung von CameraX bereit.
Diese Klasse aktualisiert einen Listener, wenn die Kamera über
onCameraStarted(@Nullable SurfaceTexture)
Ändern Sie zur Verwendung dieses Dienstprogramms die Datei BUILD
, um eine Abhängigkeit für hinzuzufügen.
"//mediapipe/java/com/google/mediapipe/components:android_camerax_helper"
.
Importieren Sie jetzt CameraXPreviewHelper
und fügen Sie folgende Zeile zu
MainActivity
:
private CameraXPreviewHelper cameraHelper;
Jetzt können wir unsere Implementierung zu startCamera()
hinzufügen:
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);
});
}
Dadurch wird ein neues CameraXPreviewHelper
-Objekt erstellt und ein anonymes Objekt
Listener für das Objekt. Wenn cameraHelper
signalisiert, dass die Kamera gestartet wurde
und ein surfaceTexture
zum Erfassen von Frames verfügbar ist, speichern wir
surfaceTexture
als previewFrameTexture
festlegen und previewDisplayView
sichtbar sind, sodass wir Frames aus previewFrameTexture
sehen können.
Bevor wir die Kamera starten, müssen wir jedoch entscheiden, welche Kamera
verwenden. CameraXPreviewHelper
übernimmt CameraHelper
. Dadurch werden zwei
Optionen FRONT
und BACK
. Wir können die Entscheidung anhand der Datei BUILD
übergeben.
enthalten, sodass keine Codeänderungen erforderlich sind,
um eine andere Version des
App mit einer anderen Kamera.
Angenommen, wir möchten die Kamera BACK
verwenden, um in einer Liveszene eine Kantenerkennung durchzuführen.
die wir von der Kamera aus betrachten, fügen Sie die Metadaten zu AndroidManifest.xml
hinzu:
...
<meta-data android:name="cameraFacingFront" android:value="${cameraFacingFront}"/>
</application>
</manifest>
und lege die Auswahl in BUILD
in der Android-Binärregel helloworld
fest
mit einem neuen Eintrag in manifest_values
:
manifest_values = {
"applicationId": "com.google.mediapipe.apps.basic",
"appName": "Hello World",
"mainActivity": ".MainActivity",
"cameraFacingFront": "False",
},
Rufen Sie nun in MainActivity
die in manifest_values
angegebenen Metadaten ab:
Fügen Sie ein ApplicationInfo
-Objekt hinzu:
private ApplicationInfo applicationInfo;
Fügen Sie in der Funktion onCreate()
Folgendes hinzu:
try {
applicationInfo =
getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
} catch (NameNotFoundException e) {
Log.e(TAG, "Cannot find application info: " + e);
}
Fügen Sie jetzt am Ende der Funktion startCamera()
die folgende Zeile hinzu:
CameraHelper.CameraFacing cameraFacing =
applicationInfo.metaData.getBoolean("cameraFacingFront", false)
? CameraHelper.CameraFacing.FRONT
: CameraHelper.CameraFacing.BACK;
cameraHelper.startCamera(this, cameraFacing, /*unusedSurfaceTexture=*/ null);
Die Anwendung sollte nun erfolgreich erstellt werden. Wenn Sie jedoch
die App auf Ihrem Gerät öffnen, sehen Sie einen schwarzen Bildschirm, obwohl die Kamera
Berechtigungen wurden gewährt). Das liegt daran, dass wir zwar die
Variable surfaceTexture
von CameraXPreviewHelper
, der
previewSurfaceView
verwendet die Ausgabe noch nicht und zeigt sie noch nicht auf dem Bildschirm an.
Da wir die Frames in einem MediaPipe-Diagramm verwenden möchten, fügen wir sehen Sie sich die Kameraausgabe direkt in dieser Anleitung an. Wir überspringen stattdessen können wir Kameraframes zur Verarbeitung an ein MediaPipe-Diagramm senden der Grafik auf dem Bildschirm.
ExternalTextureConverter
einrichten
Ein SurfaceTexture
erfasst Bildframes aus einem Stream als OpenGL ES
Textur. Um ein MediaPipe-Diagramm zu verwenden, sollten mit der Kamera aufgenommene Frames
die in einem regulären Open GL-Texturobjekt gespeichert sind. Das Framework stellt eine Klasse bereit,
ExternalTextureConverter
, um das in einem SurfaceTexture
gespeicherte Bild zu konvertieren
-Objekt zu einem normalen OpenGL-Texturobjekt werden.
Zur Verwendung von ExternalTextureConverter
benötigen wir auch eine EGLContext
,
die von einem EglManager
-Objekt erstellt und verwaltet werden. Abhängigkeit zu BUILD
hinzufügen
Datei zur Verwendung von EglManager
, "//mediapipe/java/com/google/mediapipe/glutil"
.
Fügen Sie in MainActivity
die folgenden Deklarationen hinzu:
private EglManager eglManager;
private ExternalTextureConverter converter;
Fügen Sie in der Funktion onCreate(Bundle)
eine Anweisung hinzu, um die
eglManager
-Objekt, bevor Kameraberechtigungen angefordert werden:
eglManager = new EglManager(null);
Zur Bestätigung: Wir haben die Funktion onResume()
in MainActivity
definiert.
Kameraberechtigungen wurden gewährt. Rufe startCamera()
auf. Vorher
die folgende Zeile in onResume()
einfügen, um converter
zu initialisieren
-Objekt enthält:
converter = new ExternalTextureConverter(eglManager.getContext());
Für dieses Gerät (converter
) wird jetzt das von eglManager
verwaltete GLContext
verwendet.
Außerdem müssen wir die Funktion onPause()
in MainActivity
überschreiben,
Wenn die Anwendung in den Status „Pausiert“ wechselt, wird converter
ordnungsgemäß geschlossen:
@Override
protected void onPause() {
super.onPause();
converter.close();
}
Für eine Weiterleitung der Ausgabe von previewFrameTexture
an converter
fügen Sie den Parameter
folgenden Codeblock an 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) {}
});
In diesem Codeblock fügen wir ein benutzerdefiniertes SurfaceHolder.Callback
-Element hinzu,
previewDisplayView
und implementieren Sie die Funktion surfaceChanged(SurfaceHolder holder, int
format, int width, int height)
, um eine geeignete Anzeigegröße zu berechnen.
Kameraframes auf dem Gerätebildschirm und die previewFrameTexture
und sendet Frames des berechneten displaySize
-Objekts an converter
.
Jetzt können Kameraframes in einem MediaPipe-Diagramm verwendet werden.
MediaPipe-Diagramm in Android verwenden
Relevante Abhängigkeiten hinzufügen
Um ein MediaPipe-Diagramm zu verwenden, müssen Sie Abhängigkeiten zum MediaPipe-Framework hinzufügen
für Android. Zunächst fügen wir eine Build-Regel hinzu, um eine cc_binary
mit JNI-Code zu erstellen.
des MediaPipe-Frameworks und erstellen Sie dann eine cc_library
-Regel zur Verwendung dieses Binärprogramms.
in unserer App. Fügen Sie der Datei BUILD
den folgenden Codeblock hinzu:
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,
)
Fügen Sie der Build-Regel mediapipe_lib
die Abhängigkeit ":mediapipe_jni_lib"
hinzu:
BUILD
-Datei.
Als Nächstes müssen wir Abhängigkeiten hinzufügen, die für das MediaPipe-Diagramm spezifisch sind, das wir verwenden möchten. in der Anwendung.
Fügen Sie zuerst Abhängigkeiten zum gesamten Rechnercode in der Datei libmediapipe_jni.so
hinzu.
Erstellungsregel:
"//mediapipe/graphs/edge_detection:mobile_calculators",
MediaPipe-Grafiken sind .pbtxt
-Dateien, aber um sie in der Anwendung verwenden zu können, benötigen wir
um mit der Build-Regel mediapipe_binary_graph
eine .binarypb
-Datei zu generieren.
Füge in der Android-Binär-Build-Regel helloworld
die mediapipe_binary_graph
hinzu.
für das Diagramm spezifisches Ziel als Asset:
assets = [
"//mediapipe/graphs/edge_detection:mobile_gpu_binary_graph",
],
assets_dir = "",
In der Build-Regel assets
können Sie auch andere Assets wie TensorFlowLite hinzufügen
die in Ihrer Grafik verwendet werden.
Fügen Sie außerdem zusätzliche manifest_values
für Attribute hinzu, die für die
Graph, der später in MainActivity
abgerufen wird:
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",
},
Beachten Sie, dass binaryGraphName
den Dateinamen des binären Graphen angibt.
durch das Feld output_name
im Ziel mediapipe_binary_graph
festgelegt.
inputVideoStreamName
und outputVideoStreamName
sind die Ein- und Ausgabe
Video-Stream-Name, der in der Grafik angegeben ist.
Jetzt muss der MainActivity
das MediaPipe-Framework laden. Die
Framework verwendet OpenCV, daher sollte MainActvity
auch OpenCV
laden. Verwenden Sie die Methode
nachstehender Code in MainActivity
(innerhalb der Klasse, aber nicht innerhalb einer Funktion)
um beide Abhängigkeiten zu laden:
static {
// Load all native libraries needed by the app.
System.loadLibrary("mediapipe_jni");
System.loadLibrary("opencv_java3");
}
Das Diagramm in MainActivity
verwenden
Zuerst müssen wir das Asset laden, das die .binarypb
enthält, die aus
der Datei .pbtxt
des Diagramms. Dazu können wir ein MediaPipe-Dienstprogramm verwenden,
AndroidAssetUtil
Initialisieren Sie den Asset-Manager vor der Initialisierung in onCreate(Bundle)
eglManager
:
// Initialize asset manager so that MediaPipe native libraries can access the app assets, e.g.,
// binary graphs.
AndroidAssetUtil.initializeNativeAssetManager(this);
Jetzt müssen wir ein FrameProcessor
-Objekt einrichten, das Kameraframes sendet.
die von der converter
an die MediaPipe-Grafik
die Ausgabe und aktualisiert dann previewDisplayView
, um die Ausgabe anzuzeigen. Hinzufügen
folgenden Code zur Deklaration von FrameProcessor
:
private FrameProcessor processor;
und initialisieren Sie es nach der Initialisierung von eglManager
in onCreate(Bundle)
:
processor =
new FrameProcessor(
this,
eglManager.getNativeContext(),
applicationInfo.metaData.getString("binaryGraphName"),
applicationInfo.metaData.getString("inputVideoStreamName"),
applicationInfo.metaData.getString("outputVideoStreamName"));
processor
muss die umgewandelten Frames aus dem converter
für die
Datenverarbeitung. Fügen Sie die folgende Zeile zu onResume()
hinzu, nachdem Sie den
converter
:
converter.setConsumer(processor);
Die Ausgabe von processor
sollte an previewDisplayView
gesendet werden. Fügen Sie dazu
die folgenden Funktionsdefinitionen in unser benutzerdefiniertes SurfaceHolder.Callback
ein:
@Override
public void surfaceCreated(SurfaceHolder holder) {
processor.getVideoSurfaceOutput().setSurface(holder.getSurface());
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
processor.getVideoSurfaceOutput().setSurface(null);
}
Beim Erstellen der SurfaceHolder
hatten wir die Surface
für die
VideoSurfaceOutput
von processor
. Wenn es zerstört wird, entfernen wir es aus
der VideoSurfaceOutput
von processor
.
Webseite. Sie sollten nun in der Lage sein, den auf dem Gerät ausführen und sehen, wie die Sobel-Edge-Erkennung an einer Live-Kamera ausgeführt wird Feed! Glückwunsch!
Falls Probleme aufgetreten sind, sehen Sie sich den vollständigen Code der Anleitung an. hier.