android jni 人头检测_Tengine从入门到放弃 第4篇-Tengine 人脸检测 Android版

785721185e2c633d5b5041d504f88bba.png

所有内容都在

jiangzhongbo/Tengine_Tutorial​github.com
b41fec80a13e1fe2ab2e808a9519d992.png

如果有什么不清楚的直接看代码

准备

  1. 用 Android Studio 建立一个空白Android项目

2. 把

月球基地蒋司令:Tengine从入门到放弃 第1篇-Tengine Android版本编译​zhuanlan.zhihu.com
1f50e910f30a1060e21f55cfcd94f3b5.png

中编译好的so复制到Android项目中libs目录

3. 把

月球基地蒋司令:Tengine从入门到放弃 第2篇-Tengine 转换模型​zhuanlan.zhihu.com
acb20a3a504549f0b31247e57e3c54bd.png

中转化好的模型复制到Android项目中assets目录

4. 把

月球基地蒋司令:Tengine从入门到放弃 第3篇-Tengine 人脸检测X86版本​zhuanlan.zhihu.com
52e3d3d9a5aef46761df2cab8e8ddaa3.png

中的UltraFace.cpp, UltraFace.hpp, tengine_c_api.h复制到Android项目中的cpp目录

编译环境搭建

Android NDK

我用的是android-ndk-r16b,在Android项目中local.properties中添加NDK地址,例如我的就是

sdk.dir=D:Android_ENVAndroidSdk
ndk.dir=D:Android_ENVandroid-ndk-r16b

Android OpenCV

下载

opencv-3.4.11-android-sdk.zip​github.com

然后解压

编写CMakeLists.txt和配套build.gradle

和X86版本比较大的区别就是改OpenCV为Android版本,OpenCV地址改为你下载解压后的地址

set(OpenCV_DIR "D:/Android_ENV/OpenCV-android-sdk/sdk/native/jni")
find_package(OpenCV 3.4 REQUIRED)
include_directories(D:/Android_ENV/OpenCV-android-sdk/sdk/native/jni/include)

改了动态链接库的名字

project(FaceDetect)

这个后面写JNI的时候会用到

因为我们用了CMakeLists.txt,所以需要修改下build.gradle

