yolov3-tiny基於darknet2ncnn在安卓實現

yolov3-tiny基於darknet2ncnn在安卓實現

1、構建ncnn以及編譯darknet2ncnn  參考:https://github.com/xiangweizeng/darknet2ncnn

git clone https://gitee.com/damone/darknet2ncnn.git

cd darknet2ncnn
git submodule init
git submodule update
cd darknet
make -j8
rm libdarknet.so
cd ncnn
mkdir build
cmake ..
make -j8
make install
.....
#https://github.com/xiangweizeng/darknet2ncnn

2、編譯Androoid端ncnn庫文件

#workspace ncnn
mkdir -p build-android-armv7
cd build-android-armv7
cmake -DCMAKE_TOOLCHAIN_FILE=/home/lw/Android/Sdk/ndk-  bundle/build/cmake/android.toolchain.cmake  \
-DANDROID_ABI="armeabi-v7a" \
-DANDROID_ARM_NEON=ON ..
make -j8
make install

在build-android-armv7文件夾下會生成install文件夾就是移植到Android端需要的庫文件。

3、在Androoid端調用ncnn庫文件,以及加載ncnn模型即可

      新建Android工程,安裝下面的步驟來

     (1)右擊file---New---New Project
     (2)選擇Native C++,next,語言選擇java,next,選擇C++11

     (3)在工程目錄main文件夾下新建assset和jniLibs兩個文件夾,將之前編譯的ncnn在Android下運行的庫拷貝到jniLibs文件下

     (4)將轉換的yolov3-tiny的網絡文件和權重文件拷貝到assets文件夾下,新建words.name文件,將類名寫入改文件。

     (5)在工程目錄cpp文件夾下新建darknet、darknet2ncnn和ncnn三個文件夾,並分別將pc端darknet2ncnn下的incule和src、darknet2ncnn\darkent下的incule和src、darknet2ncnn\ncnn下的incule和src拷入對應的文件夾下。

     (6)在工程目錄cpp文件夾下新建yolov3-tiny-jni.cpp,部分代碼如下:

#include <android/bitmap.h>
#include <android/log.h>
#include <android/asset_manager_jni.h>
#include <jni.h>
#include <string>
#include <vector>
 
#include <sys/time.h>
#include <unistd.h>
 
#include <stdio.h>
#include <algorithm>
#include <fstream>
 
#include "darknet2ncnn.h"
#include "ncnn/src/layer/input.h"
#include "ncnn_tools.h"
 
extern "C" {
 
static CustomizedNet yolo;
static ncnn::Mat ncnn_param;
static ncnn::Mat ncnn_bin;
 
 
JNIEXPORT jboolean JNICALL
Java_com_bket_yolov3Tiny_yolov3Tiny_Init(JNIEnv *env, jobject obj, jstring param, jstring bin) {
    __android_log_print(ANDROID_LOG_DEBUG, "yolov3TinyJni", "enter the jni func");
 
     register_darknet_layer(yolo);
 
    const char *param_path = env->GetStringUTFChars( param, NULL);
    if(param_path == NULL)
        return JNI_FALSE;
    __android_log_print(ANDROID_LOG_DEBUG, "yolov3TinyJni", "load_param %s", param_path);
 
    //yolo.
    int ret = yolo.load_param(param_path);
    __android_log_print(ANDROID_LOG_DEBUG, "yolov3TinyJni", "load_param result %d", ret);
    env->ReleaseStringUTFChars( param, param_path);
 
    const char *bin_path = env->GetStringUTFChars( bin, NULL);
    if(bin_path == NULL)
        return JNI_FALSE;
    __android_log_print(ANDROID_LOG_DEBUG, "yolov3TinyJni", "load_model %s", bin_path);
 
    int ret2 = yolo.load_model(bin_path);
    __android_log_print(ANDROID_LOG_DEBUG, "yolov3TinyJni", "load_model result %d", ret2);
    env->ReleaseStringUTFChars( bin, bin_path);
    return JNI_TRUE;
}
 
JNIEXPORT jfloatArray JNICALL Java_com_bket_yolov3Tiny_yolov3Tiny_Detect(JNIEnv* env, jobject thiz, jobject bitmap)
{
    ncnn::Input *input = (ncnn::Input *)yolo.get_layer_from_name("data");
 
    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);
 
    ncnn::Mat in = ncnn::Mat::from_pixels_resize((const unsigned char*)indata,      ncnn::Mat::PIXEL_RGBA2RGB, width, height, input->w, input->h);
 
 
    AndroidBitmap_unlockPixels(env, bitmap);
 
    const float norm_vals[3] = {1 / 255.0, 1 / 255.0, 1 / 255.0};
    in.substract_mean_normalize(0, norm_vals);
    ncnn::Extractor ex = yolo.create_extractor();
    ex.input("data",in);
    ex.set_light_mode(false);
    ex.set_num_threads(6);
 
    ncnn::Mat out;
    ncnn::Blob *out_blob = yolo.get_last_layer_output_blob();
    int result = ex.extract(out_blob->name.c_str(), out);
 
    __android_log_print(ANDROID_LOG_DEBUG, "yolov2TinyJni", "extract stop %d", result);
    __android_log_print(ANDROID_LOG_DEBUG, "yolov2TinyJni", "out.w = %d, out.h = %d", out.w, out.h);
   //if (result != 0)
        //return NULL;
    int output_wsize = out.w;
    int output_hsize = out.h;
 
    jfloat *output[output_wsize * output_hsize];
    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];
        }
    }
    jfloatArray jOutputData = env->NewFloatArray(output_wsize * output_hsize);
    if (jOutputData == nullptr) return nullptr;
    __android_log_print(ANDROID_LOG_DEBUG, "yolov2TinyJni", "output_wsize = %d", output_wsize);
    env->SetFloatArrayRegion(jOutputData, 0,  output_wsize * output_hsize,
                             reinterpret_cast<const jfloat *>(*output));  // copy
    env->SetFloatArrayRegion(jOutputData, 0,  output_wsize * output_hsize,
                             reinterpret_cast<const jfloat *>(*output));
    return jOutputData;
 
}
}

 

     (7)現在工程目錄下新建CMakeLists.txt,編寫cmakefile文件:


# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
 
# Sets the minimum version of CMake required to build the native library.
 
cmake_minimum_required(VERSION 2.8.10)#3.4.1
 
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
set(CMAKE_BUILD_TYPE RELEASE)
 
#include_directories(${ANDROID_SYSROOT}/usr/include/arm-linux-androideabi)
 
set(libs "${CMAKE_SOURCE_DIR}/src/main/jniLibs")
include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/darknet2ncnn/include
        ${CMAKE_SOURCE_DIR}/src/main/cpp/ncnn/include
        ${CMAKE_SOURCE_DIR}/src/main/cpp/darknet/include
        ${CMAKE_SOURCE_DIR}/src/main/cpp/darknet2ncnn/src
        ${CMAKE_SOURCE_DIR}/src/main/cpp/ncnn/src)
 
set(CMAKE_STATIC_LINKER_FLAGS "-lm  -pthread -fopenmp -lstdc++")
set(CMAKE_C_FLAGS  "${CMAKE_C_FLAGS} -Ofast -Wno-unused-result  -Wfatal-errors -fPIC -fno-rtti -fno-exceptions")
set(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} -std=c++11 -Ofast -Wno-unused-result  -Wfatal-errors -fPIC -fno-rtti -fno-exceptions -mfpu=neon-vfpv4")
 
 
add_library (libncnn STATIC IMPORTED)
set_target_properties(libncnn PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a/libncnn.a)
 
file(GLOB_RECURSE darknet_src ${CMAKE_SOURCE_DIR}/src/main/cpp/darknet/src/*.c)
#file(GLOB_RECURSE  DARKNET2NCNN_SRC ${CMAKE_SOURCE_DIR}/src/main/cpp/darknet2ncnn/src/*.cpp)
#file(GLOB_RECURSE DARKNET2NCNN_SRC_LAYER ${CMAKE_SOURCE_DIR}/src/main/cpp/darknet2ncnn/src/layer/*.cpp)
 
set(darknet2ncnn_dir ${CMAKE_SOURCE_DIR}/src/main/cpp/darknet2ncnn/src)
set(darknet2ncnn_src ${darknet2ncnn_dir}/layer/darknet_activation.cpp
    ${darknet2ncnn_dir}/layer/darknet_shortcut.cpp
    ${darknet2ncnn_dir}/layer/yolov1_detection.cpp
    ${darknet2ncnn_dir}/layer/yolov3_detection.cpp
    ${darknet2ncnn_dir}/object_detection.cpp
    ${darknet2ncnn_dir}/register_darknet.cpp
    ${darknet2ncnn_dir}/darknet2ncnn.cpp)
 
set(ncnn_src ${CMAKE_SOURCE_DIR}/src/main/cpp/ncnn/src)
 
set(lib_src ${darknet_src} ${darknet2ncnn_src} ${CMAKE_SOURCE_DIR}/src/main/cpp/yolov3-tiny-jni.cpp)
 
add_library( # Sets the name of the library.
        yolov3_tiny_jni
 
        # Sets the library as a shared library.
        SHARED
 
        # Provides a relative path to your source file(s).
        ${lib_src})
 
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
 
find_library( # Sets the name of the path variable.
        log-lib
 
        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log
        android)
#find_library( # Sets the name of the path variable.
        #JniGraphics
 
        # Specifies the name of the NDK library that
        # you want CMake to locate.
        #jnigraphics)
 
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
 
target_link_libraries( # Specifies the target library.
        yolov3_tiny_jni
        libncnn
        jnigraphics
        android
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

編譯後,在build\intermediates\cmake\debug\obj\armeabi-v7a文件下有編譯生成的libyolov3_tiny_jni.so庫文件,然後導入終端運行,Android端實現的yolov3-tiny,時間爲500ms以內

參考:https://github.com/xiangweizeng/darknet2ncnn
參考:https://blog.csdn.net/liuwei36120516/article/details/103783870

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章