Android 原生的人脸识别Camera+FaceDetector示例
生活随笔
收集整理的這篇文章主要介紹了
Android 原生的人脸识别Camera+FaceDetector示例
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
人臉識別google有自帶api,Androoid 原生的人臉識別是利用相機的攝像功能和android.media.FaceDetector這個類來實現的
1、android.hardware.camera
1.1 簡介
Camera 類用于設置圖像捕獲設置、開始/停止預覽、抓拍圖片和檢索幀以進行視頻編碼
Camera的源碼
1.2 人臉識別步驟:
1. 初始化相機并設置相機參數; 2. 設置預覽監聽setPreviewDisplay(); 3. 開始預覽startPreview(); 4. 實現預覽的接口onPreviewFrame并處理每一幀的數據轉成Bitmap; 5. 通過 faceDetector.findFaces()發現人臉,注意:faceDetector只能識別Bitmap.Config.RGB_565的Bitmap1.3 示例類
工具類CameraUtils
package com.zw.camera2test.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.media.MediaRecorder; import android.os.SystemClock; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView;import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.List;public class CameraUtils implements Camera.PreviewCallback {private static final String TAG = "Camera2Utils";private SurfaceView mSurfaceView;private FaceRectView mFaceRectView;private static CameraUtils mCameraUtils;private SurfaceHolder mSurfaceViewHolder;private int cameraPosition = 1; //0 后置 1 前置private Camera mCamera;private int CAMERA_WIDHT = 640;private int CAMERA_HEIGHT = 480;// private int CAMERA_WIDHT = 320; // private int CAMERA_HEIGHT = 240;private boolean detectFace = false;private MediaRecorder mediaRecorder;/***錄制視頻的videoSize*/private int height = 480, width = 640;/***保存的photo的height ,width*/private int heightPhoto = 480, widthPhoto = 640;private CameraErrorCallback cameraErrorCallback;public static CameraUtils getInstance() {if (mCameraUtils == null) {synchronized (CameraUtils.class) {if (mCameraUtils == null) {mCameraUtils = new CameraUtils();}}}return mCameraUtils;}public void initCamera(SurfaceView surfaceView, FaceRectView faceRectView) {this.mSurfaceView = surfaceView;this.mFaceRectView = faceRectView;mSurfaceViewHolder = mSurfaceView.getHolder();mSurfaceViewHolder.setFormat(PixelFormat.OPAQUE);surfaceHolderCB = new SurfaceHolderCB();}SurfaceHolderCB surfaceHolderCB;public void startCamera() {if (mSurfaceViewHolder != null) {mSurfaceViewHolder.addCallback(surfaceHolderCB);}}public void stopCamera() {stopPreview();}//打開攝像頭失敗public static final int ERROR_CAMERA_OPEN = 100001;public void startPreview() {Log.i(TAG, "--11111---2-----" + mCamera);if (mCamera != null) {stopCamera();}if (mCamera == null) {Log.i(TAG, "startPreview: " + cameraPosition);try {mCamera = Camera.open(cameraPosition);Log.i(TAG, "startPreview:------ " + (Camera.getNumberOfCameras() - 1));} catch (RuntimeException e) {Log.i(TAG, "startPreview: 方法有問題");if (cameraErrorCallback != null) {cameraErrorCallback.onCameraError(ERROR_CAMERA_OPEN);}return;}Camera.Parameters parameters = setParameters(mCamera, cameraPosition);if (parameters.getMaxNumDetectedFaces() > 0) {Log.e("tag", "【FaceDetectorActivity】類的方法:【startFaceDetection】: " + parameters.getMaxNumDetectedFaces());} else {Log.e("tag", "【FaceDetectorActivity】類的方法:【startFaceDetection】: " + "不支持");}mCamera.setDisplayOrientation(0);mCamera.setErrorCallback(cameraErrorCallback);try {if (cameraPosition == 0) {parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); //后置必須聚焦設置}mCamera.setPreviewDisplay(mSurfaceViewHolder);mCamera.setParameters(parameters);if (mCamera != null) {mCamera.setPreviewCallback(this);}} catch (IOException e) {Log.i(TAG, "startPreview: " + e.getMessage());Camera.Parameters parameters1 = mCamera.getParameters();// 得到攝像頭的參數mCamera.setParameters(parameters1);}mCamera.startPreview();mCamera.cancelAutoFocus();//聚焦detectFace = true;}}/*** 臉部檢測接口*/private class FaceDetectorListener implements Camera.FaceDetectionListener {@Overridepublic void onFaceDetection(Camera.Face[] faces, Camera camera) {if (faces.length > 0) {int score = faces[0].score;Log.i(TAG, "onFaceDetection: score " + score);detectFace = true;mFaceRectView.drawFaceRects(faces, mSurfaceView, cameraPosition);} else {Log.i(TAG, "onFaceDetection: 沒有人臉 ");detectFace = false;mFaceRectView.clearRect();}}}public void setDetectFace(boolean detectFace) {this.detectFace = detectFace;}/*** 切換前后相機*/public void changeCamera(CurrentCameraPositionInterface cameraPositionInterface) {int numberOfCameras = Camera.getNumberOfCameras();Camera.CameraInfo cameraInfo = new Camera.CameraInfo();if (numberOfCameras >= 2) {if (cameraPosition == 0) { //現在為后置,變成為前置Camera.getCameraInfo(1, cameraInfo);if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { //CAMERA_FACING_FRONT 前置方位 CAMERA_FACING_BACK 后置方位if (mCamera != null) {stopPreview();}cameraPosition = 1;startPreview();}} else if (cameraPosition == 1) {//前置更改為后置相機Camera.getCameraInfo(0, cameraInfo);if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {if (mCamera != null) {stopPreview();}cameraPosition = 0;startPreview();}}}cameraPositionInterface.cameraPosition(cameraPosition);}private class SurfaceHolderCB implements SurfaceHolder.Callback {@Overridepublic void surfaceCreated(SurfaceHolder holder) {Log.i(TAG, "--11111--------" + holder);startPreview();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {Log.i(TAG, "--2222222--------" + holder);}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {holder.removeCallback(this);stopPreview();}}@Overridepublic void onPreviewFrame(byte[] data, Camera camera) {if (detectFace) {Bitmap bmp = byte2bitmap(data, camera);mCurrentDetectFaceInterface.detectFace(bmp);mCurrentDetectFaceInterface.detectFace2(bmp);}}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);Log.i(TAG, "byte2bitmap: " + bitmap.getWidth() + "---" + bitmap.getHeight());bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);return bitmap;}private void stopPreview() {if (mCamera != null) {try {mCamera.setPreviewCallback(null);mCamera.setPreviewDisplay(null);mCamera.stopPreview();mCamera.release();mCamera = null;} catch (Exception e) {e.printStackTrace();}}detectFace = false;mFaceRectView.clearRect();}/*** 開啟閃光燈*/public void turnFlash() {try {if (mCamera == null || mCamera.getParameters() == null|| mCamera.getParameters().getSupportedFlashModes() == null) {return;}Camera.Parameters parameters = mCamera.getParameters();String mode = parameters.getFlashMode();if (Camera.Parameters.FLASH_MODE_OFF.equals(mode)) {parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);} else if (Camera.Parameters.FLASH_MODE_TORCH.equals(mode)) {parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);}mCamera.setParameters(parameters);} catch (Exception e) {e.printStackTrace();}}/*** 調節預覽的焦距** @param maxValue* @param currentValue*/public void changZoom(int maxValue, int currentValue) {if (mCamera != null) {Camera.Parameters parameters = mCamera.getParameters();int maxZoom = parameters.getMaxZoom();Log.i(TAG, "changZoom: " + maxZoom);float setZoom = ((float) maxZoom / maxValue) * currentValue;parameters.setZoom((int) setZoom);mCamera.setParameters(parameters);}}/*** @param path 保存的路徑* @param name 錄像視頻名稱(包含后綴)*/public void startRecord(String path, String name) {if (mCamera == null)return;//解鎖攝像頭并將其分配給MediaRecordermCamera.unlock();mediaRecorder = new MediaRecorder();mediaRecorder.setCamera(mCamera);//指定用于錄制的輸入源mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);//mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));//設置配置文件,或者定義輸出格式,音頻視頻編碼器,幀速以及輸出尺寸mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);// 設置錄制的視頻編碼h263 h264mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);// 設置錄制的視頻幀率。必須放在設置編碼和格式的后面,否則報錯mediaRecorder.setVideoEncodingBitRate(700 * 1024); // 設置視頻錄制的分辨率。必須放在設置編碼和格式的后面,否則報錯mediaRecorder.setVideoSize(width, height); // mediaRecorder.setVideoFrameRate(24); //容易報錯 還有上面的setVideoSize 都是需要底層支持File file = new File(path);if (!file.exists()) {file.mkdirs();}//指定一個輸出文件mediaRecorder.setOutputFile(path + File.separator + name);File file1 = new File(path + File.separator + name);if (file1.exists()) {file1.delete();}//預覽視頻流,在指定了錄制源和輸出文件后,在prepare前設置mediaRecorder.setPreviewDisplay(mSurfaceView.getHolder().getSurface());/***不設置時,錄制的視頻總是倒著,翻屏導致視頻上下翻滾*/if (cameraPosition == 1) {//前置相機mediaRecorder.setOrientationHint(180);} else if (cameraPosition == 0) {mediaRecorder.setOrientationHint(0);}try {//準備錄制mediaRecorder.prepare();mediaRecorder.start();} catch (IOException e) {e.printStackTrace();}}/*** 停止錄制*/public void stopRecord() {mediaRecorder.release();mCamera.release();mediaRecorder = null;SystemClock.sleep(200);if (mCamera != null) {mCamera = Camera.open();mediaRecorder = new MediaRecorder();doChange(mSurfaceView.getHolder());}}/*** 拍照使用** @param photoPath* @param photoName*/public void takePicture(String photoPath, String photoName, TakePictureSuccess mTakePictureSuccess) {File file = new File(photoPath);if (!file.exists()) {file.mkdir();}Camera.ShutterCallback shutter = new Camera.ShutterCallback() {@Overridepublic void onShutter() {}};Camera.Parameters parameters = mCamera.getParameters();parameters.setPictureFormat(ImageFormat.JPEG);//圖片格式 必設置 否則無法獲取圖片信息parameters.set("jpeg-quality", 90);//設置圖片的質量mCamera.setParameters(parameters);mCamera.takePicture(shutter, null, new PictureCallBack(photoPath, photoName, mTakePictureSuccess)); // mCamera.takePicture(null, null, new PictureCallBack(photoPath, photoName));}/*** 拍照功能*/private class PictureCallBack implements Camera.PictureCallback {/*** 照片保存的路徑和名稱*/private String path;private String name;private TakePictureSuccess mTakePictureSuccess;public PictureCallBack(String path, String name, TakePictureSuccess mTakePictureSuccess) {this.path = path;this.name = name;this.mTakePictureSuccess = mTakePictureSuccess;}@Overridepublic void onPictureTaken(byte[] bytes, Camera camera) {File file = new File(path, name);if (file.exists()) {file.delete();}FileOutputStream fos = null;try {fos = new FileOutputStream(file);try {fos.write(bytes);} catch (IOException e) {e.printStackTrace();}} catch (FileNotFoundException e) {e.printStackTrace();}Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);Log.i(TAG, "onPictureTaken: ----" + cameraPosition);Matrix matrix = new Matrix();if (cameraPosition == 0) {matrix.postRotate(90);} else {matrix.postRotate(270); // matrix.postRotate(180);matrix.postTranslate(-1, 0);}bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);mTakePictureSuccess.takePictureSuccess(bitmap);//拍照結束 繼續預覽camera.startPreview();}}public interface TakePictureSuccess {void takePictureSuccess(Bitmap bitmap);}/*** 切換時,重新開啟** @param holder*/private void doChange(SurfaceHolder holder) {try {mCamera.setPreviewDisplay(holder);mCamera.setDisplayOrientation(90);mCamera.startPreview();} catch (IOException e) {e.printStackTrace();}}/*** 設置相機參數** @param camera* @param cameraPosition* @return*/public Camera.Parameters setParameters(Camera camera, int cameraPosition) {Camera.Parameters parameters = null;if (camera != null) {parameters = camera.getParameters();Log.i(TAG, "setParameters: ----" + parameters.getMaxNumDetectedFaces());if (cameraPosition == 0) {parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);parameters.setPreviewFrameRate(25);}parameters.setPictureFormat(ImageFormat.NV21);//手機支持的預覽尺寸集合List<Camera.Size> sizeList = parameters.getSupportedPreviewSizes();Log.i(TAG, "setParameters:----111----- " + CAMERA_WIDHT);Log.i(TAG, "setParameters:----支持預覽----- " + sizeList.size());CAMERA_WIDHT = 640;CAMERA_HEIGHT = 480;/* if (sizeList.size() > 1) {Iterator<Camera.Size> itor = sizeList.iterator();while (itor.hasNext()) {Camera.Size cur = itor.next();Log.i(TAG, "setParameters:----size----- "+cur.width +"-----"+cur.height) ;if (cur.width >= CAMERA_WIDHT&& cur.height >= CAMERA_HEIGHT) {CAMERA_WIDHT = cur.width;CAMERA_HEIGHT = cur.height;break;}}}*///每秒3幀 每秒從攝像頭里面獲得3個畫面 // parameters.setPreviewFrameRate(3);//設置拍出來的屏幕大小parameters.setPictureSize(CAMERA_WIDHT, CAMERA_HEIGHT);//獲得攝像區域的大小parameters.setPreviewSize(CAMERA_WIDHT, CAMERA_HEIGHT);//對焦模式設置List<String> supportedFocusModes = parameters.getSupportedFocusModes();if (supportedFocusModes != null && supportedFocusModes.size() > 0) {if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);} else if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);} else if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);}}}return parameters;}/**** 獲取SupportedVideoSizes 控制輸出視頻width在300到600之間(盡可能小)* 獲取PictureSize的大小(控制在w:1000-2000之間)*/public void getVideoSize() {if (mCamera == null)return;Camera.Parameters parameters = mCamera.getParameters();List<Camera.Size> videoSize = parameters.getSupportedVideoSizes();for (int i = 0; i < videoSize.size(); i++) {int width1 = videoSize.get(i).width;int height1 = videoSize.get(i).height;if (width1 >= 300 && width1 <= 600) {if (height1 >= 200 && height1 <= 600) {width = width1;height = height1;}} // Log.d(TAG, "getVideoSize:----w:-- " + videoSize.get(i).width + "---h:--" + videoSize.get(i).height);Log.d(TAG, "width " + width + "---height" + height);}List<Camera.Size> photoSize = parameters.getSupportedPictureSizes();for (int i = 0; i < photoSize.size(); i++) {int width1 = photoSize.get(i).width;int height1 = photoSize.get(i).height;if (width1 >= 1000 && width1 <= 2000) {if (height1 >= 600 && height1 <= 2000) {widthPhoto = width1;heightPhoto = height1;}}}Log.i(TAG, "getVideoSize: " + widthPhoto + "----" + heightPhoto);}public interface CurrentCameraPositionInterface {void cameraPosition(int cameraPosition);}public void setCurrentDetectFaceInterface(CurrentDetectFaceInterface currentDetectFaceInterface) {mCurrentDetectFaceInterface = currentDetectFaceInterface;}private CurrentDetectFaceInterface mCurrentDetectFaceInterface;public interface CurrentDetectFaceInterface {void detectFace(Bitmap bitmap);void detectFace2(Bitmap bitmap);}public void setCameraErrorCallback(CameraErrorCallback cameraErrorCallback) {this.cameraErrorCallback = cameraErrorCallback;} }發現人臉的方法
public Bitmap getCutBitmap(Bitmap bitmap) {Bitmap cutBitmap = null;//由于Android內存有限,圖片太大的話,會出現無法加載圖片的異常,圖片的格式必須為Bitmap RGB565格式Bitmap bitmapDetect = bitmap.copy(Bitmap.Config.RGB_565, true);Log.i(TAG, "getCutBitmap:---寬度-- "+bitmapDetect.getWidth());Log.i(TAG, "getCutBitmap:---高度-- "+bitmapDetect.getHeight());// 設置你想檢測的數量,數值越大錯誤率越高,所以需要置信度來判斷,但有時候置信度也會出問題FaceDetector faceDetector = new FaceDetector(bitmapDetect.getWidth(), bitmapDetect.getHeight(), 1);// 返回找到圖片中人臉的數量,同時把返回的臉部位置信息放到faceArray中,過程耗時,圖片越大耗時越久int face = faceDetector.findFaces(bitmapDetect, faces);Log.i(TAG, "getCutBitmap:--------- "+face); // if (faces[0] != null) {//檢測到人臉if (face > 0) {//檢測到人臉// 獲取傳回的第一張臉信息FaceDetector.Face face1 = faces[0];// 獲取該部位為人臉的可信度,0~1float confidence = face1.confidence();Log.i(TAG, "------人臉可信度---- "+confidence);// 獲取雙眼的間距float eyesDistance = face1.eyesDistance();Log.i(TAG, "------人臉雙眼的間距---- "+eyesDistance);// 傳入X則獲取到x方向上的角度,傳入Y則獲取到y方向上的角度,傳入Z則獲取到z方向上的角度float angle = face1.pose(FaceDetector.Face.EULER_X);if (confidence < 0.5 || eyesDistance<0.3){return null;}cutBitmap = bitmap;Log.i(TAG, "getCutBitmap: ");}bitmapDetect.recycle(); // bitmap.recycle();return cutBitmap;}2 . Demo地址
下載地址
總結
以上是生活随笔為你收集整理的Android 原生的人脸识别Camera+FaceDetector示例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [剑指offer][JAVA]面试题第[
- 下一篇: 经验分享:三步走教你升级企业NAS设备