Android 原生人脸检测,只是检测

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.SurfaceTexture;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.media.FaceDetector;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import android.view.WindowManager;


import java.io.ByteArrayOutputStream;
import java.util.List;

public class MyFaceDetectorView extends TextureView implements TextureView.SurfaceTextureListener {
    private static final String TAG = MyFaceDetectorView.class.getName();


    protected Camera mCamera;
    private int mPreviewFormat = ImageFormat.NV21;

    public MyFaceDetectorView(Context context) {
        super(context);
        init();
    }

    public MyFaceDetectorView(Context context,AttributeSet attrs) {
        super(context,attrs);
        init();
    }

    public MyFaceDetectorView(Context context,AttributeSet attrs,int defStyleAttr) {
        super(context,attrs,defStyleAttr);
        init();
    }

    public List<Camera.Size> getSupportedSizes() {
        if (null != mCamera) {
            return mCamera.getParameters().getSupportedPreviewSizes();
        }
        return null;
    }

    private int mCameraIndex = 0;

    private void init() {
        this.setSurfaceTextureListener(this);
    }


    protected boolean initializeCamera(int width,int height) {
        Log.e(TAG,"Initialize java camera wh = " + width + "x" + height);
        boolean result = true;
        synchronized (this) {
            mCamera = null;

            if (mCameraIndex == -1) {
                Log.e(TAG,"Trying to open camera with old open()");
                try {
                    mCamera = Camera.open();
                } catch (Exception e) {
                    Log.e(TAG,"Camera is not available (in use or does not exist): " + e.getLocalizedMessage());
                }

                if (mCamera == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
                    boolean connected = false;
                    for (int camIdx = 0;camIdx < Camera.getNumberOfCameras();++camIdx) {
                        Log.e(TAG,"Trying to open camera with new open(" + Integer.valueOf(camIdx) + ")");
                        try {
                            mCamera = Camera.open(camIdx);
                            connected = true;
                        } catch (RuntimeException e) {
                            Log.e(TAG,"Camera #" + camIdx + "failed to open: " + e.getLocalizedMessage());
                        }
                        if (connected) break;
                    }
                }
            } else {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
                    int localCameraIndex = mCameraIndex;
                    if (mCameraIndex == Camera.CameraInfo.CAMERA_FACING_BACK) {
                        Log.e(TAG,"Trying to open back camera");
                        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
                        for (int camIdx = 0;camIdx < Camera.getNumberOfCameras();++camIdx) {
                            Camera.getCameraInfo(camIdx,cameraInfo);
                            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                                localCameraIndex = camIdx;
                                break;
                            }
                        }
                    } else if (mCameraIndex == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                        Log.e(TAG,"Trying to open front camera");
                        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
                        for (int camIdx = 0;camIdx < Camera.getNumberOfCameras();++camIdx) {
                            Camera.getCameraInfo(camIdx,cameraInfo);
                            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                                localCameraIndex = camIdx;
                                break;
                            }
                        }
                    }
                    if (localCameraIndex == 99) {
                        Log.e(TAG,"Back camera not found!");
                    } else if (localCameraIndex == 98) {
                        Log.e(TAG,"Front camera not found!");
                    } else {
                        Log.e(TAG,"Trying to open camera with new open(" + Integer.valueOf(localCameraIndex) + ")");
                        try {
                            mCamera = Camera.open(localCameraIndex);
                        } catch (RuntimeException e) {
                            Log.e(TAG,"Camera #" + localCameraIndex + "failed to open: " + e.getLocalizedMessage());
                        }
                    }
                }
            }

            if (mCamera == null)
                return false;

            /* Now set camera parameters */
            try {
                Camera.Parameters params = mCamera.getParameters();
                Log.e(TAG,"getSupportedPreviewSizes()");
                List<Camera.Size> sizes = params.getSupportedPreviewSizes();

                if (sizes != null) {
                    /* Select the size that fits surface considering maximum size allowed */
                    Size frameSize = calculateCameraFrameSize(sizes,new JavaCameraSizeAccessor(),width,height);

                    /* Image format NV21 causes issues in the Android emulators */
                    if (Build.FINGERPRINT.startsWith("generic")
                            || Build.FINGERPRINT.startsWith("unknown")
                            || Build.MODEL.contains("google_sdk")
                            || Build.MODEL.contains("Emulator")
                            || Build.MODEL.contains("Android SDK built for x86")
                            || Build.MANUFACTURER.contains("Genymotion")
                            || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
                            || "google_sdk".equals(Build.PRODUCT))
                        params.setPreviewFormat(ImageFormat.YV12);  // "generic" or "android" = android emulator
                    else
                        params.setPreviewFormat(ImageFormat.NV21);

                    mPreviewFormat = params.getPreviewFormat();

                    Log.e(TAG,"Set preview size to " + Integer.valueOf((int)frameSize.width) + "x" + Integer.valueOf((int)frameSize.height));
                    params.setPreviewSize((int)frameSize.width,(int)frameSize.height);

                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && !Build.MODEL.equals("GT-I9100"))
                        params.setRecordingHint(true);

                    List<String> FocusModes = params.getSupportedFocusModes();
                    if (FocusModes != null && FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
                        params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
                    }

                    mCamera.setParameters(params);

                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
//                        mSurfaceTexture = new SurfaceTexture();
                        mCamera.setPreviewTexture(MyFaceDetectorView.this.getSurfaceTexture());
                    } else
                        mCamera.setPreviewDisplay(null);

                    setFaceDetectCallback();
                    /* Finally we are ready to start the preview */
                    Log.e(TAG,"startPreview");
                    mCamera.startPreview();
                } else
                    result = false;
            } catch (Exception e) {
                result = false;
                e.printStackTrace();
            }
        }

        return result;
    }

    public void releaseCamera() {
        synchronized (this) {
            if (mCamera != null) {
                mCamera.stopPreview();
                mCamera.setPreviewCallback(null);
                mCamera.lock();
                mCamera.release();
            }
            mCamera = null;
        }
    }

    private static final int MAX_UNSPECIFIED = -1;
    protected int mMaxHeight = 1080;
    protected int mMaxWidth = 1920;

    /**
     * This helper method can be called by subclasses to select camera preview size.
     * It goes over the list of the supported preview sizes and selects the maximum one which
     * fits both values set via setMaxFrameSize() and surface frame allocated for this view
     *
     * @param supportedSizes
     * @param surfaceWidth
     * @param surfaceHeight
     * @return optimal frame size
     */
    protected Size calculateCameraFrameSize(List<?> supportedSizes,ListItemAccessor accessor,int surfaceWidth,int surfaceHeight) {
        int calcWidth = 0;
        int calcHeight = 0;

        int maxAllowedWidth = (mMaxWidth != MAX_UNSPECIFIED && mMaxWidth < surfaceWidth) ? mMaxWidth : surfaceWidth;
        int maxAllowedHeight = (mMaxHeight != MAX_UNSPECIFIED && mMaxHeight < surfaceHeight) ? mMaxHeight : surfaceHeight;

        for (Object size : supportedSizes) {
            int width = accessor.getWidth(size);
            int height = accessor.getHeight(size);

            if (width <= maxAllowedWidth && height <= maxAllowedHeight) {
                if (width >= calcWidth && height >= calcHeight) {
                    calcWidth = (int)width;
                    calcHeight = (int)height;
                }
            }
        }

        return new Size(calcWidth,calcHeight);
    }

    public static class JavaCameraSizeAccessor implements ListItemAccessor {

        @Override
        public int getWidth(Object obj) {
            Camera.Size size = (Camera.Size)obj;
            return size.width;
        }

        @Override
        public int getHeight(Object obj) {
            Camera.Size size = (Camera.Size)obj;
            return size.height;
        }
    }

    public interface ListItemAccessor {
        int getWidth(Object obj);

        int getHeight(Object obj);
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface,int width,int height) {
        initializeCamera(getWidth(),getHeight());
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface,int width,int height) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        releaseCamera();
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {

    }


    //人脸检测-start---------
    /**
     * 最大检测的人脸数
     */
    private int numberOfFace = 5;
    /**
     * 人脸识别类的实例
     */
    private FaceDetector myFaceDetect;  //
    /**
     * 存储多张人脸的数组变量
     */
    private FaceDetector.Face[] myFace; //
    /**
     * 两眼之间的距离
     */
    float myEyesDistance;           //
    /**
     * 实际检测到的人脸数
     */
    int numberOfFaceDetected;       //
    private long mScanBeginTime = 0;   // 扫描开始时间
    private long mScanEndTime = 0;   // 扫描结束时间
    private long mSpecPreviewTime = 0;   // 扫描持续时间

    /**
     * 摄像头的安装旋转角度
     */
    private int orientionOfCamera;   //

