使用MMDeploy(预编译包)转换MMxx(MMDeploy支持库均可)pth权重到onnx,并使用C++ SDK加载onnx得到dll动态链接库,实现在windows平台中调用(linux也适用)

注意
需要首先完成 准备工作空间 所需环境配置 使用MMDeploy得到onnx三个部分之后,再进行本文接下来的操作。

上述三个部分的内容及详细配置过程,请参考本人另外一篇文章使用MMDeploy(预编译包)转换MMxx(MMDeploy支持库均可)pth权重到onnx,并使用python SDK进行部署验证

  1. 准备工作空间
  2. 所需环境配置
  3. 使用MMDeploy得到onnx
  4. 使用MMDeploy加载onnx模型对单张图片进行推理
  5. 使用python SDK对onnx模型进行验证

在完成上述三个部分的配置之后,请接着进行本文以下部分的实践操作,来完成使用MMDeploy C++ SDK开发包加载onnx,并最终打包成dll动态链接库,并加载dll动态链接库进行推理。

注意下文中出现的“mmdeploy-0.14.0-windows-amd64-cuda11.3”等,凡是在本文文字中不存在的,均在另外一篇博文**使用MMDeploy(预编译包)转换MMxx(MMDeploy支持库均可)pth权重到onnx,并使用python SDK进行部署验证**中给予了详细地说明,请移步该博文查看。

工作空间说明

按照上述本人的另外一篇博文完成配置之后,得到的工作空间为work_space_1,那么现在需要创建一个新的工作空间work_space_2,该工作空间具体结构如下:

--------work_space_2
--------------------------bin(将之前下载好的mmdeploy-0.14.0-windows-amd64-cuda11.3中bin文件夹拷贝到这里)
--------------------------images(用于加载dll动态链接库来进行推理的图片文件夹)
--------------------------include(存放用于C++编译所需要的mmdeploy头文件,将mmdeploy-0.14.0-windows-amd64-cuda11.3中的include/mmdeploy文件夹拷贝到这里即可)
--------------------------lib(将mmdeploy-0.14.0-windows-amd64-cuda11.3文件夹下的lib拷贝到这里即可)
--------------------------onnx(将在上述本人的另一篇博文中得到的onnx以及其配套的deploy.json/detail.json/pipeline.json复制到该文件夹下即可,共四个文件)
--------------------------src(用于创建推理动态链接库dll的cpp文件,自行创建,后续会有详细示例代码demo)
--------------------------thirdparty(将mmdeploy-0.14.0-windows-amd64-cuda11.3文件夹下的thirdparty文件夹拷贝到这里即可)
--------------------------CMakeLists.txt(cmake文件,自行创建,后续会有详细地配置示例)

编译环境配置

为了实现对C++语言的编译,我这里参考了官方给出的编译环境(Visual Studio 2019),由于网上存在很多质量很好的VC配置教程,因此这里不再赘述,重点将放在使用MMDeploy需要的配置过程。

  1. CMake版本说明
    cmd 运行:cmake --version
cmake version 3.25.0

CMake suite maintained and supported by Kitware (kitware.com/cmake).
  1. opencv配置
    1) 这里需要说明,本人使用的为opencv 3.4.6的exe预编译版本,如果你想通过自行编译opencv,请查看相关博文。
    直接从如下链接下载:
    opencv 3.4.6 exe官方release下载
    2) 下载完成之后,解压exe文件到任意位置,然后将如下路径 “path/to/opencv_3_4_6_build_from_exe/opencv/build” 添加到系统环境变量中即可。

src目录下cpp推理文件的创建

详细地的cpp示例代码如下,参考于MMDeploy官方代码,文件命名为:object_detection_my.cpp

#include <fstream>
#include <opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <string>
#include <mmdeploy/detector.h>

// 加入extern "C"用于编译为dll使用
extern "C"{
__declspec(dllexport) int do_inference(const char *device_name, const char *model_path, const char *image_path);
}

