Fixes
diff --git a/app/src/main/java/com/libremobileos/facedetect/FaceBoundsOverlayView.java b/app/src/main/java/com/libremobileos/facedetect/FaceBoundsOverlayView.java
index 88ed9a9..7e3b786 100644
--- a/app/src/main/java/com/libremobileos/facedetect/FaceBoundsOverlayView.java
+++ b/app/src/main/java/com/libremobileos/facedetect/FaceBoundsOverlayView.java
@@ -1,6 +1,5 @@
package com.libremobileos.facedetect;
-import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -8,21 +7,18 @@
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
import com.libremobileos.yifan.face.shared.ImageUtils;
-import java.util.Arrays;
-
public class FaceBoundsOverlayView extends View {
private RectF[] bounds = null;
private Paint paint = null;
private Matrix transform = null;
- private int extra = 0;
+ private int extraw, extrah, viewraww, viewrawh, sensorWidth, sensorHeight;
public FaceBoundsOverlayView(Context context) {
this(context, null);
@@ -43,32 +39,59 @@
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
- if (bounds == null || transform == null) return;
- if (paint == null) {
- paint = new Paint();
- paint.setStyle(Paint.Style.STROKE);
- paint.setStrokeWidth(10f);
- paint.setColor(Color.RED);
- }
+ if (bounds == null || transform == null || paint == null)
+ return; // am I ready yet?
for (RectF bound : bounds) {
- @SuppressLint("DrawAllocation") RectF rect = new RectF(bound);
- transform.mapRect(rect);
- rect.offset(0, extra);
- canvas.drawRect(rect, paint);
+ canvas.drawRect(bound, paint);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
- int newh = (w / 3) * 4;
- extra = (h - newh) / 2;
- transform = ImageUtils.getTransformationMatrix(480, 640, w, newh, 0, false);
- transform.preScale(-1, 1, 480 / 2, 640 / 2); // swap x axis
+ viewraww = w;
+ viewrawh = h;
+ transform = null;
}
- public void updateBounds(RectF[] bounds) {
+ // please give me RectF's that wont be used otherwise as I modify them
+ public void updateBounds(RectF[] bounds, int sensorWidth, int sensorHeight) {
this.bounds = bounds;
+ // if we have no paint yet, make one
+ if (paint == null) {
+ paint = new Paint();
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeWidth(10f);
+ paint.setColor(Color.RED);
+ }
+ // if camera size or view size changed, recalculate it
+ if (this.sensorWidth != sensorWidth || this.sensorHeight != sensorHeight || (viewraww + viewrawh) > 0) {
+ this.sensorWidth = sensorWidth;
+ this.sensorHeight = sensorHeight;
+ int oldw = viewraww;
+ int oldh = viewrawh;
+ extraw = 0;
+ extrah = 0;
+ // calculate scaling keeping aspect ratio
+ int newh = (oldw / sensorWidth) * sensorHeight;
+ int neww = (oldh / sensorHeight) * sensorWidth;
+ // calculate out black bars
+ if (neww > oldw) {
+ extrah = (oldh - newh) / 2;
+ viewrawh = newh;
+ } else {
+ extraw = (oldw - neww) / 2;
+ viewraww = neww;
+ }
+ // scale from image size to view size
+ transform = ImageUtils.getTransformationMatrix(sensorWidth, sensorHeight, viewraww, viewrawh, 0, false);
+ viewraww = 0; viewrawh = 0;
+ }
+ // map bounds to view size
+ for (RectF bound : bounds) {
+ transform.mapRect(bound);
+ bound.offset(extraw, extrah);
+ }
invalidate();
}
}
diff --git a/app/src/main/java/com/libremobileos/facedetect/MainActivity.java b/app/src/main/java/com/libremobileos/facedetect/MainActivity.java
index 16b44da..f7189d5 100644
--- a/app/src/main/java/com/libremobileos/facedetect/MainActivity.java
+++ b/app/src/main/java/com/libremobileos/facedetect/MainActivity.java
@@ -1,5 +1,7 @@
package com.libremobileos.facedetect;
+import android.content.res.Configuration;
+import android.graphics.Matrix;
import android.graphics.RectF;
import android.os.Bundle;
import android.util.Log;
@@ -10,6 +12,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.OptIn;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ExperimentalGetImage;
import androidx.camera.core.ImageAnalysis;
@@ -33,6 +36,9 @@
private PreviewView previewView;
private FaceFinder faceFinder;
private FaceBoundsOverlayView overlayView;
+ private final Size desiredInputSize = new Size(640, 480);
+ private final int selectedCamera = CameraSelector.LENS_FACING_FRONT;
+ private int previewWidth, previewHeight;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -42,9 +48,16 @@
previewView.setScaleType(PreviewView.ScaleType.FIT_CENTER);
overlayView = findViewById(R.id.overlay);
- cameraProviderFuture = ProcessCameraProvider.getInstance(this);
- faceFinder = FaceFinder.create(this, 480, 640, 0);
+ /* cameras are landscape */
+ if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ previewWidth = desiredInputSize.getHeight();
+ previewHeight = desiredInputSize.getWidth();
+ } else {
+ previewWidth = desiredInputSize.getWidth();
+ previewHeight = desiredInputSize.getHeight();
+ }
+ cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
@@ -63,29 +76,44 @@
.build();
CameraSelector cameraSelector = new CameraSelector.Builder()
- .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
+ .requireLensFacing(selectedCamera)
.build();
preview.setSurfaceProvider(previewView.getSurfaceProvider());
ImageAnalysis imageAnalysis =
new ImageAnalysis.Builder()
- .setTargetResolution(new Size(480, 640))
+ .setTargetResolution(new Size(previewWidth, previewHeight))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build();
imageAnalysis.setAnalyzer(getMainExecutor(), imageProxy -> {
Pair<List<Pair<FaceDetector.Face, FaceScanner.Face>>, Long> data = faceFinder.process(BitmapUtils.getBitmap(imageProxy));
ArrayList<RectF> bounds = new ArrayList<>();
+ Log.i("cam", String.valueOf(imageProxy.getImageInfo().getRotationDegrees()));
for (Pair<FaceDetector.Face, FaceScanner.Face> faceFacePair : data.first) {
- Log.i("face", "found face id=" + faceFacePair.first.getId() + " conf=" + faceFacePair.first.getConfidence() + " loc=" + faceFacePair.first.getLocation());
- bounds.add(faceFacePair.first.getLocation());
+ RectF boundingBox = new RectF(faceFacePair.first.getLocation());
+ if (selectedCamera == CameraSelector.LENS_FACING_FRONT) {
+ // camera is frontal so the image is flipped horizontally
+ // flips horizontally
+ Matrix flip = new Matrix();
+ int sensorOrientation = imageProxy.getImageInfo().getRotationDegrees();
+ if (sensorOrientation == 0 || sensorOrientation == 180) {
+ flip.postScale(1, -1, previewWidth / 2.0f, previewHeight / 2.0f);
+ } else {
+ flip.postScale(-1, 1, previewWidth / 2.0f, previewHeight / 2.0f);
+ }
+ flip.mapRect(boundingBox);
+ }
+ bounds.add(boundingBox);
}
- overlayView.updateBounds(bounds.toArray(new RectF[0]));
+ overlayView.updateBounds(bounds.toArray(new RectF[0]), previewWidth, previewHeight);
imageProxy.close();
});
- cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, imageAnalysis, preview);
+ Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, imageAnalysis, preview);
+
+ faceFinder = FaceFinder.create(this, previewWidth, previewHeight, 0);
}
}