Android前置摄像头预览并检测人脸,获取人脸区域亮度
16lz
2022-05-12
本篇博文记录如何使用Android的前置摄像头预览,并获取人脸部分,然后计算人脸区域的亮度,下面是程序运行截图:
下面上代码:
1、前置摄像头预览时需要用到的类CameraView:
package test.com.getbright;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Point;import android.graphics.PointF;import android.hardware.Camera;import android.hardware.Camera.Size;import android.media.FaceDetector;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.view.ViewGroup;import android.view.WindowManager;import java.io.IOException;import java.util.List;/** * Created by yubo on 2015/9/20. */public class CameraView extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback { private Context context; private Camera camera; private FaceView faceView; private OnFaceDetectedListener onFaceDetectedListener; /** * 摄像头最大的预览尺寸 */ private Size maxPreviewSize; /** * 预览时Frame的计数器 */ private int frameCount; /** * 是否正在检测人脸 */ private boolean isDetectingFace = false; /** * 是否已检测到人脸 */ private boolean detectedFace = false; public CameraView(Context context) { super(context); init(context); } public CameraView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private void init(Context context) { this.context = context; getHolder().addCallback(this); } public void setFaceView(FaceView faceView) { if (faceView != null) { this.faceView = faceView; } } /** 摄像头重新开始预览 */ public void reset() { if(faceView != null) { faceView.setVisibility(View.GONE); } if(camera != null) { camera.setPreviewCallback(this); camera.startPreview(); } frameCount = 0; detectedFace = false; isDetectingFace = false; } @Override public void surfaceCreated(SurfaceHolder holder) { try { camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT); if(camera != null) { camera.setDisplayOrientation(90); camera.setPreviewDisplay(holder); camera.setPreviewCallback(this); } } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { if (camera != null) { maxPreviewSize = getMaxPreviewSize(camera); if (maxPreviewSize != null) { ViewGroup.LayoutParams params = getLayoutParams(); Point point = getScreenSize(); params.width = point.x; params.height = maxPreviewSize.width * point.x / maxPreviewSize.height; setLayoutParams(params); if(faceView != null) { faceView.setLayoutParams(params); } Camera.Parameters parameters = camera.getParameters(); parameters.setPreviewSize(maxPreviewSize.width, maxPreviewSize.height); camera.setParameters(parameters); } camera.startPreview(); frameCount = 0; detectedFace = false; } } @Override public void surfaceDestroyed(SurfaceHolder holder) { if (camera != null) { try { camera.stopPreview(); camera.setPreviewDisplay(null); camera.setPreviewCallback(null); camera.release(); camera = null; } catch (IOException e) { e.printStackTrace(); } } } /** * 获取手机屏幕的尺寸 * * @return */ private Point getScreenSize() { WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); manager.getDefaultDisplay().getMetrics(outMetrics); return new Point(outMetrics.widthPixels, outMetrics.heightPixels); } /** * 获取摄像头最大的预览尺寸 * * @param camera * @return */ private Size getMaxPreviewSize(Camera camera) { List list = camera.getParameters().getSupportedPreviewSizes(); if (list != null) { int max = 0; Size maxSize = null; for (Size size : list) { int n = size.width * size.height; if (n > max) { max = n; maxSize = size; } } return maxSize; } return null; } @Override public void onPreviewFrame(byte[] data, Camera camera) { Log.e("yubo", "onPreviewFrame..."); frameCount++; //前面15帧丢弃 if (frameCount > 15 && !isDetectingFace && !detectedFace) { Size size = camera.getParameters().getPreviewSize(); final byte[] byteArray = ImageUtils.yuv2Jpeg(data, size.width, size.height); isDetectingFace = true; new Thread() { @Override public void run() { detectFaces(byteArray); } }.start(); } } /** * 检测data数据中是否有人脸,这里需要先旋转一下图片,该方法执行在子线程中 * * @param data */ private void detectFaces(byte[] data) { Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); bitmap = ImageUtils.rotateBitmap(bitmap, -90); bitmap = bitmap.copy(Bitmap.Config.RGB_565, true); FaceDetectorUtils.detectFace(bitmap, new FaceDetectorUtils.Callback() { @Override public void onFaceDetected(final FaceDetector.Face[] faces, final Bitmap bm) { isDetectingFace = false; Log.e("yubo", "face detected..."); if (!detectedFace) { detectedFace = true; ((Activity) context).runOnUiThread(new Runnable() { @Override public void run() { if (camera != null) { camera.stopPreview(); } if (faceView != null) { float scaleRate = bm.getWidth() * 1.0f / getScreenSize().x; faceView.setScaleRate(scaleRate); faceView.setFaces(faces, bm); faceView.setVisibility(View.VISIBLE); } if (onFaceDetectedListener != null) { onFaceDetectedListener.onFaceDetected(bm); } } }); } } @Override public void onFaceNotDetected(Bitmap bm) { bm.recycle(); if (faceView != null) { faceView.clear(); } isDetectingFace = false; } }); } /** * 检测到人脸的监听器 */ public interface OnFaceDetectedListener { void onFaceDetected(Bitmap bm); } /** * 设置监听器,监听检测到人脸的动作 */ public void setOnFaceDetectedListener(OnFaceDetectedListener listener) { if (listener != null) { this.onFaceDetectedListener = listener; } }}
2、检测到人脸后将人脸区域画出来的FaceView类: package test.com.getbright;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.PointF;import android.media.FaceDetector;import android.util.AttributeSet;import android.util.Log;import android.widget.ImageView;/** * Created by yubo on 2015/9/5. * 画人脸区域的View */public class FaceView extends ImageView { private FaceDetector.Face[] faces; private Paint paint; private Bitmap bitmap; private float left; private float top; private float right; private float bottom; private int x; private int y; private int width; public FaceView(Context context) { super(context); init(context); } public FaceView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public FaceView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { paint = new Paint(); paint.setColor(Color.GREEN); paint.setStrokeWidth(5); paint.setStyle(Paint.Style.STROKE);//设置话出的是空心方框而不是实心方块 } public void setFaces(FaceDetector.Face[] faces, Bitmap bitmap) { if(faces != null && faces.length > 0) { Log.e("yubo", "FaceView setFaces, face size = " + faces.length); this.faces = faces; this.bitmap = bitmap; setImageBitmap(bitmap); calculateFaceArea(); invalidate(); }else{ Log.e("yubo", "FaceView setFaces, faces == null"); } } /** 计算人脸区域 */ private void calculateFaceArea(){ float eyesDistance = 0;//两眼间距 for(int i = 0; i < faces.length; i++){ FaceDetector.Face face = faces[i]; if(face != null){ PointF pointF = new PointF(); face.getMidPoint(pointF);//获取人脸中心点 eyesDistance = face.eyesDistance();//获取人脸两眼的间距 //计算人脸的区域 float delta = eyesDistance / 2; left = (pointF.x - eyesDistance) / scaleRate; top = (pointF.y - eyesDistance + delta) / scaleRate; right = (pointF.x + eyesDistance) / scaleRate; bottom = (pointF.y + eyesDistance + delta) / scaleRate; x = (int) (pointF.x - eyesDistance); y = (int) (pointF.y - eyesDistance + delta); width = (int) (eyesDistance * 2); } } } private float scaleRate = 1.0f; public void setScaleRate(float rate) { this.scaleRate = rate; } /** 清除数据 */ public void clear(){ this.faces = null; postInvalidate(); } /** 获取人脸区域,适当扩大了一点人脸区域 */ public Bitmap getFaceArea(){ if(this.bitmap != null) { int bmWidth = bitmap.getWidth(); int bmHeight = bitmap.getHeight(); int delta = 50; width += 50; int height = width; x = (int) (left - delta); y = (int) (top - delta); if(x < 0) { x = 0; } if(y < 0) { y = 0; } if(width > bmWidth) { width = bmWidth; } if(height > bmHeight) { height = bmHeight; } return Bitmap.createBitmap(bitmap, x, y, width, height); } return null; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if(this.faces == null || faces.length == 0) { return ; } canvas.drawRect(left, top, right, bottom, paint); }}
3、人脸检测的工具类: package test.com.getbright;import android.graphics.Bitmap;import android.media.FaceDetector;import android.media.FaceDetector.Face;/** * Created by yubo on 2015/9/5. * 人脸检测工具类 */public class FaceDetectorUtils { private static FaceDetector faceDetector; private FaceDetectorUtils(){ } public interface Callback{ void onFaceDetected(Face[] faces, Bitmap bitmap); void onFaceNotDetected(Bitmap bitmap); } /** * 检测bitmap中的人脸,在callback中返回人脸数据 * @param bitmap * @param callback */ public static void detectFace(Bitmap bitmap, Callback callback){ try { faceDetector = new FaceDetector(bitmap.getWidth(), bitmap.getHeight(), 1); Face[] faces = new Face[1]; int faceNum = faceDetector.findFaces(bitmap, faces); if(faceNum > 0) { if(callback != null) { callback.onFaceDetected(faces, bitmap); } }else{ if(callback != null) { callback.onFaceNotDetected(bitmap); bitmap.recycle(); } } } catch (Exception e) { e.printStackTrace(); } }}
4、处理图像的工具类: package test.com.getbright;import android.graphics.Bitmap;import android.graphics.ImageFormat;import android.graphics.Matrix;import android.graphics.Rect;import android.graphics.YuvImage;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;/** * Created by yubo on 2015/8/31. * 图像处理的工具类 */public class ImageUtils { /** 将yuv数据转换为jpeg */ public static byte[] yuv2Jpeg(byte[] yuvBytes, int width, int height) { YuvImage yuvImage = new YuvImage(yuvBytes, ImageFormat.NV21, width, height, null); ByteArrayOutputStream baos = new ByteArrayOutputStream(); yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, baos); return baos.toByteArray(); } /** 旋转图像 */ public static Bitmap rotateBitmap(Bitmap sourceBitmap, int degree) { Matrix matrix = new Matrix(); //旋转90度,并做镜面翻转 matrix.setRotate(degree); matrix.postScale(-1, 1); return Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight(), matrix, true); } /** 保存bitmap到文件 */ public static void saveBitmap(Bitmap bitmap, String path) { if(bitmap != null) { try { bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(new File(path))); } catch (FileNotFoundException e) { e.printStackTrace(); } } }}
5、最后是布局文件和主Activity代码: <?xml version="1.0" encoding="utf-8"?>
package test.com.getbright;import android.annotation.SuppressLint;import android.app.Activity;import android.app.AlertDialog;import android.content.DialogInterface;import android.graphics.Bitmap;import android.hardware.Camera;import android.hardware.Sensor;import android.hardware.SensorEvent;import android.hardware.SensorEventListener;import android.hardware.SensorManager;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.widget.ImageView;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity { CameraView cameraView; FaceView faceView; Bitmap fullBitmap; private SensorManager sensorManager; private Sensor sensor; private MySensorListener mySensorListener; private int sensorBright = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if(!hasFrontCamera()) { Toast.makeText(this, "没有前置摄像头", Toast.LENGTH_SHORT).show(); return ; } sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); mySensorListener = new MySensorListener(); sensorManager.registerListener(mySensorListener, sensor, SensorManager.SENSOR_DELAY_NORMAL); initView(); } private void initView(){ cameraView = (CameraView) findViewById(R.id.camera_view); faceView = (FaceView) findViewById(R.id.face_view); cameraView.setFaceView(faceView); cameraView.setOnFaceDetectedListener(new CameraView.OnFaceDetectedListener() { @Override public void onFaceDetected(Bitmap bm) { //检测到人脸后的回调方法 fullBitmap = bm; showDialog(); } }); } private class MySensorListener implements SensorEventListener { @Override public void onSensorChanged(SensorEvent sensorEvent) { //光线传感器亮度改变 sensorBright = (int) sensorEvent.values[0]; } @Override public void onAccuracyChanged(Sensor sensor, int i) { } } private void showDialog(){ AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("计算结果"); View contentView = LayoutInflater.from(this).inflate(R.layout.pop_win_layout, null); ImageView imageView = (ImageView) contentView.findViewById(R.id.imageview); TextView textView = (TextView) contentView.findViewById(R.id.textview); builder.setView(contentView); Bitmap bm = faceView.getFaceArea(); imageView.setImageBitmap(bm); textView.setText("人脸区域亮度:" + getBright(bm) + "\n整幅图片亮度:" + getBright(fullBitmap) + "\n光线传感器的值:" + sensorBright); builder.setPositiveButton("确定", new DialogInterface.OnClickListener(){ @Override public void onClick(DialogInterface dialogInterface, int i) { cameraView.reset(); } }); builder.setCancelable(false); builder.create().show(); } public int getBright(Bitmap bm) { int width = bm.getWidth(); int height = bm.getHeight(); int r, g, b; int count = 0; int bright = 0; for(int i = 0; i < width; i++) { for(int j = 0; j < height; j++) { count++; int localTemp = bm.getPixel(i, j); r = (localTemp | 0xff00ffff) >> 16 & 0x00ff; g = (localTemp | 0xffff00ff) >> 8 & 0x0000ff; b = (localTemp | 0xffffff00) & 0x0000ff; bright = (int) (bright + 0.299 * r + 0.587 * g + 0.114 * b); } } return bright / count; } /** * 判断是否有前置摄像 * @return */ @SuppressLint("NewApi") public static boolean hasFrontCamera(){ Camera.CameraInfo info = new Camera.CameraInfo(); int count = Camera.getNumberOfCameras(); for(int i = 0; i < count; i++){ Camera.getCameraInfo(i, info); if(info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){ return true; } } return false; } @Override protected void onDestroy() { super.onDestroy(); sensorManager.unregisterListener(mySensorListener); }}
代码下载点这里
更多相关文章
- Android(安卓)音视频采集那些事
- Android的MediaRecorder架构介绍
- Android学习日记----------Android(安卓)10调用摄像头闪退问题--
- Android项目总结5
- 深度揭秘android摄像头的autoFocus-----循环自动聚焦的实现(Andro
- Android(安卓)Studio如何设置代码自动提示
- Android(安卓)图像存储在SD卡ContentResolver
- Android(安卓)实现书籍翻页效果---番外篇之光影效果
- Android中单击空白区域隐藏键盘