参考资料:https://github.com/FeiGeChuanShu/ncnn-android-yolov8/tree/main/ncnn-android-yolov8
将ncnn-android-yolov8称为A工程,我自己的工程称为B工程
1.下载ncnn-android-yolov8工程,将A中的ncnn-20230223-android-vulkan、yolo.h、yolo.cpp放入B的app/src/main/cpp/目录下。这里用不到摄像头,去掉ndkcamera.h、ndkcamera.cpp。yolov8ncnn.cpp是JNI接口文件,B中已经有了,否则会冲突。

2.将A的Assets目录yolov8n.bin、yolov8n.param、yolov8s.bin、yolov8s.param,复制到B的app/src/main/

3.修改CMakeList.txt,包括了ffmpeg、opencv、ncnn,如果用不上可删除一部分
注意,ffmpeg放到app/src/main/cpp/目录下
cpp
cmake_minimum_required(VERSION 3.10)
project("rtspplayerforandroid")
# 【第一块】全局编译标准、OpenMP 放最顶部
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(OpenMP REQUIRED)
if(OpenMP_FOUND)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS} -static-openmp")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS} -static-openmp")
endif()
# 【第二块】NCNN 先配置,提前加入头文件路径(关键修复)
set(ncnn_DIR ${CMAKE_SOURCE_DIR}/ncnn-20230223-android-vulkan/${ANDROID_ABI}/lib/cmake/ncnn)
find_package(ncnn REQUIRED)
# ncnn头文件路径提前加入,编译源码时就能搜到platform.h/net.h/mat.h
include_directories(${ncnn_INCLUDE_DIRS})
# 【第三块】OpenCV配置
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/opencv-mobile-4.6.0-android/sdk/native/jni)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
# 【第四块】FFmpeg 预编译库 + 头文件
set(JNI_LIBS_DIR ${CMAKE_SOURCE_DIR}/ffmpeg)
include_directories(${JNI_LIBS_DIR}/${ANDROID_ABI}/include)
add_library(avutil SHARED IMPORTED)
set_target_properties(avutil PROPERTIES IMPORTED_LOCATION ${JNI_LIBS_DIR}/${ANDROID_ABI}/lib/libavutil.so )
add_library(swresample SHARED IMPORTED )
set_target_properties(swresample PROPERTIES IMPORTED_LOCATION ${JNI_LIBS_DIR}/${ANDROID_ABI}/lib/libswresample.so )
add_library(swscale SHARED IMPORTED )
set_target_properties(swscale PROPERTIES IMPORTED_LOCATION ${JNI_LIBS_DIR}/${ANDROID_ABI}/lib/libswscale.so )
add_library(avcodec SHARED IMPORTED )
set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${JNI_LIBS_DIR}/${ANDROID_ABI}/lib/libavcodec.so )
add_library(avformat SHARED IMPORTED )
set_target_properties(avformat PROPERTIES IMPORTED_LOCATION ${JNI_LIBS_DIR}/${ANDROID_ABI}/lib/libavformat.so )
add_library(avfilter SHARED IMPORTED )
set_target_properties(avfilter PROPERTIES IMPORTED_LOCATION ${JNI_LIBS_DIR}/${ANDROID_ABI}/lib/libavfilter.so )
# avdevice 如果你没用到可以注释,避免路径不存在报错
# add_library(avdevice SHARED IMPORTED )
# set_target_properties(avdevice PROPERTIES IMPORTED_LOCATION ${JNI_LIBS_DIR}/${ANDROID_ABI}/lib/libavdevice.so )
# 【第五块】现在才创建主库(此时所有头文件路径全部加载完毕)
add_library(
rtspplayerforandroid
SHARED
native-lib.cpp
CustomPlayer.cpp
yolo.cpp
)
# 【第六块】系统日志库
find_library(log-lib log)
# 【第七块】统一链接所有依赖(补齐所有ffmpeg库)
target_link_libraries(
rtspplayerforandroid
avutil
swresample
swscale
avcodec
avformat
avfilter
# avdevice
ncnn
${OpenCV_LIBS}
OpenMP::OpenMP_CXX
android
mediandk
${log-lib}
)
4.添加接口loadModel,加载模型
public native boolean loadModel(AssetManager mgr, int modelid, int cpugpu);
cpp
#include <android/asset_manager_jni.h>
#include <android/native_window_jni.h>
#include <android/native_window.h>
#include <android/bitmap.h>
#include <android/log.h>
#include <jni.h>
#include <string>
#include <vector>
#include <platform.h>
#include <benchmark.h>
#include "yolo.h"
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#if __ARM_NEON
#include <arm_neon.h>
#endif // __ARM_NEON
......
Yolo* g_yolo = 0;
ncnn::Mutex lock;
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_skydroid_rcsdkdemo_MyPlayer_loadModel(JNIEnv *env, jobject thiz, jobject assetManager, jint modelid,
jint cpugpu) {
if (modelid < 0 || modelid > 6 || cpugpu < 0 || cpugpu > 1)
{
return JNI_FALSE;
}
AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
__android_log_print(ANDROID_LOG_DEBUG, "ncnn", "loadModel %p", mgr);
const char* modeltypes[] =
{
"n",
"s",
};
const int target_sizes[] =
{
320,
320,
};
const float mean_vals[][3] =
{
{103.53f, 116.28f, 123.675f},
{103.53f, 116.28f, 123.675f},
};
const float norm_vals[][3] =
{
{ 1 / 255.f, 1 / 255.f, 1 / 255.f },
{ 1 / 255.f, 1 / 255.f, 1 / 255.f },
};
const char* modeltype = modeltypes[(int)modelid];
int target_size = target_sizes[(int)modelid];
bool use_gpu = (int)cpugpu == 1;
// reload
{
ncnn::MutexLockGuard g(lock);
if (use_gpu && ncnn::get_gpu_count() == 0)
{
// no gpu
delete g_yolo;
g_yolo = 0;
}
else
{
if (!g_yolo)
g_yolo = new Yolo;
g_yolo->load(mgr, modeltype, target_size, mean_vals[(int)modelid], norm_vals[(int)modelid], use_gpu);
}
}
return JNI_TRUE;
}
在JNI_OnUnload添加
cpp
{
ncnn::MutexLockGuard g(lock);
delete g_yolo;
g_yolo = 0;
}

5.Java加载模型
cpp
myPlayer = new MyPlayer();
myPlayer.loadModel(getAssets(),0,0);
6.在CustomPlayer.cpp加入识别代码
注意yolo.detect默认mat为rgb,如果是RGBA格式,需要修改yolo.detect函数
cpp
#include "yolo.h"
extern Yolo* g_yolo;
extern ncnn::Mutex lock;
......
if (g_yolo)
{
std::vector<Object> objects;
g_yolo->detect(mat, objects, 0.25f, 0.45f);
g_yolo->draw(mat, objects);
}
将ncnn::Mat::PIXEL_RGB2BGR改为ncnn::Mat::PIXEL_RGBA2BGR

