android 拍摄预览过程中人脸识别

仔细想想距离写上篇文章已经很久了,最近都忙于工作和睡觉打游戏(朋友的名字叫游溪),以至于没有写接下来的东西。。记得上篇文章写的是关于自定义camera的(http://blog.csdn.net/lzan13/article/details/54017224)。。那么该篇将在原有的基础上加上人脸识别的功能。

已经亲测,可以实现!!!

三个类,很简单,其他难得我也不会搞:

  主要通过:FaceDetectionListener 实现

废话不多说直接上代码:

AutioTakeActiity  该页面只有一个跳转按钮,和一个用来显示拍摄照片的imageview

package com.example.auto_take_picture;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;

/**
 * Created by Administrator on 2017/5/5 0005.
 */
public class AutioTakeActiity extends Activity {
    private static final int REQUEST_CAMERA_CODE_TEACHER = 1;// 拍照
    private ImageView ima;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_takephoto_result);
        ima=(ImageView)findViewById(R.id.ima);
    }



    /**
     * 点击拍照
     * @param view
     */
    public void takePhoto(View view){
        getPerssiom();
    }

    /**
     * android6.0 申请拍照权限
     */
    private void getPerssiom(){
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
                && ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
                && ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
            gotoTake();
        } else {
            ActivityCompat.requestPermissions(this, new String[]{
                    Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.CAMERA,
                    Manifest.permission.READ_EXTERNAL_STORAGE
            }, REQUEST_CAMERA_CODE_TEACHER);
        }
    }

    /**
     * 跳转至自定义的拍照页面
     */
    private void gotoTake(){
        Intent intent =new Intent(this,AutioTakePhotoActivity.class);
        startActivityForResult(intent ,1);
    }


    /**
     * 拍照完成之后拿到路径设置imageview
     * @param requestCode
     * @param resultCode
     * @param data
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(resultCode==RESULT_OK){
            if(requestCode==1){
               boolean isBack= data.getBooleanExtra("isBack",true);
                String path  =  data.getStringExtra("picPath");
                Bitmap bitmap = BitmapFactory.decodeFile(path);
                Matrix matrix=new Matrix();
                if(isBack){//由于拍照时旋转了90度。这里通矩阵旋转回来。(后置摄像头)
                    matrix.setRotate(90);
                }else{
                    matrix.setRotate(-90);             // ( 前置摄像头)
                }
                Bitmap bit=  bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
                ima.setImageBitmap(bit);
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case REQUEST_CAMERA_CODE_TEACHER:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED
                        && grantResults.length > 1 && grantResults[1] == PackageManager.PERMISSION_GRANTED
                        && grantResults.length > 2 && grantResults[2] == PackageManager.PERMISSION_GRANTED) {
                    gotoTake();
                } else {
                    Toast.makeText(this, "获取权限失败", Toast.LENGTH_SHORT).show();
                }
                break;

            default:
                break;
        }
    }



}
 
 
//上面类对应的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">


    <TextView
        android:id="@+id/take"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="去拍照"
        android:padding="15dp"
        android:onClick="takePhoto"
        android:layout_gravity="center"
        />

    <ImageView
        android:id="@+id/ima"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@drawable/show"
        />

</LinearLayout>

// 该类完成拍摄和展示,以及人脸识别的功能
package com.example.auto_take_picture;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

/**
 * Created by Administrator on 2017/5/5 0005.
 */
