当前位置:   article > 正文

tensorrt+yolov5dll部署_yolov5生成dll

yolov5生成dll

上一篇博文将yolov5利用tensorrt部署的环境和操作流程进行了大概介绍,由于在工业应用现场更多的是通过ui界面调用后台检测模型实现最终目标检测功能,因此,为了更方便的将yolov5经加速后的模型部署到现场,这个博文记录一下自己将yolov5编译为dll动态库与ui界面之间调用的过程。

1、使用yolov5s.engine加速

利用gen_wts.py文件将yolov5s.pt文件转换为yolov5s.wts文件。转换命令如下:

python gen_wts.py -w yolov5s.pt -o yolov5s.wts

然后利用trnsorrt生成的yolov5.exe将生成的yolov5s.wts文件转换为yolov5s.engine文件。命令如下:

yolov5 -s yolov5s.wts yolov5s.engine s

在生成.engine文件后,便可以使用yolov5.exe调用进行图片推理。推理命令如下:

yolov5 -d yolov5s.engine ./images

上述命令中,yolov5.exe与.engine文件在同一文件夹下,同时images是该文件夹下的一个文件夹,里面为测试图像。在实际应用中,可以根据实际需求将路径进行修改。推理过程下图所示

上述过程在上一个博文已经详细介绍过,因此,这里仅仅是介绍一下最后推理的相关过程。

2、生成yolov5的dll文件

其实归根结底的说,生成yolov5.dll文件是在上述生成yolov5.exe基础上进行。在利用cmake生成yolov5.exe时,项目下最重要的文件为yolov5.cpp文件,该cpp文件内详细封装好了利用wts文件生成engine文件的方法,以及yolov5的整个网络架构和预处理过程(包括图像的resize和通道转换),当然其中也封装好了cuda现存释放和predict的方法。因此,生成yolov5.dll其实就是在此基础上进行修改。

2.1、生成Yolov5TRTContext.h文件

为了能够更好的区分和代码维护,这里新建了一个头文件,与项目中其他相关文件区分。Yolov5TRTContext.h头文件内容

  1. #pragma once
  2. #include <iostream>
  3. #include <chrono>
  4. #include <cmath>
  5. #include "cuda_utils.h"
  6. #include "logging.h"
  7. #include "common.hpp"
  8. #include "utils.h"
  9. #include "calibrator.h"
  10. #include "preprocess.h"
  11. #include "macros.h"
  12. class Yolov5TRTContext {
  13. public:
  14. float* data;
  15. float* prob;
  16. IRuntime* runtime;
  17. ICudaEngine* engine;
  18. IExecutionContext* context;
  19. void* buffers[2];
  20. cudaStream_t stream;
  21. int inputIndex;
  22. int outputIndex;
  23. };
  24. extern "C" API void* Init(char* model_path);
  25. extern "C" API void Detect(void* h, int rows, int cols, unsigned char* src_data, float(*res_array)[6]);
  26. extern "C" API void cuda_free(void* h);

该头文件建立后放置的位置与yolov5.cpp文件夹为同一个目录下。

2.2、修改yolov5.cpp文件

