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?

+3


source to share


1 answer


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.

+2


source







All Articles