android使用YOLOV8数据返回到JAVA方法(JAVA)

4 篇文章 0 订阅
1 篇文章 0 订阅

一、下载扩展文件(最耗时,所以放第一步)

1.opencv下载

1)官网:Releases - OpenCV

2)下载最新版本的android包

2.NCNN下载

1)NCNN下载地址(20220420版本):https://github.com/Tencent/ncnn/releases/download/20220420/ncnn-20220420-android-vulkan.zip

3.在你的android app目录下的build.gradle里面的dependencies添加

implementation 'org.opencv:opencv:4.10.0'

二、使用

1.下载代码示例https://github.com/FeiGeChuanShu/ncnn-android-yolov8

1)把ncnn-android-yolov8-main/ncnn-android-yolov8解压出来打开

2)复制你下载的opencv;ncnn包以及示例代码到这里

3)把这些文件复制进assets目录

4)在res/values/string.xml里面添加

    <string-array name="model_array">
        <item>n</item>
        <item>s</item>
    </string-array>
    <string-array name="cpugpu_array">
        <item>CPU</item>
        <item>GPU</item>
    </string-array>

5)创建jniLibs文件夹把OpenCV-android-sdk/sdk/native/libs里面的东西全放进来

6)修改CMakeLists.txt文件

# 项目名称
project(yolov8ncnn)

# 指定了构建项目所需的最小 CMake 版本为 3.10
cmake_minimum_required(VERSION 3.10)
# opencv下载地址
# https://opencv.org/releases

# 设置了 OpenCV 目录的路径,并使用 find_package 命令来查找 OpenCV 包。REQUIRED 参数表示如果找不到 OpenCV,则构建会失败。core 和 imgproc 是指定要使用的 OpenCV 组件
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/OpenCV-android-sdk/sdk/native/jni)
find_package(OpenCV REQUIRED core imgproc)

# ncnn下载地址
# https://github.com/Tencent/ncnn/releases
# 设置了 ncnn 目录的路径,并查找 ncnn 包。ncnn 是一个高性能神经网络推理框架,常用于移动设备上运行深度学习模型
set(ncnn_DIR ${CMAKE_SOURCE_DIR}/ncnn-20220420-android-vulkan/${ANDROID_ABI}/lib/cmake/ncnn)
find_package(ncnn REQUIRED)

# 定义了一个名为 yolov8ncnn 的共享库(.so 文件),它包含了 yolov8ncnn.cpp, yolo.cpp, 和 ndkcamera.cpp 这三个源文件
add_library(yolov8ncnn SHARED yolov8ncnn.cpp yolo.cpp ndkcamera.cpp)

# 指定了 yolov8ncnn 库需要链接的其他库。具体来说,它将链接 ncnn 库、OpenCV 库(通过 ${OpenCV_LIBS} 变量)、以及 camera2ndk 和 mediandk 这两个库
target_link_libraries(yolov8ncnn ncnn ${OpenCV_LIBS} camera2ndk mediandk)

7)创建SurfaceCallBack和Yolov8Ncnn文件

SurfaceCallBack文件内容

package com.youlian.weight.yolov8;

import android.util.Log;
import android.view.SurfaceHolder;

import androidx.appcompat.app.AppCompatActivity;

import java.util.ArrayList;

public class SurfaceCallBack extends AppCompatActivity implements SurfaceHolder.Callback {
    private String Tag = "SurfaceCallBack";
    private Yolov8Ncnn yolov8ncnn;
    public void setYolov8ncnn(Yolov8Ncnn yolov8ncnn){
        this.yolov8ncnn = yolov8ncnn;
    }

    // 在 Surface 被创建时调用
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    }

    // 在 Surface 尺寸改变时调用
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // 如果需要调整预览大小,可以在 surfaceChanged 中进行
        Log.d(Tag, "尺寸改变");
        yolov8ncnn.setOutputWindow(holder.getSurface(), this);
    }

    // 在 Surface 被销毁时调用
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }

    /**
     * C++检测到商品的回调
     * @param output
     */
    public void onDetect(ArrayList<float[]> output) {
        if (output != null) {
            Log.e(Tag,"检测到" + output.size() + "个目标");
            for (int i = 0; i < output.size(); i++) {
                float[] array = output.get(i);
                float x = array[0];
                float y = array[1];
                float width = array[2];
                float height = array[3];
                float floatValue = array[4];
                int label = (int) floatValue;
                float prob = array[5];
                Log.d(Tag, "x:" + x + ", y:" + y + ", width:" + width + ", height:" + height + ", label:" + label + ", prob:" + prob);
            }
        } else {
            Log.e(Tag, "未检测到商品");
        }
    }
}

