在android studio上使用rknn模块下面的yolov8_pose模子

打印 上一主题 下一主题

主题 1658|帖子 1658|积分 4974

我的第一想法就是直接把rk的demo当成so库封装来用,我直接在yolov8_pose的c代码下面添加yolov8_pose.cc与yolov8_pose.h用作封装,先上代码
  yolov8_pose.cc
  1. #include "yolov8_pose.h"
  2. #include <stdint.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include "yolov8-pose.h"
  7. #include "image_utils.h"
  8. #include "file_utils.h"
  9. #include "image_drawing.h"
  10. #include "postprocess.h"
  11. int skeleton[38] ={16, 14, 14, 12, 17, 15, 15, 13, 12, 13, 6, 12, 7, 13, 6, 7, 6, 8,
  12.             7, 9, 8, 10, 9, 11, 2, 3, 1, 2, 1, 3, 2, 4, 3, 5, 4, 6, 5, 7};
  13. int ret;
  14. rknn_app_context_t rknn_app_ctx;
  15. image_buffer_t src_image;
  16. int yolov8_init() {
  17.         memset(&rknn_app_ctx, 0, sizeof(rknn_app_context_t));
  18.        
  19.         init_post_process();
  20.        
  21.     ret = init_yolov8_pose_model("/data/user/0/com.rockchip.gpadc.yolodemo/cache/yolov8_pose.rknn", &rknn_app_ctx);
  22.     if (ret != 0) {
  23.         printf("yolov8_init fail! ret=%d\n", ret);
  24.     }
  25.     return ret;
  26. }
  27. char* run_yolov8_pose(unsigned char* pixeldata,int cound) {
  28.     memset(&src_image, 0, sizeof(image_buffer_t));
  29.     //ret = read_image("/data/model/test.jpg", &src_image);
  30.        
  31.          // 默认图像为3通道
  32.     int w = 1280, h = 720, c = 3;
  33.     // printf("load image wxhxc=%dx%dx%d path=%s\n", w, h, c, path);
  34.     int msize = w * h * c;
  35.     // 设置图像数据
  36.     (&src_image)->virt_addr = pixeldata;
  37.     (&src_image)->width = w;
  38.     (&src_image)->height = h;
  39.         (&src_image)->format = IMAGE_FORMAT_RGB888;
  40.        
  41.   //  if (ret != 0)
  42.    // {
  43.    //     printf("read image fail! ret=%d image_path=%s\n", ret, "/data/model/test.jpg");
  44.    // }
  45.     object_detect_result_list od_results;
  46.     ret = inference_yolov8_pose_model(&rknn_app_ctx, &src_image, &od_results);
  47.     if (ret != 0)
  48.     {
  49.         printf("inference_yolov8_pose_model fail! ret=%d\n", ret);
  50.     }
  51.          char buffers[1024]; // 用于存储格式化后的字符串
  52.          char *finalBuffer = NULL; // 用于存储最终的字符串
  53.          // 分配足够的内存来存储所有字符串
  54.      finalBuffer = (char *)malloc(4084);
  55.      if (finalBuffer == NULL) {
  56.          perror("内存分配失败");
  57.      }
  58.          
  59.         // 初始化最终缓冲区
  60.     finalBuffer[0] = '\0';
  61.                
  62.         // 格式化字符串
  63.      snprintf(reinterpret_cast<char *const>(buffers), sizeof(buffers), "%3d\n", "");
  64.       
  65.     // 画框和概率
  66.     char text[256];
  67.    
  68.     for (int i = 0; i < od_results.count; i++)
  69.     {
  70.                 //做一个限制人数的功能
  71.                 if(od_results.count <= cound){
  72.                         object_detect_result *det_result = &(od_results.results[i]);
  73.                     // 将信息格式化到临时缓冲区
  74.                         //snprintf(buffers, 1024, "%s (left:%d top:%d right:%d bottom:%d) 概率:%.3f length:%d\n",
  75.                         //                        coco_cls_to_name(det_result->cls_id),
  76.                         //                        det_result->box.left, det_result->box.top,
  77.                         //                        det_result->box.right, det_result->box.bottom,
  78.                         //                        det_result->prop,od_results.count);
  79.                        
  80.                         snprintf(buffers, 1024, "%s (left:%d top:%d right:%d bottom:%d) 概率:%.3f length:%d\n",
  81.                                                 "person-pose",
  82.                                                 det_result->box.left, det_result->box.top,
  83.                                                 det_result->box.right, det_result->box.bottom,
  84.                                                 det_result->prop,od_results.count);
  85.                        
  86.                        
  87.                        
  88.        
  89.                         // 将格式化后的字符串附加到 finalBuffer
  90.                         strcat(finalBuffer, buffers);
  91.    
  92.                         for (int j = 0; j < 38/2; ++j)
  93.                         {
  94.                                 int x1 = (int)(det_result->keypoints[skeleton[2*j]-1][0]);
  95.                                 int y1 = (int)(det_result->keypoints[skeleton[2*j]-1][1]);
  96.                                 int x2 = (int)(det_result->keypoints[skeleton[2*j+1]-1][0]);
  97.                                 int y2 = (int)(det_result->keypoints[skeleton[2*j+1]-1][1]);
  98.                
  99.                                 // 将线段坐标添加到 finalBuffer
  100.                                 snprintf(buffers, 1024, "skeleton:(%d, %d,%d, %d)\n", x1, y1, x2, y2);
  101.                                 strcat(finalBuffer, buffers);
  102.                         }
  103.                        
  104.                         for (int j = 0; j < 17; ++j)
  105.                         {
  106.                                 int cx = (int)(det_result->keypoints[j][0]);
  107.                                 int cy = (int)(det_result->keypoints[j][1]);
  108.                                 // 将关键点坐标添加到 finalBuffer
  109.                                 snprintf(buffers, 1024, "key:(%d, %d)\n",cx, cy);
  110.                                 strcat(finalBuffer, buffers);
  111.                         }
  112.                 }
  113.         
  114.     }
  115.    // write_image("/data/model/out.jpg", &src_image);
  116.        
  117. //}
  118.        
  119.     return finalBuffer;
  120. }
  121. void yolov8_cleanup() {
  122.     deinit_post_process();
  123.     ret = release_yolov8_pose_model(&rknn_app_ctx);
  124.     if (ret != 0)
  125.     {
  126.         printf("release_yolov5_model fail! ret=%d\n", ret);
  127.     }
  128.     if (src_image.virt_addr != NULL)
  129.     {
  130.         free(src_image.virt_addr);
  131.     }
  132. }