android {
    ...
    defaultConfig {
        ...
        externalNativeBuild {
            cmake {
                cppFlags ""
                cppFlags "-std=c++11 -frtti -fexceptions"
                abiFilters 'armeabi-v7a', 'arm64-v8a'

                arguments "-DANDROID_TOOLCHAIN=clang"
                cFlags "-O2 -fvisibility=hidden -fomit-frame-pointer -fstrict-aliasing -ffunction-sections -fdata-sections -ffast-math "
                cppFlags "-O2 -fvisibility=hidden -fvisibility-inlines-hidden -fomit-frame-pointer -fstrict-aliasing -ffunction-sections -fdata-sections -ffast-math "

                //rtti(run-time type interface)运行时类型信息,这是编译器的一个特性,默认时关闭状态
                //如果需要在C/C++代码中调用Java的方法,需要手动开启此特性
                cppFlags "-frtti -fexceptions -std=c++11 -v -Wdeprecated-declarations"
            }
        }
        ndk {
            //声明启用Android日志, 在c/c++的源文件中使用的#include <android/log.h> 日志将得到输出
            ldLibs "log"

            //声明创建指定cpu架构的so库
            //如果想在模拟器运行 加上 "x86"
            abiFilters 'armeabi-v7a', 'arm64-v8a'

            stl "gnustl_static"
        }
    }
    externalNativeBuild {
        cmake {
            path 'src/main/cpp/CMakeLists.txt'
            version "3.10.2"
        }
    }
    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
    ...

编写Java和C++的交互代码

编写JNI,让Java和C++联系起来

java native接口

public class FaceDetector {
    static {
        System.loadLibrary("FaceDetect");
    }

    public static native void init();

    public static native float[] detect(byte[] img, int w, int h);

    public static native void release();

    public static List<FaceInfo> detectByBytes(byte[] img, int w, int h){
        float[] data = detect(img, w, h);
        if(data != null && data.length % 5 == 0){
            int num = data.length / 5;
            List<FaceInfo> faceInfos = new ArrayList<>(num);
            for(int i = 0; i < num; i++){
                FaceInfo faceInfo = new FaceInfo();
                faceInfo.x1 = data[i * 5 + 0];
                faceInfo.y1 = data[i * 5 + 1];
                faceInfo.x2 = data[i * 5 + 2];
                faceInfo.y2 = data[i * 5 + 3];
                faceInfo.score = data[i * 5 + 4];
                faceInfos.add(faceInfo);
            }
            return faceInfos;
        }
        return null;
    }
}

JNI接口

如果JNI用c++写,extern "C"是一定要的,不然会出错

extern "C"{


jfloatArray faces_to_floats(JNIEnv *env, std::vector<FaceInfo> &faces){
    jfloatArray jarr = env->NewFloatArray(faces.size() * 5);
    jfloat *arr = env->GetFloatArrayElements(jarr, NULL);
    for (int i = 0; i < faces.size(); i++) {
        arr[5 * i + 0] = faces[i].x1;
        arr[5 * i + 1] = faces[i].y1;
        arr[5 * i + 2] = faces[i].x2;
        arr[5 * i + 3] = faces[i].y2;
        arr[5 * i + 4] = faces[i].score;
    }
    env->ReleaseFloatArrayElements(jarr, arr, 0);
    return jarr;
}

UltraFace *ultraface;
JNIEXPORT void JNICALL
Java_com_facesdk_FaceDetector_init(JNIEnv *env, jclass){
    if(!ultraface){
        ultraface = new UltraFace("/sdcard/OAL/version-RFB-320_simplified.tmfile", 320, 240, 4, 0.65);
    }
}

JNIEXPORT jfloatArray JNICALL
Java_com_facesdk_FaceDetector_detect(JNIEnv *env, jclass, jbyteArray img, jint w, jint h){
    jbyte* arr = env->GetByteArrayElements(img, 0);
    cv::Mat frame(h, w, CV_8UC4, (char *)arr);
    cv::Mat rgb;
    cv::cvtColor(frame, rgb, CV_RGBA2RGB);
    std::vector<FaceInfo> face_info;
    ultraface->detect(rgb, face_info);
    env->ReleaseByteArrayElements(img, arr, 0);
    return faces_to_floats(env, face_info);
}

JNIEXPORT void JNICALL
Java_com_facesdk_FaceDetector_release(JNIEnv *env, jclass){
    if(ultraface){
        delete ultraface;
    }
}
}

测试

Drawable d = null;
Bitmap bb = null;
try {
    d = Drawable.createFromStream(getAssets().open("girls.jpg"), null);
    showImage.setImageDrawable(d);
    bb = ((BitmapDrawable)d).getBitmap();
}catch (Exception e){
    e.printStackTrace();
}

byte[] girl = bitmap2Bytes(bb);

FaceDetector.init();
List<FaceInfo> faceInfos = FaceDetector.detectByBytes(girl, d.getIntrinsicWidth(), d.getIntrinsicHeight());
FaceDetector.release();

我们看下效果

原图

37f9f11d06bf29aa3daac175ee680eb6.png

效果

da2e7624ee2379ea87307616011fb743.png

参考

https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB​github.com OAID/Tengine​github.com
7064a57ae4f610fb5ddcc9e4c7bcf7b2.png

源码

https://github.com/jiangzhongbo/Tengine_Tutorial​github.com

—完—

@GitHub Hunt · 发现有趣,好玩,硬核的开源项目

有收获的朋友,欢迎赞同、关注、分享三连 վ'ᴗ' ի ❤

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值