我是靠谱客的博主 怡然汽车,最近开发中收集的这篇文章主要介绍Android前置摄像头预览并检测人脸,获取人脸区域亮度,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

本篇博文记录如何使用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前置摄像头预览并检测人脸,获取人脸区域亮度所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部