复制代码
yolov8_pose.h
  1. #ifndef YOLOV8_POSE_H
  2. #define YOLOV8_POSE_H
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. // 初始化模型
  7. int yolov8_init();
  8. // 执行推理
  9. char*  run_yolov8_pose(unsigned char* pixeldata,int cound);
  10. // 清理工作
  11. void yolov8_cleanup();
  12. #ifdef __cplusplus
  13. }
  14. #endif
  15. #endif // YOLOV8_POSE_H
复制代码
1.代码解析


  • 我细致研究了一下代码,我发现,rk的demo是读取一张640*640的图片输入模子,然后再输出一张640*640带上骨架等信息的图片
  • 我的功能逻辑是实时输入摄像头帧数据,然后输出骨架信息,人相框信息等
  • 我这里默认使用1280*720的像素, 我这里写死了rknn模子的地点,你们可以自行更改
  • 既然我把功能代码封装好了,我们就需要把这些功能代码打包成库,所以我们需要更改一下配置文件
  • 这里的CMakeLists.txt文件我没有去做编削,我只是在原根本上增加打包库文件,并且使用全部的接口,如下源码
  1. cmake_minimum_required(VERSION 3.10)
  2. project(rknn_yolov8_pose_demo)
  3. set(rknpu_yolov8-pose_file rknpu2/yolov8-pose.cc)
  4. # 添加第三方库和工具库
  5. add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/ 3rdparty.out)
  6. add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../../utils/ utils.out)
  7. set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
  8. file(GLOB SRCS ${CMAKE_CURRENT_SOURCE_DIR}/*.cc)
  9. # 定义共享库 yolov8_pose
  10. add_library(yolov8_pose SHARED
  11.     yolov8_pose.cc
  12.     postprocess.cc
  13.     ${rknpu_yolov8-pose_file}
  14. )
  15. # 将包含目录添加到 yolov8_pose 库
  16. target_include_directories(yolov8_pose PRIVATE
  17.     ${CMAKE_CURRENT_SOURCE_DIR}                    
  18.     ${LIBRKNNRT_INCLUDES}                        
  19.     ${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty   
  20.     ${CMAKE_CURRENT_SOURCE_DIR}/../../../utils/   
  21. )
  22. # 定义一个变量,包含公共库
  23. set(COMMON_LIBS
  24.     imageutils
  25.     fileutils
  26.     imagedrawing   
  27.     ${LIBRKNNRT}
  28.     dl
  29. )
  30. # 将共享库 yolov8_pose 链接到相关库
  31. target_link_libraries(yolov8_pose ${COMMON_LIBS})
  32. # 添加可执行文件
  33. add_executable(${PROJECT_NAME}
  34.     main.cc
  35.     postprocess.cc
  36.     ${rknpu_yolov8-pose_file}
  37. )
  38. # 将可执行文件链接到共享库和公共库
  39. target_link_libraries(${PROJECT_NAME}
  40.     yolov8_pose
  41.     ${COMMON_LIBS}  # 也链接公共库
  42. )
  43. if (CMAKE_SYSTEM_NAME STREQUAL "Android")
  44.     target_link_libraries(${PROJECT_NAME}
  45.         log
  46.     )
  47. endif()
  48. if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
  49.     set(THREADS_PREFER_PTHREAD_FLAG ON)
  50.     find_package(Threads REQUIRED)
  51.     target_link_libraries(${PROJECT_NAME} Threads::Threads)
  52. endif()
  53. target_include_directories(${PROJECT_NAME} PRIVATE
  54.     ${CMAKE_CURRENT_SOURCE_DIR}
  55.     ${LIBRKNNRT_INCLUDES}
  56. )
  57. # 安装目标
  58. install(TARGETS ${PROJECT_NAME} DESTINATION .)
  59. install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../model/bus.jpg DESTINATION ./model)
  60. install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../model/yolov8_pose_labels_list.txt DESTINATION ./model)
  61. file(GLOB RKNN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/../model/*.rknn")
  62. install(FILES ${RKNN_FILES} DESTINATION model)
  63. # 安装共享库
  64. install(TARGETS yolov8_pose DESTINATION lib)
复制代码
编译:这里就能在install下面找到我们编译成功的库

   2.android studio使用,直接使用ndk开辟


先上代码:
   native-lib.cc
  1. #include <jni.h>
  2. #include <unistd.h>
  3. #include <errno.h>
  4. #include <string.h>
  5. #include <pthread.h>
  6. #include <sys/syscall.h>
  7. #include <sched.h>
  8. #include <stdint.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include "yolov8_pose.h"
  12. /******************************************************yolov8***************************************************/
  13. // 其他必要的引入
  14. #include <android/log.h>
  15. //#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "YOLOv8PoseJNI", __VA_ARGS__))
  16. #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "YOLOv8PoseJNI", ##__VA_ARGS__);
  17. extern "C" JNIEXPORT void JNICALL
  18. Java_com_rockchip_gpadc_demo_yolo_InferenceWrapper_native_1inityolov8(JNIEnv *env, jobject obj) {
  19.     int ret = yolov8_init();
  20.     LOGI("Java_com_rockchip_gpadc_demo_yolo_InferenceWrapper_native_1inityolov8  yolov8_init: %d",
  21.          ret);
  22. }
  23. // 推理
  24. extern "C" JNIEXPORT void JNICALL
  25. Java_com_rockchip_gpadc_demo_yolo_InferenceWrapper_native_1inference(JNIEnv *env, jobject obj,
  26.                                                                      jobject call_back,
  27.                                                                      jbyteArray imageData,
  28.                                                                      jint width, jint height) {
  29.     // 创建一个 JNI 全局引用
  30.     jobject global_callback = (*env).NewGlobalRef(call_back);
  31.     // 获取回调方法的方法ID
  32.     jclass cls = (*env).GetObjectClass(call_back);
  33.     jmethodID gCallBackMid = (*env).GetMethodID(cls, "onCall", "(Ljava/lang/String;)V");
  34.     // 获取字节数组的指针
  35.     jbyte *byteArray = (*env).GetByteArrayElements(imageData, NULL);
  36.     if (byteArray == nullptr) {
  37.         return; // 获取数组元素失败
  38.     }
  39.     //我这里限制五个人 前五个 后面的不管 数据量太大的话可能刷新不过来
  40.     char *result = run_yolov8_pose(reinterpret_cast<unsigned char *>(byteArray),5);
  41.     // 将 char* 转换为 Java 字符串
  42.     jstring resultString = env->NewStringUTF(result);
  43.     // 调用回调方法,将结果字符串传递回 Java 侧
  44.     env->CallVoidMethod(global_callback, gCallBackMid, resultString);
  45.     // 释放 JNI 创建的字符串
  46.     env->DeleteLocalRef(resultString); // 删除局部引用的字符串
  47.     // 释放字节数组的元素
  48.     env->ReleaseByteArrayElements(imageData, byteArray, 0);
  49.     // 释放全局引用
  50.     env->DeleteGlobalRef(global_callback);
  51. }
  52. // 清理资源
  53. extern "C" JNIEXPORT void JNICALL
  54. Java_com_rockchip_gpadc_demo_yolo_InferenceWrapper_native_1releaseModel(JNIEnv *env, jobject obj) {
  55.     yolov8_cleanup();
  56. }
复制代码
  CMakeLists.txt
  1. # For more information about using CMake with Android Studio, read the
  2. # documentation: https://d.android.com/studio/projects/add-native-code.html
  3. # Sets the minimum version of CMake required to build the native library.
  4. cmake_minimum_required(VERSION 3.4.1)
  5. # Creates and names a library, sets it as either STATIC
  6. # or SHARED, and provides the relative paths to its source code.
  7. # You can define multiple libraries, and CMake builds them for you.
  8. # Gradle automatically packages shared libraries with your APK.
  9. # include rga.
  10. #include_directories(src/main/cpp/rga)
  11. add_library( # Sets the name of the library.
  12.              rknn4j
  13.              # Sets the library as a shared library.
  14.              SHARED
  15.              # Provides a relative path to your source file(s).
  16.              src/main/cpp/native-lib.cc
  17.              src/main/cpp/yolov8_pose.h
  18.              )
  19. # Searches for a specified prebuilt library and stores the path as a
  20. # variable. Because CMake includes system libraries in the search path by
  21. # default, you only need to specify the name of the public NDK library
  22. # you want to add. CMake verifies that the library exists before
  23. # completing its build.
  24. find_library( # Sets the name of the path variable.
  25.               log-lib
  26.               # Specifies the name of the NDK library that
  27.               # you want CMake to locate.
  28.               log )
  29. # Specifies libraries CMake should link to your target library. You
  30. # can link multiple libraries, such as libraries you define in this
  31. # build script, prebuilt third-party libraries, or system libraries.
  32. target_link_libraries( # Specifies the target library.
  33.                        rknn4j
  34.                        # Links the target library to the log library
  35.                        # included in the NDK.
  36.                        ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/librknnrt.so
  37.                        ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/librga.so
  38.                        ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libyolov8_pose.so
  39.                        ${log-lib} )
复制代码
   这里我在native-lib.cc使用了实时回调,把模子推理数据实时的回调给app,app调用
  1. package com.rockchip.gpadc.demo.yolo;
  2. import com.rockchip.gpadc.demo.callstr;
  3. /**
  4. * Created by randall on 18-4-18.
  5. */
  6. public class InferenceWrapper {
  7.     private final String TAG = "rkyolo.InferenceWrapper";
  8.     static {
  9.         System.loadLibrary("rknn4j");
  10.     }
  11.     public InferenceWrapper() {
  12.     }
  13.       public void setmessage(byte[] bytes, final callstr mcallstr){
  14.          // Log.e("TAG","setmessage bytes==="+bytes.length);
  15.           native_inference(new INativeListener() {
  16.               @Override
  17.               public void onCall(String str) {
  18.                 //  Log.e("TAG","模型回调数据======"+str);
  19.                   mcallstr.onCall(str);
  20.               }
  21.           },bytes,1280,720);
  22.      }
  23.     public int initModel(){
  24.         native_inityolov8();
  25.         return 0;
  26.     }
  27.     public void deinit() {
  28.         native_releaseModel();
  29.     }
  30.     // java回调接口 INativeListener.java
  31.     interface INativeListener {
  32.         void onCall(String str);
  33.     }
  34.     /**************************************************yolov8******************************************/
  35.     private native void native_inityolov8();
  36.     private native void native_inference(INativeListener mINativeListener,byte[] imageData, int width, int height);
  37.     private native void native_releaseModel();
  38. }
复制代码
   这里我做了个回调接口,在对应的地方调用即可
  这里还有个说明,因为rknn的推理数据是rgb的数据,但是很多摄像头的数据是yuv-nv12或者nv21,这里输入数据的时候需要转化一下,这个网上随便搜,很多.
  

  • 详细的打开摄像头,解析数据等代码这里我不能贴出来
  • 其实步骤很简单,在oncreat里面先初始化调用
    1. public int initModel(){
    2.     native_inityolov8();
    3.     return 0;
    4. }
    复制代码
  • 然后转换一下数据格式传入jni,就能实时得到数据了
    1. native_inference(new INativeListener() {
    2.     @Override
    3.     public void onCall(String str) {
    4.         Log.e("TAG","模型回调数据======"+str);
    5.         //解析
    6.     }
    7. },bytes,1280,720);
    复制代码
  • 详细怎么解析你们可以自定义上面的格式,这里我是一个数据一行,你们可以更改上面的yolov8_pose.cc里面的finalBuffer数据,这个数据就是全部数据回调
  • 详细就这些了,有什么不懂的可以找我咨询.
  



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

汕尾海湾

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表