本篇博文记录如何使用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);    }}

代码下载点这里




更多相关文章

  1. Android(安卓)音视频采集那些事
  2. Android的MediaRecorder架构介绍
  3. Android学习日记----------Android(安卓)10调用摄像头闪退问题--
  4. Android项目总结5
  5. 深度揭秘android摄像头的autoFocus-----循环自动聚焦的实现(Andro
  6. Android(安卓)Studio如何设置代码自动提示
  7. Android(安卓)图像存储在SD卡ContentResolver
  8. Android(安卓)实现书籍翻页效果---番外篇之光影效果
  9. Android中单击空白区域隐藏键盘

随机推荐

  1. Android Input子系统浅谈
  2. WebView In Mobile App
  3. 使用ViewFlipper来组织控件
  4. Android(安卓)NDK编译C/C++为so共享对象
  5. 将Android DHCPInfo 属性转换为int类型(使
  6. Android有趣的全透明效果--Activity及Dia
  7. 实例:在Android调用WCF服务(wcf restful)
  8. Android开发资源完全汇总
  9. android 学习RxJava+Retrofit的资料
  10. Android EditText光标颜色 与inputType