//    private void initFace() {
//        myFaceDetect = new FaceDetector(getWidth(),getHeight(),numberOfFace);
//        myFace = new FaceDetector.Face[numberOfFace];       //分配人脸数组空间
//        BitmapFactory.Options BitmapFactoryOptionsbfo = new BitmapFactory.Options();
//        BitmapFactoryOptionsbfo.inPreferredConfig = Bitmap.Config.RGB_565;  //构造位图生成的参数,必须为565。类名+enum
//        numberOfFaceDetected = myFaceDetect.findFaces(myBitmap, myFace);    //FaceDetector 构造实例并解析人脸
//        Log.i(TAG,"numberOfFaceDetected is " + numberOfFaceDetected);
//    }
    OnFaceDetectorListener mOnFaceDetectorListener;
    public interface OnFaceDetectorListener {
        void onDetectored();
    }
    public void setOnFaceDetectorListener(OnFaceDetectorListener mOnFaceDetectorListener) {
        this.mOnFaceDetectorListener = mOnFaceDetectorListener;
    }

    /**
     * 设置预览回调
     */
    private void setFaceDetectCallback() {
        Camera.Parameters parameters = mCamera.getParameters();
        setCameraDisplayOrientation(0,mCamera);              //设置预览方向

        mCamera.setPreviewCallback(new Camera.PreviewCallback() {
            public void onPreviewFrame(byte[] data,Camera camera) {
                cameraFrame2Img(data,camera);
            }
        });
    }

    /**
     * 开始检测
     */
    private void cameraFrame2Img(byte[] data,Camera camera) {
        Log.i(TAG,"startFaceDetection");

        mScanEndTime = System.currentTimeMillis();   //记录摄像头返回数据的时间
        mSpecPreviewTime = mScanEndTime - mScanBeginTime;  //从onPreviewFrame获取摄像头数据的时间
        Log.i(TAG,"onPreviewFrame and mSpecPreviewTime = " + String.valueOf(mSpecPreviewTime));
        Camera.Size localSize = camera.getParameters().getPreviewSize();  //获得预览分辨率
        YuvImage localYuvImage = new YuvImage(data,17,localSize.width,localSize.height,null);
        ByteArrayOutputStream localByteArrayOutputStream = new ByteArrayOutputStream();
        localYuvImage.compressToJpeg(new android.graphics.Rect(0,0,localSize.width,localSize.height)
                ,90,localByteArrayOutputStream);    //把摄像头回调数据转成YUV,再按图像尺寸压缩成JPEG,从输出流中转成数组
        byte[] arrayOfByte = localByteArrayOutputStream.toByteArray();
//                releaseCamera();   //及早释放camera资源,避免影响camera设备的正常调用
        storeByteImage(arrayOfByte);

//        mCamera.startPreview();         //该语句可放在回调后面,当执行到这里,调用前面的setPreviewCallback
        mScanBeginTime = System.currentTimeMillis();// 记录下系统开始扫描的时间
    }

    /**
     * 设置预览方向的函数说明,该函数比较重要,因为方向直接影响bitmap构造时的矩阵旋转角度,影响最终人脸识别的成功与否
     * 获得摄像头的安装旋转角度
     */
    public void setCameraDisplayOrientation(int cameraId,Camera paramCamera) {
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId,info);
        int rotation = ((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE))
                .getDefaultDisplay().getRotation();  //获得显示器件角度
        int degrees = 0;
        Log.e(TAG,"getRotation's rotation is " + String.valueOf(rotation));
        switch (rotation) {
            case Surface.ROTATION_0:
                degrees = 0;
                break;
            case Surface.ROTATION_90:
                degrees = 90;
                break;
            case Surface.ROTATION_180:
                degrees = 180;
                break;
            case Surface.ROTATION_270:
                degrees = 270;
                break;
        }

        orientionOfCamera = info.orientation;      //获得摄像头的安装旋转角度
        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        } else {  // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }
        paramCamera.setDisplayOrientation(result);  //注意前后置的处理,前置是映象画面,该段是SDK文档的标准DEMO
    }

    long mSpecStopTime;
    long mSpecCameraTime ;
    public void storeByteImage(byte[] paramArrayOfByte) {
        mSpecStopTime = System.currentTimeMillis();
        mSpecCameraTime = mSpecStopTime - mScanBeginTime;

        Log.i(TAG,"StoreByteImage and mSpecCameraTime is " + String.valueOf(mSpecCameraTime));

        BitmapFactory.Options localOptions = new BitmapFactory.Options();
        Bitmap localBitmap1 = BitmapFactory.decodeByteArray(paramArrayOfByte,0,paramArrayOfByte.length,localOptions);
        int i = localBitmap1.getWidth();
        int j = localBitmap1.getHeight();   //从上步解出的JPEG数组中接出BMP,即RAW->JPEG->BMP
        Matrix localMatrix = new Matrix();
        //int k = cameraResOr;
        Bitmap localBitmap2 = null;
        FaceDetector localFaceDetector = null;
        Log.e(TAG,"StoreByteImage orientionOfCamera is " +orientionOfCamera);
        switch (orientionOfCamera) {   //根据前置安装旋转的角度来重新构造BMP
            case 0:
                localFaceDetector = new FaceDetector(i,j,1);
                localMatrix.postRotate(0.0F,i / 2,j / 2);
                localBitmap2 = Bitmap.createBitmap(i,j,Bitmap.Config.RGB_565);
                break;
            case 90:
                localFaceDetector = new FaceDetector(j,i,1);   //长宽互换
                localMatrix.postRotate(-270.0F,j / 2,i / 2);  //正90度的话就反方向转270度,一样效果
                localBitmap2 = Bitmap.createBitmap(j,i,Bitmap.Config.RGB_565);
//                localFaceDetector = new FaceDetector(j,i,1);   //长宽互换
//                localMatrix.postRotate(-270.0F,j / 2,i / 2);  //正90度的话就反方向转270度,一样效果
//                localBitmap2 = Bitmap.createBitmap(i,j,Bitmap.Config.RGB_565);
                break;
            case 180:
                localFaceDetector = new FaceDetector(i,j,1);
                localMatrix.postRotate(-180.0F,i / 2,j / 2);
                localBitmap2 = Bitmap.createBitmap(i,j,Bitmap.Config.RGB_565);
                break;
            case 270:
                localFaceDetector = new FaceDetector(j,i,1);
                localMatrix.postRotate(-90.0F,j / 2,i / 2);
                localBitmap2 = Bitmap.createBitmap(j,i,Bitmap.Config.RGB_565);  //localBitmap2应是没有数据的
                break;
        }

        FaceDetector.Face[] arrayOfFace = new FaceDetector.Face[1];
        Paint localPaint1 = new Paint();
        Paint localPaint2 = new Paint();
        localPaint1.setDither(true);
        localPaint2.setColor(Color.GREEN);
        localPaint2.setStyle(Paint.Style.STROKE);
        localPaint2.setStrokeWidth(4.0F);
        Canvas localCanvas = new Canvas();
        localCanvas.setBitmap(localBitmap2);
        localCanvas.setMatrix(localMatrix);
        localCanvas.drawBitmap(localBitmap1,0.0F,0.0F,localPaint1); //该处将localBitmap1和localBitmap2关联(可不要?)

        numberOfFaceDetected = localFaceDetector.findFaces(localBitmap2,arrayOfFace); //返回识脸的结果
        localBitmap2.recycle();
        localBitmap1.recycle();   //释放位图资源

        if (numberOfFaceDetected > 0) {
            if (null != mOnFaceDetectorListener) {
                mOnFaceDetectorListener.onDetectored();
            }
        }

//        FaceDetectDeal(numberOfFaceDetected);
    }

    public static class Size {

        public double width, height;

        public Size(double width, double height) {
            this.width = width;
            this.height = height;
        }

        public Size() {
            this(0, 0);
        }

//        public Size(Point p) {
//            width = p.x;
//            height = p.y;
//        }

        public Size(double[] vals) {
            set(vals);
        }

        public void set(double[] vals) {
            if (vals != null) {
                width = vals.length > 0 ? vals[0] : 0;
                height = vals.length > 1 ? vals[1] : 0;
            } else {
                width = 0;
                height = 0;
            }
        }

        public double area() {
            return width * height;
        }

        public boolean empty() {
            return width <= 0 || height <= 0;
        }

        public org.opencv.core.Size clone() {
            return new org.opencv.core.Size(width, height);
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            long temp;
            temp = Double.doubleToLongBits(height);
            result = prime * result + (int) (temp ^ (temp >>> 32));
            temp = Double.doubleToLongBits(width);
            result = prime * result + (int) (temp ^ (temp >>> 32));
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (!(obj instanceof org.opencv.core.Size)) return false;
            org.opencv.core.Size it = (org.opencv.core.Size) obj;
            return width == it.width && height == it.height;
        }

        @Override
        public String toString() {
            return (int)width + "x" + (int)height;
        }

    }

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343