人脸识别google有自带api,Androoid 原生的人脸识别是利用相机的摄像功能和android.media.FaceDetector这个类来实现的
Camera 类用于设置图像捕获设置、开始/停止预览、抓拍图片和检索帧以进行视频编码
Camera的源码
1. 初始化相机并设置相机参数;
2. 设置预览监听setPreviewDisplay();
3. 开始预览startPreview();
4. 实现预览的接口onPreviewFrame并处理每一帧的数据转成Bitmap;
5. 通过 faceDetector.findFaces()发现人脸,注意:faceDetector只能识别Bitmap.Config.RGB_565的Bitmap
工具类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 {
@Override
public 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 {
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.i(TAG, "--11111--------" + holder);
startPreview();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i(TAG, "--2222222--------" + holder);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
holder.removeCallback(this);
stopPreview();
}
}
@Override
public 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;
//解锁摄像头并将其分配给MediaRecorder
mCamera.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 h264
mediaRecorder.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() {
@Override
public 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;
}
@Override
public 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~1
float 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;
}