Android camera2.params.face canvas placement rectangle
I am trying to implement face detection in a camera preview. I have followed android link pages to implement a custom camera preview in TextureView
, placed in FrameLayout
. Also this one FrameLayout
has SurfaceView
a clear background (overlapping camera preview). My app draws Rect
which is recognized by the first CaptureResult.STATISTICS_FACES
bounding constraint dynamically to the canvas SurfaceView
, every time the camera preview is refreshed (once per frame). My application assumes that there is only one face to be recognized.
My problem occurs when I draw a rectangle. I get the rectangle in the right place if I keep my face in the center of the camera's view, but when I move my head up, the rectangle moves to the right, and when I move my head to the right, the rectangle moves down. It's like the canvas needs to be rotated by -90, but that doesn't work for me (explained below code).
in my activity onCreate()
:
//face recognition
rectangleView = (SurfaceView) findViewById(R.id.rectangleView);
rectangleView.setZOrderOnTop(true);
rectangleView.getHolder().setFormat(
PixelFormat.TRANSPARENT); //remove black background from view
purplePaint = new Paint();
purplePaint.setColor(Color.rgb(175,0,255));
purplePaint.setStyle(Paint.Style.STROKE);
in TextureView.SurfaceTextureListener.onSurfaceTextureAvailable()
(in a block try{}
that encapsulates camera.open()
:
Rect cameraBounds = cameraCharacteristics.get( CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); cameraWidth = cameraBounds.right; cameraHeight = cameraBounds.bottom;
in the same listener within onSurfaceTextureUpdated()
:
if (detectedFace != null && rectangleFace.height() > 0) {
Canvas currentCanvas = rectangleView.getHolder().lockCanvas();
if (currentCanvas != null) {
currentCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
int canvasWidth = currentCanvas.getWidth();
int canvasHeight = currentCanvas.getHeight();
int l = rectangleFace.right;
int t = rectangleFace.bottom;
int r = rectangleFace.left;
int b = rectangleFace.top;
int left = (canvasWidth*l)/cameraWidth;
int top = (canvasHeight*t)/cameraHeight;
int right = (canvasWidth*r)/cameraWidth;
int bottom = (canvasHeight*b)/cameraHeight;
currentCanvas.drawRect(left, top, right, bottom, purplePaint);
}
rectangleView.getHolder().unlockCanvasAndPost(currentCanvas);
}
method onCaptureCompleted
in CameraCaptureSession.CameraCallback
called by CameraCaptureSession.setRepeatingRequest()
looper:
//May need better face recognition sdk or api
Face[] faces = result.get(CaptureResult.STATISTICS_FACES);
if (faces.length > 0)
{
detectedFace = faces[0];
rectangleFace = detectedFace.getBounds();
}
All variables are created outside of functions.
If you cannot understand my question or need more information, a similar question will be posted here:
How can I handle rotation problem with Preview and FaceDetection
However, unlike the poster above, I couldn't even get my canvas to show the rectangle after rotating my canvas, so this can't be a solution.
I tried to rotate my points by -90 degrees using x = -y, y = x (left = -top, top = left) and it doesn't do that either. I feel like some function should be applied to points, but I don't know how.
Any ideas on how to fix this?
source to share
For future reference, this is the solution I came across:
set Activity class / variable named orientation_offset
:
orientation_offset = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
This is the angle at which the camera sensor image (or rectangle for face detection) needs to be viewed for viewing.
Then I changed onSurfaceTextureUpdated()
:
Canvas currentCanvas = rectangleView.getHolder().lockCanvas();
if (currentCanvas != null) {
currentCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
if (detectedFace != null && rectangleFace.height() > 0) {
int canvasWidth = currentCanvas.getWidth();
int canvasHeight = currentCanvas.getHeight();
int faceWidthOffset = rectangleFace.width()/8;
int faceHeightOffset = rectangleFace.height()/8;
currentCanvas.save();
currentCanvas.rotate(360 - orientation_offset, canvasWidth / 2,
canvasHeight / 2);
int l = rectangleFace.right;
int t = rectangleFace.bottom;
int r = rectangleFace.left;
int b = rectangleFace.top;
int left = (canvasWidth - (canvasWidth*l)/cameraWidth)-(faceWidthOffset);
int top = (canvasHeight*t)/cameraHeight - (faceHeightOffset);
int right = (canvasWidth - (canvasWidth*r)/cameraWidth) + (faceWidthOffset);
int bottom = (canvasHeight*b)/cameraHeight + (faceHeightOffset);
currentCanvas.drawRect(left, top, right, bottom, purplePaint);
currentCanvas.restore();
}
}
rectangleView.getHolder().unlockCanvasAndPost(currentCanvas);
I'll leave the question open in case anyone else has a solution.
source to share