1. 前言
通过前两篇文章 Android 导入ncnn-android-yolov8-seg : 实现人体识别和人像分割 、Android ncnn-android-yolov8-seg源码解析 : 实现人像分割 ,我们已经跑起来了程序,也分析了其源码。
接下来,这篇文章我们来实战一下,抽取出Demo
的核心代码,在自己的项目中,使用Java
层的Camera API
,在JNI
层使用OpenCV+YOLOv8+NCNN
,来实现人体识别和人像分割功能。
实现效果如下,整个图像的是相机的原图,左上角部分,是我们进行人像识别、人像分割后,处理得到的图像 (未做镜像处理,所以暂时和原图左右是相反的)
>>> 本文的源码demo可以直接看这里 :
Android 基于 OpenCV+YOLOv8+NCNN 实现人像分割 Demo 源码下载
2. 新建项目
2.1 新建主项目
2.2 新建 Native library
2.3 在app中添加MyNcnnLib依赖
implementation(project(mapOf("path" to ":MyNcnnLib")))
2.4 配置NDK版本
记得在项目根目录下的local.properties
中,配置NDK
版本,这里的NDK
版本需要在NDK16-NDK20
之间
# 这里的路径需修改为你电脑中ndk的具体路径
ndk.dir=C\:\\Developer\\Android_SDK\\ndk\\20.0.5594570
3. 接入OpenCV+YOLOv8+NCNN
3.1 导入NCNN和OpenCV
我们将ncnn-20221128-android-vulkan
和opencv-mobile-4.6.0-android
复制到cpp
文件夹下
3.2 复制cpp文件
将yolo.cpp
、yolo.h
复制到cpp
文件夹下
3.3 配置Cmake
新版Android Studio
中CMakeLists.txt
的位置和Android Studio 3.6
中CMakeLists.txt
的路径位置不一样,所以CMakeLists.txt
在设置配置的时候,设置的路径也是不一样的。
初始的CMakeLists.txt
cmake_minimum_required(VERSION 3.22.1)
project("myncnnlib")
add_library(${
CMAKE_PROJECT_NAME} SHARED
myncnnlib.cpp)
target_link_libraries(${
CMAKE_PROJECT_NAME}
android
log)
配置后的CMakeLists.txt
cmake_minimum_required(VERSION 3.22.1)
project("myncnnlib")
set(OpenCV_DIR ${
CMAKE_SOURCE_DIR}/opencv-mobile-4.6.0-android/sdk/native/jni)
find_package(OpenCV REQUIRED core imgproc)
set(ncnn_DIR ${
CMAKE_SOURCE_DIR}/ncnn-20221128-android-vulkan/${
ANDROID_ABI}/lib/cmake/ncnn)
find_package(ncnn REQUIRED)
add_library(${
CMAKE_PROJECT_NAME} SHARED
myncnnlib.cpp
yolo.cpp)
target_link_libraries(${
CMAKE_PROJECT_NAME}
ncnn
camera2ndk
mediandk
${
OpenCV_LIBS}
android
log)
4. 创建JNI接口
4.1 新建JNI接口
在NcnnNativeLib.kt
中,新增两个JNI
方法
/**
* 初始化NCNN
*
* @return 是否成功
*/
external fun load(mgr: AssetManager, modelid: Int, cpugpu: Int): Boolean
/**
* 人像检测
*
*/
external fun detect(data: ByteArray?, width: Int, height: Int, cameraId: Int): ByteArray
4.2 cpp中增加对应JNIf方法
在myncnnlib.cpp
中,增加对应的JIN
方法
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_heiko_myncnnlib_NativeLib_load(JNIEnv *env, jobject thiz, jobject assetManager,
jint modelid, jint cpugpu) {
}
extern "C"
JNIEXPORT jbyteArray JNICALL
Java_com_heiko_myncnnlib_NativeLib_detect(JNIEnv *env, jobject thiz, jbyteArray data_,
jint w, jint h, jint camera_id) {
}
4.3 声明include
#include <jni.h>
#include <string>
#include <platform.h>
#include <benchmark.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include "opencv2/opencv.hpp"
#include <string>
#include <iostream>
#include "yolo.h"
static Yolo *g_yolo = 0;
static ncnn::Mutex lock;
4.4 加载模型
这里将Demo
中的loadModel
中的代码,全部拷贝过来
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_heiko_myncnnlib_NativeLib_load(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[] =
{