Android-人臉Camera2人臉識別

package com.;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.Face;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;

import com.iflytek.yl.R;
import com.iflytek.yl.common.base.BaseTitleActivity;
import com.iflytek.yl.common.util.YlLogger;
import com.iflytek.yl.common.volley.YLVolleyUtil;
import com.iflytek.yl.common.widget.BaseToast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.UUID;

public class DetectFaceActivity extends BaseTitleActivity implements View.OnClickListener {

    private CameraManager cManager;
    private static String TAG = "DetectFaceActivity";

    //爲了使照片豎直顯示
    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();

    static {
        ORIENTATIONS.append(Surface.ROTATION_0, 90);
        ORIENTATIONS.append(Surface.ROTATION_90, 0);
        ORIENTATIONS.append(Surface.ROTATION_180, 270);
        ORIENTATIONS.append(Surface.ROTATION_270, 180);
    }

    private TextureView cView;//用於相機預覽
    /**
     * 頭像框
     */
    private RelativeLayout capture_crop_layout;

    private Surface previewSurface;//預覽Surface
    private ImageReader cImageReader;
    private Surface captureSurface;//拍照Surface
    HandlerThread cHandlerThread;//相機處理線程
    Handler cHandler;//相機處理
    CameraDevice cDevice;
    CameraCaptureSession cSession;
    CameraDevice.StateCallback cDeviceOpenCallback = null;//相機開啓回調
    CaptureRequest.Builder previewRequestBuilder;//預覽請求構建
    CaptureRequest previewRequest;//預覽請求
    CameraCaptureSession.CaptureCallback previewCallback;//預覽回調
    CaptureRequest.Builder captureRequestBuilder;
    CaptureRequest captureRequest;
    CameraCaptureSession.CaptureCallback captureCallback;
    int[] faceDetectModes;
    // Rect rRect;//相機成像矩形
    Size cPixelSize;//相機成像尺寸
    int cOrientation;
    Size captureSize;
    boolean isFront;
    private ImageView scan;
    private YLVolleyUtil volleyUtil;
    private Handler mHandler;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_faceverify);
        initVIew();
    }

    /**
     * 初始化界面
     */
    private void initVIew() {
        mHandler = new InnerHandler(this);
//        volleyUtil = new YLVolleyUtil(this, mHandler);

        cView = (TextureView) findViewById(R.id.sfv_preview);
        scan = (ImageView) findViewById(R.id.capture_scan_line);
        capture_crop_layout = (RelativeLayout) findViewById(R.id.capture_crop_layout);
        findViewById(R.id.face_photo).setOnClickListener(this);

        ViewGroup.LayoutParams params = capture_crop_layout.getLayoutParams();
        params.width = getResources().getDisplayMetrics().widthPixels / 4 * 3;
        params.height = getResources().getDisplayMetrics().widthPixels / 4 * 3;
        capture_crop_layout.setLayoutParams(params);
    }

    private void startCamera() {
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                openCamera(true);
            }
        }, 100);
    }

    @SuppressLint("NewApi")
    private void openCamera(boolean isFront) {
        this.isFront = isFront;
        //前置攝像頭
        String cId = "";
        if (isFront) {
            cId = CameraCharacteristics.LENS_FACING_BACK + "";
        } else {
            cId = CameraCharacteristics.LENS_FACING_FRONT + "";
        }
        cManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(this, "請授予攝像頭權限", Toast.LENGTH_LONG).show();
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 0);
        } else {
            //根據攝像頭ID,開啓攝像頭
            try {
                //獲取開啓相機的相關參數
                CameraCharacteristics characteristics = cManager.getCameraCharacteristics(cId);
                StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                Size[] previewSizes = map.getOutputSizes(SurfaceTexture.class);//獲取預覽尺寸
                Size[] captureSizes = map.getOutputSizes(ImageFormat.JPEG);//獲取拍照尺寸
                cOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);//獲取相機角度
                Rect cRect = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);//獲取成像區域
                cPixelSize = characteristics.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE);//獲取成像尺寸,同上

                YlLogger.i(TAG, "獲取相機角度 : " + cOrientation);

                //可用於判斷是否支持人臉檢測,以及支持到哪一種程度
                faceDetectModes = characteristics.get(CameraCharacteristics
                        .STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES);//支持的人臉檢測模式
                int maxFaceCount = characteristics.get(CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT);
                //支持的最大檢測人臉數量

                //此處寫死640*480,實際從預覽尺寸列表選擇
                //previewSizes[2];
                Size sSize = new Size(640, 480);
                //設置預覽尺寸(避免控件尺寸與預覽畫面尺寸不一致時畫面變形)
                cView.getSurfaceTexture().setDefaultBufferSize(sSize.getWidth(), sSize.getHeight());

                cManager.openCamera(cId, getCDeviceOpenCallback(), getCHandler());

                TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0,
                        Animation.RELATIVE_TO_SELF, 0
                        , Animation.RELATIVE_TO_SELF, -1, Animation.RELATIVE_TO_SELF, 0);
                translateAnimation.setDuration(1300);
                translateAnimation.setRepeatCount(-1);
                translateAnimation.setRepeatMode(Animation.RESTART);
                scan.startAnimation(translateAnimation);
            } catch (CameraAccessException e) {
                YlLogger.i(TAG, Log.getStackTraceString(e));
            }
        }
    }


    /**
     * 初始化並獲取相機開啓回調對象。當準備就緒後,發起預覽請求
     */
    @SuppressLint("NewApi")
    private CameraDevice.StateCallback getCDeviceOpenCallback() {
        if (cDeviceOpenCallback == null) {
            cDeviceOpenCallback = new CameraDevice.StateCallback() {
                @Override
                public void onOpened(@NonNull CameraDevice camera) {
                    cDevice = camera;
                    try {
                        //建立Session,需先完成畫面呈現目標(此處爲預覽和拍照Surface)的初始化
                        camera.createCaptureSession(Arrays.asList(getPreviewSurface(), getCaptureSurface()), new
                                CameraCaptureSession.StateCallback() {
                                    @Override
                                    public void onConfigured(@NonNull CameraCaptureSession session) {
                                        cSession = session;
                                        //構建預覽請求,併發起請求
                                        YlLogger.i(TAG, "[發出預覽請求]");
                                        try {
                                            session.setRepeatingRequest(getPreviewRequest(), getPreviewCallback(),
                                                    getCHandler());
                                        } catch (CameraAccessException e) {
                                            YlLogger.i(TAG, Log.getStackTraceString(e));
                                        }
                                    }

                                    @Override
                                    public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                                        session.close();
                                    }
                                }, getCHandler());
                    } catch (CameraAccessException e) {
                        YlLogger.i(TAG, Log.getStackTraceString(e));
                    }
                }

                @Override
                public void onDisconnected(@NonNull CameraDevice camera) {
                    camera.close();
                }

                @Override
                public void onError(@NonNull CameraDevice camera, int error) {
                    camera.close();
                }
            };
        }
        return cDeviceOpenCallback;
    }

    /**
     * 初始化並獲取相機線程處理
     *
     * @return
     */
    private Handler getCHandler() {
        if (cHandler == null) {
            //單獨開一個線程給相機使用
            cHandlerThread = new HandlerThread("cHandlerThread");
            cHandlerThread.start();
            cHandler = new Handler(cHandlerThread.getLooper());
        }
        return cHandler;
    }

    /**
     * 獲取支持的最高人臉檢測級別
     *
     * @return
     */
    private int getFaceDetectMode() {
        if (faceDetectModes == null) {
            return CaptureRequest.STATISTICS_FACE_DETECT_MODE_FULL;
        } else {
            return faceDetectModes[faceDetectModes.length - 1];
        }
    }

    /**
     * 初始化並獲取預覽回調對象
     *
     * @return
     */
    @SuppressLint("NewApi")
    private CameraCaptureSession.CaptureCallback getPreviewCallback() {
        if (previewCallback == null) {
            previewCallback = new CameraCaptureSession.CaptureCallback() {
                @Override
                public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest
                        request, @NonNull TotalCaptureResult result) {
//                    onCameraImagePreviewed(result);
                }
            };
        }
        return previewCallback;
    }

    /**
     * 生成並獲取預覽請求
     *
     * @return
     */
    @SuppressLint("NewApi")
    private CaptureRequest getPreviewRequest() {
        previewRequest = getPreviewRequestBuilder().build();
        return previewRequest;
    }

    /**
     * 初始化並獲取預覽請求構建對象,進行通用配置,並每次獲取時進行人臉檢測級別配置
     *
     * @return
     */
    @SuppressLint("NewApi")
    private CaptureRequest.Builder getPreviewRequestBuilder() {
        if (previewRequestBuilder == null) {
            try {
                previewRequestBuilder = cSession.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                previewRequestBuilder.addTarget(getPreviewSurface());
                previewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);//自動曝光、白平衡、對焦
            } catch (CameraAccessException e) {
                YlLogger.i(TAG, Log.getStackTraceString(e));
            }
        }
        previewRequestBuilder.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE, getFaceDetectMode());//設置人臉檢測級別
        previewRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, 0);
        return previewRequestBuilder;
    }

    /**
     * 獲取預覽Surface
     *
     * @return
     */
    private Surface getPreviewSurface() {
        if (previewSurface == null) {
            previewSurface = new Surface(cView.getSurfaceTexture());
        }
        return previewSurface;
    }

    /**
     * 處理相機畫面處理完成事件,獲取檢測到的人臉座標,換算並繪製方框
     *
     * @param result
     */
    @SuppressLint({"NewApi", "LocalSuppress"})
    private void onCameraImagePreviewed(CaptureResult result) {
        Face faces[] = result.get(CaptureResult.STATISTICS_FACES);
        YlLogger.i(TAG, "檢測到有人臉,進行拍照操做:faceLength=" + faces.length);
        if (faces.length > 0) {
            //檢測到有人臉,控制相機進行拍照操做
            executeCapture();
        }
    }

    /**
     * 初始化拍照相關
     */
    @SuppressLint("NewApi")
    private Surface getCaptureSurface() {
        if (cImageReader == null) {
            cImageReader = ImageReader.newInstance(getCaptureSize().getWidth(), getCaptureSize().getHeight(),
                    ImageFormat.JPEG, 2);
            cImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
                @Override
                public void onImageAvailable(ImageReader reader) {
                    //拍照最終回調
                    onCaptureFinished(reader);
                }
            }, getCHandler());
            captureSurface = cImageReader.getSurface();
        }
        return captureSurface;
    }

    /**
     * 獲取拍照尺寸
     *
     * @return
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private Size getCaptureSize() {
        if (captureSize != null) {
            return captureSize;
        } else {
            return new Size(cView.getWidth(), cView.getHeight());
        }
    }

    /**
     * 執行拍照
     */
    @SuppressLint("NewApi")
    private void executeCapture() {
        try {
            YlLogger.i(TAG, "發出請求");
            cSession.capture(getCaptureRequest(), getCaptureCallback(), getCHandler());
        } catch (CameraAccessException e) {
            YlLogger.i(TAG, Log.getStackTraceString(e));
        }
    }

    @SuppressLint("NewApi")
    private CaptureRequest getCaptureRequest() {
        captureRequest = getCaptureRequestBuilder().build();
        return captureRequest;
    }

    @SuppressLint("NewApi")
    private CaptureRequest.Builder getCaptureRequestBuilder() {
        if (captureRequestBuilder == null) {
            try {
                captureRequestBuilder = cSession.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
                captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
                //設置拍照回調接口
                captureRequestBuilder.addTarget(getCaptureSurface());
                //TODO 1 照片旋轉
                int rotation = getWindowManager().getDefaultDisplay().getRotation();
                int rotationTo = getOrientation(rotation);
                captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, rotationTo);
            } catch (CameraAccessException e) {
                YlLogger.i(TAG, Log.getStackTraceString(e));
            }
        }
        return captureRequestBuilder;
    }

    @SuppressLint("NewApi")
    private CameraCaptureSession.CaptureCallback getCaptureCallback() {
        if (captureCallback == null) {
            captureCallback = new CameraCaptureSession.CaptureCallback() {
                @Override
                public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest
                        request, @NonNull TotalCaptureResult result) {
                }
            };
        }
        return captureCallback;
    }

    /**
     * Retrieves the JPEG orientation from the specified screen rotation.
     *
     * @param rotation The screen rotation.
     * @return The JPEG orientation (one of 0, 90, 270, and 360)
     */
    private int getOrientation(int rotation) {
        return (ORIENTATIONS.get(rotation) + cOrientation + 270) % 360;
    }

    /**
     * 處理相機拍照完成的數據
     *
     * @param reader
     */
    @SuppressLint("NewApi")
    private void onCaptureFinished(ImageReader reader) {
        Image image = reader.acquireLatestImage();
        ByteBuffer buffer = image.getPlanes()[0].getBuffer();
        byte[] data = new byte[buffer.remaining()];
        buffer.get(data);
        image.close();
        buffer.clear();
        Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
        showImage(bitmap);
        Runtime.getRuntime().gc();
    }

    /**
     * 保存照片,調用人臉識別接口
     *
     * @param image
     */
    private void showImage(final Bitmap image) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                upload(image);
            }
        });
    }

    private void upload(Bitmap face) {
        if (face == null) {
            BaseToast.showToast(getApplicationContext(), "拍照出錯,請重試!");
            return;
        }
        try {
            final File file = File.createTempFile(UUID.randomUUID().toString() + "", ".jpg");
            int minWidth = Math.min(face.getWidth(), face.getHeight());
            int x = (face.getWidth() - minWidth) / 2;
            int y = (face.getHeight() - minWidth) / 2;
            Bitmap bitmap = Bitmap.createBitmap(face, x, y, minWidth, minWidth);
            resize(bitmap, file, 480, 480);

            Intent intent = new Intent();
            intent.putExtra("filePath", file.getAbsolutePath());
            setResult(RESULT_OK, intent);
            finish();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void deleteFace(File file) {
        if (file != null && file.exists()) {
            file.delete();
        }
    }

    @SuppressLint("NewApi")
    private void closeCamera() {
        if (cSession != null) {
            try {
                cSession.stopRepeating();
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
            cSession.close();
            cSession = null;
        }

        if (cDevice != null) {
            cDevice.close();
            cDevice = null;
        }
        if (cImageReader != null) {
            cImageReader.close();
            cImageReader = null;
            captureRequestBuilder = null;
        }
        if (cHandlerThread != null) {
            cHandlerThread.quitSafely();
            try {
                cHandlerThread.join();
                cHandlerThread = null;
                cHandler = null;
            } catch (InterruptedException e) {
                YlLogger.i(TAG, Log.getStackTraceString(e));
            }
        }

        if (captureRequestBuilder != null) {
            captureRequestBuilder.removeTarget(captureSurface);
            captureRequestBuilder = null;
        }
        if (captureSurface != null) {
            captureSurface.release();
            captureSurface = null;
        }
        if (previewRequestBuilder != null) {
            previewRequestBuilder.removeTarget(previewSurface);
            previewRequestBuilder = null;
        }
        if (previewSurface != null) {
            previewSurface.release();
            previewSurface = null;
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        startCamera();
    }

    @Override
    protected void onPause() {
        super.onPause();
        closeCamera();
    }

    private static class InnerHandler extends Handler {
        private WeakReference<DetectFaceActivity> mWeakReference;

        public InnerHandler(DetectFaceActivity activity) {
            super();
            this.mWeakReference = new WeakReference<DetectFaceActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            if (mWeakReference == null || mWeakReference.get() == null) {
                return;
            }
            DetectFaceActivity activity = mWeakReference.get();
            if (activity == null) {
                return;
            }
            if (msg == null) {
                return;
            }
            switch (msg.what) {
                default:
                    break;
            }
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.face_photo:
                executeCapture();
                break;
            default:
                break;
        }
    }

    private void resize(Bitmap bitmap, File outputFile, int maxWidth, int maxHeight) {
        try {
            int bitmapWidth = bitmap.getWidth();
            int bitmapHeight = bitmap.getHeight();
            // 圖片大於最大高寬,按大的值縮放
            if (bitmapWidth > maxHeight || bitmapHeight > maxWidth) {
                float widthScale = maxWidth * 1.0f / bitmapWidth;
                float heightScale = maxHeight * 1.0f / bitmapHeight;

                float scale = Math.min(widthScale, heightScale);
                Matrix matrix = new Matrix();
                matrix.postScale(scale, scale);
                bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight, matrix, false);
            }
            FileOutputStream out = new FileOutputStream(outputFile);
            try {
                bitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    out.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
複製代碼
相關文章
相關標籤/搜索