使用Android自带SDK进行人脸识别
现在市面上有很多人脸识别以及人脸对比的SDK,比如说FACE++(旷世)、阿里云、百度云、科大讯飞、云从科技等等,基本上都是通过API调用返回相应的数据,经过资料查询以及体验部分第三方的API,最后我选择了Android 自带的人脸识别的SDK,亲测有效,话不多说,代码走起。(代码传送门:http://download.csdn.net/download/u010718838/10157191),android6.0以上需要自己写一下动态请求相机的权限代码。
首先我们通过SurfaceView获取摄像头的数据。
SurfaceView preview;
preview= (SurfaceView) findViewById(R.id.preview);
// 设置缓冲类型
preview.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
// 设置surface的分辨率
preview.getHolder().setFixedSize(1920,1080);
// 设置屏幕常亮
preview.getHolder().setKeepScreenOn(true);
preview.getHolder().addCallback(new SurfaceCallback());
然后通过SurfaceCallback()回调设置相机获取图片的相应参数;
private final classSurfaceCallbackimplementsCallback {
@Override
public voidsurfaceChanged(SurfaceHolder holder, intformat, intwidth,
intheight) {
if(camera!=null) {
parameters=camera.getParameters();
parameters.setPictureFormat(PixelFormat.JPEG);
// 设置预览区域的大小
parameters.setPreviewSize(width,height);
// 设置每秒钟预览帧数 帧数越大识别速度越快,但建议范围25-60帧数,视手机自身性能而定
parameters.setPreviewFrameRate(60);
// 设置预览图片的大小
parameters.setPictureSize(width,height);
parameters.setJpegQuality(80);
}
}
@Override
public voidsurfaceCreated(SurfaceHolder holder) {
intcameraCount =0;
Camera.CameraInfo cameraInfo =newCamera.CameraInfo();
cameraCount = Camera.getNumberOfCameras();
for(inti =0;i < cameraCount;i++) {
Camera.getCameraInfo(i,cameraInfo);
if(cameraInfo.facing== Camera.CameraInfo.CAMERA_FACING_FRONT) {
try{
camera= Camera.open(i);
camera.setPreviewDisplay(holder);
setCameraDisplayOrientation(i,camera);
camera.setPreviewCallback(newMyPreviewCallback());
camera.startPreview();
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
@Override
public voidsurfaceDestroyed(SurfaceHolder holder) {
if(camera!=null) {
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
camera=null;
}
}
}
通过camera.setPreviewCallback(newMyPreviewCallback());回调的图像数据进行处理
重点来了
private classMyPreviewCallbackimplementsPreviewCallback {
@Override
public voidonPreviewFrame(byte[] data,Camera camera) {
Camera.Size size = camera.getParameters().getPreviewSize();
YuvImage yuvImage =newYuvImage(data,ImageFormat.NV21,
size.width,size.height, null);
ByteArrayOutputStream baos =newByteArrayOutputStream();
yuvImage.compressToJpeg(newRect(0,0,size.width,size.height),
80,baos);
byte[] byteArray = baos.toByteArray();
detectionFaces(byteArray);
}
}
/**
* 检测人脸
*
*@paramdata预览的图像数据
*/
private voiddetectionFaces(byte[] data) {
BitmapFactory.Options options =newBitmapFactory.Options();
Bitmap bitmap1 = BitmapFactory.decodeByteArray(data,0,data.length,
options);
intwidth = bitmap1.getWidth();
intheight = bitmap1.getHeight();
Matrix matrix =newMatrix();
Bitmap bitmap2 =null;
FaceDetector detector =null;
switch(orientionOfCamera) {
case0:
detector =newFaceDetector(width,height,10);
matrix.postRotate(0.0f,width /2,height /2);
// 以指定的宽度和高度创建一张可变的bitmap(图片格式必须是RGB_565,不然检测不到人脸)
bitmap2 = Bitmap.createBitmap(width,height,Bitmap.Config.RGB_565);
break;
case90:
detector =newFaceDetector(height,width,1);
matrix.postRotate(-270.0f,height /2,width /2);
bitmap2 = Bitmap.createBitmap(height,width,Bitmap.Config.RGB_565);
break;
case180:
detector =newFaceDetector(width,height,1);
matrix.postRotate(-180.0f,width /2,height /2);
bitmap2 = Bitmap.createBitmap(width,height,Bitmap.Config.RGB_565);
break;
case270:
detector =newFaceDetector(height,width,1);
matrix.postRotate(-90.0f,height /2,width /2);
bitmap2 = Bitmap.createBitmap(height,width,Bitmap.Config.RGB_565);
break;
}
faces=newFaceDetector.Face[10];
Paint paint =newPaint();
paint.setDither(true);
Canvas canvas =newCanvas();
canvas.setBitmap(bitmap2);
canvas.setMatrix(matrix);
// 将bitmap1画到bitmap2上(这里的偏移参数根据实际情况可能要修改)
canvas.drawBitmap(bitmap1,0,0,paint);
faceNumber= detector.findFaces(bitmap2,faces);
Log.e("---------->","faceNumber:"+faceNumber+"faces.size:"+faces.length);
// mTV.setText("facnumber----" + faceNumber);
mTV.setTextColor(Color.RED);
if(faceNumber!=0) {
mFindFaceView.setVisibility(View.VISIBLE);
mFindFaceView.drawRect(faces,faceNumber);
}else{
mFindFaceView.setVisibility(View.GONE);
}
bitmap2.recycle();
bitmap1.recycle();
}
/**
* 设置相机的显示方向(这里必须这么设置,不然检测不到人脸)
*
*@paramcameraId相机ID(0是后置摄像头,1是前置摄像头)
*@paramcamera相机对象
*/
private voidsetCameraDisplayOrientation(intcameraId,Camera camera) {
Camera.CameraInfo info =newCamera.CameraInfo();
Camera.getCameraInfo(cameraId,info);
introtation = getWindowManager().getDefaultDisplay().getRotation();
intdegree =0;
switch(rotation) {
caseSurface.ROTATION_0:
degree =0;
break;
caseSurface.ROTATION_90:
degree =90;
break;
caseSurface.ROTATION_180:
degree =180;
break;
caseSurface.ROTATION_270:
degree =270;
break;
}
orientionOfCamera= info.orientation;
intresult;
if(info.facing== Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation+ degree) %360;
result = (360- result) %360;
}else{
result = (info.orientation- degree +360) %360;
}
camera.setDisplayOrientation(result);
}
如果需要对找到人脸的大致范围,可以使用自定义控件 FindFaceView
// 因为拍摄的相片跟实际显示的图像是镜像关系,所以在图片上获取的两眼中间点跟手机上显示的是相反方向
//根据人脸数据的返回的人脸中心点以及两眼之间的距离,算出大致的范围,需要根据不同的分辨进行调整,然后使用画笔画出。
canvas.drawRect((int) ((mWidth-midPoint.x) - (eyesDistance*2+eyesDistance/2)),
(int) (midPoint.y-eyesDistance)+210,
(int) ( (mWidth-midPoint.x) + (eyesDistance/3)),
(int) (midPoint.y+ (eyesDistance*2+eyesDistance/2))+210,paint);