Yolov8Ncnn文件内容

package com.youlian.weight.yolov8;

import android.content.res.AssetManager;
import android.view.Surface;

public class Yolov8Ncnn
{
    public native boolean loadModel(AssetManager mgr, int modelid, int cpugpu);
    public native boolean openCamera(int facing);
    public native boolean closeCamera();
    public native boolean setOutputWindow(Surface surface, SurfaceCallBack nativeCallback);

    static {
        System.loadLibrary("yolov8ncnn");
    }
}

8)在首页初始化YOLO和opencv



    /**
     * 初始化 OpenCV
     */
    public void openCvInit(){
//        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        System.loadLibrary("opencv_java4");
    }

    private void yolov8Init(){
        // getPermissions();  // 获取相机和录音权限
        SurfaceCallBack surfaceCallBack = new SurfaceCallBack();
        surfaceCallBack.setYolov8ncnn(yolov8ncnn);

        cameraView = findViewById(R.id.cameraView);
//        cameraView.setVisibility(View.GONE);
        cameraView.getHolder().setFormat(PixelFormat.RGBA_8888);
        cameraView.getHolder().addCallback(surfaceCallBack);

        int current_model = 0; // 使用模型id
        int current_cpugpu = 0; // 使用gpu的ID
        boolean ret_init = yolov8ncnn.loadModel(getAssets(), current_model, current_cpugpu);
        if (!ret_init)
        {
            Log.e(Tag, "yolov8ncnn 加载模型失败!");
        }

        Log.d(Tag,"加载模型成功");

        yolov8ncnn.openCamera(1);
    }

9)页面添加(用于显示内容,可自己修改页面)

    <SurfaceView
        android:id="@+id/cameraView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent">
    </SurfaceView>

10)修改jni里面的yolov8ncnn.cpp文件

还有这几个方法

名称修改规则:Java_com_你的包名_Yolov8Ncnn_loadModel

例如:我的包名是package com.youlian.weight.yolov8,Java_com_youlian_weight_yolov8_Yolov8Ncnn_loadModel

注意Yolov8Ncnn_setOutputWindow方法需要添加这个

JNIEXPORT jboolean JNICALL Java_com_你的包名_Yolov8Ncnn_setOutputWindow(JNIEnv* env, jobject thiz, jobject surface
                                                                                     , jobject native_callback)
{
    ANativeWindow* win = ANativeWindow_fromSurface(env, surface);

    __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "setOutputWindow %p", win);

    g_camera->set_window(win);

    g_yolo->initNativeCallback(javaVM, native_callback);
    return JNI_TRUE;
}

11)修改jni里面的yolo.h文件

    /**
     * 全局引用
     * */
    JavaVM *javaVM;
    //回调类
    jobject j_callback;
    void initNativeCallback(JavaVM *vm, jobject pJobject);

12)修改jni里面的yolo.cpp文件

实现initNativeCallback函数

void Yolo::initNativeCallback(JavaVM *vm, jobject pJobject) {
    javaVM = vm;

    /**
     * JNIEnv不支持跨线程调用
     * */
    JNIEnv *env;
    vm->AttachCurrentThread(&env, nullptr);

    j_callback = env->NewGlobalRef(pJobject);
}

把class_nams放外面去

搜索Yolo::detect方法添加

    /**
     * 回调给Java/Kotlin层
     * */
    JNIEnv *env;
    javaVM->AttachCurrentThread(&env, nullptr);
    jclass callback_clazz = env->GetObjectClass(j_callback);
    jmethodID j_method_id = env->GetMethodID(
            callback_clazz, "onDetect", "(Ljava/util/ArrayList;)V"
    );

    //获取ArrayList类
    jclass list_clazz = env->FindClass("java/util/ArrayList");
    jmethodID arraylist_init = env->GetMethodID(list_clazz, "<init>", "()V");
    jmethodID arraylist_add = env->GetMethodID(list_clazz, "add", "(Ljava/lang/Object;)Z");
    //初始化ArrayList对象
    jobject arraylist_obj = env->NewObject(list_clazz, arraylist_init);

    for (const auto &item: objects) {
        float array[6];
        array[0] = item.rect.x;
        array[1] = item.rect.y;
        array[2] = item.rect.width;
        array[3] = item.rect.height;
        array[4] = (float) item.label;
        array[5] = item.prob;

        jfloatArray result_array = env->NewFloatArray(6);
        env->SetFloatArrayRegion(result_array, 0, 6, array);
        env->CallBooleanMethod(arraylist_obj, arraylist_add, result_array);
    }
    //回调
    env->CallVoidMethod(j_callback, j_method_id, arraylist_obj);

OK!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值