在 建立好上述头文件后,开始对yolov5.cpp文件进行修改。头文件内声明了3个以标准C格式的接口外放的方法。init为模型初始化方法,detect为模型推理方法,cuda_free为现存释放的方法。因此需要在yolov5.cpp内将上述3个方法的方法体进行实现。可以直接复制下面代码至yolov5.cpp中,也可以自己根据不同点进行修改。yolov5.cpp内容如下:

  1. #include <iostream>
  2. #include <chrono>
  3. #include <cmath>
  4. #include "cuda_utils.h"
  5. #include "logging.h"
  6. #include "common.hpp"
  7. #include "utils.h"
  8. #include "calibrator.h"
  9. #include "preprocess.h"
  10. #include "macros.h"
  11. #include"Yolov5TRTContext.h" //这里新建立的头文件
  12. /*
  13. 下面是头文件对应的3个方法的方法体
  14. */
  15. void* Init(char* model_path)
  16. {
  17. cudaSetDevice(DEVICE);
  18. // create a model using the API directly and serialize it to a stream
  19. char* trtModelStream{ nullptr };
  20. size_t size_e{ 0 };
  21. std::string engine_name = model_path;
  22. std::ifstream file(engine_name, std::ios::binary);
  23. Yolov5TRTContext* trt = new Yolov5TRTContext();
  24. if (file.good()) {
  25. file.seekg(0, file.end);
  26. size_e = file.tellg();
  27. file.seekg(0, file.beg);
  28. trtModelStream = new char[size_e];
  29. assert(trtModelStream);
  30. file.read(trtModelStream, size_e);
  31. file.close();
  32. }
  33. trt->runtime = createInferRuntime(gLogger);
  34. assert(trt->runtime != nullptr);
  35. trt->engine = trt->runtime->deserializeCudaEngine(trtModelStream, size_e);
  36. assert(trt->engine != nullptr);
  37. trt->context = trt->engine->createExecutionContext();
  38. assert(trt->context != nullptr);
  39. //delete[] trtModelStream;
  40. assert(trt->engine->getNbBindings() == 2);
  41. trt->data = new float[BATCH_SIZE * 3 * INPUT_H * INPUT_W];
  42. trt->prob = new float[BATCH_SIZE * OUTPUT_SIZE];
  43. trt->inputIndex = trt->engine->getBindingIndex(INPUT_BLOB_NAME);
  44. trt->outputIndex = trt->engine->getBindingIndex(OUTPUT_BLOB_NAME);
  45. assert(trt->inputIndex == 0);
  46. assert(trt->outputIndex == 1);
  47. // Create GPU buffers on device
  48. CUDA_CHECK(cudaMalloc(&trt->buffers[trt->inputIndex], BATCH_SIZE * 3 * INPUT_H * INPUT_W * sizeof(float)));
  49. CUDA_CHECK(cudaMalloc(&trt->buffers[trt->outputIndex], BATCH_SIZE * OUTPUT_SIZE * sizeof(float)));
  50. // Create stream
  51. CUDA_CHECK(cudaStreamCreate(&trt->stream));
  52. // In order to bind the buffers, we need to know the names of the input and output tensors.
  53. // Note that indices are guaranteed to be less than IEngine::getNbBindings()
  54. return (void*)trt;
  55. }
  56. void Detect(void* h, int rows, int cols, unsigned char* src_data, float(*res_array)[6])
  57. {
  58. Yolov5TRTContext* trt = (Yolov5TRTContext*)h;
  59. cv::Mat img = cv::Mat(rows, cols, CV_8UC3, src_data);
  60. // prepare input data ---------------------------
  61. cv::Mat pr_img = preprocess_img(img, INPUT_W, INPUT_H); // letterbox BGR to RGB
  62. int i = 0;
  63. for (int row = 0; row < INPUT_H; ++row) {
  64. uchar* uc_pixel = pr_img.data + row * pr_img.step;
  65. for (int col = 0; col < INPUT_W; ++col)
  66. {
  67. trt->data[0 * 3 * INPUT_H * INPUT_W + i] = (float)uc_pixel[2] / 255.0;
  68. trt->data[0 * 3 * INPUT_H * INPUT_W + i + INPUT_H * INPUT_W] = (float)uc_pixel[1] / 255.0;
  69. trt->data[0 * 3 * INPUT_H * INPUT_W + i + 2 * INPUT_H * INPUT_W] = (float)uc_pixel[0] / 255.0;
  70. uc_pixel += 3;
  71. ++i;
  72. }
  73. }
  74. // Run inference
  75. doInference(*trt->context, trt->stream, trt->buffers, trt->data, trt->prob, BATCH_SIZE);
  76. std::vector<std::vector<Yolo::Detection>> batch_res(1);
  77. auto& res = batch_res[0];
  78. nms(res, &trt->prob[0 * OUTPUT_SIZE], CONF_THRESH, NMS_THRESH);
  79. int len = res.size();
  80. for (size_t j = 0; j < res.size(); j++) {
  81. cv::Rect r = get_rect(img, res[j].bbox);
  82. res_array[j][0] = r.x;
  83. res_array[j][1] = r.y;
  84. res_array[j][2] = r.width;
  85. res_array[j][3] = r.height;
  86. res_array[j][4] = res[j].class_id;
  87. res_array[j][5] = res[j].conf;
  88. }
  89. }
  90. void cuda_free(void* h) {
  91. Yolov5TRTContext* trt = (Yolov5TRTContext*)h;
  92. cudaStreamDestroy(trt->stream);
  93. CUDA_CHECK(cudaFree(trt->buffers[trt->inputIndex]));
  94. CUDA_CHECK(cudaFree(trt->buffers[trt->outputIndex]));
  95. trt->context->destroy();
  96. trt->engine->destroy();
  97. trt->runtime->destroy();
  98. }

2.3、编译器模式修改

修改编译器生成dll文件。在tensorrtx-yolov5-v6.0\yolov5\build目录中通过Visual studio打开yolov5s.sln,设置yolov5模块-》鼠标右键-》属性-》高级-》目标扩展名-》输入**.dll**;同时设置 常规-》配置类型:动态库(.dll)

设置完成后,进行编译。

