Android NDK开发——人脸检测与静默活体检测
前言
1.開發(fā)環(huán)境是win10,IDE是Android studio 北極狐,用到的庫有NCNN,OpenCV。
2.NCNN庫可以用官方編譯好的releases庫,也可以按官方文檔自己編譯。
3.OpenCV用的是nihui大佬簡化過的opencv-mobile,大小只有10多M,如果不嫌大也可以用OpenCV官方的版本。
4.項目的各種依賴版本:
一、人臉檢測
人臉活體檢測的前提條件是先檢測到當(dāng)前的畫面是否存在人臉,這里用的人臉檢測用的yolov5-face,yolov5-face是一種實時、高精度的人臉檢測,搭配NCNN在安卓上(華為Mate 30 pro)cpu 能跑出18 FPS左右,GPU能跑出25 FPS。算法源碼地址:https://github.com/deepcam-cn/yolov5-face 。論文地址:https://arxiv.org/abs/2105.12931 。
二、活體檢測
1、人臉活體檢測是用來檢測當(dāng)前攝像頭所檢測到的人臉是否是偽造的,是人臉驗證和人臉識別的前提條件,如果不能檢測出來是否是活體,那么就會出現(xiàn)比如常見用照片,人臉面具,3D人像等其他媒介來騙過人臉識別系統(tǒng)。
2、目前主流的活體解決方案分為配合式活體檢測和非配合式活體檢測(靜默活體檢測)。配合式活體檢測需要用戶根據(jù)提示完成指定的動作(比如眨眼,頭往哪邊轉(zhuǎn)一下),然后再進(jìn)行活體校驗,靜默活體則在用戶無感的情況下直接進(jìn)行活體校驗。
3、這里演示的是靜默活體檢測,算法地址:https://github.com/minivision-ai/Silent-Face-Anti-Spoofing 。
三、創(chuàng)建項目
1.創(chuàng)建一個Native C++工程。
2.在CPP目錄下導(dǎo)入OpenCV和NCNN庫。
四、代碼
1.添加打開安卓攝像頭的ndkcamera,這是一個快速打開前后攝像頭的輕量級C++庫。
2.添加用于檢測人臉的代碼yoloface.h和yoloface.cpp。
3.添加活體檢測代碼facelive.h和ffacelive.cpp 。
4.在資源里面添加到的模型。
5.添加布局代碼。
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><SurfaceViewandroid:id="@+id/cameraview"android:layout_width="fill_parent"android:layout_height="fill_parent"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintHorizontal_bias="1.0"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintVertical_bias="0.0" /><ImageButtonandroid:id="@+id/button_switch_camera"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="20dp"android:layout_marginBottom="30dp"android:src="@drawable/ic_switch_camera"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintStart_toStartOf="parent"></ImageButton><ImageButtonandroid:id="@+id/btn_open_image"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginBottom="30dp"android:src="@drawable/ic_gallery"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintHorizontal_bias="0.498"app:layout_constraintStart_toStartOf="parent"></ImageButton><ImageButtonandroid:id="@+id/spinner_CPUGPU"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="330dp"android:layout_marginBottom="30dp"android:src="@drawable/ic_baseline"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintStart_toStartOf="parent"></ImageButton></androidx.constraintlayout.widget.ConstraintLayout>6.編寫makefile文件。
project(ncnnyoloface)cmake_minimum_required(VERSION 3.10)set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/opencv/sdk/native/jni) find_package(OpenCV REQUIRED core imgproc)set(ncnn_DIR ${CMAKE_SOURCE_DIR}/ncnn/${ANDROID_ABI}/lib/cmake/ncnn) find_package(ncnn REQUIRED)add_library(livedetect SHARED yoloface.cpp facelive.cpp yolofacencnn.cpp ndkcamera.cpp)target_link_libraries(livedetect ncnn ${OpenCV_LIBS} camera2ndk mediandk)7.JNI交互代碼
7.1 在Java里面面定義與C++交互的接口如下:
7.2 在Native C++里面實現(xiàn)接口。
extern "C" {JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {__android_log_print(ANDROID_LOG_DEBUG, "ncnn", "JNI_OnLoad");g_camera = new MyNdkCamera;return JNI_VERSION_1_4; }JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved) {__android_log_print(ANDROID_LOG_DEBUG, "ncnn", "JNI_OnUnload");{ncnn::MutexLockGuard g(lock);delete yolo_detect;delete face_live;face_live = 0;yolo_detect = 0;}delete g_camera;g_camera = 0; }JNIEXPORT jboolean JNICALL Java_com_dashu_livedetect_LiveDetect_loadModel(JNIEnv* env, jobject thiz, jobject assetManager, jint cpugpu) {if ( cpugpu < 0 || cpugpu > 1){return JNI_FALSE;}AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);bool use_gpu = (int)cpugpu == 1;// reload{ncnn::MutexLockGuard g(lock);if (use_gpu && ncnn::get_gpu_count() == 0){// no gpudelete yolo_detect;delete face_live;yolo_detect = 0;face_live = 0;}else{if (!yolo_detect){yolo_detect = new YoloFace;face_live = new FaceLive;}yolo_detect->loadModel(mgr,face_model,use_gpu);face_live->LoadModel(mgr,live_model,use_gpu);}}return JNI_TRUE; }JNIEXPORT jobject JNICALL Java_com_dashu_livedetect_LiveDetect_yoloTarget(JNIEnv *env,jobject, jobject image) {cv::Mat cv_src,cv_dst,cv_doc;//bitmap轉(zhuǎn)化成matBitmapToMat(env,image,cv_src);cv::cvtColor(cv_src,cv_doc,cv::COLOR_BGRA2BGR);std::vector<Object> objects;yolo_detect->detection(cv_doc, objects);yolo_detect->drawTarget(cv_doc, objects);MatToBitmap(env,cv_doc,image);cv_dst.release();return image; }JNIEXPORT jboolean JNICALL Java_com_dashu_livedetect_LiveDetect_openCamera(JNIEnv* env, jobject thiz, jint facing) {if (facing < 0 || facing > 1)return JNI_FALSE;__android_log_print(ANDROID_LOG_DEBUG, "ncnn", "openCamera %d", facing);g_camera->open((int)facing);return JNI_TRUE; }JNIEXPORT jboolean JNICALL Java_com_dashu_livedetect_LiveDetect_closeCamera(JNIEnv* env, jobject thiz) {__android_log_print(ANDROID_LOG_DEBUG, "ncnn", "closeCamera");g_camera->close();return JNI_TRUE; }// public native boolean setOutputWindow(Surface surface); JNIEXPORT jboolean JNICALL Java_com_dashu_livedetect_LiveDetect_setOutputWindow(JNIEnv* env, jobject thiz, jobject surface) {ANativeWindow* win = ANativeWindow_fromSurface(env, surface);__android_log_print(ANDROID_LOG_DEBUG, "ncnn", "setOutputWindow %p", win);g_camera->set_window(win);return JNI_TRUE; }7.3 MainActivity里面調(diào)用Java類與C++交互的接口實現(xiàn)功能。
//切換攝像頭ImageButton buttonSwitchCamera = (ImageButton) findViewById(R.id.button_switch_camera);buttonSwitchCamera.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View arg0) {int new_facing = 1 - facing;yolo_fire.closeCamera();yolo_fire.openCamera(new_facing);facing = new_facing;}});//打開圖像open_image = (ImageButton) findViewById(R.id.btn_open_image);open_image.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View arg0){Intent i = new Intent(Intent.ACTION_PICK);i.setType("image/*");startActivityForResult(i, SELECT_IMAGE);yolo_fire.closeCamera();}});//切換CPU/GPUspinnerCPUGPU = (ImageButton) findViewById(R.id.spinner_CPUGPU);spinnerCPUGPU.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View arg0) {if(current_cpugpu == 0){current_cpugpu = 1;Toast.makeText(MainActivity.this, "啟用CPU推理", Toast.LENGTH_SHORT).show();}else{current_cpugpu = 0;Toast.makeText(MainActivity.this, "啟用GPU推理", Toast.LENGTH_SHORT).show();}reload();}});reload();}7.4 運(yùn)行效果。
五.資源文件
1.可執(zhí)行的apk文件:https://download.csdn.net/download/matt45m/85007518
2.整個工程源碼和模型:https://download.csdn.net/download/matt45m/85007554
總結(jié)
以上是生活随笔為你收集整理的Android NDK开发——人脸检测与静默活体检测的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于深度学习的人脸检测与静默活体检测——
- 下一篇: 深度学习目标检测(YoloV5)项目——