代码链接:

https://github.com/watersink/MobileNetSSD-linux-as

本代码可以在模拟器下进行跑。

 

环境:

Android studio 3.6

Sdk:android10 api 29

Ndk:r15c

Ncnn:20200226

 

Linux下的代码测试:

mkdir buildcd buildcmake ..make./ssd

效果:

基于Android studio3.6的JNI教程之ncnn之目标检测ssd_第1张图片

 

Android下的开发:

(1)增加ncnn的依赖库.a(src/main/jniLibs)

增加ncnn的头文件include(src/main/cpp)

基于Android studio3.6的JNI教程之ncnn之目标检测ssd_第2张图片

(2)增加ssd模型文件(src/main/assets)

和ssd模型的加密后的*.id.h文件(src/main/cpp)

基于Android studio3.6的JNI教程之ncnn之目标检测ssd_第3张图片

(3)增加需要使用的图片(src/main/res/drawable)

(4)修改布局文件(src/main/res/layout/activity_main.xml)

(5)修改java部分代码(src/main/java)

增加MobileNetssd,主要实现初始化Init和检测Detect代码

package com.example.mobilenetssd;import android.graphics.Bitmap;/** *  MobileNetssd的java接口,与本地c++代码相呼应 native为本地 此文件与 MobileNetssd.cpp相呼应 */public class MobileNetssd {    public native boolean Init(byte[] param, byte[] bin); // 初始化函数    public native float[] Detect(Bitmap bitmap); // 检测函数    // Used to load the 'native-lib' library on application startup.    static {        System.loadLibrary("MobileNetssd");    }}//修改MainActivity代码,主要onCreate函数中实现模型初始化,label文件读取,模型的检测,结果显示。    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        try        {            initMobileNetSSD();//初始化模型            Log.e("MainActivity", "initMobileNetSSD ok");        } catch (IOException e) {            Log.e("MainActivity", "initMobileNetSSD error");        }        readCacheLabelFromLocalFile();//初始化读取words.txt        init_view();//检测+view画图}

(6)修改cpp部分代码(src/main/cpp)

基于Android studio3.6的JNI教程之ncnn之目标检测ssd_第4张图片

MobileNetssd.h和MobileNetssd.cpp分别实现了MOBILENETSSD及其相关方法。

ssd_jni.cpp实现了jnl方式的c++方法。

 

MobileNetssd.h中的MOBILENETSSD类及其方法,

class MOBILENETSSD {public:    MOBILENETSSD(string param_path, string bin_path);MOBILENETSSD(ncnn::Mat param_path, ncnn::Mat bin_path);ncnn::Mat detect(ncnn::Mat in);    ~MOBILENETSSD();private:    ncnn::Net net;    const int target_size = 300;    const float mean_vals[3] = {127.5f, 127.5f, 127.5f};    const float norm_vals[3] = {0.007843f, 0.007843f, 0.007843f};};

 

MobileNetssd.cpp中的具体实现,

MOBILENETSSD::MOBILENETSSD(string param_path, string bin_path) {    const char *param_path_char = param_path.c_str();    const char *bin_path_char = bin_path.c_str();    int ret_param = net.load_param_bin(param_path_char);    int ret_bin = net.load_model(bin_path_char);//std::cout<<"### "<

 

ssd_jni.cpp的具体实现,

static MOBILENETSSD *ncnn_net;extern "C"JNIEXPORT jboolean JNICALLJava_com_example_mobilenetssd_MobileNetssd_Init(JNIEnv *env, jobject thiz, jbyteArray param,                                                jbyteArray bin) {    // TODO: implement Init()    ncnn::Mat ncnn_param;    ncnn::Mat ncnn_bin;    // init param    {        int len = env->GetArrayLength(param);        ncnn_param.create(len, (size_t) 1u);        env->GetByteArrayRegion(param, 0, len, (jbyte *) ncnn_param);    }    // init bin    {        int len = env->GetArrayLength(bin);        ncnn_bin.create(len, (size_t) 1u);        env->GetByteArrayRegion(bin, 0, len, (jbyte *) ncnn_bin);    }    ncnn_net = new MOBILENETSSD(ncnn_param,ncnn_bin);    return JNI_TRUE;}extern "C"JNIEXPORT jfloatArray JNICALLJava_com_example_mobilenetssd_MobileNetssd_Detect(JNIEnv *env, jobject thiz, jobject bitmap) {    // TODO: implement Detect()    // ncnn from bitmap    ncnn::Mat in;    {        AndroidBitmapInfo info;        AndroidBitmap_getInfo(env, bitmap, &info);        int width = info.width;        int height = info.height;        if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888)            return NULL;        void* indata;        AndroidBitmap_lockPixels(env, bitmap, &indata);        // 把像素转换成data,并指定通道顺序        // 因为图像预处理每个网络层输入的数据格式不一样一般为300*300 128*128等等所以这类需要一个resize的操作可以在cpp中写,也可以是java读入图片时有个resize操作        //in = ncnn::Mat::from_pixels_resize((const unsigned char*)indata, ncnn::Mat::PIXEL_RGBA2RGB, width, height,300,300);        in = ncnn::Mat::from_pixels(static_cast(indata), ncnn::Mat::PIXEL_RGBA2RGB, width, height);        // 下面一行为debug代码        __android_log_print(ANDROID_LOG_DEBUG, "MobilenetssdJniIn", "Mobilenetssd_predict_has_input1, in.w: %d; in.h: %d", in.w, in.h);        //AndroidBitmap_unlockPixels(env, bitmap);    }    {        ncnn::Mat out = ncnn_net->detect(in);        int output_wsize = out.w;        int output_hsize = out.h;        //输出整理        jfloat *output[output_wsize * output_hsize];   // float类型        for(int i = 0; i< out.h; i++) {            for (int j = 0; j < out.w; j++) {                output[i*output_wsize + j] = &out.row(i)[j];            }        }        //建立float数组 长度为 output_wsize * output_hsize,如果只是ouput_size相当于只有一行的out的数据那就是一个object检测数据        jfloatArray jOutputData = env->NewFloatArray(output_wsize * output_hsize);        if (jOutputData == nullptr) return nullptr;        env->SetFloatArrayRegion(jOutputData, 0,  output_wsize * output_hsize,                                 reinterpret_cast(*output));        return jOutputData;    }}

(7)CMakeLists修改(src/main/cpp/CMakeLists),加入ncnn路径

cmake_minimum_required(VERSION 3.4.1)#include头文件目录include_directories(include)#添加ncnn库#source directory源文件目录file(GLOB SSD_SRC *.h        *.cpp)set(SSD_COMPILE_CODE ${SSD_SRC})add_library(libncnn STATIC IMPORTED )set_target_properties(libncnn        PROPERTIES IMPORTED_LOCATION        ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libncnn.a)add_library( # Sets the name of the library.        MobileNetssd ## 为生成.so的文字最好直接和.c名字一样,需要更改        # Sets the library as a shared library.        SHARED        # Provides a relative path to your source file(s).        ${SSD_COMPILE_CODE})##cpp文件的namefind_library( # Sets the name of the path variable.              log-lib              log )target_link_libraries( # Specifies the target library.                       MobileNetssd                       libncnn                       android                       jnigraphics                       # Links the target library to the log library                       # included in the NDK.                       ${log-lib} )

(8) build.gradle修改,增加ndk,cmake选项。

externalNativeBuild {            cmake {                arguments "-DANDROID_TOOLCHAIN=clang"                cFlags "-fopenmp -O2 -fvisibility=hidden -fomit-frame-pointer -fstrict-aliasing -ffunction-sections -fdata-sections -ffast-math "                cppFlags "-fopenmp -O2 -fvisibility=hidden -fvisibility-inlines-hidden -fomit-frame-pointer -fstrict-aliasing -ffunction-sections -fdata-sections -ffast-math "                arguments "-DANDROID_STL=c++_shared", "-DANDROID_CPP_FEATURES=rtti exceptions"                cppFlags ""                cppFlags "-std=c++11"                cppFlags "-frtti"                cppFlags "-fexceptions"            }        }        ndk {            abiFilters 'armeabi-v7a'// , 'arm64-v8a' //,'x86', 'x86_64', 'armeabi'            stl "gnustl_static"        }

(9)整体目录结构,

基于Android studio3.6的JNI教程之ncnn之目标检测ssd_第5张图片

 

运行结果:

基于Android studio3.6的JNI教程之ncnn之目标检测ssd_第6张图片

 

 

更多相关文章

  1. Android获取SD卡上图片和视频文件及其缩略图
  2. Android 代码修改按钮上的图片
  3. Android实现网络图片查看器和网页源码查看器
  4. Android 九宫格图片展示的实现
  5. 在Android中使用GIF图片
  6. Android进阶之代码应用技巧

随机推荐

  1. 关于Android 中sqlite 报can not open da
  2. android之IntentService类的实现
  3. Android 向菜单按钮说再见
  4. Android Studio 插件的使用
  5. MTP 服务流程
  6. android音频播放简单示例
  7. IndicatorViewPager (笔记)
  8. android中数据存储的contentprovider的使
  9. Android 视频缩略图之MediaMetadataRetri
  10. 记一次会议