darknet使用ncnn並移植到android


更新:https://github.com/paleomoon/darknet-ncnn-android ,下面的都不要看了。

//-------------------------------------------------------------------------------------------

項目使用的版本是老版darknet2ncnn,之后作者適配到了ncnn最新版

編譯安卓版ncnn

在linux下編譯,查看官方教程即可。注意使用與android studio相同版本的ndk。設置android studio ndk:修改local.properties,ndk.dir=D:\softback\Android\android-ndk-r15c

添加相關源文件

將darknet、ncnn、darknet2ncnn相關源文件和頭文件按目錄添加到cpp目錄下,目錄結構如下:

├─darknet
│  ├─include
│  └─src
├─darknet2ncnn
│  ├─include
│  └─src
└─ncnn
    ├─include
    └─src

darknet源碼報錯:compare.c:17:13 error: initializing 'network' (aka 'struct network') with an expression of incompatible type 'network *' (aka 'struct network *'); dereference with *.修改compare.c,多處對應的指針類型和引用改一下就OK。

在darknet和darknet2ncnn package下new package,添加相關源碼,但編譯后android studio中該源碼目錄會顯示在cpp目錄下,不清楚啥原因,不過不影響編譯。

編寫Cmakelists.txt

這個是重點,很多問題就是沒有寫好Cmakelists.txt引起的。

cmake_minimum_required(VERSION 2.8.10)

set(CMAKE_BUILD_TYPE RELEASE)

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")

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)

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})

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)

target_link_libraries( # Specifies the target library.
        yolov3_tiny_jni
        libncnn
        jnigraphics

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

錯誤解決

報錯:undefined reference to 'typeinfo for ncnn::Layer',這個在arm-linux交叉編譯時遇到過,添加-fno-rtti編譯選項即可。

報錯:fatal error: use of undeclared identifier 'nullptr',添加-std=c++11編譯選項即可。

make project編譯成功,so生成位置:app\build\intermediates\cmake\debug\obj\armeabi-v7a\

build apk報錯:Cause: org.jetbrains.plugins.gradle.tooling.util.ModuleComponentIdentifierImpl.getModuleIdentifier()Lorg/gradle/api/artifacts/ModuleIdentifier; 更新android studio即可.

ex.extract返回-100,一般是沒找到目標,這里有兩種可能,一種是模型正確檢測正確,測試圖片本來就沒目標,另一種情況就是模型有問題,不能正常檢測到我們的目標。我反復檢查了測試圖片和模型都沒問題,最后發現還是加載模型錯誤:

private String getPathFromAssets(String assetsFileName){
    File f = new File(getCacheDir()+"/"+assetsFileName);
    if (!f.exists())
        try {
        InputStream is = getAssets().open(assetsFileName);
        int size = is.available();
        byte[] buffer = new byte[size];
        is.read(buffer);
        is.close();
        FileOutputStream fos = new FileOutputStream(f);
        fos.write(buffer);
        fos.close();
    } catch (Exception e) { throw new RuntimeException(e); }
    return f.getPath();
}

之前的模型已經加載到緩存中了,后來我更換過一次模型,但是緩存沒刪除,還是之前的模型,所以一直檢測不到目標,將if (!f.exists())注釋掉,每次初始化都重新寫入緩存,最后成功檢測到目標。

總結

其實也比較簡單,主要就寫了個Cmakelists.txt。參考以下兩項目,感謝作者大佬。

參考

安卓應用層

darknet2ncnn


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM