1 Star 0 Fork 4

liupen / JavaCV-FaceDetect

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
README.md 14.49 KB
一键复制 编辑 原始数据 按行查看 历史
冬季穿短裤 提交于 2021-07-19 17:18 . Update README.md

JavaCV-FaceDetect

Android端基于JavaCV实现人脸检测功能

目前仅支持摄像机预览角度为0°

实现功能

项目引入框架

效果展示

FaceDetectCameraView运行效果

FaceDetectCameraView动图演示效果

FaceDetectRequestDialog运行效果

FaceDetectCameraView动图演示效果

引入

将JitPack存储库添加到您的项目中(项目根目录下build.gradle文件)

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

添加依赖

在您引入项目的build.gradle中添加

android {
    ...
    defaultConfig {
        ...
        ndk {
            // 设置支持的SO库架构,仅支持armeabi-v7a、arm64-v8a,若想减小APK体积,可只引用对应的SO库架构
            abiFilters 'armeabi-v7a', 'arm64-v8a'
        }
    }
    
    //解决JavaCV中文件重复问题
    packagingOptions {
        pickFirst 'META-INF/native-image/android-arm/jnijavacpp/jni-config.json'
        pickFirst 'META-INF/native-image/android-arm64/jnijavacpp/jni-config.json'
        pickFirst 'META-INF/native-image/android-arm/jnijavacpp/reflect-config.json'
        pickFirst 'META-INF/native-image/android-arm64/jnijavacpp/reflect-config.json'
    }
}

dependencies {
    implementation 'com.github.shenbengit:JavaCV-FaceDetect:Tag'
}

使用事例

  • FaceDetectCameraView

布局示例

    <com.shencoder.javacv_facedetect.FaceDetectCameraView
        android:id="@+id/fdv"
        android:layout_width="match_parent"
        android:layout_height="500dp"
        app:fdv_cameraFacing="back"
        app:fdv_classifierFileRaw="@raw/haarcascade_frontalface_alt"
        app:fdv_detectAreaLimited="true"
        app:fdv_drawFaceRect="true"
        app:fdv_faceRectStrokeColor="@color/design_default_color_error"
        app:fdv_faceRectStrokeWidth="3dp"
        app:fdv_keepMaxFace="true"
        app:fdv_previewMirror="true" />

布局说明

    <declare-styleable name="FaceDetectCameraView">
        <!--摄像头类型,default:back-->
        <attr name="fdv_cameraFacing" format="enum">
            <enum name="back" value="0" />
            <enum name="front" value="1" />
        </attr>
        <!--是否仅检测最大人脸,default:true-->
        <attr name="fdv_keepMaxFace" format="boolean" />
        <!--预览画面是否镜像,default:false-->
        <attr name="fdv_previewMirror" format="boolean" />
        <!--是否限制检测区域,default:true-->
        <attr name="fdv_detectAreaLimited" format="boolean" />

        <!--级联分类器,default:R.raw.haarcascade_frontalface_alt-->
        <attr name="fdv_classifierFileRaw" format="reference" />

        <!--是否绘制人脸框,default:true-->
        <attr name="fdv_drawFaceRect" format="boolean" />
        <!--绘制人脸框的颜色,default:Color.GREEN-->
        <attr name="fdv_faceRectStrokeColor" format="color" />
        <!--绘制人脸框的宽度-->
        <attr name="fdv_faceRectStrokeWidth" format="dimension" />

    </declare-styleable>

代码示例

