英文:
Unable to access current frame being processed in the "ML Kit Vision Quickstart Sample App"
问题
I am working on an android project where I have access facial landmarks from the currently processed frame. Then I have to perform some calculation based on the face positions. At last I have to save the current frame being processed.
For this I am using ML Kit Vision Quickstart Sample App. This code is doing most of my work. From this code I am using the LivePreviewActivity.java, FaceDetectorProcessor.java and FaceGraphic.java class. I have performed all the calculations inside the FaceGraphics.java class. But I am NOT able to access the frame that is being processed currently.
LivePreviewActivity.java
/*
* Copyright 2020 Google LLC. All rights reserved.
*
* 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.
*/
FaceDetectorProcessor.java
/*
* Copyright 2020 Google LLC. All rights reserved.
*
* 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.
*/
FaceGraphics.java
/*
* Copyright 2020 Google LLC. All rights reserved.
*
* 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.
*/
In the above code, you want to access the current frame being processed either inside the LivePreviewActivity.java
or FaceGraphics.java
. To access the current frame, you can make use of the InputImage
object in the detectInImage
method of the FaceDetectorProcessor.java
class. This InputImage
object represents the image being processed.
You can access the image data from the InputImage
object and perform any required calculations on it. For example, if you want to save the current frame, you can save the image data using the appropriate methods or libraries.
Please let me know if you need further assistance with specific code implementations.
英文:
I am working on an android project where I have access facial landmarks from the currently processed frame. Then I have to perform some calculation based on the face positions. At last I have to save the current frame being processed.
For this I am using ML Kit Vision Quickstart Sample App. This code is doing most of my work. From this code I am using the LivePreviewActivity.java, FaceDetectorProcessor.java and FaceGraphic.java class. I have performed all the calculations inside the FaceGraphics.java class. But I am NOT able to access the frame that is being processed currently.
LivePreviewActivity.java
/*
* Copyright 2020 Google LLC. All rights reserved.
*
* 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.mlkit.vision.demo;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import androidx.core.app.ActivityCompat;
import androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback;
import androidx.core.content.ContextCompat;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.Toast;
import android.widget.ToggleButton;
import com.google.android.gms.common.annotation.KeepName;
import com.google.mlkit.common.model.LocalModel;
import com.google.mlkit.vision.demo.automl.AutoMLImageLabelerProcessor;
import com.google.mlkit.vision.demo.barcodescanner.BarcodeScannerProcessor;
import com.google.mlkit.vision.demo.facedetector.FaceDetectorProcessor;
import com.google.mlkit.vision.demo.labeldetector.LabelDetectorProcessor;
import com.google.mlkit.vision.demo.objectdetector.ObjectDetectorProcessor;
import com.google.mlkit.vision.demo.preference.PreferenceUtils;
import com.google.mlkit.vision.demo.preference.SettingsActivity;
import com.google.mlkit.vision.demo.preference.SettingsActivity.LaunchSource;
import com.google.mlkit.vision.demo.textdetector.TextRecognitionProcessor;
import com.google.mlkit.vision.face.FaceDetectorOptions;
import com.google.mlkit.vision.label.custom.CustomImageLabelerOptions;
import com.google.mlkit.vision.label.defaults.ImageLabelerOptions;
import com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions;
import com.google.mlkit.vision.objects.defaults.ObjectDetectorOptions;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Live preview demo for ML Kit APIs.
*/
@KeepName
public final class LivePreviewActivity extends AppCompatActivity
implements OnRequestPermissionsResultCallback,
OnItemSelectedListener,
CompoundButton.OnCheckedChangeListener {
private static final String FACE_DETECTION = "Face Detection";
private static final String TAG = "LivePreviewActivity";
private static final int PERMISSION_REQUESTS = 1;
private CameraSource cameraSource = null;
private CameraSourcePreview preview;
private GraphicOverlay graphicOverlay;
private String selectedModel = FACE_DETECTION;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
setContentView(R.layout.activity_vision_live_preview);
preview = findViewById(R.id.preview);
if (preview == null) {
Log.d(TAG, "Preview is null");
}
graphicOverlay = findViewById(R.id.graphic_overlay);
if (graphicOverlay == null) {
Log.d(TAG, "graphicOverlay is null");
}
Spinner spinner = findViewById(R.id.spinner);
List<String> options = new ArrayList<>();
options.add(FACE_DETECTION);
// Creating adapter for spinner
ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(this, R.layout.spinner_style, options);
// Drop down layout style - list view with radio button
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// attaching data adapter to spinner
spinner.setAdapter(dataAdapter);
spinner.setOnItemSelectedListener(this);
ToggleButton facingSwitch = findViewById(R.id.facing_switch);
facingSwitch.setOnCheckedChangeListener(this);
ImageView settingsButton = findViewById(R.id.settings_button);
settingsButton.setOnClickListener(
v -> {
Intent intent = new Intent(getApplicationContext(), SettingsActivity.class);
intent.putExtra(SettingsActivity.EXTRA_LAUNCH_SOURCE,
SettingsActivity.LaunchSource.LIVE_PREVIEW);
startActivity(intent);
});
if (allPermissionsGranted()) {
createCameraSource(selectedModel);
} else {
getRuntimePermissions();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.live_preview_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.settings) {
Intent intent = new Intent(this, SettingsActivity.class);
intent.putExtra(SettingsActivity.EXTRA_LAUNCH_SOURCE, LaunchSource.LIVE_PREVIEW);
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public synchronized void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
// An item was selected. You can retrieve the selected item using
// parent.getItemAtPosition(pos)
selectedModel = parent.getItemAtPosition(pos).toString();
Log.d(TAG, "Selected model: " + selectedModel);
preview.stop();
if (allPermissionsGranted()) {
createCameraSource(selectedModel);
startCameraSource();
} else {
getRuntimePermissions();
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// Do nothing.
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Log.d(TAG, "Set facing");
if (cameraSource != null) {
if (isChecked) {
cameraSource.setFacing(CameraSource.CAMERA_FACING_FRONT);
} else {
cameraSource.setFacing(CameraSource.CAMERA_FACING_BACK);
}
}
preview.stop();
startCameraSource();
}
private void createCameraSource(String model) {
// If there's no existing cameraSource, create one.
if (cameraSource == null) {
cameraSource = new CameraSource(this, graphicOverlay);
}
try {
Log.i(TAG, "Using Face Detector Processor");
FaceDetectorOptions faceDetectorOptions = new FaceDetectorOptions.Builder()
.setContourMode(FaceDetectorOptions.CONTOUR_MODE_ALL)
.build();
// PreferenceUtils.getFaceDetectorOptionsForLivePreview(this);
cameraSource.setMachineLearningFrameProcessor(
new FaceDetectorProcessor(this, faceDetectorOptions));
} catch (Exception e) {
Log.e(TAG, "Can not create image processor: " + model, e);
Toast.makeText(
getApplicationContext(),
"Can not create image processor: " + e.getMessage(),
Toast.LENGTH_LONG)
.show();
}
}
/**
* Starts or restarts the camera source, if it exists. If the camera source doesn't exist yet
* (e.g., because onResume was called before the camera source was created), this will be called
* again when the camera source is created.
*/
private void startCameraSource() {
if (cameraSource != null) {
try {
if (preview == null) {
Log.d(TAG, "resume: Preview is null");
}
if (graphicOverlay == null) {
Log.d(TAG, "resume: graphOverlay is null");
}
preview.start(cameraSource, graphicOverlay);
} catch (IOException e) {
Log.e(TAG, "Unable to start camera source.", e);
cameraSource.release();
cameraSource = null;
}
}
}
@Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume");
createCameraSource(selectedModel);
startCameraSource();
}
/**
* Stops the camera.
*/
@Override
protected void onPause() {
super.onPause();
preview.stop();
}
@Override
public void onDestroy() {
super.onDestroy();
if (cameraSource != null) {
cameraSource.release();
}
}
private String[] getRequiredPermissions() {
try {
PackageInfo info =
this.getPackageManager()
.getPackageInfo(this.getPackageName(), PackageManager.GET_PERMISSIONS);
String[] ps = info.requestedPermissions;
if (ps != null && ps.length > 0) {
return ps;
} else {
return new String[0];
}
} catch (Exception e) {
return new String[0];
}
}
private boolean allPermissionsGranted() {
for (String permission : getRequiredPermissions()) {
if (!isPermissionGranted(this, permission)) {
return false;
}
}
return true;
}
private void getRuntimePermissions() {
List<String> allNeededPermissions = new ArrayList<>();
for (String permission : getRequiredPermissions()) {
if (!isPermissionGranted(this, permission)) {
allNeededPermissions.add(permission);
}
}
if (!allNeededPermissions.isEmpty()) {
ActivityCompat.requestPermissions(
this, allNeededPermissions.toArray(new String[0]), PERMISSION_REQUESTS);
}
}
@Override
public void onRequestPermissionsResult(
int requestCode, String[] permissions, int[] grantResults) {
Log.i(TAG, "Permission granted!");
if (allPermissionsGranted()) {
createCameraSource(selectedModel);
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
private static boolean isPermissionGranted(Context context, String permission) {
if (ContextCompat.checkSelfPermission(context, permission)
== PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "Permission granted: " + permission);
return true;
}
Log.i(TAG, "Permission NOT granted: " + permission);
return false;
}
}
FaceDetectorProcessor.java
/*
* Copyright 2020 Google LLC. All rights reserved.
*
* 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.mlkit.vision.demo.facedetector;
import android.content.Context;
import android.graphics.PointF;
import android.util.Log;
import androidx.annotation.NonNull;
import com.google.android.gms.tasks.Task;
import com.google.mlkit.vision.common.InputImage;
import com.google.mlkit.vision.demo.GraphicOverlay;
import com.google.mlkit.vision.demo.VisionProcessorBase;
import com.google.mlkit.vision.face.Face;
import com.google.mlkit.vision.face.FaceDetection;
import com.google.mlkit.vision.face.FaceDetector;
import com.google.mlkit.vision.face.FaceDetectorOptions;
import com.google.mlkit.vision.face.FaceLandmark;
import java.util.List;
import java.util.Locale;
/**
* Face Detector Demo.
*/
public class FaceDetectorProcessor extends VisionProcessorBase<List<Face>> {
private static final String TAG = "FaceDetectorProcessor";
private final FaceDetector detector;
public FaceDetectorProcessor(Context context) {
this(
context,
new FaceDetectorOptions.Builder()
.setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)
.enableTracking()
.build());
}
public FaceDetectorProcessor(Context context, FaceDetectorOptions options) {
super(context);
Log.v(MANUAL_TESTING_LOG, "Face detector options: " + options);
detector = FaceDetection.getClient(options);
}
@Override
public void stop() {
super.stop();
detector.close();
}
@Override
protected Task<List<Face>> detectInImage(InputImage image) {
return detector.process(image);
}
@Override
protected void onSuccess(@NonNull List<Face> faces, @NonNull GraphicOverlay graphicOverlay) {
for (Face face : faces) {
graphicOverlay.add(new FaceGraphic(graphicOverlay, face));
logExtrasForTesting(face);
}
}
private static void logExtrasForTesting(Face face) {
if (face != null) {
Log.v(MANUAL_TESTING_LOG, "face bounding box: " + face.getBoundingBox().flattenToString());
Log.v(MANUAL_TESTING_LOG, "face Euler Angle X: " + face.getHeadEulerAngleX());
Log.v(MANUAL_TESTING_LOG, "face Euler Angle Y: " + face.getHeadEulerAngleY());
Log.v(MANUAL_TESTING_LOG, "face Euler Angle Z: " + face.getHeadEulerAngleZ());
// All landmarks
int[] landMarkTypes =
new int[]{
FaceLandmark.MOUTH_BOTTOM,
FaceLandmark.MOUTH_RIGHT,
FaceLandmark.MOUTH_LEFT,
FaceLandmark.RIGHT_EYE,
FaceLandmark.LEFT_EYE,
FaceLandmark.RIGHT_EAR,
FaceLandmark.LEFT_EAR,
FaceLandmark.RIGHT_CHEEK,
FaceLandmark.LEFT_CHEEK,
FaceLandmark.NOSE_BASE
};
String[] landMarkTypesStrings =
new String[]{
"MOUTH_BOTTOM",
"MOUTH_RIGHT",
"MOUTH_LEFT",
"RIGHT_EYE",
"LEFT_EYE",
"RIGHT_EAR",
"LEFT_EAR",
"RIGHT_CHEEK",
"LEFT_CHEEK",
"NOSE_BASE"
};
for (int i = 0; i < landMarkTypes.length; i++) {
FaceLandmark landmark = face.getLandmark(landMarkTypes[i]);
if (landmark == null) {
Log.v(
MANUAL_TESTING_LOG,
"No landmark of type: " + landMarkTypesStrings[i] + " has been detected");
} else {
PointF landmarkPosition = landmark.getPosition();
String landmarkPositionStr =
String.format(Locale.US, "x: %f , y: %f", landmarkPosition.x, landmarkPosition.y);
Log.v(
MANUAL_TESTING_LOG,
"Position for face landmark: "
+ landMarkTypesStrings[i]
+ " is :"
+ landmarkPositionStr);
}
}
Log.v(
MANUAL_TESTING_LOG,
"face left eye open probability: " + face.getLeftEyeOpenProbability());
Log.v(
MANUAL_TESTING_LOG,
"face right eye open probability: " + face.getRightEyeOpenProbability());
Log.v(MANUAL_TESTING_LOG, "face smiling probability: " + face.getSmilingProbability());
Log.v(MANUAL_TESTING_LOG, "face tracking id: " + face.getTrackingId());
}
}
@Override
protected void onFailure(@NonNull Exception e) {
Log.e(TAG, "Face detection failed " + e);
}
}
FaceGraphics.java
/*
* Copyright 2020 Google LLC. All rights reserved.
*
* 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.mlkit.vision.demo.facedetector;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.util.Log;
import com.google.mlkit.vision.demo.GraphicOverlay;
import com.google.mlkit.vision.demo.GraphicOverlay.Graphic;
import com.google.mlkit.vision.face.Face;
import com.google.mlkit.vision.face.FaceContour;
import com.google.mlkit.vision.face.FaceLandmark;
import com.google.mlkit.vision.face.FaceLandmark.LandmarkType;
import java.util.Locale;
/**
* Graphic instance for rendering face position, contour, and landmarks within the associated
* graphic overlay view.
*/
public class FaceGraphic extends Graphic {
private static final float FACE_POSITION_RADIUS = 4.0f;
private static final float ID_TEXT_SIZE = 30.0f;
private static final float ID_Y_OFFSET = 40.0f;
private static final float ID_X_OFFSET = -40.0f;
private static final float BOX_STROKE_WIDTH = 5.0f;
private static final int NUM_COLORS = 10;
private static final int[][] COLORS = new int[][]{
// {Text color, background color}
{Color.BLACK, Color.WHITE},
{Color.WHITE, Color.MAGENTA},
{Color.BLACK, Color.LTGRAY},
{Color.WHITE, Color.RED},
{Color.WHITE, Color.BLUE},
{Color.WHITE, Color.DKGRAY},
{Color.BLACK, Color.CYAN},
{Color.BLACK, Color.YELLOW},
{Color.WHITE, Color.BLACK},
{Color.BLACK, Color.GREEN}
};
private final Paint facePositionPaint;
private final Paint[] idPaints;
private final Paint[] boxPaints;
private final Paint[] labelPaints;
private volatile Face face;
FaceGraphic(GraphicOverlay overlay, Face face) {
super(overlay);
this.face = face;
final int selectedColor = Color.WHITE;
facePositionPaint = new Paint();
facePositionPaint.setColor(selectedColor);
int numColors = COLORS.length;
idPaints = new Paint[numColors];
boxPaints = new Paint[numColors];
labelPaints = new Paint[numColors];
for (int i = 0; i < numColors; i++) {
idPaints[i] = new Paint();
idPaints[i].setColor(COLORS[i][0] /* text color */);
idPaints[i].setTextSize(ID_TEXT_SIZE);
boxPaints[i] = new Paint();
boxPaints[i].setColor(COLORS[i][1] /* background color */);
boxPaints[i].setStyle(Paint.Style.STROKE);
boxPaints[i].setStrokeWidth(BOX_STROKE_WIDTH);
labelPaints[i] = new Paint();
labelPaints[i].setColor(COLORS[i][1] /* background color */);
labelPaints[i].setStyle(Paint.Style.FILL);
}
}
/**
* Draws the face annotations for position on the supplied canvas.
*/
@Override
public void draw(Canvas canvas) {
Face face = this.face;
if (face == null) {
return;
}
// Draws a circle at the position of the detected face, with the face's track id below.
float x0 = translateX(face.getBoundingBox().centerX());
float y0 = translateY(face.getBoundingBox().centerY());
// canvas.drawCircle(x0, y0, FACE_POSITION_RADIUS, facePositionPaint);
// Calculate positions.
float left = x0 - scale(face.getBoundingBox().width() / 2.0f);
float top = y0 - scale(face.getBoundingBox().height() / 2.0f);
float right = x0 + scale(face.getBoundingBox().width() / 2.0f);
float bottom = y0 + scale(face.getBoundingBox().height() / 2.0f);
float lineHeight = ID_TEXT_SIZE + BOX_STROKE_WIDTH;
float yLabelOffset = -lineHeight;
// Decide color based on face ID
int colorID = (face.getTrackingId() == null)
? 0 : Math.abs(face.getTrackingId() % NUM_COLORS);
/**
// Calculate width and height of label box
float textWidth = idPaints[colorID].measureText("ID: " + face.getTrackingId());
if (face.getSmilingProbability() != null) {
yLabelOffset -= lineHeight;
textWidth = Math.max(textWidth, idPaints[colorID].measureText(
String.format(Locale.US, "Happiness: %.2f", face.getSmilingProbability())));
}
if (face.getLeftEyeOpenProbability() != null) {
yLabelOffset -= lineHeight;
textWidth = Math.max(textWidth, idPaints[colorID].measureText(
String.format(Locale.US, "Left eye: %.2f", face.getLeftEyeOpenProbability())));
}
if (face.getRightEyeOpenProbability() != null) {
yLabelOffset -= lineHeight;
textWidth = Math.max(textWidth, idPaints[colorID].measureText(
String.format(Locale.US, "Right eye: %.2f", face.getLeftEyeOpenProbability())));
}
// Draw labels
canvas.drawRect(left - BOX_STROKE_WIDTH,
top + yLabelOffset,
left + textWidth + (2 * BOX_STROKE_WIDTH),
top,
labelPaints[colorID]);
yLabelOffset += ID_TEXT_SIZE;
canvas.drawRect(left, top, right, bottom, boxPaints[colorID]);
canvas.drawText("ID: " + face.getTrackingId(), left, top + yLabelOffset,
idPaints[colorID]);
yLabelOffset += lineHeight;
**/
/**
// Draws all face contours.
for (FaceContour contour : face.getAllContours()) {
for (PointF point : contour.getPoints()) {
canvas.drawCircle(
translateX(point.x), translateY(point.y), FACE_POSITION_RADIUS, facePositionPaint);
}
}
**/
FaceContour contour = face.getContour(FaceContour.NOSE_BRIDGE);
float x1 = 0, y1 = 0;
for (PointF point : contour.getPoints()) {
// canvas.drawCircle(translateX(point.x), translateY(point.y), FACE_POSITION_RADIUS, facePositionPaint);
x1 = translateX(point.x);
y1 = translateY(point.y);
break;
}
/**
// Draws smiling and left/right eye open probabilities.
if (face.getSmilingProbability() != null) {
canvas.drawText(
"Smiling: " + String.format(Locale.US, "%.2f", face.getSmilingProbability()),
left,
top + yLabelOffset,
idPaints[colorID]);
yLabelOffset += lineHeight;
}
**/
/**
FaceLandmark leftEye = face.getLandmark(FaceLandmark.LEFT_EYE);
if (leftEye != null && face.getLeftEyeOpenProbability() != null) {
canvas.drawText(
"Left eye open: " + String.format(Locale.US, "%.2f", face.getLeftEyeOpenProbability()),
translateX(leftEye.getPosition().x) + ID_X_OFFSET,
translateY(leftEye.getPosition().y) + ID_Y_OFFSET,
idPaints[colorID]);
} else if (leftEye != null && face.getLeftEyeOpenProbability() == null) {
canvas.drawText(
"Left eye",
left,
top + yLabelOffset,
idPaints[colorID]);
yLabelOffset += lineHeight;
} else if (leftEye == null && face.getLeftEyeOpenProbability() != null) {
canvas.drawText(
"Left eye open: " + String.format(Locale.US, "%.2f", face.getLeftEyeOpenProbability()),
left,
top + yLabelOffset,
idPaints[colorID]);
yLabelOffset += lineHeight;
}
FaceLandmark rightEye = face.getLandmark(FaceLandmark.RIGHT_EYE);
if (rightEye != null && face.getRightEyeOpenProbability() != null) {
canvas.drawText(
"Right eye open: " + String.format(Locale.US, "%.2f", face.getRightEyeOpenProbability()),
translateX(rightEye.getPosition().x) + ID_X_OFFSET,
translateY(rightEye.getPosition().y) + ID_Y_OFFSET,
idPaints[colorID]);
} else if (rightEye != null && face.getRightEyeOpenProbability() == null) {
canvas.drawText(
"Right eye",
left,
top + yLabelOffset,
idPaints[colorID]);
yLabelOffset += lineHeight;
} else if (rightEye == null && face.getRightEyeOpenProbability() != null) {
canvas.drawText(
"Right eye open: " + String.format(Locale.US, "%.2f", face.getRightEyeOpenProbability()),
left,
top + yLabelOffset,
idPaints[colorID]);
}
**/
/**
// Draw facial landmarks
drawFaceLandmark(canvas, FaceLandmark.LEFT_EYE);
drawFaceLandmark(canvas, FaceLandmark.RIGHT_EYE);
drawFaceLandmark(canvas, FaceLandmark.LEFT_CHEEK);
drawFaceLandmark(canvas, FaceLandmark.RIGHT_CHEEK);
**/
}
private void drawFaceLandmark(Canvas canvas, @LandmarkType int landmarkType) {
FaceLandmark faceLandmark = face.getLandmark(landmarkType);
if (faceLandmark != null) {
canvas.drawCircle(
translateX(faceLandmark.getPosition().x),
translateY(faceLandmark.getPosition().y),
FACE_POSITION_RADIUS,
facePositionPaint);
}
}
}
In the above code I want to access the current frame being processed. Either inside the LivePreviewActivity or FaceGraphics.java.
Please help me.
答案1
得分: 2
以下是您要翻译的部分:
"By Frame , i am assuming you want the bitmap which satisfy your algorithm . Also as you mentioned that you are using LivePreviewActivity that means you are real time face detection.
There is no way to access the bitmap or current frame from FaceDetectorProcessor
Instead what you need to do is to access the original Image inside VisionProcessorBase.java
modify the common process logic like this to pass the current bitmap to FaceDetectorProcessor
// -----------------Common processing logic-------------------------------------------------------
private Task
final InputImage image,
final GraphicOverlay graphicOverlay,
@Nullable final Bitmap originalCameraImage,
boolean shouldShowFps) {
final long startMs = SystemClock.elapsedRealtime();
return detectInImage(image)
.addOnSuccessListener(
executor,
results -> {
long currentLatencyMs = SystemClock.elapsedRealtime() - startMs;
numRuns++;
frameProcessedInOneSecondInterval++;
totalRunMs += currentLatencyMs;
maxRunMs = Math.max(currentLatencyMs, maxRunMs);
minRunMs = Math.min(currentLatencyMs, minRunMs);
// Only log inference info once per second. When frameProcessedInOneSecondInterval is
// equal to 1, it means this is the first frame processed during the current second.
if (frameProcessedInOneSecondInterval == 1) {
Log.d(TAG, "Max latency is: " + maxRunMs);
Log.d(TAG, "Min latency is: " + minRunMs);
Log.d(TAG, "Num of Runs: " + numRuns + ", Avg latency is: " + totalRunMs / numRuns);
MemoryInfo mi = new MemoryInfo();
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem / 0x100000L;
Log.d(TAG, "Memory available in system: " + availableMegs + " MB");
}
graphicOverlay.clear();
if (originalCameraImage != null) {
graphicOverlay.add(new CameraImageGraphic(graphicOverlay, originalCameraImage));
}
//passing the original bitmap to FaceDetectorProcessor
VisionProcessorBase.this.onSuccess(originalCameraImage,results, graphicOverlay);
graphicOverlay.add(
new InferenceInfoGraphic(
graphicOverlay, currentLatencyMs, shouldShowFps ? framesPerSecond : null));
graphicOverlay.postInvalidate();
})
.addOnFailureListener(
executor,
e -> {
graphicOverlay.clear();
graphicOverlay.postInvalidate();
String error = "Failed to process. Error: " + e.getLocalizedMessage();
Toast.makeText(
graphicOverlay.getContext(),
error + "\nCause: " + e.getCause(),
Toast.LENGTH_SHORT)
.show();
Log.d(TAG, error);
e.printStackTrace();
VisionProcessorBase.this.onFailure(e);
});
}
You also need to change abstract onSuccess FaceDetectorProcessor like this :
protected abstract void onSuccess(Bitmap currentBitmap,@NonNull T results, @NonNull GraphicOverlay graphicOverlay);
After the required changes , you can access the currentBitmap in onSuccess Method inside FaceDetectorProcessor and you can also pass this to FaceGraphic.java from here
@Override
protected void onSuccess(Bitmap currentBitmap, @NonNull List
for (Face face : faces) {
graphicOverlay.add(new FaceGraphic(currentBitmap,graphicOverlay, face));
logExtrasForTesting(face);
}
}
Inside FaceGraphic.java access current bitmap from constructor
FaceGraphic(Bitmap currentBitmap,GraphicOverlay overlay, Face face) {
this.currentBitmap = currentBitmap;
}
I hope this will help you out and fulfill your need."
英文:
By Frame , i am assuming you want the bitmap which satisfy your algorithm . Also as you mentioned that you are using LivePreviewActivity that means you are real time face detection.
There is no way to access the bitmap or current frame from FaceDetectorProcessor
Instead what you need to do is to access the original Image inside VisionProcessorBase.java
modify the common process logic like this to pass the current bitmap to FaceDetectorProcessor
// -----------------Common processing logic-------------------------------------------------------
private Task<T> requestDetectInImage(
final InputImage image,
final GraphicOverlay graphicOverlay,
@Nullable final Bitmap originalCameraImage,
boolean shouldShowFps) {
final long startMs = SystemClock.elapsedRealtime();
return detectInImage(image)
.addOnSuccessListener(
executor,
results -> {
long currentLatencyMs = SystemClock.elapsedRealtime() - startMs;
numRuns++;
frameProcessedInOneSecondInterval++;
totalRunMs += currentLatencyMs;
maxRunMs = Math.max(currentLatencyMs, maxRunMs);
minRunMs = Math.min(currentLatencyMs, minRunMs);
// Only log inference info once per second. When frameProcessedInOneSecondInterval is
// equal to 1, it means this is the first frame processed during the current second.
if (frameProcessedInOneSecondInterval == 1) {
Log.d(TAG, "Max latency is: " + maxRunMs);
Log.d(TAG, "Min latency is: " + minRunMs);
Log.d(TAG, "Num of Runs: " + numRuns + ", Avg latency is: " + totalRunMs / numRuns);
MemoryInfo mi = new MemoryInfo();
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem / 0x100000L;
Log.d(TAG, "Memory available in system: " + availableMegs + " MB");
}
graphicOverlay.clear();
if (originalCameraImage != null) {
graphicOverlay.add(new CameraImageGraphic(graphicOverlay, originalCameraImage));
}
//passing the original bitmap to FaceDetectorProcessor
VisionProcessorBase.this.onSuccess(originalCameraImage,results, graphicOverlay);
graphicOverlay.add(
new InferenceInfoGraphic(
graphicOverlay, currentLatencyMs, shouldShowFps ? framesPerSecond : null));
graphicOverlay.postInvalidate();
})
.addOnFailureListener(
executor,
e -> {
graphicOverlay.clear();
graphicOverlay.postInvalidate();
String error = "Failed to process. Error: " + e.getLocalizedMessage();
Toast.makeText(
graphicOverlay.getContext(),
error + "\nCause: " + e.getCause(),
Toast.LENGTH_SHORT)
.show();
Log.d(TAG, error);
e.printStackTrace();
VisionProcessorBase.this.onFailure(e);
});
}
You also need to change abstract onSuccess FaceDetectorProcessor like this :
protected abstract void onSuccess(Bitmap currentBitmap,@NonNull T results, @NonNull GraphicOverlay graphicOverlay);
After the required changes , you can access the currentBitmap in onSuccess Method inside FaceDetectorProcessor and you can also pass this to FaceGraphic.java from here
@Override
protected void onSuccess(Bitmap currentBitmap, @NonNull List<Face> faces, @NonNull GraphicOverlay graphicOverlay) {
for (Face face : faces) {
graphicOverlay.add(new FaceGraphic(currentBitmap,graphicOverlay, face));
logExtrasForTesting(face);
}
}
Inside FaceGraphic.java access current bitmap from constructor
FaceGraphic(Bitmap currentBitmap,GraphicOverlay overlay, Face face) {
this.currentBitmap = currentBitmap;
}
I hope this will help you out and fulfill your need.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论