diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/AndroidManifest.xml b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/AndroidManifest.xml new file mode 100644 index 000000000..b61304f0d --- /dev/null +++ b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/AndroidManifest.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/BUILD b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/BUILD new file mode 100644 index 000000000..689e8babe --- /dev/null +++ b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/BUILD @@ -0,0 +1,95 @@ +# Copyright 2019 The MediaPipe Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) + +# Basic library common across example apps. +android_library( + name = "basic_lib", + srcs = glob(["*.java"]), + manifest = "AndroidManifest.xml", + resource_files = glob(["res/**"]), + visibility = ["//visibility:public"], + deps = [ + "//mediapipe/framework/formats:detection_java_proto_lite", + "//mediapipe/framework/formats:location_data_java_proto_lite", + "//mediapipe/java/com/google/mediapipe/components:android_camerax_helper", + "//mediapipe/java/com/google/mediapipe/components:android_components", + "//mediapipe/java/com/google/mediapipe/framework:android_framework", + "//mediapipe/java/com/google/mediapipe/glutil", + "//mediapipe/java/com/google/mediapipe/solutioncore:camera_input", + "//mediapipe/java/com/google/mediapipe/solutioncore:solution_rendering", + "//mediapipe/java/com/google/mediapipe/solutions/facedetection", + "//mediapipe/java/com/google/mediapipe/solutions/posetracking", + "//third_party:androidx_appcompat", + "//third_party:androidx_constraint_layout", + "//third_party:opencv", + "@maven//:androidx_concurrent_concurrent_futures", + "@maven//:com_google_guava_guava", + ], +) + +# Manifest common across example apps. +exports_files( + srcs = ["AndroidManifest.xml"], +) + +# Native dependencies to perform edge detection in the Hello World example. +cc_binary( + name = "libmediapipe_jni.so", + linkshared = 1, + linkstatic = 1, + deps = [ + "//mediapipe/graphs/edge_detection:mobile_calculators", + "//mediapipe/java/com/google/mediapipe/framework/jni:mediapipe_framework_jni", + #facedetection deps + "//mediapipe/graphs/face_detection:face_detection_full_range_mobile_gpu_deps", + "//mediapipe/graphs/face_detection:mobile_calculators", + #pose tracking deps + "//mediapipe/graphs/pose_tracking:pose_tracking_gpu_deps", + ], +) + +# Converts the .so cc_binary into a cc_library, to be consumed in an android_binary. +cc_library( + name = "mediapipe_jni_lib", + srcs = [":libmediapipe_jni.so"], + alwayslink = 1, +) + +# Hello World example app. +android_binary( + name = "helloworld", + # assets = [ + # "//mediapipe/graphs/edge_detection:mobile_gpu.binarypb", + # ], + # assets_dir = "", + manifest = "AndroidManifest.xml", + manifest_values = { + "applicationId": "com.google.mediapipe.apps.posetrackingsolutiongpu", + "appName": "Hello World", + "mainActivity": ".MainActivity", + # "cameraFacingFront": "False", + # "binaryGraphName": "mobile_gpu.binarypb", + # "inputVideoStreamName": "input_video", + # "outputVideoStreamName": "output_video", + # "flipFramesVertically": "True", + # "converterNumBuffers": "2", + }, + multidex = "native", + deps = [ + ":basic_lib", + ":mediapipe_jni_lib", + ], +) diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/FaceDetectionResultImageView.java b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/FaceDetectionResultImageView.java new file mode 100644 index 000000000..c22c732b2 --- /dev/null +++ b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/FaceDetectionResultImageView.java @@ -0,0 +1,110 @@ +// Copyright 2021 The MediaPipe Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.mediapipe.apps.posetrackingsolutiongpu; + +import static java.lang.Math.min; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.google.mediapipe.formats.proto.DetectionProto.Detection; +import com.google.mediapipe.solutions.facedetection.FaceDetectionResult; +import com.google.mediapipe.solutions.facedetection.FaceKeypoint; + +/** An ImageView implementation for displaying {@link FaceDetectionResult}. */ +public class FaceDetectionResultImageView extends AppCompatImageView { + private static final String TAG = "FaceDetectionResultImageView"; + + private static final int KEYPOINT_COLOR = Color.RED; + private static final int KEYPOINT_RADIUS = 8; // Pixels + private static final int BBOX_COLOR = Color.GREEN; + private static final int BBOX_THICKNESS = 5; // Pixels + private Bitmap latest; + + public FaceDetectionResultImageView(Context context) { + super(context); + setScaleType(ScaleType.FIT_CENTER); + } + + /** + * Sets a {@link FaceDetectionResult} to render. + * + * @param result a {@link FaceDetectionResult} object that contains the solution outputs and the + * input {@link Bitmap}. + */ + public void setFaceDetectionResult(FaceDetectionResult result) { + if (result == null) { + return; + } + Bitmap bmInput = result.inputBitmap(); + int width = bmInput.getWidth(); + int height = bmInput.getHeight(); + latest = Bitmap.createBitmap(width, height, bmInput.getConfig()); + Canvas canvas = new Canvas(latest); + + canvas.drawBitmap(bmInput, new Matrix(), null); + int numDetectedFaces = result.multiFaceDetections().size(); + for (int i = 0; i < numDetectedFaces; ++i) { + drawDetectionOnCanvas(result.multiFaceDetections().get(i), canvas, width, height); + } + } + + /** Updates the image view with the latest {@link FaceDetectionResult}. */ + public void update() { + postInvalidate(); + if (latest != null) { + setImageBitmap(latest); + } + } + + private void drawDetectionOnCanvas(Detection detection, Canvas canvas, int width, int height) { + if (!detection.hasLocationData()) { + return; + } + // Draw keypoints. + Paint keypointPaint = new Paint(); + keypointPaint.setColor(KEYPOINT_COLOR); + for (int i = 0; i < FaceKeypoint.NUM_KEY_POINTS; ++i) { + int xPixel = + min( + (int) (detection.getLocationData().getRelativeKeypoints(i).getX() * width), + width - 1); + int yPixel = + min( + (int) (detection.getLocationData().getRelativeKeypoints(i).getY() * height), + height - 1); + canvas.drawCircle(xPixel, yPixel, KEYPOINT_RADIUS, keypointPaint); + } + if (!detection.getLocationData().hasRelativeBoundingBox()) { + return; + } + // Draw bounding box. + Paint bboxPaint = new Paint(); + bboxPaint.setColor(BBOX_COLOR); + bboxPaint.setStyle(Paint.Style.STROKE); + bboxPaint.setStrokeWidth(BBOX_THICKNESS); + float left = detection.getLocationData().getRelativeBoundingBox().getXmin() * width; + float top = detection.getLocationData().getRelativeBoundingBox().getYmin() * height; + float right = left + detection.getLocationData().getRelativeBoundingBox().getWidth() * width; + float bottom = top + detection.getLocationData().getRelativeBoundingBox().getHeight() * height; + canvas.drawRect(left, top, right, bottom, bboxPaint); + } +} diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/MainActivity.java b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/MainActivity.java new file mode 100644 index 000000000..5c3545283 --- /dev/null +++ b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/MainActivity.java @@ -0,0 +1,151 @@ +// Copyright 2019 The MediaPipe Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.mediapipe.apps.posetrackingsolutiongpu; + +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.graphics.SurfaceTexture; +import android.os.Bundle; +import androidx.appcompat.app.AppCompatActivity; +import android.util.Log; +import android.util.Size; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import com.google.mediapipe.components.CameraHelper; +import com.google.mediapipe.components.CameraXPreviewHelper; +import com.google.mediapipe.components.ExternalTextureConverter; +import com.google.mediapipe.components.FrameProcessor; +import com.google.mediapipe.components.PermissionHelper; +import com.google.mediapipe.formats.proto.LocationDataProto; +import com.google.mediapipe.framework.AndroidAssetUtil; +import com.google.mediapipe.glutil.EglManager; +import com.google.mediapipe.solutioncore.CameraInput; +import com.google.mediapipe.solutioncore.SolutionGlSurfaceView; +import com.google.mediapipe.solutions.facedetection.FaceDetection; +import com.google.mediapipe.solutions.facedetection.FaceDetectionOptions; +import com.google.mediapipe.solutions.posetracking.PoseTracking; +import com.google.mediapipe.solutions.posetracking.PoseTrackingOptions; +import com.google.mediapipe.solutions.posetracking.PoseTrackingResult; + +import java.util.ArrayList; + + +/** Main activity of MediaPipe basic app. */ +public class MainActivity extends AppCompatActivity { + private static final String TAG = "MainActivity"; + + // Flips the camera-preview frames vertically by default, before sending them into FrameProcessor + // to be processed in a MediaPipe graph, and flips the processed frames back when they are + // displayed. This maybe needed because OpenGL represents images assuming the image origin is at + // the bottom-left corner, whereas MediaPipe in general assumes the image origin is at the + // top-left corner. + // NOTE: use "flipFramesVertically" in manifest metadata to override this behavior. + private static final boolean FLIP_FRAMES_VERTICALLY = true; + + // Number of output frames allocated in ExternalTextureConverter. + // NOTE: use "converterNumBuffers" in manifest metadata to override number of buffers. For + // example, when there is a FlowLimiterCalculator in the graph, number of buffers should be at + // least `max_in_flight + max_in_queue + 1` (where max_in_flight and max_in_queue are used in + // FlowLimiterCalculator options). That's because we need buffers for all the frames that are in + // flight/queue plus one for the next frame from the camera. + private static final int NUM_BUFFERS = 2; + + static { + // Load all native libraries needed by the app. + System.loadLibrary("mediapipe_jni"); + try { + System.loadLibrary("opencv_java3"); + } catch (java.lang.UnsatisfiedLinkError e) { + // Some example apps (e.g. template matching) require OpenCV 4. + System.loadLibrary("opencv_java4"); + } + } + + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(getContentViewLayoutResId()); + + PoseTrackingOptions poseTrackingOptions = PoseTrackingOptions.builder() + .setStaticImageMode(false).build(); + PoseTracking poseTracking = new PoseTracking(this,poseTrackingOptions); + + poseTracking.setErrorListener( + (message, e) -> Log.e(TAG, "MediaPipe Face Detection error:" + message)); + CameraInput cameraInput = new CameraInput(this); + + + cameraInput.setNewFrameListener( + textureFrame -> poseTracking.send(textureFrame)); + SolutionGlSurfaceView glSurfaceView = + new SolutionGlSurfaceView<>( + this, poseTracking.getGlContext(), poseTracking.getGlMajorVersion()); + glSurfaceView.setSolutionResultRenderer(new PoseTrackingResultGlRenderer()); + glSurfaceView.setRenderInputImage(true); + + poseTracking.setResultListener( + faceDetectionResult -> { + if (faceDetectionResult.multiPoseTrackings().isEmpty()) { + return; + } + LocationDataProto.LocationData locationData = faceDetectionResult + .multiPoseTrackings() + .get(0) + .getLocationData(); +// .getRelativeKeypoints(FaceKeypoint.NOSE_TIP); + Log.i( + TAG, locationData.toString()); +// String.format( +// "MediaPipe Face Detection nose tip normalized coordinates (value range: [0, 1]): x=%f, y=%f", +// noseTip.getX(), noseTip.getY())); + // Request GL rendering. + glSurfaceView.setRenderData(faceDetectionResult); + glSurfaceView.requestRender(); + }); + // The runnable to start camera after the GLSurfaceView is attached. + glSurfaceView.post( + () -> + cameraInput.start( + this, + poseTracking.getGlContext(), + CameraInput.CameraFacing.FRONT, + glSurfaceView.getWidth(), + glSurfaceView.getHeight())); + glSurfaceView.setVisibility(View.VISIBLE); + FrameLayout frameLayout = findViewById(R.id.preview_display_layout); + frameLayout.removeAllViewsInLayout(); + frameLayout.addView(glSurfaceView); + glSurfaceView.setVisibility(View.VISIBLE); + frameLayout.requestLayout(); + } + + + // Used to obtain the content view for this application. If you are extending this class, and + // have a custom layout, override this method and return the custom layout. + protected int getContentViewLayoutResId() { + return R.layout.activity_main; + } + + + + +} diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/PoseTrackingResultGlRenderer.java b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/PoseTrackingResultGlRenderer.java new file mode 100644 index 000000000..e0a4cb25a --- /dev/null +++ b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/PoseTrackingResultGlRenderer.java @@ -0,0 +1,147 @@ +// Copyright 2021 The MediaPipe Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.mediapipe.apps.posetrackingsolutiongpu; + +import android.opengl.GLES20; + +import com.google.mediapipe.formats.proto.DetectionProto.Detection; +import com.google.mediapipe.solutioncore.ResultGlRenderer; +import com.google.mediapipe.solutions.posetracking.PoseTrackingResult; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; + +/** A custom implementation of {@link ResultGlRenderer} to render {@link PoseTrackingResult}. */ +public class PoseTrackingResultGlRenderer implements ResultGlRenderer { + private static final String TAG = "PoseTrackingResultGlRenderer"; + + private static final float[] KEYPOINT_COLOR = new float[] {1f, 0f, 0f, 1f}; + private static final float KEYPOINT_SIZE = 16f; + private static final float[] BBOX_COLOR = new float[] {0f, 1f, 0f, 1f}; + private static final int BBOX_THICKNESS = 8; + private static final String VERTEX_SHADER = + "uniform mat4 uProjectionMatrix;\n" + + "uniform float uPointSize;\n" + + "attribute vec4 vPosition;\n" + + "void main() {\n" + + " gl_Position = uProjectionMatrix * vPosition;\n" + + " gl_PointSize = uPointSize;" + + "}"; + private static final String FRAGMENT_SHADER = + "precision mediump float;\n" + + "uniform vec4 uColor;\n" + + "void main() {\n" + + " gl_FragColor = uColor;\n" + + "}"; + private int program; + private int positionHandle; + private int pointSizeHandle; + private int projectionMatrixHandle; + private int colorHandle; + + private int loadShader(int type, String shaderCode) { + int shader = GLES20.glCreateShader(type); + GLES20.glShaderSource(shader, shaderCode); + GLES20.glCompileShader(shader); + return shader; + } + + @Override + public void setupRendering() { + program = GLES20.glCreateProgram(); + int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER); + int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER); + GLES20.glAttachShader(program, vertexShader); + GLES20.glAttachShader(program, fragmentShader); + GLES20.glLinkProgram(program); + positionHandle = GLES20.glGetAttribLocation(program, "vPosition"); + pointSizeHandle = GLES20.glGetUniformLocation(program, "uPointSize"); + projectionMatrixHandle = GLES20.glGetUniformLocation(program, "uProjectionMatrix"); + colorHandle = GLES20.glGetUniformLocation(program, "uColor"); + } + + @Override + public void renderResult(PoseTrackingResult result, float[] projectionMatrix) { + if (result == null) { + return; + } + GLES20.glUseProgram(program); + GLES20.glUniformMatrix4fv(projectionMatrixHandle, 1, false, projectionMatrix, 0); + GLES20.glUniform1f(pointSizeHandle, KEYPOINT_SIZE); + int numDetectedFaces = result.multiPoseTrackings().size(); + for (int i = 0; i < numDetectedFaces; ++i) { + drawDetection(result.multiPoseTrackings().get(i)); + } + } + + /** + * Deletes the shader program. + * + *

