Android camera实时预览 实时处理,面部认证。
预览操作是网友共享的代码,我在继承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);}@Overridepublic void surfaceCreated(SurfaceHolder surfaceHolder) {Log.i(TAG, "surfaceCreated...");}@Overridepublic void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {Log.i(TAG, "surfaceChanged...");}@Overridepublic 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 */@Overridepublic void onPreviewFrame(byte[] bytes, Camera camera) {if(number<FACENUM){//收集//判断监听器 开始if(onFaceCollectListener!=null){onFaceCollectListener.OnFaceCollectStart(true);//有byte数组转为bitmapbitmaps[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和PictureSizeCamera.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 blocke.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 stubLog.i(TAG, "myShutterCallback:onShutter...");}};/*Camera.PictureCallback mRawCallback = new Camera.PictureCallback()// 拍摄的未压缩原数据的回调,可以为null{public void onPictureTaken(byte[] data, Camera camera) {// TODO Auto-generated method stubLog.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 stubLog.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");}//保存图片到sdcardif (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;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);Thread openThread = new Thread(){@Overridepublic 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中的代码实现绑定 */@Overridepublic void cameraHasOpened() {SurfaceHolder holder = surfaceView.getSurfaceHolder();CameraInterface.getInstance().doStartPreview(holder, previewRate,surfaceView );}@Overrideprotected void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();CameraInterface.getInstance().doStopCamera();Log.d("RunTime", "onDestroy:time:"+te);TimeHandler.removeCallbacks(TimeRunnable);}@Overrideprotected void onPause() {// TODO Auto-generated method stubsuper.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() {@Overridepublic 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×64ViewGroup.LayoutParams p2 = shutterBtn.getLayoutParams();p2.width = DisplayUtil.dip2px(this, 80);p2.height = DisplayUtil.dip2px(this, 80);shutterBtn.setLayoutParams(p2);}/** * 自建 * @param bitmaps 返回的五张脸的数组 */@Overridepublic void OnFaceCollected(Bitmap[] bitmaps) {}/** * 自建 * @param isStart 是否重新收集 */@Overridepublic void OnFaceCollectStart(boolean isStart) {if(isStart){Log.d("CameraActivity","开始收集");}}private class BtnListeners implements View.OnClickListener {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubswitch(v.getId()){case R.id.btn_shutter:CameraInterface.getInstance().doTakePicture();Intent intent =new Intent(CameraActivity.this, ShowPic.class);// 默认一个暂存的路径 /FaceDetection/useso/Pictures/Tmp/tmp.pngString FolderPath = "/FaceDetection/useso/Pictures/Tmp/tmp.png";String path = Environment.getExternalStorageDirectory()+FolderPath;intent.putExtra("picpath",path);startActivity(intent);finish();break;default:break;}}}}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。