JavaCV-FaceDetect

Android end based on JavaCV to achieve face detection function

Realize the function

  • Face detection: FaceDetectCameraView
  • Automatic network request after face detection: FaceDetectRequestDialog

Project introduction Framework

  • javacv
  • CameraView
  • okhttp
  • LoadingDialog

Results show

FaceDetectCameraView effect

FaceDetectRequestDialog effect

The introduction of

Add the JitPack repository to your project (build.gradle file in the project root directory)

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

Add the dependent

Add to build.gradle where you import the project

android {
    ...
    defaultConfig {
        ...
        ndk {
            Armeabi-v7a, arm64-V8A, armeabi-v7A, arm64-V8A
            abiFilters 'armeabi-v7a'.'arm64-v8a'}}// Resolve file duplication in 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. Making. Shenbengit: JavaCV - FaceDetect: 0.0.5'
}
Copy the code

Use case

  • FaceDetectCameraView

Sample layout

    <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" />
Copy the code

Layout instructions

    <declare-styleable name="FaceDetectCameraView">
        <! -- Camera type, 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" />

        <! - cascade classifier, default: R.r aw. Haarcascade_frontalface_alt - >
        <attr name="fdv_classifierFileRaw" format="reference" />

        <! Default :true-->
        <attr name="fdv_drawFaceRect" format="boolean" />
        <! -- Draw the Color of the face frame, default: color.green -->
        <attr name="fdv_faceRectStrokeColor" format="color" />
        <! Draw the width of the face frame -->
        <attr name="fdv_faceRectStrokeWidth" format="dimension" />

    </declare-styleable>
Copy the code

Code sample

FaceDetectCameraView fdv = findViewById(R.id.fdv);
// Set the camera callback
fdv.setOnCameraListener(new OnCameraListener() {
    @Override
    public void onCameraOpened(a) {}@Override
    public void onCameraClosed(a) {}@Override
    public void onCameraError(@NonNull CameraException exception) {}});// Set the face detection related callback interface