FaceDetectCameraView fdv = findViewById(R.id.fdv);
//设置摄像头相关回调
fdv.setOnCameraListener(new OnCameraListener() {
    @Override
    public void onCameraOpened() {

    }

    @Override
    public void onCameraClosed() {

    }

    @Override
    public void onCameraError(@NonNull CameraException exception) {

    }
});
//设置人脸检测相关回调接口
fdv.setOnFaceDetectListener(new OnFaceDetectListener() {
    /**
     * 摄像头的预览帧画面里检测到人就会调用
     * 子线程调用
     *
     * @param data         nv21
     * @param width        camera frame width
     * @param height       camera frame height
     * @param faceRectList 人脸位置数据
     */
    @WorkerThread
    @Override
    public void somebodyFrame(byte[] data, int width, int height, List<Rect> faceRectList) {

    }
        
    /**
     * 检测到有人会调用一次,和{@link OnFaceDetectListener#somebody()}一起调用
     * 子线程调用
     *
     * @param data         nv21
     * @param width        camera frame width
     * @param height       camera frame height
     * @param faceRectList 人脸位置数据
     */
    @WorkerThread
    @Override
    public void somebodyFirstFrame(byte[] data, int width, int height, List<Rect> faceRectList) {
        Bitmap bitmap = Nv21Util.nv21ToBitmap(data, width, height);
        if (!faceRectList.isEmpty()) {
            Rect rect = faceRectList.get(0);
            //剪裁人脸
            Bitmap cropBitmap = Nv21Util.cropNv21ToBitmap(data, width, height, rect);
         }
    }
        
    /**
     * 首次检测到有人时调用一次
     */
    @MainThread
    @Override
    public void somebody() {

    }
        
    /**
     * 首次检测到无人时调用一次
     */
    @MainThread
    @Override
    public void nobody() {

    }
});

//设置相机预览分辨率
fdv.setPreviewStreamSize(source -> Collections.singletonList(new Size(1280, 720)));
//设置摄像头
fdv.setCameraFacing(Facing.BACK);
//设置是否只保留最大人脸
fdv.setKeepMaxFace(true);
//是否镜像预览
fdv.setPreviewMirror(false);
//设置是否检测区域限制,注意:目前限制的区域是人脸是否完整在预览View显示的画面里
fdv.setDetectAreaLimited(true);
//是否绘制人脸框
fdv.setDrawFaceRect(true);
//设置人脸框颜色
fdv.setFaceRectStrokeColor(Color.GREEN);
//设置人脸框的宽度
fdv.setFaceRectStrokeWidth(2f);
//重试操作
fdv.needRetry();
//延迟重试操作
fdv.needRetryDelay(1000L);
//设置目标检测的级联分类器
fdv.loadClassifierCascade(R.raw.haarcascade_eye, new LoadClassifierCallback() {
    @Override
    public void onSuccess() {
                
    }

    @Override
    public void onError(Exception e) {

    }
});

fdv.setLifecycleOwner(this);
//fdv.open();
//fdv.close();
//fdv.destroy();
  • FaceDetectRequestDialog

代码示例

