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