com.kevalpatel.userawarevieoview.FaceAnalyser.java Source code

Java tutorial

Introduction

Here is the source code for com.kevalpatel.userawarevieoview.FaceAnalyser.java

Source

/*
 * Copyright 2016 Keval Patel.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.kevalpatel.userawarevieoview;

import android.Manifest;
import android.app.Activity;
import android.app.Dialog;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.support.v4.app.ActivityCompat;
import android.util.Log;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.vision.CameraSource;
import com.google.android.gms.vision.MultiProcessor;
import com.google.android.gms.vision.Tracker;
import com.google.android.gms.vision.face.Face;
import com.google.android.gms.vision.face.FaceDetector;

import java.io.IOException;

/**
 * Created by Keval on 27-Oct-16.
 * This class is responsible for analysing and detecting the eyes and face from the frame of the
 * front camera using mobile vision library.
 *
 * @author {@link 'https://github.com/kevalpatel2106'}
 */

class FaceAnalyser {
    private static final int RC_HANDLE_GMS = 4525;

    private final UserAwareVideoView mUserAwareVideoView; //Instance of the video view
    private FaceDetector mDetector; //Face detector instance
    private CameraSource mCameraSource;
    private CameraSourcePreview mPreview;

    private boolean isTrackingRunning = false; //Bool to indicate is eye tracking is currently running or not?
    private Activity mActivity;

    /**
     * Public constructor.
     *
     * @param activity activity.
     */
    FaceAnalyser(Activity activity, UserAwareVideoView userAwareVideoView, CameraSourcePreview preview) {
        if (activity != null) {
            mActivity = activity;
            mUserAwareVideoView = userAwareVideoView;
        } else {
            throw new RuntimeException("Cannot start without callback listener.");
        }

        if (preview != null) {
            mPreview = preview;
        } else {
            throw new RuntimeException("Cannot start without camera source preview.");
        }
    }

    /**
     * Stop eye tracking.
     */
    void stopEyeTracker() {
        isTrackingRunning = false;

        if (mDetector != null)
            mDetector.release();
        if (mPreview != null)
            mPreview.release();
    }

    /**
     * Create face decoder and camera source.
     */
    private void creteCameraTracker() {
        mDetector = new FaceDetector.Builder(mActivity).setTrackingEnabled(false)
                .setClassificationType(FaceDetector.ALL_CLASSIFICATIONS).build();

        mDetector.setProcessor(new MultiProcessor.Builder<>(new GraphicFaceTrackerFactory()).build());

        if (!mDetector.isOperational()) {
            mUserAwareVideoView.onErrorOccurred();
            Log.e("Start Tracking", "Face tracker is not operational.");
        }

        mCameraSource = new CameraSource.Builder(mActivity, mDetector).setRequestedPreviewSize(640, 480)
                .setFacing(CameraSource.CAMERA_FACING_FRONT).setRequestedFps(30.0f).build();
    }

    /**
     * Start eye tracking.
     */
    void startFaceTracker() {
        //check if the device has front camera.
        if (!isFrontCameraAvailable()) {
            mUserAwareVideoView.onFrontCameraNotFound();
            Log.e("Start Tracking", "Front camera not found.");
            return;
        }

        //check for the camera permission
        if (ActivityCompat.checkSelfPermission(mActivity,
                Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            mUserAwareVideoView.onCameraPermissionNotAvailable();
            Log.e("Start Tracking", "Camera permission not found.");
            return;
        }

        // check that the device has play services available.
        int statusCode = GoogleApiAvailability.getInstance()
                .isGooglePlayServicesAvailable(mActivity.getApplicationContext());
        if (statusCode != ConnectionResult.SUCCESS) {
            Dialog dlg = GoogleApiAvailability.getInstance().getErrorDialog(mActivity, statusCode, RC_HANDLE_GMS);
            dlg.show();
            Log.e("Start Tracking", "Google Play Service not found.");

            mUserAwareVideoView.onErrorOccurred();
            return;
        }

        //create camera source
        creteCameraTracker();

        if (mCameraSource != null) {
            try {
                mPreview.start(mCameraSource);
            } catch (IOException e) {
                Log.d("startTracking", e.getMessage());
                mUserAwareVideoView.onErrorOccurred();
                mCameraSource.release();
                mCameraSource = null;

                mUserAwareVideoView.onErrorOccurred();
            }
        }

        isTrackingRunning = true;
    }

    /**
     * Boolean to indicate if the tracking is running or not?
     *
     * @return true if eye tracking is running.
     */
    boolean isTrackingRunning() {
        return isTrackingRunning;
    }

    /**
     * Factory for creating a face tracker to be associated with a new face.  The multiprocessor
     * uses this factory to create face trackers as needed -- one for each individual.
     */
    private class GraphicFaceTrackerFactory implements MultiProcessor.Factory<Face> {
        @Override
        public Tracker<Face> create(Face face) {
            return new GraphicFaceTracker();
        }
    }

    /**
     * Face tracker for each detected individual. This maintains a face graphic within the app's
     * associated face overlay.
     */
    private class GraphicFaceTracker extends Tracker<Face> {
        int isEyesClosedCount = 0;

        private GraphicFaceTracker() {
        }

        @Override
        public void onNewItem(int faceId, Face item) {
            Log.d("onNewItem", "" + faceId);
        }

        /**
         * When new frame analysed.
         */
        @Override
        public void onUpdate(FaceDetector.Detections<Face> detectionResults, Face face) {
            Log.d("FaceTracker", "onUpdate" + face.getIsLeftEyeOpenProbability());

            //if left and right eyes are open. (Probability more than 10%)
            if (face.getIsLeftEyeOpenProbability() > 0.10 && face.getIsRightEyeOpenProbability() > 0.10) {
                isEyesClosedCount = 0;
                mUserAwareVideoView.onUserAttentionAvailable();
            } else {
                isEyesClosedCount++;
                if (isEyesClosedCount > 2)
                    mUserAwareVideoView.onUserAttentionGone();
            }
        }

        /**
         * Hide the graphic when the corresponding face was not detected.  This can happen for
         * intermediate frames temporarily (e.g., if the face was momentarily blocked from
         * view).
         */
        @Override
        public void onMissing(FaceDetector.Detections<Face> detectionResults) {
            Log.d("onMissing", "");
        }

        /**
         * Called when the face is assumed to be gone for good. Remove the graphic annotation from
         * the overlay.
         */
        @Override
        public void onDone() {
            mUserAwareVideoView.onUserAttentionGone();
        }
    }

    /**
     * Check if the device has front camera or not?
     *
     * @return true if the device has front camera.
     */
    private boolean isFrontCameraAvailable() {
        int numCameras = Camera.getNumberOfCameras();
        return numCameras > 0
                && mActivity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
    }

}