人脸检测算法需要用大小位置不同的窗口在图像中进行滑动,然后判断窗口中是否存在人脸。本文采用的是 dlib 中的是HOG(histogram of oriented gradient)方法对人脸进行检测,其检测效果要好于 opencv。dlib 中同样提供了 CNN 方法来进行人脸检测,效果好于 HOG,不过需要使用 GPU 加速,不然程序运行会非常慢。
class FaceDetector { private: dlib::frontal_face_detector face_detector; std::vector<dlib::rectangle> det_rects; public: FaceDetector(); // 实现人脸检测算法 int Detect(const cv::Mat &image); // 返回检测结果 std::vector<dlib::rectangle> getDetResultRects(); }; FaceDetector::FaceDetector() { // 定义人脸检测器 face_detector = dlib::get_frontal_face_detector(); } int FaceDetector::Detect(const cv::Mat &image) { if (image.empty()) return 0; if (image.channels() == 1) { cv::cvtColor(image, image, CV_GRAY2BGR); } dlib::cv_image<dlib::bgr_pixel> dlib_image(image); det_rects.clear(); // 返回检测到的人脸矩形特征框 det_rects = face_detector(dlib_image); return det_rects.size(); } std::vector<dlib::rectangle> FaceDetector::getDetResultRects() { return det_rects; } 4.3 native 方法实现 JNI_VisionDetRet *g_pJNI_VisionDetRet; JavaVM *g_javaVM = NULL; // 该函数在加载本地库时被调用 JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { g_javaVM = vm; JNIEnv *env; vm->GetEnv((void **) &env, JNI_VERSION_1_6); // 初始化 g_pJNI_VisionDetRet g_pJNI_VisionDetRet = new JNI_VisionDetRet(env); return JNI_VERSION_1_6; } // 该函数用于执行清理操作 void JNI_OnUnload(JavaVM *vm, void *reserved) { g_javaVM = NULL; delete g_pJNI_VisionDetRet; } namespace { #define JAVA_NULL 0 using DetPtr = FaceDetector *; // 用于存放人脸检测类对象的指针,关联Jave层对象与C++底层对象(相互对应) class JNI_FaceDet { public: JNI_FaceDet(JNIEnv *env) { jclass clazz = env->FindClass(CLASSNAME_FACE_DET); mNativeContext = env->GetFieldID(clazz, "mNativeFaceDetContext", "J"); env->DeleteLocalRef(clazz); } DetPtr getDetectorPtrFromJava(JNIEnv *env, jobject thiz) { DetPtr const p = (DetPtr) env->GetLongField(thiz, mNativeContext); return p; } void setDetectorPtrToJava(JNIEnv *env, jobject thiz, jlong ptr) { env->SetLongField(thiz, mNativeContext, ptr); } jfieldID mNativeContext; }; // Protect getting/setting and creating/deleting pointer between java/native std::mutex gLock; std::shared_ptr<JNI_FaceDet> getJNI_FaceDet(JNIEnv *env) { static std::once_flag sOnceInitflag; static std::shared_ptr<JNI_FaceDet> sJNI_FaceDet; std::call_once(sOnceInitflag, [env]() { sJNI_FaceDet = std::make_shared<JNI_FaceDet>(env); }); return sJNI_FaceDet; } // 从java对象获取它持有的c++对象指针 DetPtr const getDetPtr(JNIEnv *env, jobject thiz) { std::lock_guard<std::mutex> lock(gLock); return getJNI_FaceDet(env)->getDetectorPtrFromJava(env, thiz); } // The function to set a pointer to java and delete it if newPtr is empty // C++对象new以后,将指针转成long型返回给java对象持有 void setDetPtr(JNIEnv *env, jobject thiz, DetPtr newPtr) { std::lock_guard<std::mutex> lock(gLock); DetPtr oldPtr = getJNI_FaceDet(env)->getDetectorPtrFromJava(env, thiz); if (oldPtr != JAVA_NULL) { delete oldPtr; } getJNI_FaceDet(env)->setDetectorPtrToJava(env, thiz, (jlong) newPtr); } } // end unnamespace #ifdef __cplusplus extern "C" { #endif #define DLIB_FACE_JNI_METHOD(METHOD_NAME) Java_com_lightweh_dlib_FaceDet_##METHOD_NAME void JNIEXPORT DLIB_FACE_JNI_METHOD(jniNativeClassInit)(JNIEnv *env, jclass _this) {} // 生成需要返回的结果数组 jobjectArray getRecResult(JNIEnv *env, DetPtr faceDetector, const int &size) { // 根据检测到的人脸数创建相应大小的jobjectArray jobjectArray jDetRetArray = JNI_VisionDetRet::createJObjectArray(env, size); for (int i = 0; i < size; i++) { // 对检测到的每一个人脸创建对应的实例对象,然后插入数组 jobject jDetRet = JNI_VisionDetRet::createJObject(env); env->SetObjectArrayElement(jDetRetArray, i, jDetRet); dlib::rectangle rect = faceDetector->getDetResultRects()[i]; // 将人脸矩形框的值赋给对应的jobject实例对象 g_pJNI_VisionDetRet->setRect(env, jDetRet, rect.left(), rect.top(), rect.right(), rect.bottom()); } return jDetRetArray; } JNIEXPORT jobjectArray JNICALL DLIB_FACE_JNI_METHOD(jniBitmapDet)(JNIEnv *env, jobject thiz, jobject bitmap) { cv::Mat rgbaMat; cv::Mat bgrMat; jniutils::ConvertBitmapToRGBAMat(env, bitmap, rgbaMat, true); cv::cvtColor(rgbaMat, bgrMat, cv::COLOR_RGBA2BGR); // 获取人脸检测类指针 DetPtr mDetPtr = getDetPtr(env, thiz); // 调用人脸检测算法,返回检测到的人脸数 jint size = mDetPtr->Detect(bgrMat); // 返回检测结果 return getRecResult(env, mDetPtr, size); } jint JNIEXPORT JNICALL DLIB_FACE_JNI_METHOD(jniInit)(JNIEnv *env, jobject thiz) { DetPtr mDetPtr = new FaceDetector(); // 设置人脸检测类指针 setDetPtr(env, thiz, mDetPtr); return JNI_OK; } jint JNIEXPORT JNICALL DLIB_FACE_JNI_METHOD(jniDeInit)(JNIEnv *env, jobject thiz) { // 指针置0 setDetPtr(env, thiz, JAVA_NULL); return JNI_OK; } #ifdef __cplusplus } #endif 5 Java端调用人脸检测算法Android 中使用 dlib+opencv 实现动态人脸检测 (2)
内容版权声明:除非注明,否则皆为本站原创文章。