更新: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。參考以下兩項目,感謝作者大佬。