FaceDetectRequestDialog requestDialog = FaceDetectRequestDialog.builder(this,
                new RequestDialogLayoutCallback() {
                    /**
                     * 设置{@link FaceDetectRequestDialog#setContentView(int)}
                     *
                     * @return
                     */
                    @Override
                    public int getLayoutId() {
                        return R.layout.dialog_face_detect_request;
                    }
                    
                    /**
                     * 设置{@link RequestDialogLayoutCallback#getLayoutId()} 中 {@link FaceDetectCameraView}的id
                     *
                     * @return
                     */
                    @Override
                    public int getFaceDetectCameraViewId() {
                        return R.id.detectCameraView;
                    }
                    
                    /**
                     * init view
                     * (e.g. {@code dialog.findViewById(id)}).
                     *
                     * @param dialog FaceDetectRequestDialog
                     */
                    @Override
                    public void initView(FaceDetectRequestDialog dialog) {
//                        Button btnClose = dialog.findViewById(R.id.btnClose);
                    }

                    /**
                     * Called when the dialog is starting.
                     *
                     * @param dialog FaceDetectRequestDialog
                     */
                    @Override
                    public void onStart(FaceDetectRequestDialog dialog) {

                    }

                    /**
                     * Called when the dialog is starting.
                     *
                     * @param dialog FaceDetectRequestDialog
                     */
                    @Override
                    public void onStop(FaceDetectRequestDialog dialog) {

                    }
                    
                    /**
                     * @param dialog FaceDetectRequestDialog
                     * @see FaceDetectRequestDialog#destroy()
                     */
                    @Override
                    public void onDestroy(FaceDetectRequestDialog dialog) {

                    }
                },
                new RequestCallback() {
                
                    /**
                     * 生成用于网络请求的{@link OkHttpClient}
                     * 自动调用{@link OkHttpClient.Builder#build()}
                     *
                     * @param builder
                     * @return
                     */
                    @Override
                    @NonNull
                    public OkHttpClient.Builder generateOkhttpClient(OkHttpClient.Builder builder) {
                        return builder;
                    }

                    /**
                     * 生成网络请求的{@link Request}
                     * 自行根据人脸照片数据进行二次封装
                     * <p>
                     * 自动调用{@link Request.Builder#build()}
                     *
                     * @param builder
                     * @return
                     */
                    @NonNull
                    @Override
                    public Request.Builder generateRequest(Request.Builder builder, byte[] data, int width, int height, List<Rect> faceRectList) {
                        Bitmap bitmap = Nv21Util.nv21ToBitmap(data, width, height);
//                        Bitmap bitmap = Nv21Util.cropNv21ToBitmap(data, width, height, faceRectList.get(0));
                        if (bitmap != null) {
                            String base64 = BitmapUtil.bitmapToBase64(bitmap, 100);
                            RequestFaceBean bean = new RequestFaceBean("cmd", base64);
                            RequestBody body = RequestBody.create(MediaType.parse("application/json"), GsonUtil.toJson(bean));
                            builder.url("http://xxx:8080")
                                    .post(body);
                        }
                        return builder;
                    }

                    /**
                     * 网络请求开始
                     *
                     * @param dialog FaceDetectRequestDialog
                     */
                    @Override
                    public void onRequestStart(FaceDetectRequestDialog dialog) {

                    }

                    /**
                     * 网络请求失败
                     *
                     * @param e      error
                     * @param dialog FaceDetectRequestDialog
                     */
                    @Override
                    public void onRequestFailure(Exception e, FaceDetectRequestDialog dialog) {
                        Toast.makeText(MainActivity.this, "人脸识别Error:" + e.getMessage(), Toast.LENGTH_SHORT).show();
                        dialog.needRetryDelay(2000L);
                    }

                    /**
                     * 网络请求成功
                     *
                     * @param bodyStr 网络请求返回的String字符串
                     * @param dialog  FaceDetectRequestDialog
                     */
                    @Override
                    public void onRequestSuccess(String bodyStr, FaceDetectRequestDialog dialog) {
                        ResultBean resultBean = GsonUtil.jsonToBean(bodyStr, ResultBean.class);
                        if (resultBean.getResCode() == 1) {
                            Toast.makeText(MainActivity.this, "人脸识别成功:" + resultBean.getData().getUserName(), Toast.LENGTH_SHORT).show();
                        } else {
                            Toast.makeText(MainActivity.this, "人脸识别失败", Toast.LENGTH_SHORT).show();
                            dialog.needRetryDelay(2000L);
                        }
                    }
                })
                .setPreviewSizeSelector(source -> Collections.singletonList(new Size(1280, 720)))
                .setShowLoadingDialog(true)
                .setCameraListener(exception -> Toast.makeText(MainActivity.this, "摄像头开启异常:" + exception.getMessage(), Toast.LENGTH_SHORT).show())
                .setAnybodyCallback(new AnybodyCallback() {
                    @Override
                    public void somebody() {
                        System.out.println("有人--->");
                    }

                    @Override
                    public void nobody() {
                        System.out.println("无人--->");
                    }
                }).build();
                
//重试操作
requestDialog.needRetry();
//延迟重试操作
requestDialog.needRetryDelay(1000L);
//设置目标检测的级联分类器
requestDialog.loadClassifierCascade(R.raw.haarcascade_eye, new LoadClassifierCallback() {
    @Override
    public void onSuccess() {
                
    }

    @Override
    public void onError(Exception e) {

    }
});


requestDialog.show();
requestDialog.dismiss();//requestDialog.cancel();
requestDialog.destroy();
  • Nv21Util

nv21转bitmap工具类

//nv21转Bitmap
Nv21Util.nv21ToBitmap(@NonNull byte[] nv21, int width, int height);
//nv21剪裁转Bitmap,注:会进行二次转换,剪裁出的图片要比提供位置矩阵的略大
Nv21Util.cropNv21ToBitmap(@NonNull byte[] nv21, int width, int height, Rect rect);
  • BitmapUtil
//Bitmap转base64
BitmapUtil.bitmapToBase64(@Nullable Bitmap bitmap, int quality);

级联分类器

基于OpenCV源码

License

马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Java
1
https://gitee.com/lipenug13592/JavaCV-FaceDetect.git
git@gitee.com:lipenug13592/JavaCV-FaceDetect.git
lipenug13592
JavaCV-FaceDetect
JavaCV-FaceDetect
master

搜索帮助

344bd9b3 5694891 D2dac590 5694891