public class AutioTakePhotoActivity extends Activity implements  SurfaceHolder.Callback{
    private SurfaceHolder holder;
    private SurfaceView surfaceView;
    Camera mCamera;
    byte[] photoBytes;
    private ImageView image;
    private RelativeLayout rela_result;
    public static int cameraId;
    private boolean isBack=true;
    private FaceView faceView;
    private TextView txt_turn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_take_photo);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//保持屏幕常亮
        rela_result=(RelativeLayout)findViewById(R.id.result) ;  //在预览界面之上覆盖一层页面,显示拍摄的图片
        image=(ImageView)findViewById(R.id.image);               //显示拍摄的图片
        surfaceView=(SurfaceView)findViewById(R.id.surfaceview);
        holder= surfaceView.getHolder();
        faceView=(FaceView)findViewById(R.id.face_view);        //自定义的view 。用来绘制检测人脸的方框;
        cameraId=findBackCamera();                              //摄像头的id,区分前置还是后置摄像头
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        txt_turn=(TextView)findViewById(R.id.turn);
        txt_turn.setText("前置/后置------当前:后置");
        holder.addCallback(this);
    }

    public void take(View view){          //点击拍照的方法。
        Camera.Parameters parameters =mCamera.getParameters();
        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
        mCamera.autoFocus(new Camera.AutoFocusCallback() {
            @Override
            public void onAutoFocus(boolean b, Camera camera) {
                if(b){        //如果焦点获取成功,拍照
                    mCamera.takePicture(null,null,pictureCallBack);  //pictureCallBack 为拍照的回掉。
                }
            }
        });
    }

    /**
     * 摄像头的切换
     * @param view
     */
    public void turn(View view){
            if(isBack){
                cameraId=findFrontCamera();  //前置摄像头id
                txt_turn.setText("前置/后置------当前:前置");
            }else{
                cameraId=findBackCamera();  //后置
                txt_turn.setText("前置/后置------当前:后置");
            }
        isBack=!isBack;
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release(); // 释放照相机
        }
        mCamera = Camera.open(cameraId);
        setCameraParams(1080,1920);//随便设的值
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.setDisplayOrientation(90);
            mCamera.startPreview();
            mainHandler.sendEmptyMessage(1);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 点击完成保存图片,并将路径回传给上个页面
     * @param view
     */
    public void finish(View view){          //完成
        File file=new File(Environment.getExternalStorageDirectory().getPath() + "/test2.jpg");
        if (file.exists()) {
            file.delete();
        }
        try {
            FileOutputStream fo=new FileOutputStream(file);
            fo.write(photoBytes);
            fo.close();
            Toast.makeText(AutioTakePhotoActivity.this,"已保存图片", Toast.LENGTH_SHORT).show();
            Intent intent =new Intent(AutioTakePhotoActivity.this,AutioTakeActiity.class);                         //完成拍照,回到mainActivity,并将图片的路径回传
            intent.putExtra("picPath", Environment.getExternalStorageDirectory().getPath() + "/test2.jpg");
            intent.putExtra("isBack",isBack);
            setResult(RESULT_OK,intent);
            finish();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 取消,放弃该图片
     * @param view
     */
    public void cancle(View view){          //取消
        photoBytes=null;
        rela_result.setVisibility(View.GONE);
        mCamera.startPreview();
    }


    /**
     * 显示拍出的图片
     */
    private  void show(byte[] photoBytes){
        Bitmap bitmap = BitmapFactory.decodeByteArray(photoBytes, 0, photoBytes.length);
        Matrix matrix=new Matrix();
        if(isBack){  //后置摄像头
            matrix.setRotate(90);
        }else{
            matrix.setRotate(-90); //前置摄像头
        }
        Bitmap bit=  bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
        if(bitmap!=null&&!bitmap.isRecycled()){
            bitmap.recycle();
        }
        if(bit!=null){
            image.setImageBitmap(bit);
        }
        rela_result.setVisibility(View.VISIBLE);
    }

    private Camera.PictureCallback  pictureCallBack =new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] bytes, Camera camera) {     //bytes 即是拍照回来的内容,将内容写入本地即可
            photoBytes=bytes;
            show(photoBytes);
        }
    };
    /**
     * 拿到前置摄像头id
     */
    public static int findFrontCamera() {
        int cameraId = -1;
        int numberCameras = Camera.getNumberOfCameras();
        for (int i = 0; i < numberCameras; i++) {
            Camera.CameraInfo info = new Camera.CameraInfo();
            Camera.getCameraInfo(i, info);
            if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                cameraId = i;
                break;
            }
        }
        return cameraId;
    }

    /**
     * 拿到后置摄像头id
     */
    public static int findBackCamera() {
        int cameraId = -1;
        int numberCameras = Camera.getNumberOfCameras();
        for (int i = 0; i < numberCameras; i++) {
            Camera.CameraInfo info = new Camera.CameraInfo();
            Camera.getCameraInfo(i, info);
            if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                cameraId = i;
                break;
            }
        }
        return cameraId;
    }
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Log.e("zjun","surfaceCreated");
        try {
            if(mCamera==null){
                mCamera= Camera.open(cameraId);

                mCamera.setPreviewDisplay(holder);
               setCameraParams(1080,1920);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        Log.e("zjun","surfaceChanged");
        mCamera.startPreview();
        mainHandler.sendEmptyMessage(1);
    }



    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (mCamera != null) {
            mCamera.release(); // 释放照相机
            mCamera = null;
        }
    }

    /**
     * 设置参数
     * @param width
     * @param height
     */
    private void setCameraParams(int width, int height) {
        Camera.Parameters parameters = mCamera.getParameters();
        // 获取摄像头支持的PictureSize列表
        List<Camera.Size> pictureSizeList = parameters.getSupportedPictureSizes();
        /**从列表中选取合适的分辨率*/
        Camera.Size picSize = getProperSize(pictureSizeList, ((float) height / width));
        if (null == picSize) {
            picSize = parameters.getPictureSize();
        }
        // 根据选出的PictureSize重新设置SurfaceView大小
        parameters.setPictureSize(picSize.width,picSize.height);

        // 获取摄像头支持的PreviewSize列表
        List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes();
        Camera.Size preSize = getProperSize(previewSizeList, ((float) height) / width);
        if (null != preSize) {
            Log.e("zjun", "preSize.width=" + preSize.width + "  preSize.height=" + preSize.height);
            parameters.setPreviewSize(preSize.width, preSize.height);
        }
        parameters.setJpegQuality(100); // 设置照片质量
        if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 连续对焦模式
        }
        mCamera.cancelAutoFocus();//自动对焦。
        mCamera.setDisplayOrientation(90);// 设置PreviewDisplay的方向,效果就是将捕获的画面旋转多少度显示
        mCamera.setParameters(parameters);

    }

    private MainHandler mainHandler = new MainHandler();

    private void startGoogleDetect() {
        Camera.Parameters parameters =mCamera.getParameters();
        if (parameters.getMaxNumDetectedFaces() > 0) {
            if (faceView != null) {
                faceView.clearFaces();
                faceView.setVisibility(View.VISIBLE);
            }
            mCamera.setFaceDetectionListener(new GoogleDetectListenerImpl(AutioTakePhotoActivity.this, mainHandler));
            mCamera.startFaceDetection();
        }
    }
    private class MainHandler extends Handler {

        @Override
        public void handleMessage(final Message msg) {
            int what = msg.what;
            switch (what) {
                case 1:
                    startGoogleDetect();
                    Log.e("renlei110", "开启人脸识别");
                    break;
                case 2:
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Camera.Face[] faces = (Camera.Face[]) msg.obj;
                            faceView.setFaces(faces);
                            Log.e("renlei111", "收到人脸识别的信息");
                        }
                    });

                    break;
            }
            super.handleMessage(msg);
        }
    }

    /**
     * 从列表中选取合适的分辨率
     * 默认w:h = 4:3
     * <p>注意:这里的w对应屏幕的height
     *            h对应屏幕的width<p/>
     */
    private Camera.Size getProperSize(List<Camera.Size> pictureSizeList, float screenRatio) {
        Log.i("zjun", "screenRatio=" + screenRatio);
        Camera.Size result = null;
        for (Camera.Size size : pictureSizeList) {
            float currentRatio = ((float) size.width) / size.height;
            if (currentRatio - screenRatio == 0) {
                result = size;
                break;
            }
        }

        if (null == result) {
            for (Camera.Size size : pictureSizeList) {
                float curRatio = ((float) size.width) / size.height;
                if (curRatio == 4f / 3) {// 默认w:h = 4:3
                    result = size;
                    break;
                }
            }
        }

        return result;
    }

}
//上面类对应布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <SurfaceView
    android:id="@+id/surfaceview"
    android:layout_width="match_parent"
    android:visibility="visible"
    android:layout_height="match_parent" />
    <TextView
    android:id="@+id/take"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="15dp"
    android:onClick="take"
    android:text="拍照"
    android:background="@android:color/holo_green_light"
    android:layout_centerHorizontal="true"
    android:layout_alignParentBottom="true"/>
    <TextView
        android:id="@+id/turn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="15dp"
        android:onClick="turn"
        android:text="前置/后置"
        android:background="@android:color/holo_green_light"
        android:layout_centerHorizontal="true"/>
    <com.example.auto_take_picture.FaceView
        android:id="@+id/face_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone"
        ></com.example.auto_take_picture.FaceView>
    <RelativeLayout
        android:id="@+id/result"
        android:layout_width="match_parent"
        android:background="#222"
        android:visibility="gone"
        android:layout_height="match_parent">
        <ImageView
            android:id="@+id/image"
            android:layout_width="match_parent"
            android:layout_alignParentTop="true"
            android:layout_height="match_parent" />
        <TextView
            android:id="@+id/finish"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="15dp"
            android:onClick="finish"
            android:text="完成"
            android:background="@android:color/holo_green_light"
            android:layout_alignParentBottom="true"/>

        <TextView
            android:id="@+id/cancle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="15dp"
            android:onClick="cancle"
            android:text="取消"
            android:layout_alignParentRight="true"
            android:background="@android:color/holo_green_light"
            android:layout_alignParentBottom="true"/>
    </RelativeLayout>