在Release目录下查看生成的dll文件

至此,yolov5.dll文件就生成成功。

3、Python调用dll文件

在上个博客中介绍的,yolov5编译好的yolov5_tensorrt文件夹下有一个名为python_trt.py文件,将该文件放置在生成yolov5.dll文件夹下。放置好如下

放置完成后修改python_trt.py文件中的相关路径。

  1. from ctypes import *
  2. import cv2
  3. import numpy as np
  4. import numpy.ctypeslib as npct
  5. class Detector():
  6. def __init__(self,model_path,dll_path):
  7. #self.yolov5 = CDLL(dll_path)
  8. self.yolov5 = CDLL(dll_path, winmode=0)#python3.8版本加载dll失败时用
  9. self.yolov5.Detect.argtypes = [c_void_p,c_int,c_int,POINTER(c_ubyte),npct.ndpointer(dtype = np.float32, ndim = 2, shape = (50, 6), flags="C_CONTIGUOUS")]
  10. self.yolov5.Init.restype = c_void_p
  11. self.yolov5.Init.argtypes = [c_void_p]
  12. self.yolov5.cuda_free.argtypes = [c_void_p]
  13. self.c_point = self.yolov5.Init(model_path)
  14. def predict(self,img):
  15. rows, cols = img.shape[0], img.shape[1]
  16. res_arr = np.zeros((50,6),dtype=np.float32)
  17. print("res_Arr===",res_arr)
  18. self.yolov5.Detect(self.c_point,c_int(rows), c_int(cols), img.ctypes.data_as(POINTER(c_ubyte)),res_arr)
  19. print("res_Arr===",res_arr)
  20. self.bbox_array = res_arr[~(res_arr==0).all(1)]
  21. print("bbox===",self.bbox_array)
  22. return self.bbox_array
  23. def free(self):
  24. self.yolov5.cuda_free(self.c_point)
  25. def visualize(img,bbox_array):
  26. for temp in bbox_array:
  27. bbox = [temp[0],temp[1],temp[2],temp[3]] #xywh
  28. clas = int(temp[4])
  29. score = temp[5]
  30. cv2.rectangle(img,(int(temp[0]),int(temp[1])),(int(temp[0]+temp[2]),int(temp[1]+temp[3])), (105, 237, 249), 2)
  31. img = cv2.putText(img, "class:"+str(clas)+" "+str(round(score,2)), (int(temp[0]),int(temp[1])-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (105, 237, 249), 1)
  32. return img
  33. # 修改模型路径
  34. det = Detector(model_path=b"./yolov5s.engine",dll_path="./yolov5.dll") # b'' is needed
  35. # 待检测图像路径
  36. img = cv2.imread("./images/zidane.jpg")
  37. result = det.predict(img)
  38. img = visualize(img,result)
  39. cv2.imshow("img",img)
  40. cv2.waitKey(0)
  41. det.free()
  42. cv2.destroyAllWindows()

这里要注意的是,yolov5.dll文件加载处,python>3.7时,python对于dll库的调用进行了更为严格的语法更改,因此需要更改一下调用时的参数。更改完成进行代码执行。

python python_trt.py

执行结果如下

4、C++调用dll文件

创建空项目testYoloDll项目,创建源文件testYolov5Dll.cpp

  • 项目导入Yolov5TRTContext.h;
  • 将yolov5.dll、yolov5.exp、yolov5.lib、yolov5s.engine拷贝至项目目录下

4.1、项目配置

将以下文件替换成自己的文件目录即可。

VC++目录-》包含目录:

  1. D:\Space\VisualStudioSpace\tensorrtx-yolov5-v6.0\yolov5
  2. D:\AITool\TensorRT\TensorRT-8.4.1.5\include
  3. D:\AITool\CUDA\CUDA_Development\include
  4. D:\Tool\opencv4.5.1\opencv\build\include\opencv2
  5. D:\Tool\opencv4.5.1\opencv\build\include

VC++目录-》库目录:

  1. D:\Tool\opencv4.5.1\opencv\build\x64\vc15\lib
  2. D:\Space\VisualStudioSpace\tensorrtx-yolov5-v6.0\yolov5\build\Release
  3. D:\AITool\TensorRT\TensorRT-8.4.1.5\lib
  4. D:\AITool\CUDA\CUDA_Development\lib\x64

链接器->输入:

  1. opencv_world451d.lib
  2. cudart.lib
  3. cudart_static.lib
  4. yolov5.lib
  5. nvinfer.lib
  6. nvinfer_plugin.lib
  7. nvonnxparser.lib
  8. nvparsers.lib

4.2、testYolov5Dll.cpp内容

  1. #pragma once
  2. #include <iostream>
  3. #include <opencv2/opencv.hpp>
  4. #include <opencv2/dnn.hpp>
  5. #include <opencv2/highgui/highgui.hpp>
  6. #include <Windows.h>
  7. #include <iostream>
  8. #include <string>
  9. #include <tchar.h>
  10. #include <time.h>
  11. using namespace std;
  12. using namespace cv;
  13. void display(Mat dst,vector<vector<float>> list);//显示boundingbox
  14. //根据自己模型定义 类别
  15. const static int class_num = 80;
  16. const static string classes[class_num] = { "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
  17. "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
  18. "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
  19. "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
  20. "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
  21. "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
  22. "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
  23. "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
  24. "hair drier", "toothbrush" };
  25. int main(){
  26. HMODULE module = LoadLibrary(_T("yolov5.dll"));//显示加载dll
  27. if (module == NULL)
  28. {
  29. cout << "加载yolov5.dll动态库失败" << endl;
  30. return -1;
  31. }
  32. else {
  33. cout << "加载成功!!!" << endl;
  34. }
  35. typedef void * (*InitFuc)(char* ); // 定义函数指针类型
  36. typedef void (*DetectFuc)(void* , int , int , unsigned char* , float(*)[6]); // 定义函数指针类型
  37. typedef void (*cuda_freeFuc)(void*);
  38. //从dll中加载Init、Detect、cuda_free
  39. InitFuc Init;
  40. Init = (InitFuc)GetProcAddress(module,"Init");
  41. //推理
  42. DetectFuc Detect;
  43. Detect = (DetectFuc)GetProcAddress(module, "Detect");
  44. //free
  45. cuda_freeFuc cuda_free;
  46. cuda_free = (cuda_freeFuc)GetProcAddress(module, "cuda_free");
  47. char model[] = "yolov5s.engine";//yolov5s.engine 位置
  48. char* model_path = model;
  49. float res_arr[50][6] = { 0.0f };//50个anchor 6(x,y,w,h,class,confidence)
  50. Mat img, dst;
  51. void* trt = (void*)Init(model_path);//初始化模型
  52. const char* image_path = "./images/bus.jpg";//图片路径
  53. img = cv::imread(image_path);//读取图片
  54. dst = img;
  55. Detect(trt, img.rows, img.cols, img.data, res_arr);//推理
  56. vector<vector<float>> list;
  57. for (int i = 0; i < 50; i++) {
  58. if (res_arr[i][0] != 0) {
  59. vector<float> temp;
  60. temp.push_back(res_arr[i][0]);//x
  61. temp.push_back(res_arr[i][1]);//y
  62. temp.push_back(res_arr[i][2]);//w
  63. temp.push_back(res_arr[i][3]);//h
  64. temp.push_back(res_arr[i][4]);//class
  65. temp.push_back(res_arr[i][5]);//confidence
  66. list.push_back(temp);
  67. }
  68. }
  69. display(img, list);
  70. waitKey(0);
  71. img.release();dst.release();
  72. cuda_free(trt);
  73. return 0;
  74. }
  75. void display(Mat dst, vector<vector<float>> list) {
  76. //初始化m
  77. //遍历list
  78. Scalar scalar(0, 255, 0);//BGR(Green)
  79. vector<float> temp;
  80. for (int i = 0; i < list.size(); i++) {
  81. temp = list.at(i);
  82. float x = temp.at(0);
  83. float y = temp.at(1);
  84. float w = temp.at(2);
  85. float h = temp.at(3);
  86. int c = (int)temp.at(4);
  87. float confidence = temp.at(5);
  88. // 在dst上面作图
  89. //cout << "x=" << x << ",y=" << y << ",w" << w << ",h" << h << ",class=" << c << ",confidence=" << confidence << endl;
  90. Rect rect(x, y, w, h);//绘制矩形
  91. rectangle(dst, rect, scalar, 2, LINE_8, 0);
  92. //在dst上添加class confidence
  93. string text = classes[c] + format(",%0.3f", confidence);
  94. putText(dst, text, Point2f(x, y + 10), FONT_HERSHEY_SIMPLEX, 0.5, scalar);
  95. temp.clear();
  96. }
  97. namedWindow("yolov5-6.0", WINDOW_AUTOSIZE); //WINDOW_NORMAL
  98. imshow("yolov5-6.0", dst);
  99. }

4.3、运行结果

结语

至此,yolov5.dll文件的生成和利用c++和python调用就完成了。下面博客还会介绍自己利用C#调用yolov5.dll的过程,同时结合一些图像处理库软件。希望大家点赞支持。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/136713
推荐阅读
相关标签
  

闽ICP备14008679号