4

Face Tracker app based on Google Vision Face Tracker. By default, Face Tracker use rear/back camera, but I want to detect faces with front camera.

This is the code for CameraSourcePreview that google vision provide:

package com.google.android.gms.samples.vision.face.facetracker.ui.camera;

import android.content.Context;
import android.content.res.Configuration;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;

import com.google.android.gms.common.images.Size;
import com.google.android.gms.vision.CameraSource;

import java.io.IOException;

public class CameraSourcePreview extends ViewGroup {
    private static final String TAG = "CameraSourcePreview";

    private Context mContext;
    private SurfaceView mSurfaceView;
    private boolean mStartRequested;
    private boolean mSurfaceAvailable;
    private CameraSource mCameraSource;

    private GraphicOverlay mOverlay;

    public CameraSourcePreview(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        mStartRequested = false;
        mSurfaceAvailable = false;

        mSurfaceView = new SurfaceView(context);
        mSurfaceView.getHolder().addCallback(new SurfaceCallback());
        addView(mSurfaceView);
    }

    public void start(CameraSource cameraSource) throws IOException {
        if (cameraSource == null) {
            stop();
        }

        mCameraSource = cameraSource;

        if (mCameraSource != null) {
            mStartRequested = true;
            startIfReady();
        }
    }

    public void start(CameraSource cameraSource, GraphicOverlay overlay) throws IOException {
        mOverlay = overlay;
        start(cameraSource);
    }

    public void stop() {
        if (mCameraSource != null) {
            mCameraSource.stop();
        }
    }

    public void release() {
        if (mCameraSource != null) {
            mCameraSource.release();
            mCameraSource = null;
        }
    }

    private void startIfReady() throws IOException {
        if (mStartRequested && mSurfaceAvailable) {
            mCameraSource.start(mSurfaceView.getHolder());
            if (mOverlay != null) {
                Size size = mCameraSource.getPreviewSize();
                int min = Math.min(size.getWidth(), size.getHeight());
                int max = Math.max(size.getWidth(), size.getHeight());
                if (isPortraitMode()) {
                    // Swap width and height sizes when in portrait, since it will be rotated by
                    // 90 degrees
                    mOverlay.setCameraInfo(min, max, mCameraSource.getCameraFacing());
                } else {
                    mOverlay.setCameraInfo(max, min, mCameraSource.getCameraFacing());
                }
                mOverlay.clear();
            }
            mStartRequested = false;
        }
    }

    private class SurfaceCallback implements SurfaceHolder.Callback {
        @Override
        public void surfaceCreated(SurfaceHolder surface) {
            mSurfaceAvailable = true;
            try {
                startIfReady();
            } catch (IOException e) {
                Log.e(TAG, "Could not start camera source.", e);
            }
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder surface) {
            mSurfaceAvailable = false;
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        int width = 640;
        int height = 480;
        if (mCameraSource != null) {
            Size size = mCameraSource.getPreviewSize();
            if (size != null) {
                width = size.getWidth();
                height = size.getHeight();
            }
        }

        // Swap width and height sizes when in portrait, since it will be rotated 90 degrees
        if (isPortraitMode()) {
            int tmp = width;
            width = height;
            height = tmp;
        }

        final int layoutWidth = right - left;
        final int layoutHeight = bottom - top;

        // Computes height and width for potentially doing fit width.
        int childWidth = layoutWidth;
        int childHeight = (int)(((float) layoutWidth / (float) width) * height);

        // If height is too tall using fit width, does fit height instead.
        if (childHeight > layoutHeight) {
            childHeight = layoutHeight;
            childWidth = (int)(((float) layoutHeight / (float) height) * width);
        }

        for (int i = 0; i < getChildCount(); ++i) {
            getChildAt(i).layout(0, 0, childWidth, childHeight);
        }

        try {
            startIfReady();
        } catch (IOException e) {
            Log.e(TAG, "Could not start camera source.", e);
        }
    }

    private boolean isPortraitMode() {
        int orientation = mContext.getResources().getConfiguration().orientation;
        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
            return false;
        }
        if (orientation == Configuration.ORIENTATION_PORTRAIT) {
            return true;
        }

        Log.d(TAG, "isPortraitMode returning false by default");
        return false;
    }
}

I call camera source with this method:

private void startCameraSource() {

        // check that the device has play services available.
        int code = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(
                getApplicationContext());
        if (code != ConnectionResult.SUCCESS) {
            Dialog dlg =
                    GoogleApiAvailability.getInstance().getErrorDialog(this, code, RC_HANDLE_GMS);
            dlg.show();
        }

        if (mCameraSource != null) {
            try {
                mPreview.start(mCameraSource, mGraphicOverlay);
            } catch (IOException e) {
                Log.e(TAG, "Unable to start camera source.", e);
                mCameraSource.release();
                mCameraSource = null;
            }
        }
    }

Face Tracker front camera still too dark compare with default phone camera app.

How to brighten front camera in face tracker google vision? Is it related with surface view?

<com.google.android.gms.samples.vision.face.facetracker.ui.camera.CameraSourcePreview
    android:id="@+id/preview"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1.00"
    android:weightSum="1">

<com.google.android.gms.samples.vision.face.facetracker.ui.camera.GraphicOverlay
    android:id="@+id/faceOverlay"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="0.79" />

</com.google.android.gms.samples.vision.face.facetracker.ui.camera.CameraSourcePreview>
Elra Ghifary
  • 113
  • 1
  • 14

1 Answers1

1

It is not related with the SurfaceView at all. It is a Camera API misconfiguration. You will have to make some additional changes inside your CameraSource.java file. You can find it on this GitHub repository

First, you need to know that it is an Exposure Problem. It refers to the light the camera allows to receive on the lens. You need to know if your Camera supports Exposure Compensation. You will have to query getMinExposureCompensation() and getMaxExposureCompensation() from your Camera.Parameters instance. As the documentation explains, if both methods return 0, exposure compensation is not supported and there's nothing you can do.

Luckily most of the time this characteristic is supported by all phones. Now you can check the current camera exposure by calling getExposureCompensation() which will return the default value (usually 0, which means exposure is not adjusted). Now to prevent dark images, you only have to set your new exposure between the min and max values using setExposureCompensation() and apply the Camera.Parameters to your camera.

Finally, you can Lock the Exposure to avoid losing the configuration using setAutoExposureLock(), getAutoExposureLock() and most important: before setting the Exposure Lock you must be sure that isAutoExposureLockSupported() returned true.

Good Luck!

Ezequiel Adrian
  • 726
  • 1
  • 11
  • 29