</RelativeLayout>



//FaceView 类用来绘制人脸识别的方框

package com.example.auto_take_picture;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.hardware.Camera;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;

/**
 * Created by Administrator on 2017/5/9 0009.
 */
public class FaceView extends ImageView {
    private Context mContext;
    private Camera.Face[] mFaces;
    private Matrix mMatrix = new Matrix();
    private boolean mirror;
    private Paint mLinePaint;


    public FaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initPaint();
        this.mContext = context;
    }

    public void setFaces(Camera.Face[] faces) {
        this.mFaces = faces;
        invalidate();
    }
    public void clearFaces(){
        mFaces = null;
        invalidate();
    }
    @Override
    protected void onDraw(Canvas canvas) {
        if(mFaces == null || mFaces.length < 1){
            return;
        }
        if (mFaces != null&&mFaces.length>=1) {
            canvas.translate(getWidth()/2,getHeight()/2);
            canvas.rotate(-0);
            mirror=(AutioTakePhotoActivity.cameraId== Camera.CameraInfo.CAMERA_FACING_FRONT) ;
            Log.e("mFaces","mFaces"+mFaces.length);
            for (int i = 0; i < mFaces.length; i++) {
                Camera.Face face= mFaces[i];
                int width=face.rect.right-face.rect.left;
                int  needWidth=getWidth()*width/2000;
                if(!mirror){
                    int cx = -face.rect.centerY(); //因为之前对camera做了旋转,所以这里需要转换一下坐   //后置摄像头
                    int cy = face.rect.centerX();
                    RectF rectF = new RectF(getWidth()*cx/2000f-needWidth/2,getHeight()*cy/2000f-needWidth/2,getWidth()*cx/2000f+needWidth/2,getHeight()*cy/2000f+needWidth/2);
                    canvas.drawRect(rectF,mLinePaint);
                }else{
                    int cx = -face.rect.centerY(); //因为之前对camera做了旋转,所以这里需要转换一下坐  //前置摄像头
                    int cy = -face.rect.centerX();
                    RectF rectF = new RectF(getWidth()*cx/2000f-needWidth/2,getHeight()*cy/2000f-needWidth/2,getWidth()*cx/2000f+needWidth/2,getHeight()*cy/2000f+needWidth/2);
                    canvas.drawRect(rectF,mLinePaint);
                }
            }
        }
        super.onDraw(canvas);
    }



    /**
     * <p>Here is the matrix to convert driver coordinates to View coordinates
     * in pixels.</p>
     * <pre>
     * Matrix matrix = new Matrix();
     * CameraInfo info = CameraHolder.instance().getCameraInfo()[cameraId];
     * // Need mirror for front camera.
     * boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
     * matrix.setScale(mirror ? -1 : 1, 1);
     * // This is the value for android.hardware.Camera.setDisplayOrientation.
     * matrix.postRotate(displayOrientation);
     * // Camera driver coordinates range from (-1000, -1000) to (1000, 1000).
     * // UI coordinates range from (0, 0) to (width, height).
     * matrix.postScale(view.getWidth() / 2000f, view.getHeight() / 2000f);
     * matrix.postTranslate(view.getWidth() / 2f, view.getHeight() / 2f);
     * </pre>
     */
    private void prepareMatrix() {
        mMatrix.setScale(mirror ? -1 : 1, 1);
        mMatrix.postRotate(9);
        mMatrix.postScale(getWidth() / 2000f, getHeight() / 2000f);
        mMatrix.postTranslate(getWidth() / 2f, getHeight() / 2f);
    }

    private void initPaint() {
        mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//      int color = Color.rgb(0, 150, 255);
        int color = Color.rgb(98, 212, 68);
//      mLinePaint.setColor(Color.RED);
        mLinePaint.setColor(color);
        mLinePaint.setStyle(Paint.Style.STROKE);
        mLinePaint.setStrokeWidth(5f);
        mLinePaint.setAlpha(180);
    }
}

《完。。》很简单的三个类,不怎么写文章,也不知道怎么说,如果发现有坑,恭候怼我。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值