概述
本篇博文记录如何使用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<Size> 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"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="@color/black">
<test.com.getbright.CameraView
android:id="@+id/camera_view"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<test.com.getbright.FaceView
android:id="@+id/face_view"
android:layout_gravity="center"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</FrameLayout>
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前置摄像头预览并检测人脸,获取人脸区域亮度所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复