Java 调用 C++ 的完整流程(插件开发)

关于我为啥捣鼓这玩意

这是我的废话...不想看的直接上拉跳过看下个标题

  • 先声明下,本人没有系统地学习过JAVA或者C++
  • 我个人觉得学习东西,不要直接就去看那些所谓的教程,现在AI这么发达,完全可以直接问
  • 所以,当我产生了开发Autojs插件的想法的时候,我第一时间不是去学JAVA基础,而是直接去看插件开发流程
  • 因为有其它语言基础,至少Java一些共通点还是懂得,不懂的时候直接问AI,java的各种代码都是Ai给我写的,我只需要知道每一块代码的作用,并把它们拼接起来
  • 于是在AI的帮助下,我成功开发出Autojs的插件了,虽然让我直接写java,可能即使是一个toast我都写不出来,但是至少在阅读或者修改源码方面是无障碍了,而这就足够了
  • 在前天,我成功把Autojs的YoloV8插件开发出来了,各种功能都符合预想,但是yolov8训练出来的pt模型导出麻烦,比如修改代码文件后先导出onnx,再用pnnx工具将onnx导出ncnn才能使用
  • yolov8目前是自带一键将pt导出ncnn的,但是用在我上面的插件上却不行,而ncnn提供了最新的yolov8.cpp代码,这个是适配一键导出的模型的
  • 那么问题就来了....我不会C++
  • 此时我有两个选择,
    • 凑合用吧,也就导出模型麻烦,至少能用不是吗?
    • 继续造,C++而已,干他
      我选择了后者,给我自己一天时间,不行就放弃。
  • 于是我就思考可行的方案,一种是在现有的代码框架上修改源码,一一比对,看看到底差在哪里了,结果浪费了半天都没比对出个啥,一改就是各种报错,放弃了,毕竟对我来说还是个全新的语言,全文都没看懂怎么改
  • 换了一种方案:不去研究代码的实现,去研究如何如何调用,到时候把原有的cpp相关的都删掉,自己再重新调用就好了
  • 通过从java层的函数进行调用溯源追踪,一步一步追加到了C++,我明白了整个流程。
  • 但是过程没那么顺利,老是有红字报错,差点给他搞奔溃了,AI也没问出个所以然,各种排查问题,交叉编译是真的让人头疼
  • 当然,既然你看到了这篇文章,那就说明我最后还是成功了~

效果图示

这是由纯yolov8自带的ncnn一键导出的模型推理的结果。


至于插件的后续开发,还得两三天,在此占个位,后续补充最终插件成果!

配置 CMake 路径

在 build.gradle 文件的 android 节点下配置 CMake 路径。CMake 是用于构建本地代码的工具,通过它可以在 Android 应用中集成 C++ 代码。

android {
    ...
    externalNativeBuild {
        cmake {
            version "3.22.1" // 指定CMake版本
            path file('src/main/jni/CMakeLists.txt') // CMakeLists.txt文件的位置
        }
    }
}

配置 CMakeLists.txt

CMakeLists.txt 是 CMake 的配置文件,用于定义项目构建的各种规则和选项。在这个文件中,你需要指定使用的 C++ 标准、库文件、以及与 Java 层的接口函数。

# 设置CMake的最低版本
cmake_minimum_required(VERSION 3.22.1)

# 定义项目名称和使用的语言
project(yolov8ncnn LANGUAGES CXX)

# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 添加源文件并生成共享库
add_library(yolov8ncnn SHARED yolov8ncnn.cpp)

# 链接必要的库
find_library(log-lib log) # 查找log库,用于日志输出
target_link_libraries(yolov8ncnn ${log-lib} ncnn) # 链接ncnn库和log库

实现接口层 (yolov8ncnn.cpp)

在 C++ 文件中,编写 JNI 接口函数,该函数将暴露给 Java 层使用。需要用 extern "C" 来防止函数名被 C++ 编译器修改(名字修饰)。

#include <jni.h>
#include <vector>
#include <opencv2/opencv.hpp> // OpenCV库
#include "ncnn/include/net.h" // ncnn库
#include "yolov8ncnn.h" // 引入声明函数和数据结构

// 编写具体的 YOLOv8 检测逻辑
int detect_yolov8(const cv::Mat& bgr, std::vector<Object>& objects) {
    // 实现检测逻辑,例如利用ncnn库进行YOLOv8推理
    // 1. 创建ncnn::Net对象
    // 2. 加载YOLOv8模型
    // 3. 执行检测并解析输出

    return 0; // 假设0表示成功
}

// JNI 接口函数定义
extern "C" {
    JNIEXPORT jint JNICALL Java_com_daowuya_ajyolov8_NCNN_detectYolov8(JNIEnv* env, jobject thiz, jobject bitmap) {
        // 从Bitmap转换为OpenCV的Mat对象
        cv::Mat bgr; // 这里需要完成Bitmap到Mat的转换
        std::vector<Object> objects;

        // 调用本地检测函数
        int result = detect_yolov8(bgr, objects);

        // 检测完成后,可以将检测结果返回给Java层

        return result; // 返回检测结果
    }
}

声明接口层函数 (yolov8ncnn.h)

声明本地函数接口,以便清晰地分离接口层和具体实现。

// 声明你需要的对象结构体
struct Object {
    cv::Rect_<float> rect;
    int label;
    float prob;
};
int detect_yolov8(const cv::Mat& bgr, std::vector<Object>& objects);

Java 对接层 (com.daowuya.ajyolov8.NCNN)

在 Java 层中,使用 System.loadLibrary 加载本地库,并调用 JNI 接口函数。你需要在 Java 类中声明一个 native 方法,这个方法名必须与 C++ 代码中的 JNI 函数名相对应。

package com.daowuya.ajyolov8;

public class NCNN {
    // 加载本地库
    static {
        System.loadLibrary("yolov8ncnn");
    }

    // 声明一个native方法,用于调用C++中的检测函数
    public native int detectYolov8(Bitmap bitmap);

    // 可以实现一个Java方法来调用native方法并处理结果
    public void runDetection(Bitmap bitmap) {
        int result = detectYolov8(bitmap);
        // 根据result做进一步处理,例如显示检测结果
    }
}

结语

  • 本文仅仅是笔主为了记录学习历程、分享技术而作。
  • 如果你是C++大佬,本文中如果有不对的地方欢迎留言指正!

作 者:道无涯
来 源:道无涯博客
链 接: https://www.daowuya.love/java-调用-c-的完整流程(插件开发)/
版 权 声 明:本博客所有文章除特别声明外,均采用CC BY-NC-SA 4.0许可协议。文章版权归作者所有,未经允许请勿转载!


暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