时间:2020-12-08 23:13:31 | 栏目:Android代码 | 点击:次
Android camera实时预览 实时处理,面部认证。
预览操作是网友共享的代码,我在继承SurfaceView 的CameraSurfaceView 中加入了帧监听事件,每次预览监听前五个数据帧,在处理做一个面部识别。
先看目录关系
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; } } } }