int do_inference(const char *device_name, const char *model_path, const char *image_path) {
  cv::Mat img = cv::imread(image_path);
  if (!img.data) {
    fprintf(stderr, "failed to load image: %s\n", image_path);
    return 1;
  }

  mmdeploy_detector_t detector{};
  int status{};
  status = mmdeploy_detector_create_by_path(model_path, device_name, 0, &detector);
  if (status != MMDEPLOY_SUCCESS) {
    fprintf(stderr, "failed to create detector, code: %d\n", (int)status);
    return 1;
  }

  mmdeploy_mat_t mat{
      img.data, img.rows, img.cols, 3, MMDEPLOY_PIXEL_FORMAT_BGR, MMDEPLOY_DATA_TYPE_UINT8};

  mmdeploy_detection_t* bboxes{};
  int* res_count{};
  status = mmdeploy_detector_apply(detector, &mat, 1, &bboxes, &res_count);
  if (status != MMDEPLOY_SUCCESS) {
    fprintf(stderr, "failed to apply detector, code: %d\n", (int)status);
    return 1;
  }

  fprintf(stdout, "bbox_count=%d\n", *res_count);

  for (int i = 0; i < *res_count; ++i) {
    const auto& box = bboxes[i].bbox;
    const auto& mask = bboxes[i].mask;

    fprintf(stdout, "box %d, left=%.2f, top=%.2f, right=%.2f, bottom=%.2f, label=%d, score=%.4f\n",
            i, box.left, box.top, box.right, box.bottom, bboxes[i].label_id, bboxes[i].score);

    // skip detections with invalid bbox size (bbox height or width < 1)
    if ((box.right - box.left) < 1 || (box.bottom - box.top) < 1) {
      continue;
    }

    // skip detections less than specified score threshold
    if (bboxes[i].score < 0.3) {
      continue;
    }

    // generate mask overlay if model exports masks
    if (mask != nullptr) {
      fprintf(stdout, "mask %d, height=%d, width=%d\n", i, mask->height, mask->width);

      cv::Mat imgMask(mask->height, mask->width, CV_8UC1, &mask->data[0]);
      auto x0 = std::max(std::floor(box.left) - 1, 0.f);
      auto y0 = std::max(std::floor(box.top) - 1, 0.f);
      cv::Rect roi((int)x0, (int)y0, mask->width, mask->height);

      // split the RGB channels, overlay mask to a specific color channel
      cv::Mat ch[3];
      split(img, ch);
      int col = 0;  // int col = i % 3;
      cv::bitwise_or(imgMask, ch[col](roi), ch[col](roi));
      merge(ch, 3, img);
    }

    cv::rectangle(img, cv::Point{(int)box.left, (int)box.top},
                  cv::Point{(int)box.right, (int)box.bottom}, cv::Scalar{0, 255, 0});
  }

  cv::imwrite("output_detection.png", img);

  mmdeploy_detector_release_result(bboxes, res_count, 1);

  mmdeploy_detector_destroy(detector);

  return 0;
}

CMakeList.txt文件示例

如下为本人编写的CMakeList.txt文件示例:

PROJECT(ObjectDetection)
cmake_minimum_required(VERSION 3.20)
# 设置C++17标准
set(CMAKE_CXX_STANDARD 17)

# 包含需要编译得到的头文件
SET(LIBOD_SRC ./src/object_detection_my.cpp)
ADD_LIBRARY(objectdetection SHARED ${LIBOD_SRC})

# 这里需要更改为自己的3.4.6版本opencv包的build路径
set(OpenCV_DIR "path/to/opencv_3_4_6_build_from_exe/opencv/build")
find_package(OpenCV REQUIRED)
if(OpenCV_FOUND)
    target_include_directories(objectdetection PUBLIC ${OpenCV_INCLUDE_DIRS})
    target_link_libraries(objectdetection PRIVATE ${OpenCV_LIBS})
endif()

# 添加mmdeploy编译需要的文件
if (NOT (${CMAKE_PROJECT_NAME} STREQUAL "MMDeploy"))
    find_package(MMDeploy REQUIRED)
endif ()

if (MMDEPLOY_BUILD_SDK_MONOLITHIC)
    target_link_libraries(objectdetection PRIVATE mmdeploy)
else ()
    # Load MMDeploy modules
    mmdeploy_load_static(objectdetection MMDeployStaticModules)
    mmdeploy_load_dynamic(objectdetection MMDeployDynamicModules)
    # Link to MMDeploy libraries
    target_link_libraries(objectdetection PRIVATE MMDeployLibs)
endif ()

编译上述cpp文件得到dll动态链接库

在work_space_2工作空间目录下,运行windows power shell,然后运行如下命令:

cmake -G "Visual Studio 16 2019" -B "./build/" -DTENSORRT_DIR="path\to\work_space_2\thirdparty\tensorrt" -DONNXRUNTIME_DIR="path\to\work_space_2\thirdparty\onnxruntime"

然后,运行如下命令进行build:

cmake --build "./build/"

编译成功之后,你会在work_space_2工作空间的build\Debug目录下找到所需要的dll动态链接库objectdetection.dll

加载dll动态链接库传入需要的字符串数据,得到返回结果

然后在work_space_2工作空间下创建test文件夹,其中,放入以下运行依赖的dll库:

mmdeploy_ort_net.dll
mmdeploy_trt_net.dll
mmdeploy.dll
上述三个dll可以在work_space_2工作空间下的bin目录下找到。

opencv_world346.dll
opencv_world346d.dll
上述两个dll可以在以下路径:path\to\opencv_3_4_6_build_from_exe\opencv\build\x64\vc15\bin中找到

然后在test文件夹下加入objectdetection.dll。

接着,在test文件夹下创建一个test.py文件,用于测试得到的dll是否可以成功做图片推理任务,test.py文件示例代码如下:

import ctypes
import os

# 这行代码很重要,告诉系统运行objectdetection.dll需要的其他的dll依赖的位置
os.chdir(r'path/to/your/work_space_2/test')

# 加载dll动态链接库
object_detection_dll = ctypes.cdll.LoadLibrary('objectdetection.dll')

# 得到推理结果
results = object_detection_dll.do_inference(b"cpu", b"path/to/your/work_space_2/onnx", 
                                            b"path/to/your/work_space_2/images/demo.jpg")
                                            
print("调用C DLL动态库得到的结果为: {}".format(results))

然后,你会在test文件夹找到推理结果图片。

参考
[1] https://github.com/open-mmlab/mmdeploy/blob/main/docs/en/01-how-to-build/windows.md

2023.4.22 于 西安

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wyypersist

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值