fdv.setOnFaceDetectListener(new OnFaceDetectListener() {
    /** * The child thread will call ** when a person is detected in the camera's preview frame@param data         nv21
     * @param width        camera frame width
     * @param height       camera frame height
     * @paramFaceRectList Face position data */
    @WorkerThread
    @Override
    public void somebodyFrame(byte[] data, int width, int height, List<Rect> faceRectList) {}/** * detects that someone will call once, and {@linkOnFaceDetectListener#somebody()} with the * child thread call * *@param data         nv21
     * @param width        camera frame width
     * @param height       camera frame height
     * @paramFaceRectList Face position data */
    @WorkerThread
    @Override
    public void somebodyFirstFrame(byte[] data, int width, int height, List<Rect> faceRectList) {
        if(! faceRectList.isEmpty()) { Rect rect = faceRectList.get(0);
            // Crop the faceBitmap cropBitmap = Nv21ToBitmapUtil.cropNv21ToBitmap(data, width, height, rect); Bitmap bitmap = Nv21ToBitmapUtil.nv21ToBitmap(data, width, height); }}/** * the first time someone is detected */ is called
    @MainThread
    @Override
    public void somebody(a) {}/** * call */ for the first time when no one is detected
    @MainThread
    @Override
    public void nobody(a) {}});// Set the camera preview resolution
fdv.setPreviewStreamSize(source -> Collections.singletonList(new Size(1280.720)));
// Set the camera
fdv.setCameraFacing(Facing.BACK);
// Set whether to keep only the largest face
fdv.setKeepMaxFace(true);
// Whether to mirror the preview
fdv.setPreviewMirror(false);
// Set whether to detect region limits. Note: The current limit is whether the face is complete in the preview View
fdv.setDetectAreaLimited(true);
// Whether to draw a face frame
fdv.setDrawFaceRect(true);
// Set the color of the face frame
fdv.setFaceRectStrokeColor(Color.GREEN);
// Set the width of the face frame
fdv.setFaceRectStrokeWidth(2f);
// Retry the operation
fdv.needRetry();
// Delay the retry operation
fdv.needRetryDelay(1000L);

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

Copy the code
  • FaceDetectRequestDialog

Code sample

FaceDetectRequestDialog dialog = FaceDetectRequestDialog.builder(this.new RequestDialogLayoutCallback() {
                    /** * set {@link FaceDetectRequestDialog#setContentView(int)}
                     *
                     * @return* /
                    @Override
                    public int getLayoutId(a) {
                        return R.layout.dialog_face_detect_request;
                    }
                    
                    /** * set {@link RequestDialogLayoutCallback#getLayoutId()} 中 {@link FaceDetectCameraView}的id
                     *
                     * @return* /
                    @Override
                    public int getFaceDetectCameraViewId(a) {
                        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() {
                
                    /** * generate {for network requests@linkOkHttpClient} * automatic call {@link OkHttpClient.Builder#build()}
                     *
                     * @param builder
                     * @return* /
                    @Override
                    @NonNull
                    public OkHttpClient.Builder generateOkhttpClient(OkHttpClient.Builder builder) {
                        return builder;
                    }

                    /** * generate network request {@linkRequest} * Automatic reencapsulation of face photo data * <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 = Nv21ToBitmapUtil.nv21ToBitmap(data, width, height);
// Bitmap bitmap = Nv21ToBitmapUtil.cropNv21ToBitmap(data, width, height, faceRectList.get(0));
                        if(bitmap ! =null) {
                            String base64 = Nv21ToBitmapUtil.bitmapToBase64(bitmap, 100);
                            RequestFaceBean bean = new RequestFaceBean("imagecompare", base64);
                            RequestBody body = RequestBody.create(MediaType.parse("application/json"), GsonUtil.toJson(bean));
                            builder.url("http://192.168.2.186:25110")
                                    .post(body);
                        }
                        return builder;
                    }

                    @Override
                    public void onRequestStart(a) {}@Override
                    public void onRequestFailure(Exception e) {
                        Toast.makeText(MainActivity.this."Face recognition Error:" + e.getMessage(), Toast.LENGTH_SHORT).show();
                        dialog.needRetryDelay(2000L);
                    }

                    @Override
                    public void onRequestSuccess(String bodyStr) {
                        ResultBean resultBean = GsonUtil.jsonToBean(bodyStr, ResultBean.class);
                        if (resultBean.getResCode() == 1) {
                            Toast.makeText(MainActivity.this."Face recognition success :" + resultBean.getData().getUserName(), Toast.LENGTH_SHORT).show();
                        } else {
                            Toast.makeText(MainActivity.this."Face recognition failure.", Toast.LENGTH_SHORT).show();
                            dialog.needRetryDelay(2000L);
                        }
                    }
                })
                .setPreviewSizeSelector(source -> Collections.singletonList(new Size(1280.720)))
                .setShowLoadingDialog(true)
                .setCameraListener(exception -> Toast.makeText(MainActivity.this."Abnormal camera startup:" + exception.getMessage(), Toast.LENGTH_SHORT).show())
                .setAnybodyCallback(new AnybodyCallback() {
                    @Override
                    public void somebody(a) {
                        System.out.println("Someone -- - >");
                    }

                    @Override
                    public void nobody(a) {
                        System.out.println("No one -- - >");
                    }
                }).build();

dialog.show();
dialog.dismiss();//dialog.cancel();
dialog.destroy();
Copy the code
  • Nv21ToBitmapUtil

Nv21 to Bitmap utility class

/ / Bitmap base64
Nv21ToBitmapUtil.bitmapToBase64(@Nullable Bitmap bitmap, int quality);
/ / nv21 Bitmap
Nv21ToBitmapUtil.nv21ToBitmap(@NonNull byte[] nv21, int width, int height);
// Nv21 crop to Bitmap, note: there will be a secondary conversion, the crop image is slightly larger than the location matrix
Nv21ToBitmapUtil.cropNv21ToBitmap(@NonNull byte[] nv21, int width, int height, Rect rect);
Copy the code

Making portal