Android camera實時預覽 實時處理,面部認證。

MaxCentaur發表於2017-01-21

Android camera實時預覽 實時處理,面部認證。

說的不清晰 程式碼在下面 是用android studio寫的。
程式碼地址(地址有問題 下午更新)
不好意思因為沒有事先說明 程式碼是再專案裡面的facelock那個module裡面。
https://share.weiyun.com/2e3f8b18e390e12b1836d6625e541172(這是微雲下載連線)
http://download.csdn.net/detail/u012222078/9749716


程式功能:預覽camera,並自動收集幾個資料幀儲存為bitmap陣列方便做面部識別的處理


預覽操作是網友共享的程式碼,我在繼承SurfaceView 的CameraSurfaceView 中加入了幀監聽事件,每次預覽監聽前五個資料幀,在處理做一個面部識別。需要程式碼的直接下載或者在評論區留下郵箱

先看目錄關係
這裡寫圖片描述

  • 自定義控制元件CameraSurfaceView.java
  • 自定義介面方法CameraInterface.java
  • CameraActivity預覽介面。

CameraSurfaceView.java

package com.centaur.camera.preview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.centaur.camera.camera.CameraInterface;

import java.io.ByteArrayOutputStream;

/**
 * Created by Tianchaoxiong on 2017/1/16.
 */

public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback{


    private static final int FACENUM = 5;

    private static final String TAG = "yanzi";
    CameraInterface mCameraInterface;
    Context mContext;
    SurfaceHolder mSurfaceHolder;

    private boolean isFinish;
    //傳輸五個bitmap陣列
    Bitmap [] bitmaps = new Bitmap[5];

    int number = 0;//作為計數器用

    OnFaceCollectListener onFaceCollectListener = null;

    public CameraSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        mSurfaceHolder = getHolder();
        mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);//translucent半透明 transparent透明
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        mSurfaceHolder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        Log.i(TAG, "surfaceCreated...");
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        Log.i(TAG, "surfaceChanged...");
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        Log.i(TAG, "surfaceDestroyed...");
        CameraInterface.getInstance().doStopCamera();
    }
    public SurfaceHolder getSurfaceHolder(){
        return mSurfaceHolder;
    }

    /**
     * 收集五張圖片 監聽器
     */
    public static interface OnFaceCollectListener {

        /**
         * 收集五張face
         * @param bitmaps 返回的五張臉的陣列
         */
        void OnFaceCollected(Bitmap[] bitmaps);

        /**
         * face重新繪製
         * @param isStart 是否重新收集
         */
        void OnFaceCollectStart(boolean isStart);
    }
    /**
     * 設定面部的監聽器
     * @param onFaceCollectListener
     */
    public void setOnFaceCollectListener(OnFaceCollectListener onFaceCollectListener){

        if(onFaceCollectListener!=null){
            this.onFaceCollectListener = onFaceCollectListener;
        }
    }

    /***
     * 想在這裡做一個監聽處理 收五偵 傳輸出去
     * @param bytes
     * @param camera
     */
    @Override
    public void onPreviewFrame(byte[] bytes, Camera camera) {
        if(number<FACENUM){
            //收集
            //判斷監聽器 開始
            if(onFaceCollectListener!=null){
                onFaceCollectListener.OnFaceCollectStart(true);
                //有byte陣列轉為bitmap
                bitmaps[number] = byte2bitmap(bytes,camera);
                Log.d("ceshiTian","********收集了"+number+"個************");
                number = number+1;
                if(number==5){
                    Log.d("ceshiTian","********收集夠5個************");
                    //提交
                    onFaceCollectListener.OnFaceCollected(bitmaps);
                }
            }
        }else {
            //不做操作
            onFaceCollectListener.OnFaceCollectStart(false);
            onFaceCollectListener.OnFaceCollected(null);
        }
    }

    private Bitmap byte2bitmap(byte[] bytes, Camera camera) {
        Bitmap bitmap = null;

        Camera.Size size = camera.getParameters().getPreviewSize(); // 獲取預覽大小
        final int w = size.width; // 寬度
        final int h = size.height;
        final YuvImage image = new YuvImage(bytes, ImageFormat.NV21, w, h,
                null);
        ByteArrayOutputStream os = new ByteArrayOutputStream(bytes.length);
        if (!image.compressToJpeg(new Rect(0, 0, w, h), 100, os)) {
            return null;
        }
        byte[] tmp = os.toByteArray();
        bitmap = BitmapFactory.decodeByteArray(tmp, 0, tmp.length);

        Matrix matrix = new Matrix();
        matrix.setRotate(-90);
        bitmap = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);

        return bitmap;
    }
}

CameraInterface.java

package com.centaur.camera.camera;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;

import com.centaur.camera.util.CamParaUtil;
import com.centaur.camera.util.ImageUtil;
import com.centaur.util.FileUtils;

import java.io.IOException;
import java.util.List;

/**
 * Created by Tianchaoxiong on 2017/1/16.
 */

