文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

基于Android studio3.6的JNI教程之ncnn之目标检测ssd

2022-06-06 13:26

关注

 

代码链接:

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

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

 

环境:

Android studio 3.6

Sdk:android10 api 29

Ndk:r15c

Ncnn:20200226

 

Linux下的代码测试:

mkdir build
cd build
cmake ..
make
./ssd

效果:

 

Android下的开发:

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

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

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

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

(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;

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)

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<<"### "<<ret_param<<" "<<ret_bin<<std::endl;
}
MOBILENETSSD::MOBILENETSSD(ncnn::Mat param_path, ncnn::Mat bin_path) {
    int ret_param = net.load_param((const unsigned char *)param_path);
    int ret_bin = net.load_model((const unsigned char *)bin_path);
    LOGD("############### %d  %d", ret_param,ret_bin);
    //std::cout<<"### "<<ret_param<<" "<<ret_bin<<std::endl;
}
ncnn::Mat MOBILENETSSD::detect(ncnn::Mat in) {
    int img_w = in.w;
    int img_h = in.h;
    //ncnn::Mat in = ncnn::Mat::from_pixels_resize(bgr.data, ncnn::Mat::PIXEL_BGR, bgr.cols, bgr.rows, target_size, target_size);
    in.substract_mean_normalize(mean_vals, norm_vals);
    ncnn::Extractor ex = net.create_extractor();
    ex.set_num_threads(2);
    ex.input(mobilenet_ssd_voc_ncnn_param_id::BLOB_data, in);
    ncnn::Mat out;
    ex.extract(mobilenet_ssd_voc_ncnn_param_id::BLOB_detection_out, out);
    return out;
}
MOBILENETSSD::~MOBILENETSSD() {
    net.clear();
}

 

ssd_jni.cpp的具体实现,

static MOBILENETSSD *ncnn_net;
extern "C"
JNIEXPORT jboolean JNICALL
Java_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 JNICALL
Java_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 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文件的name
find_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)整体目录结构,

 

运行结果:

 

 


作者:watersink


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