GraphicOverlay.java
import android.content.Context;
import android.view.WindowManager;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
import com.google.mlkit.vision.face.Face;
import com.google.mlkit.vision.face.FaceContour;
import com.google.mlkit.vision.common.*;
import java.util.List;
public class GraphicOverlay extends View {
private List<Face> faces;
private Paint paint;
private Paint lipPaint;
private int imageWidth, imageHeight, devicewidth, deviceheight;
private float scalex, scaley, scale, offsetX, offsetY;
public GraphicOverlay(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
paint.setColor(0xFF00FF00); // Green color
paint.setStrokeWidth(2.0f);
paint.setStyle(Paint.Style.STROKE);
}
public void setFaceMeshes(List<Face> faces) {
this.faces = faces;
invalidate();
}
public void setImageInfo(int width, int height, int devicewidth, int deviceheight) {
this.imageWidth = width;
this.imageHeight = height;
this.devicewidth = devicewidth;
this.deviceheight = deviceheight;
scalex = (float) devicewidth /width;
scaley = (float) deviceheight /height;
scale = Math.min(scalex, scaley);
offsetX = (devicewidth - imageWidth * scale) / 2;
offsetY = (deviceheight - imageHeight * scale) / 2;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (faces == null || imageWidth == 0 || imageHeight == 0) return;
for (Face face : faces) {
List<PointF> upperLipBottomContour = face.getContour(FaceContour.UPPER_LIP_BOTTOM).getPoints();
drawFaceMesh(canvas,upperLipBottomContour,paint);
List<PointF> upperLipTopContour = face.getContour(FaceContour.UPPER_LIP_TOP).getPoints();
drawFaceMesh(canvas,upperLipTopContour,paint);
List<PointF> LowerLipBottomContour = face.getContour(FaceContour.LOWER_LIP_BOTTOM).getPoints();
drawFaceMesh(canvas,LowerLipBottomContour,paint);
List<PointF> LowerLipTopContour = face.getContour(FaceContour.LOWER_LIP_TOP).getPoints();
drawFaceMesh(canvas,LowerLipTopContour,paint);
List<PointF> LEFT_EYEBROW_BOTTOM = face.getContour(FaceContour.LEFT_EYEBROW_BOTTOM).getPoints();
drawFaceMesh(canvas,LEFT_EYEBROW_BOTTOM,paint);
List<PointF> RIGHT_EYEBROW_BOTTOM = face.getContour(FaceContour.RIGHT_EYEBROW_BOTTOM).getPoints();
drawFaceMesh(canvas,RIGHT_EYEBROW_BOTTOM,paint);
List<PointF> LEFT_EYEBROW_TOP = face.getContour(FaceContour.LEFT_EYEBROW_TOP).getPoints();
drawFaceMesh(canvas,LEFT_EYEBROW_TOP,paint);
List<PointF> RIGHT_EYEBROW_TOP = face.getContour(FaceContour.RIGHT_EYEBROW_TOP).getPoints();
drawFaceMesh(canvas,RIGHT_EYEBROW_TOP,paint);
}
}
private void drawFaceMesh(Canvas canvas, List<PointF> points, Paint paint) {
for (PointF point : points) {
float x = point.x ;//* scalex - offsetX;
float y = point.y ;//* scaley - offsetY;
canvas.drawCircle(x, y, 2, paint);
}
}
}
MainActivity.java
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.media.Image;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowManager;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.mlkit.vision.common.InputImage;
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 java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
public class MainActivity extends AppCompatActivity implements ImageAnalysis.Analyzer {
private static final int REQUEST_CAMERA_PERMISSION = 1001;
private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
private PreviewView previewView;
private GraphicOverlay graphicOverlay;
int screenWidth, screenHeight;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
previewView = findViewById(R.id.viewFinder);
graphicOverlay = findViewById(R.id.graphicOverlay);
DisplayMetrics displayMetrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
screenWidth = displayMetrics.widthPixels;
screenHeight = displayMetrics.heightPixels;
Log.e("Device Screen Resolution","Height : "+screenHeight+" Width : "+screenWidth);
// Check and request camera permissions
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA_PERMISSION);
} else {
startCamera();
}
}
private Executor getExecutor() {
return ContextCompat.getMainExecutor(this);
}
private void startCamera() {
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
bindCameraX(cameraProvider);
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
}, getExecutor());
}
private void bindCameraX(@NonNull ProcessCameraProvider cameraProvider) {
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_FRONT)
.build();
Preview preview = new Preview.Builder().build();
preview.setSurfaceProvider(previewView.getSurfaceProvider());
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build();
imageAnalysis.setAnalyzer(getExecutor(), this);
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis);
}
@Override
public void analyze(@NonNull ImageProxy imageProxy) {
Image mediaImage = imageProxy.getImage();
if (mediaImage != null) {
int imageWidth = imageProxy.getWidth();
int imageHeight = imageProxy.getHeight();
Log.e("ImageProxy dimension","Height : "+imageHeight+" Weidth : "+imageWidth);
graphicOverlay.setImageInfo(imageWidth, imageHeight, screenWidth, screenHeight);
InputImage image = InputImage.fromMediaImage(mediaImage, imageProxy.getImageInfo().getRotationDegrees());
FaceDetectorOptions realTimeOpts = new FaceDetectorOptions.Builder()
.setContourMode(FaceDetectorOptions.CONTOUR_MODE_ALL)
.build();
FaceDetector detector = FaceDetection.getClient(realTimeOpts);
detector .process(image)
.addOnSuccessListener(new OnSuccessListener<List<Face>>() {
@Override
public void onSuccess(List<Face> faces) {
graphicOverlay.setFaceMeshes(faces);
imageProxy.close();
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
imageProxy.close();
}
});
} else {
imageProxy.close();
}
}
}
The above code is working fine but the points which are displaying are not on the correct position and also when i turn my head towards right th points move left and same in right direction too but not in up or down movement
Well i tried scalling the points but i did not get the result i was expecting , it worsten the result. My device screen width is 2441×1080 and the image going for processing is of 640×480.
Can someone plz tell me whats wrong and help me by updating plz.
P.S- I’m a novice in android development