public class CameraInterface {
    private static final String TAG = "Tianchaoxiong";
    private Camera mCamera;
    private Camera.Parameters mParams;
    private boolean isPreviewing = false;
    private float mPreviwRate = -1f;
    private static CameraInterface mCameraInterface;

    public interface CamOpenOverCallback {
        public void cameraHasOpened();
    }

    private CameraInterface() {

    }

    public static synchronized CameraInterface getInstance() {
        if (mCameraInterface == null) {
            mCameraInterface = new CameraInterface();
        }
        return mCameraInterface;
    }

    /**
     * 開啟Camera
     *
     * @param callback
     */
    public void doOpenCamera(CamOpenOverCallback callback) {
        Log.i(TAG, "Camera open....");
        mCamera = Camera.open(1);
        Log.i(TAG, "Camera open over....");
        callback.cameraHasOpened();
    }

    /**
     * 開啟預覽
     *
     * @param holder
     * @param previewRate
     */
    public void doStartPreview(SurfaceHolder holder, float previewRate, Camera.PreviewCallback previewCallback) {
        Log.i(TAG, "doStartPreview...");
        if (isPreviewing) {
            mCamera.stopPreview();
            return;
        }
        if (mCamera != null) {

            mParams = mCamera.getParameters();
            mParams.setPictureFormat(PixelFormat.JPEG);//設定拍照後儲存的圖片格式

            //對支援的圖片的大小的一個收集
            CamParaUtil.getInstance().printSupportPictureSize(mParams);
            CamParaUtil.getInstance().printSupportPreviewSize(mParams);
            //設定PreviewSize和PictureSize
            Camera.Size pictureSize = CamParaUtil.getInstance().getPropPictureSize(
                    mParams.getSupportedPictureSizes(), previewRate, 800);
            mParams.setPictureSize(pictureSize.width, pictureSize.height);
            Camera.Size previewSize = CamParaUtil.getInstance().getPropPreviewSize(
                    mParams.getSupportedPreviewSizes(), previewRate, 800);
            mParams.setPreviewSize(previewSize.width, previewSize.height);

            mCamera.setDisplayOrientation(90);

            CamParaUtil.getInstance().printSupportFocusMode(mParams);
            List<String> focusModes = mParams.getSupportedFocusModes();
            if (focusModes.contains("continuous-video")) {
                mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
            }
            mCamera.setParameters(mParams);    //引數設定完畢

            try {
                mCamera.setPreviewDisplay(holder);
                mCamera.setPreviewCallback(previewCallback);
                mCamera.startPreview();//開啟預覽
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            isPreviewing = true;
            mPreviwRate = previewRate;

            mParams = mCamera.getParameters(); //重新get一次
            Log.i(TAG, "最終設定:PreviewSize--With = " + mParams.getPreviewSize().width
                    + "Height = " + mParams.getPreviewSize().height);
            Log.i(TAG, "最終設定:PictureSize--With = " + mParams.getPictureSize().width
                    + "Height = " + mParams.getPictureSize().height);
        }
    }

    /**
     * 停止預覽,釋放Camera
     */
    public void doStopCamera() {
        if (null != mCamera) {
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            isPreviewing = false;
            mPreviwRate = -1f;
            mCamera.release();
            mCamera = null;
        }
    }

    /**
     * 拍照
     */
    public void doTakePicture() {
        if (isPreviewing && (mCamera != null)) {
            Log.d("FileUtils", "程式執行到這裡了111");
            mCamera.takePicture(mShutterCallback, null, mJpegPictureCallback);
        }
    }

    /*為了實現拍照的快門聲音及拍照儲存照片需要下面三個回撥變數*/
    Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback()
            //快門按下的回撥,在這裡我們可以設定類似播放“咔嚓”聲之類的操作。預設的就是咔嚓。
    {
        public void onShutter() {
            // TODO Auto-generated method stub
            Log.i(TAG, "myShutterCallback:onShutter...");
        }
    };
    /*    Camera.PictureCallback mRawCallback = new Camera.PictureCallback()
                // 拍攝的未壓縮原資料的回撥,可以為null
        {

            public void onPictureTaken(byte[] data, Camera camera) {
                // TODO Auto-generated method stub
                Log.i(TAG, "myRawCallback:onPictureTaken...");

            }
        };*/
    Camera.PictureCallback mJpegPictureCallback = new Camera.PictureCallback()
            //對jpeg影象資料的回撥,最重要的一個回撥
    {
        public void onPictureTaken(byte[] data, Camera camera) {
            Log.d("FileUtils", "程式執行到這裡了222");
            // TODO Auto-generated method stub
            Log.i(TAG, "myJpegCallback:onPictureTaken...");
            Bitmap b = null;
            if (null != data) {
                b = BitmapFactory.decodeByteArray(data, 0, data.length);//data是位元組資料,將其解析成點陣圖
                mCamera.stopPreview();
                isPreviewing = false;
                Log.d("FileUtils", "程式執行到這裡了333");
            }
            //儲存圖片到sdcard
            if (null != b) {
                Log.d("FileUtils", "程式執行到這裡了444");
                //設定FOCUS_MODE_CONTINUOUS_VIDEO)之後,myParam.set("rotation", 90)失效。
                //圖片竟然不能旋轉了,故這裡要旋轉下
                Log.d("FileUtils", "程式執行到這裡了");
                Bitmap rotaBitmap = ImageUtil.getRotateBitmap(b, -90.0f);
                FileUtils.savePaiZhaoBitmap(rotaBitmap);
            }
        }
    };

}

CameraActivity

package com.centaur.camera.Activity;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;

import com.centaur.camera.camera.CameraInterface;
import com.centaur.camera.preview.CameraSurfaceView;
import com.centaur.camera.util.DisplayUtil;
import com.centaur.testutil.R;
import com.centaur.testutil.ShowPic;
import com.centaur.util.DetecteSDK;
import com.centaur.util.DetecteSeeta;



public class CameraActivity extends AppCompatActivity implements CameraSurfaceView.OnFaceCollectListener, CameraInterface.CamOpenOverCallback{
    private static final String TAG = "CameraActivity";