This is only necessary if one wants to release the program while keeping the context around. + */ + public void release() { + GLES20.glDeleteProgram(program); + } + + private void drawDetection(Detection detection) { + if (!detection.hasLocationData()) { + return; + } + // Draw keypoints. +// float[] points = new float[FaceKeypoint.NUM_KEY_POINTS * 2]; +// for (int i = 0; i < FaceKeypoint.NUM_KEY_POINTS; ++i) { +// points[2 * i] = detection.getLocationData().getRelativeKeypoints(i).getX(); +// points[2 * i + 1] = detection.getLocationData().getRelativeKeypoints(i).getY(); +// } + GLES20.glUniform4fv(colorHandle, 1, KEYPOINT_COLOR, 0); +// FloatBuffer vertexBuffer = +// ByteBuffer.allocateDirect(points.length * 4) +// .order(ByteOrder.nativeOrder()) +// .asFloatBuffer() +// .put(points); +// vertexBuffer.position(0); + GLES20.glEnableVertexAttribArray(positionHandle); +// GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 0, vertexBuffer); +// GLES20.glDrawArrays(GLES20.GL_POINTS, 0, FaceKeypoint.NUM_KEY_POINTS); + if (!detection.getLocationData().hasRelativeBoundingBox()) { + return; + } + // Draw bounding box. + float left = detection.getLocationData().getRelativeBoundingBox().getXmin(); + float top = detection.getLocationData().getRelativeBoundingBox().getYmin(); + float right = left + detection.getLocationData().getRelativeBoundingBox().getWidth(); + float bottom = top + detection.getLocationData().getRelativeBoundingBox().getHeight(); + drawLine(top, left, top, right); + drawLine(bottom, left, bottom, right); + drawLine(top, left, bottom, left); + drawLine(top, right, bottom, right); + } + + private void drawLine(float y1, float x1, float y2, float x2) { + GLES20.glUniform4fv(colorHandle, 1, BBOX_COLOR, 0); + GLES20.glLineWidth(BBOX_THICKNESS); + float[] vertex = {x1, y1, x2, y2}; + FloatBuffer vertexBuffer = + ByteBuffer.allocateDirect(vertex.length * 4) + .order(ByteOrder.nativeOrder()) + .asFloatBuffer() + .put(vertex); + vertexBuffer.position(0); + GLES20.glEnableVertexAttribArray(positionHandle); + GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 0, vertexBuffer); + GLES20.glDrawArrays(GLES20.GL_LINES, 0, 2); + } +} diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/drawable-v24/ic_launcher_foreground.xml b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..c7bd21dbd --- /dev/null +++ b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/drawable/ic_launcher_background.xml b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..01f0af0ad --- /dev/null +++ b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/layout/activity_main.xml b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/layout/activity_main.xml new file mode 100644 index 000000000..c19d7e628 --- /dev/null +++ b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/layout/activity_main.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-anydpi-v26/ic_launcher.xml b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 000000000..d372a4fca --- /dev/null +++ b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-anydpi-v26/ic_launcher_round.xml b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000..d372a4fca --- /dev/null +++ b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-hdpi/ic_launcher.png b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..920cbf3f1 Binary files /dev/null and b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-hdpi/ic_launcher.png differ diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-hdpi/ic_launcher_foreground.png b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..7dfa35f78 Binary files /dev/null and b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-hdpi/ic_launcher_round.png b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 000000000..20dfc6c13 Binary files /dev/null and b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-mdpi/ic_launcher.png b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..3813caa21 Binary files /dev/null and b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-mdpi/ic_launcher.png differ diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-mdpi/ic_launcher_foreground.png b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..d49232778 Binary files /dev/null and b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-mdpi/ic_launcher_round.png b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 000000000..18f9ac5e7 Binary files /dev/null and b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xhdpi/ic_launcher.png b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..b79cc77a0 Binary files /dev/null and b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xhdpi/ic_launcher_foreground.png b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..811b17cee Binary files /dev/null and b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xhdpi/ic_launcher_round.png b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 000000000..2f3c752e5 Binary files /dev/null and b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxhdpi/ic_launcher.png b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..05585e4c6 Binary files /dev/null and b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxhdpi/ic_launcher_foreground.png b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..46b77639c Binary files /dev/null and b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxhdpi/ic_launcher_round.png b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..f87332424 Binary files /dev/null and b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxxhdpi/ic_launcher.png b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..8ccd6c840 Binary files /dev/null and b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..06b982e31 Binary files /dev/null and b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxxhdpi/ic_launcher_round.png b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..501748acc Binary files /dev/null and b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/values/colors.xml b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/values/colors.xml new file mode 100644 index 000000000..69b22338c --- /dev/null +++ b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #008577 + #00574B + #D81B60 + diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/values/strings.xml b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/values/strings.xml new file mode 100644 index 000000000..e45fdb48f --- /dev/null +++ b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/values/strings.xml @@ -0,0 +1,3 @@ + + Please grant camera permissions. + diff --git a/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/values/styles.xml b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/values/styles.xml new file mode 100644 index 000000000..5885930df --- /dev/null +++ b/mediapipe/examples/android/src/java/com/google/mediapipe/apps/posetrackingsolutiongpu/res/values/styles.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/mediapipe/graphs/pose_tracking/pose_tracking_gpu.pbtxt b/mediapipe/graphs/pose_tracking/pose_tracking_gpu.pbtxt index 35be3f0e0..6e25cedf8 100644 --- a/mediapipe/graphs/pose_tracking/pose_tracking_gpu.pbtxt +++ b/mediapipe/graphs/pose_tracking/pose_tracking_gpu.pbtxt @@ -19,6 +19,7 @@ node { } } + # Throttles the images flowing downstream for flow control. It passes through # the very first incoming image unaltered, and waits for downstream nodes # (calculators and subgraphs) in the graph to finish their tasks before it @@ -29,6 +30,9 @@ node { # real-time mobile applications. It also eliminates unnecessarily computation, # e.g., the output produced by a node may get dropped downstream if the # subsequent nodes are still busy processing previous inputs. + + + node { calculator: "FlowLimiterCalculator" input_stream: "input_video" @@ -37,9 +41,18 @@ node { tag_index: "FINISHED" back_edge: true } - output_stream: "throttled_input_video" + output_stream: "throttled_input_video_cpu" } +# Converts Image to GpuBuffer for PoseLandmarkGPU to consume. +node { + calculator: "FromImageCalculator" + input_stream: "IMAGE:throttled_input_video_cpu" + output_stream: "IMAGE_GPU:throttled_input_video" + output_stream: "SOURCE_ON_GPU:is_gpu_image" +} + + # Subgraph that detects poses and corresponding landmarks. node { calculator: "PoseLandmarkGpu" diff --git a/mediapipe/java/com/google/mediapipe/solutions/posetracking/AndroidManifest.xml b/mediapipe/java/com/google/mediapipe/solutions/posetracking/AndroidManifest.xml new file mode 100644 index 000000000..07da672e8 --- /dev/null +++ b/mediapipe/java/com/google/mediapipe/solutions/posetracking/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/mediapipe/java/com/google/mediapipe/solutions/posetracking/BUILD b/mediapipe/java/com/google/mediapipe/solutions/posetracking/BUILD new file mode 100644 index 000000000..a20dbc3b6 --- /dev/null +++ b/mediapipe/java/com/google/mediapipe/solutions/posetracking/BUILD @@ -0,0 +1,50 @@ +# Copyright 2021 The MediaPipe Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) + +android_library( + name = "posetracking", + srcs = [ + "PersonKeypoint.java", + "PoseTracking.java", + "PoseTrackingOptions.java", + "PoseTrackingResult.java", + ], + assets = [ + "//mediapipe/modules/face_detection:face_detection_full_range_image.binarypb", + "//mediapipe/modules/face_detection:face_detection_full_range_sparse.tflite", + "//mediapipe/modules/face_detection:face_detection_short_range.tflite", + "//mediapipe/modules/face_detection:face_detection_short_range_image.binarypb", + "//mediapipe/graphs/pose_tracking:pose_tracking_gpu.binarypb", + "//mediapipe/modules/pose_landmark:pose_landmark_heavy.tflite", + "//mediapipe/modules/pose_landmark:pose_landmark_full.tflite", + "//mediapipe/modules/pose_landmark:pose_landmark_lite.tflite", + "//mediapipe/modules/pose_detection:pose_detection.tflite", + ], + assets_dir = "", + javacopts = ["-Acom.google.auto.value.AutoBuilderIsUnstable"], + manifest = ":AndroidManifest.xml", + visibility = ["//visibility:public"], + deps = [ + "//mediapipe/framework/formats:detection_java_proto_lite", + "//mediapipe/java/com/google/mediapipe/framework:android_framework", + "//mediapipe/java/com/google/mediapipe/solutioncore:camera_input", + "//mediapipe/java/com/google/mediapipe/solutioncore:solution_base", + "//third_party:autovalue", + "@maven//:androidx_annotation_annotation", + "@maven//:com_google_code_findbugs_jsr305", + "@maven//:com_google_guava_guava", + ], +) diff --git a/mediapipe/java/com/google/mediapipe/solutions/posetracking/PersonKeypoint.java b/mediapipe/java/com/google/mediapipe/solutions/posetracking/PersonKeypoint.java new file mode 100644 index 000000000..8ba9f592c --- /dev/null +++ b/mediapipe/java/com/google/mediapipe/solutions/posetracking/PersonKeypoint.java @@ -0,0 +1,42 @@ +// Copyright 2021 The MediaPipe Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.mediapipe.solutions.posetracking; + +import androidx.annotation.IntDef; + +/** The 6 face keypoints. */ +public final class PersonKeypoint { + public static final int NUM_KEY_POINTS = 6; + + public static final int RIGHT_EYE = 0; + public static final int LEFT_EYE = 1; + public static final int NOSE_TIP = 2; + public static final int MOUTH_CENTER = 3; + public static final int RIGHT_EAR_TRAGION = 4; + public static final int LEFT_EAR_TRAGION = 5; + + /** Represents a face keypoint type. */ + @IntDef({ + RIGHT_EYE, + LEFT_EYE, + NOSE_TIP, + MOUTH_CENTER, + RIGHT_EAR_TRAGION, + LEFT_EAR_TRAGION, + }) + public @interface FaceKeypointType {} + + private PersonKeypoint() {} +} diff --git a/mediapipe/java/com/google/mediapipe/solutions/posetracking/PoseTracking.java b/mediapipe/java/com/google/mediapipe/solutions/posetracking/PoseTracking.java new file mode 100644 index 000000000..423a26c5b --- /dev/null +++ b/mediapipe/java/com/google/mediapipe/solutions/posetracking/PoseTracking.java @@ -0,0 +1,106 @@ +// Copyright 2021 The MediaPipe Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.mediapipe.solutions.posetracking; + +import android.content.Context; +import com.google.common.collect.ImmutableList; +import com.google.mediapipe.framework.MediaPipeException; +import com.google.mediapipe.framework.Packet; +import com.google.mediapipe.solutioncore.ErrorListener; +import com.google.mediapipe.solutioncore.ImageSolutionBase; +import com.google.mediapipe.solutioncore.OutputHandler; +import com.google.mediapipe.solutioncore.ResultListener; +import com.google.mediapipe.solutioncore.SolutionInfo; +import com.google.mediapipe.formats.proto.DetectionProto.Detection; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Nullable; + +/** + * MediaPipe Face Detection Solution API. + * + *

MediaPipe Face Detection processes a {@link TextureFrame} or a {@link Bitmap} and returns the + * {@link PoseTrackingResult} representing each detected face. Please refer to + * https://solutions.mediapipe.dev/face_detection#android-solution-api for usage examples. + */ +public class PoseTracking extends ImageSolutionBase { + private static final String TAG = "PoseTracking"; + + private static final String SHORT_RANGE_GRAPH_NAME = "pose_tracking_gpu.binarypb"; + private static final String FULL_RANGE_GRAPH_NAME = "face_detection_full_range_image.binarypb"; + private static final String IMAGE_INPUT_STREAM = "input_video"; + private static final ImmutableList OUTPUT_STREAMS = + ImmutableList.of("pose_detection", "throttled_input_video"); + private static final int DETECTIONS_INDEX = 0; + private static final int INPUT_IMAGE_INDEX = 1; + private final OutputHandler outputHandler; + + /** + * Initializes MediaPipe Face Detection solution. + * + * @param context an Android {@link Context}. + * @param options the configuration options defined in {@link PoseTrackingOptions}. + */ + public PoseTracking(Context context, PoseTrackingOptions options) { + outputHandler = new OutputHandler<>(); + outputHandler.setOutputConverter( + packets -> { + PoseTrackingResult.Builder poseTrackingResultBuilder = PoseTrackingResult.builder(); + try { + poseTrackingResultBuilder.setMultiPoseTrackings( + getProtoVector(packets.get(DETECTIONS_INDEX), Detection.parser())); + } catch (MediaPipeException e) { + reportError("Error occurs while getting MediaPipe pose tracking results.", e); + } + return poseTrackingResultBuilder + .setImagePacket(packets.get(INPUT_IMAGE_INDEX)) + .setTimestamp( + staticImageMode ? Long.MIN_VALUE : packets.get(INPUT_IMAGE_INDEX).getTimestamp()) + .build(); + }); + + SolutionInfo solutionInfo = + SolutionInfo.builder() + .setBinaryGraphPath( + options.modelSelection() == 0 ? SHORT_RANGE_GRAPH_NAME : FULL_RANGE_GRAPH_NAME) + .setImageInputStreamName(IMAGE_INPUT_STREAM) + .setOutputStreamNames(OUTPUT_STREAMS) + .setStaticImageMode(options.staticImageMode()) + .build(); + + initialize(context, solutionInfo, outputHandler); + Map emptyInputSidePackets = new HashMap<>(); + start(emptyInputSidePackets); + } + + /** + * Sets a callback to be invoked when a {@link PoseTrackingResult} becomes available. + * + * @param listener the {@link ResultListener} callback. + */ + public void setResultListener(ResultListener listener) { + this.outputHandler.setResultListener(listener); + } + + /** + * Sets a callback to be invoked when the Face Detection solution throws errors. + * + * @param listener the {@link ErrorListener} callback. + */ + public void setErrorListener(@Nullable ErrorListener listener) { + this.outputHandler.setErrorListener(listener); + this.errorListener = listener; + } +} diff --git a/mediapipe/java/com/google/mediapipe/solutions/posetracking/PoseTrackingOptions.java b/mediapipe/java/com/google/mediapipe/solutions/posetracking/PoseTrackingOptions.java new file mode 100644 index 000000000..908c4cc74 --- /dev/null +++ b/mediapipe/java/com/google/mediapipe/solutions/posetracking/PoseTrackingOptions.java @@ -0,0 +1,61 @@ +// Copyright 2021 The MediaPipe Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.mediapipe.solutions.posetracking; + +import com.google.auto.value.AutoValue; + +/** + * MediaPipe Face Detection solution-specific options. + * + *

staticImageMode: Whether to treat the input images as a batch of static and possibly unrelated + * images, or a video stream. Default to false. See details in + * https://solutions.mediapipe.dev/face_detection#static_image_mode. + * + *

minDetectionConfidence: Minimum confidence value ([0.0, 1.0]) for face detection to be + * considered successful. See details in + * https://solutions.mediapipe.dev/face_detection#min_detection_confidence. + * + *

modelSelection: 0 or 1. 0 to select a short-range model that works best for faces within 2 + * meters from the camera, and 1 for a full-range model best for faces within 5 meters. See details + * in https://solutions.mediapipe.dev/face_detection#model_selection. + */ +@AutoValue +public abstract class PoseTrackingOptions { + public abstract boolean staticImageMode(); + + public abstract int modelSelection(); + + public abstract float minDetectionConfidence(); + + public static Builder builder() { + return new AutoValue_PoseTrackingOptions.Builder().withDefaultValues(); + } + + /** Builder for {@link PoseTrackingOptions}. */ + @AutoValue.Builder + public abstract static class Builder { + public Builder withDefaultValues() { + return setStaticImageMode(false).setModelSelection(0).setMinDetectionConfidence(0.5f); + } + + public abstract Builder setStaticImageMode(boolean value); + + public abstract Builder setModelSelection(int value); + + public abstract Builder setMinDetectionConfidence(float value); + + public abstract PoseTrackingOptions build(); + } +} diff --git a/mediapipe/java/com/google/mediapipe/solutions/posetracking/PoseTrackingResult.java b/mediapipe/java/com/google/mediapipe/solutions/posetracking/PoseTrackingResult.java new file mode 100644 index 000000000..b82989f73 --- /dev/null +++ b/mediapipe/java/com/google/mediapipe/solutions/posetracking/PoseTrackingResult.java @@ -0,0 +1,65 @@ +// Copyright 2021 The MediaPipe Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.mediapipe.solutions.posetracking; + +import android.graphics.Bitmap; +import com.google.auto.value.AutoBuilder; +import com.google.common.collect.ImmutableList; +import com.google.mediapipe.framework.Packet; +import com.google.mediapipe.framework.TextureFrame; +import com.google.mediapipe.solutioncore.ImageSolutionResult; +import com.google.mediapipe.formats.proto.DetectionProto.Detection; +import java.util.List; + +/** + * FaceDetectionResult contains the detected faces, and the input {@link Bitmap} or {@link + * TextureFrame}. If not in static image mode, the timestamp field will be set to the timestamp of + * the corresponding input image. + */ +public class PoseTrackingResult extends ImageSolutionResult { + private final ImmutableList multiPoseTrackings; + + PoseTrackingResult( + ImmutableList multiPoseTrackings, Packet imagePacket, long timestamp) { + this.multiPoseTrackings = multiPoseTrackings; + this.timestamp = timestamp; + this.imagePacket = imagePacket; + } + + // Collection of detected faces, where each face is represented as a detection proto message that + // contains a bounding box and 6 {@link FaceKeypoint}s. The bounding box is composed of xmin and + // width (both normalized to [0.0, 1.0] by the image width) and ymin and height (both normalized + // to [0.0, 1.0] by the image height). Each keypoint is composed of x and y, which are normalized + // to [0.0, 1.0] by the image width and height respectively. + public ImmutableList multiPoseTrackings() { + return multiPoseTrackings; + } + + public static Builder builder() { + return new AutoBuilder_PoseTrackingResult_Builder(); + } + + /** Builder for {@link PoseTrackingResult}. */ + @AutoBuilder + public abstract static class Builder { + abstract Builder setMultiPoseTrackings(List value); + + abstract Builder setTimestamp(long value); + + abstract Builder setImagePacket(Packet value); + + abstract PoseTrackingResult build(); + } +}