1 Star 0 Fork 4

liupen / JavaCV-FaceDetect

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

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

MIT License Copyright (c) 2021 沈犇 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

Android端基于JavaCV实现人脸检测功能 展开 收起
Java
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Java
1
https://gitee.com/lipenug13592/JavaCV-FaceDetect.git
git@gitee.com:lipenug13592/JavaCV-FaceDetect.git
lipenug13592
JavaCV-FaceDetect
JavaCV-FaceDetect
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891