    private float recLen = 0;
    long te;
    float previewRate = -1f;
    DetecteSDK detecteSDK;
    DetecteSeeta detecteSeeta;

    Bitmap bmp;
    Bitmap bitmapfianl;

    private ImageButton shutterBtn;
    private TextView textView;
    private CameraSurfaceView surfaceView = null;


    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        Thread openThread = new Thread(){
            @Override
            public void run() {
                CameraInterface.getInstance().doOpenCamera(CameraActivity.this);
            }
        };
        openThread.start();
        te = System.currentTimeMillis();
        setContentView(R.layout.activity_camera);
        initView();
        initViewParams();
        surfaceView.setOnFaceCollectListener(this);

        shutterBtn.setOnClickListener(new BtnListeners());
        TimeHandler.postDelayed(TimeRunnable, 500);
    }
    /**
     * 回撥方法
     * activity中的檢視和 interface中的程式碼實現繫結
     */
    @Override
    public void cameraHasOpened() {
        SurfaceHolder holder = surfaceView.getSurfaceHolder();
        CameraInterface.getInstance().doStartPreview(holder, previewRate,surfaceView );
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        CameraInterface.getInstance().doStopCamera();
        Log.d("RunTime", "onDestroy:time:"+te);
        TimeHandler.removeCallbacks(TimeRunnable);
    }
    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        CameraInterface.getInstance().doStopCamera();
        te = System.currentTimeMillis()-te;
        Log.d("RunTime", "onPause:time:"+te);
        TimeHandler.removeCallbacks(TimeRunnable);
    }

    Handler TimeHandler = new Handler();
    Runnable TimeRunnable = new Runnable() {
        @Override
        public void run() {
            recLen+=500;
            textView.setText("檢測時間:" + recLen/1000+"秒");
            TimeHandler.postDelayed(this, 500);
        }
    };


    private void initView(){
        surfaceView = (CameraSurfaceView)findViewById(R.id.camera_surfaceview);
        shutterBtn = (ImageButton)findViewById(R.id.btn_shutter);
        textView = (TextView) findViewById(R.id.time);
    }
    private void initViewParams(){
        ViewGroup.LayoutParams params = surfaceView.getLayoutParams();
        Point p = DisplayUtil.getScreenMetrics(this);
        params.width = p.x;
        params.height = p.y;
        previewRate = DisplayUtil.getScreenRate(this); //預設全屏的比例預覽
        surfaceView.setLayoutParams(params);
        //手動設定拍照ImageButton的大小為120dip×120dip,原圖片大小是64×64
        ViewGroup.LayoutParams p2 = shutterBtn.getLayoutParams();
        p2.width = DisplayUtil.dip2px(this, 80);
        p2.height = DisplayUtil.dip2px(this, 80);
        shutterBtn.setLayoutParams(p2);

    }




    /**
     * 自建
     * @param bitmaps 返回的五張臉的陣列
     */
    @Override
    public void OnFaceCollected(Bitmap[] bitmaps) {

    }

    /**
     * 自建
     * @param isStart 是否重新收集
     */
    @Override
    public void OnFaceCollectStart(boolean isStart) {
        if(isStart){
            Log.d("CameraActivity","開始收集");
        }

    }

    private class BtnListeners implements View.OnClickListener {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            switch(v.getId()){
                case R.id.btn_shutter:
                    CameraInterface.getInstance().doTakePicture();
                    Intent intent =new Intent(CameraActivity.this, ShowPic.class);
                    // 預設一個暫存的路徑 /FaceDetection/useso/Pictures/Tmp/tmp.png
                    String FolderPath = "/FaceDetection/useso/Pictures/Tmp/tmp.png";
                    String path = Environment.getExternalStorageDirectory()+FolderPath;
                    intent.putExtra("picpath",path);
                    startActivity(intent);
                    finish();
                    break;
                default:break;
            }
        }

    }
}

相關文章