最近在做一款商户入网的应用,为防止不法商户对公司渠道的接入,公司加大了对商户的审核,人脸识别就是其中的一项。人脸识别的第一步是检测商户的张嘴动作,通过之后采集照片,上传到服务器。第二步是检测商户的摇头动作,通过之后采集照片,上传到服务器。至此完成人脸识别。下面我对主干代码进行分析:
首先导入jar包Msc(讯飞)。检测人脸关键部位的坐标
private void setFaceDetection() { mThread = new Thread(new Runnable() { @Override public void run() { List<Object> previewDate = CameraInterface.getInstance() .getPreviewDate(); buffer = (byte[]) previewDate.get(0); nv21 = (byte[]) previewDate.get(1); while (!mStopTrack) { if (null == nv21) { continue; } synchronized (nv21) { System.arraycopy(nv21, 0, buffer, 0, nv21.length); } // 获取手机朝向,返回值0,1,2,3分别表示0,90,180和270度 int direction = Accelerometer.getDirection(); boolean frontCamera = (Camera.CameraInfo.CAMERA_FACING_FRONT == mCameraId); // 前置摄像头预览显示的是镜像,需要将手机朝向换算成摄相头视角下的朝向。 // 转换公式:a' = (360 - a)%360,a为人眼视角下的朝向(单位:角度) if (frontCamera) { // SDK中使用0,1,2,3,4分别表示0,90,180,270和360度 direction = (4 - direction) % 4; } if (mFaceDetector == null) { /** * 离线视频流检测功能需要单独下载支持离线人脸的SDK 请开发者前往语音云官网下载对应SDK */ ShowToast.showToast(getActivity(), "本SDK不支持离线视频流检测"); break; } String result = mFaceDetector.trackNV21(buffer, PREVIEW_WIDTH, PREVIEW_HEIGHT, isAlign, direction); FaceRect[] faces = ParseResult.parseResult(result); drawRect(frontCamera, faces); } }
对人脸动作的检测
if (isFace) { // 进行活体检测 if (rectLength >= 160 && rectLength < 180) { // 判断张嘴后进行拍照 if (mouth_bt >= 40 && !isOpenMouth) { isOpenMouth = true; isShakeHead = true; mHandler.sendEmptyMessageDelayed( StaticArguments.FACE_OPEN_MOUTH, 1000); } // 进行摇头判断 if (eyebrow_mlr_y < 79 && eyebrow_mlr_y >= 0 && isShakeHead) { isOpenMouth = true; countHead++; if (countHead % 2 == 0) { mHandler.sendEmptyMessageDelayed( StaticArguments.FACE_SHAKE_HEAD, 3000); } } } else if (rectLength >= 180 && rectLength < 200) { // 判断张嘴后进行拍照 if (mouth_bt >= 45 && !isOpenMouth) { isShakeHead = true; isOpenMouth = true; mHandler.sendEmptyMessageDelayed( StaticArguments.FACE_OPEN_MOUTH, 1000); } // 进行摇头判断 if (eyebrow_mlr_y < 89 && eyebrow_mlr_y >= 0 && isShakeHead) { isOpenMouth = true; countHead++; if (countHead % 2 == 0) { mHandler.sendEmptyMessageDelayed( StaticArguments.FACE_SHAKE_HEAD, 1000); } } } else if (rectLength >= 200 && rectLength < 340) { // 判断张嘴后进行拍照 if (mouth_bt >= 50 && !isOpenMouth) { isShakeHead = true; isOpenMouth = true; mHandler.sendEmptyMessageDelayed( StaticArguments.FACE_OPEN_MOUTH, 500); } // 进行摇头判断 if (eyebrow_mlr_y < 95 && eyebrow_mlr_y >= 0 && isShakeHead) { isOpenMouth = true; countHead++; if (countHead % 2 == 0) { mHandler.sendEmptyMessageDelayed( StaticArguments.FACE_SHAKE_HEAD, 1000); } } } else if (rectLength < 160) {// 检测脸部离手机太远 mHandler.sendEmptyMessage(StaticArguments.FACE_LENGTH_LONG); } else if (rectLength >= 340 && rectLength >= 0) {// 检测脸部离手机太近 mHandler.sendEmptyMessage(StaticArguments.FACE_LENGTH_NEAR); } }
人脸张嘴或者摇头的动作后捕获视频的帧数据
public void doStartPreview(SurfaceHolder holder, float previewRate) { if (isPreview) { mCamera.stopPreview(); return; } if (mCamera != null) { mParams = mCamera.getParameters(); mParams.setPictureFormat(PixelFormat.JPEG);// 设置拍照后存储的图片格式 // 设置PreviewSize和PictureSize mParams.setPreviewFormat(ImageFormat.NV21); mParams.setPreviewSize(PREVIEW_WIDTH, PREVIEW_HEIGHT); mCamera.setParameters(mParams); mCamera.setDisplayOrientation(90); List<String> focusModes = mParams.getSupportedFocusModes(); if (focusModes.contains("continuous-video")) { mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); } mCamera.setPreviewCallback(new PreviewCallback() { @Override public void onPreviewFrame(byte[] data, Camera camera) { System.arraycopy(data, 0, nv21, 0, data.length); if (takePictureFlag == 1) { Bitmap mBitmap = null; Camera.Parameters parameters = camera.getParameters(); int format = parameters.getPreviewFormat(); if (format == PixelFormat.YCbCr_420_SP || format == PixelFormat.YCbCr_422_I) { int w = parameters.getPreviewSize().width; int h = parameters.getPreviewSize().height; int[] i = new int[data.length]; decodeYUV420SP(i, data, w, h); mBitmap = Bitmap.createBitmap(i, w, h, Bitmap.Config.RGB_565); } else if (format == PixelFormat.JPEG || format == PixelFormat.RGB_565) { mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length); } if (null != mBitmap) { if (takePictureFlag == 1) { takePictureFlag++; } else { return; } // 设置FOCUS_MODE_CONTINUOUS_VIDEO)之后,myParam.set("rotation", // 90)失效。 // 图片竟然不能旋转了,故这里要旋转下 Bitmap rotateImage = FaceUtil.rotateImage(270, mBitmap); if (mListener != null) { mListener.onTakePictuerResult(rotateImage); } } } } }); try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } isPreview = true; } }
源码下载地址:
https://github.com/reachchen/FaceRecognition