赞
踩
1.首先生成自己的engine文件
yolov5 obb 旋转框 tensorrt 部署踩坑,c++,win10,cuda 11.7,tensorrt 8.4,opencv4.5.5_vokxchh的博客-CSDN博客https://blog.csdn.net/vokxchh/article/details/1307896192.修改文件yolov5_use.cpp。
- #include <iostream>
- #include <chrono>
- #include <cmath>
- #include "cuda_utils.h"
- #include "logging.h"
- #include "common.hpp"
- #include<string>
- #include "yolov5_obb_dll.h"
- #define USE_FP16 // set USE_INT8 or USE_FP16 or USE_FP32
- #define DEVICE 0 // GPU id
- #define NMS_THRESH 0.1
- #define CONF_THRESH 0.1
- #define objThreshold 0.1
- #define BATCH_SIZE 1
- #define MAX_IMAGE_INPUT_SIZE_THRESH 3000 * 3000 // ensure it exceed the maximum size in the input images !
- using namespace std;
- // stuff we know about the network and the input/output blobs
- static const int INPUT_H = Yolo::INPUT_H;
- static const int INPUT_W = Yolo::INPUT_W;
- static const int CLASS_NUM = Yolo::CLASS_NUM;
- static const int OUTPUT_SIZE = Yolo::MAX_OUTPUT_BBOX_COUNT * sizeof(Yolo::Detection) / sizeof(float) + 1; // we assume the yololayer outputs no more than MAX_OUTPUT_BBOX_COUNT boxes that conf >= 0.1
- const char* INPUT_BLOB_NAME = "data";
- const char* OUTPUT_BLOB_NAME = "prob";
- const bool keep_ratio = true;
- static Logger gLogger;
- using namespace cv;
- using namespace std;
- typedef struct BoxInfo
- {
- RotatedRect box;
- float score;
- int label;
- } BoxInfo;
-
- cv::Mat resize_image(cv::Mat srcimg, int *newh, int *neww, int *top, int *left)
- {
- int srch = srcimg.rows, srcw = srcimg.cols;
- *newh = INPUT_H;
- *neww = INPUT_W;
- cv::Mat dstimg;
- if (keep_ratio && srch != srcw) {
- float hw_scale = (float)srch / srcw;
- if (hw_scale > 1) {
- *newh = INPUT_H;
- *neww = INPUT_W;
- cv::resize(srcimg, dstimg, Size(*neww, *newh), INTER_AREA);
- *left = int((INPUT_W - *neww) * 0.5);
- cv::copyMakeBorder(dstimg, dstimg, 0, 0, *left, INPUT_W - *neww - *left, BORDER_CONSTANT, 114);
- }
- else {
- *newh = (int)INPUT_H * hw_scale;
- *neww = INPUT_W;
- cv::resize(srcimg, dstimg, Size(*neww, *newh), INTER_AREA);
- *top = (int)(INPUT_H - *newh) * 0.5;
- cv::copyMakeBorder(dstimg, dstimg, *top, INPUT_H - *newh - *top, 0, 0, BORDER_CONSTANT, 114);
- }
- }
- else {
- resize(srcimg, dstimg, Size(*neww, *newh), INTER_AREA);
- }
- return dstimg;
-
-
- }
- void nms_angle(vector<BoxInfo>& input_boxes)
- {
- sort(input_boxes.begin(), input_boxes.end(), [](BoxInfo a, BoxInfo b) { return a.score > b.score; });
- vector<float> vArea(input_boxes.size());
- for (int i = 0; i < int(input_boxes.size()); ++i)
- {
- vArea[i] = input_boxes[i].box.size.area();
- }
-
- vector<bool> isSuppressed(input_boxes.size(), false);
- for (int i = 0; i < int(input_boxes.size()); ++i)
- {
- if (isSuppressed[i]) { continue; }
- for (int j = i + 1; j < int(input_boxes.size()); ++j)
- {
- if (isSuppressed[j]) { continue; }
- vector<Point2f> intersectingRegion;
- rotatedRectangleIntersection(input_boxes[i].box, input_boxes[j].box, intersectingRegion);
- if (intersectingRegion.empty()) { continue; }
- float inter = contourArea(intersectingRegion);
- float ovr = inter / (vArea[i] + vArea[j] - inter);
-
- if (ovr >= NMS_THRESH)
- {
- isSuppressed[j] = true;
- }
- }
- }
- // return post_nms;
- int idx_t = 0;
- input_boxes.erase(remove_if(input_boxes.begin(), input_boxes.end(), [&idx_t, &isSuppressed](const BoxInfo& f) { return isSuppressed[idx_t++]; }), input_boxes.end());
- }
-
- void doInference(IExecutionContext& context, cudaStream_t& stream, void **buffers, float* input, float* output, int batchSize) {
- CUDA_CHECK(cudaMemcpyAsync(buffers[0], input, batchSize * 3 * INPUT_H * INPUT_W * sizeof(float), cudaMemcpyHostToDevice, stream));// °ÑÕâ¸öÈÎÎñͨ¹ýcudaMemcpyAsync·Åµ½cudastramÉÏ
-
- // infer on the batch asynchronously, and DMA output back to host
- context.enqueue(batchSize, buffers, stream, nullptr);
- CUDA_CHECK(cudaMemcpyAsync(output, buffers[1], batchSize * OUTPUT_SIZE * sizeof(float), cudaMemcpyDeviceToHost, stream));
- cudaStreamSynchronize(stream);
- }
- IExecutionContext* context = nullptr;
- cudaStream_t stream;
- float* buffers[2];
- static float prob[BATCH_SIZE * OUTPUT_SIZE];
- ICudaEngine* engine = nullptr;
- int Init(std::string engine_name0)
- {
- cudaSetDevice(DEVICE);
-
- std::string engine_name = engine_name0;
-
-
- // deserialize the .engine and run inference
- std::ifstream file(engine_name, std::ios::binary);
- if (!file.good()) {
- std::cerr << "read " << engine_name << " error!" << std::endl;
- return -1;
- }
- char* trtModelStream = nullptr;
- size_t size = 0;
- file.seekg(0, file.end);
- size = file.tellg();
- file.seekg(0, file.beg);
- trtModelStream = new char[size];
- assert(trtModelStream);
- file.read(trtModelStream, size);
- file.close();
-
-
-
-
- IRuntime* runtime = createInferRuntime(gLogger);
- assert(runtime != nullptr);
- engine = runtime->deserializeCudaEngine(trtModelStream, size);
- assert(engine != nullptr);
- context = engine->createExecutionContext();
- assert(context != nullptr);
- delete[] trtModelStream;
- assert(engine->getNbBindings() == 2);
-
- // In order to bind the buffers, we need to know the names of the input and output tensors.
- // Note that indices are guaranteed to be less than IEngine::getNbBindings()
- const int inputIndex = engine->getBindingIndex(INPUT_BLOB_NAME);
- const int outputIndex = engine->getBindingIndex(OUTPUT_BLOB_NAME);
- assert(inputIndex == 0);
- assert(outputIndex == 1);
- // Create GPU buffers on device
- CUDA_CHECK(cudaMalloc((void**)&buffers[inputIndex], BATCH_SIZE * 3 * INPUT_H * INPUT_W * sizeof(float)));
- CUDA_CHECK(cudaMalloc((void**)&buffers[outputIndex], BATCH_SIZE * OUTPUT_SIZE * sizeof(float)));
-
- // Create stream
-
- CUDA_CHECK(cudaStreamCreate(&stream));
- uint8_t* img_host = nullptr;
- uint8_t* img_device = nullptr;
- // prepare input data cache in pinned memory
- CUDA_CHECK(cudaMallocHost((void**)&img_host, MAX_IMAGE_INPUT_SIZE_THRESH * 3));
- // prepare input data cache in device memory
- CUDA_CHECK(cudaMalloc((void**)&img_device, MAX_IMAGE_INPUT_SIZE_THRESH * 3));
-
- }
-
- void detect_yolov5_trt(cv::Mat img0, std::string engine_name, Result* stu)
- {
-
-
- static float data[1 * 3 * INPUT_H * INPUT_W];
- cv::Mat pr_img = img0;
-
- int newh = 0, neww = 0, padh = 0, padw = 0;
- Mat img = resize_image(pr_img, &newh, &neww, &padh, &padw);
-
- int i = 0;
- int b = 0;//Õâ¸öbÔ±¾ÓÃÀ´¿ØÖÆbatchsizeµÄ£¬µ«ÊÇÎÒÃÇÖ»ÓÐÒ»ÕÅͼƬ ¾ÍÉèÖóÉÁË0
- for (int row = 0; row < INPUT_H; ++row)
- {
- uchar* uc_pixel = img.data + row * img.step;
- for (int col = 0; col < INPUT_W; ++col)
- {
- data[b * 3 * INPUT_H * INPUT_W + i] = (float)uc_pixel[2] / 255.0;
- data[b * 3 * INPUT_H * INPUT_W + i + INPUT_H * INPUT_W] = (float)uc_pixel[1] / 255.0;
- data[b * 3 * INPUT_H * INPUT_W + i + 2 * INPUT_H * INPUT_W] = (float)uc_pixel[0] / 255.0;
- uc_pixel += 3;
- ++i;
- }
- }
-
- //auto start = std::chrono::system_clock::now();
- doInference(*context, stream, (void**)buffers, data, prob, 1);
- //auto end = std::chrono::system_clock::now();
- //auto costtime = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
- //std::cout << "inference time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;
- vector<BoxInfo> generate_boxes;
- float ratioh = (float)pr_img.rows / newh, ratiow = (float)pr_img.cols / neww;
- float* pdata = (float*)prob;
- int det_size = 7;//box(4)+conf +classid + classangle
- for (int i = 0; i < pdata[0] && i < Yolo::MAX_OUTPUT_BBOX_COUNT; i++) {
-
- if (pdata[7 * i + 4 + 1] <= CONF_THRESH) continue;//ÕâÀïÄã»áºÜÆæ¹ÖΪʲô´Ópdata[5]ÊÇconf ÒòΪpdata[0]´æ·ÅµÄÊÇ0£¬´ú±íµÚÒ»¸öͼƬ
- Yolo::Detection det;
- memcpy(&det, &pdata[1 + det_size * i], det_size * sizeof(float));
- float max_class_socre = det.conf;//ÖÃÐŶÈ
- if (max_class_socre > CONF_THRESH)
- {
- float cx = (det.bbox[0] - padw) * ratiow;
- float cy = (det.bbox[1] - padh) * ratioh;
- float w = det.bbox[2] * ratiow;
- float h = det.bbox[3] * ratioh;
-
- int class_idx = det.class_id;
- float angle = 90 - det.angle_id;
- RotatedRect box = RotatedRect(Point2f(cx, cy), Size2f(w, h), angle);
-
- generate_boxes.push_back(BoxInfo{ box, (float)max_class_socre, class_idx });
- }
-
- }
-
- nms_angle(generate_boxes);
- for (size_t i = 0; i < generate_boxes.size(); ++i)
- {
- RotatedRect rectInput = generate_boxes[i].box;
- std::cout << "box center:" << generate_boxes[i].box.center << " angle:" << generate_boxes[i].box.angle << std::endl;
- Point2f* vertices = new cv::Point2f[4];
- rectInput.points(vertices);
-
- stu[i].x1 = vertices[0].x;
- stu[i].y1 = vertices[0].y;
- stu[i].x2 = vertices[1].x;
- stu[i].y2 = vertices[1].y;
- stu[i].x3 = vertices[2].x;
- stu[i].y3 = vertices[2].y;
- stu[i].x4 = vertices[3].x;
- stu[i].y4 = vertices[3].y;
- stu[i].conf = generate_boxes[i].score;
- stu[i].classid = generate_boxes[i].label;
- stu[i].angel = generate_boxes[i].box.angle;
-
- }
- }
-
- const bool yolov5_obb_trt(const char* img_dir, const char* eng_dir, Result* stu)
- {
- std::string img_dir2 = img_dir;
- std::string engine_name = eng_dir;
- if (engine == nullptr) Init(engine_name);
- cv::Mat img = cv::imread(img_dir2);
- detect_yolov5_trt(img, engine_name, stu);
- return 0;
- }
- const void yolov5_obb_trt2(uchar* data, int width, int height, int stride, const char* eng_dir, Result* stu)
- {
- std::string engine_name = eng_dir;
- if (engine == nullptr) Init(engine_name);
- cv::Mat img = cv::Mat(cv::Size(width, height), CV_8UC3, data, stride);
- detect_yolov5_trt(img, engine_name, stu);
- }
-

3.添加 yolov5_obb_dll.h
- #pragma once
- struct Result
- {
- float classid;
- float conf;
- float x1;
- float y1;
- float x2;
- float y2;
- float x3;
- float y3;
- float x4;
- float y4;
- float angel;
- };
-
-
- extern "C" _declspec(dllexport) const bool yolov5_obb_trt(const char* img_dir, const char* eng_dir, Result * stu);
- extern "C" _declspec(dllexport) const void yolov5_obb_trt2(uchar * data, int width, int height, int stride, const char* eng_dir, Result * stu);
-

4.编译生成dll
5.使用c# 调用dll
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Diagnostics;
- using System.Drawing;
- using System.Drawing.Imaging;
- using System.IO;
- using System.Linq;
- using System.Runtime.InteropServices;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows.Forms;
- using static System.Net.WebRequestMethods;
-
- namespace WindowsFormsApp5
- {
- public partial class Form1 : Form
- {
- public Form1()
- {
- InitializeComponent();
- }
- [DllImport("yolov5_obb_trt.dll", CallingConvention = CallingConvention.Cdecl,CharSet = CharSet.Ansi)]
- extern static bool yolov5_obb_trt(string imgdr,string engdr,[Out] Result[] re);//发送路径
- [DllImport("yolov5_obb_trt.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
- extern static bool yolov5_obb_trt2(IntPtr data, int width, int height, int stride, string engdr, [Out] Result[] re);//发送图片
-
- [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1), Serializable]
- public struct Result
- {
- public float classid;
- public float conf;
- public float x1;
- public float y1;
- public float x2;
- public float y2;
- public float x3;
- public float y3;
- public float x4;
- public float y4;
- public float angel;
- }
-
- public static string engdr = Environment.CurrentDirectory + "\\yolov5n-obb-fp16.engine";
- public Bitmap DrawRect(Bitmap bmp, Result[] re)
- {
-
- Graphics gg = Graphics.FromImage(bmp);
- Pen p = new Pen(Brushes.Lime);
- foreach (var i in re)
- {
- if (i.conf == 0) { break; }
- gg.DrawLine (p, i.x1, i.y1, i.x2, i.y2);
- gg.DrawLine(p, i.x2, i.y2, i.x3, i.y3);
- gg.DrawLine(p, i.x3, i.y3, i.x4, i.y4);
- gg.DrawLine(p, i.x4, i.y4, i.x1, i.y1);
- Font drawFont = new Font("Arial", 8, FontStyle.Bold, GraphicsUnit.Millimeter);
- SolidBrush drawBush = new SolidBrush(Color.Lime);
- gg.DrawString(coco[(int)i.classid]+" "+i.conf.ToString("0.000"), drawFont, drawBush, i.x1, i.y1);
- }
- gg.Dispose();
- return bmp;
- }
- Result[] yolov5_sendbmp(string path)//发送图片
- {
- Result[] re = new Result[100];
- Bitmap img = new Bitmap(path);
- BitmapData imgData = img.LockBits(new Rectangle(0, 0, img.Width, img.Height), ImageLockMode.ReadWrite,
- PixelFormat.Format24bppRgb);
- int width = imgData.Width;
- int height = imgData.Height;
- int stride = imgData.Stride;
- try
- {
- yolov5_obb_trt2(imgData.Scan0, width, height, stride, engdr, re);
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.ToString());
- }
- img.UnlockBits(imgData);
- DrawRect(img, re);
-
- pictureBox1.Image =img;
- return re;
-
- }
-
- private void button1_Click(object sender, EventArgs e)//发送图片的路径
- {
- Result[] re = new Result[100];
- label1.Text = "";
- Stopwatch stp = new Stopwatch();
- string imgdr = Environment.CurrentDirectory + "\\images\\OK_00004.bmp";
- stp.Start();
- yolov5_obb_trt(imgdr,engdr,re);
- stp.Stop();
- Bitmap bp=(Bitmap)Image.FromFile(imgdr);
- DrawRect(bp, re);
- pictureBox1.Image = bp;
-
- label1.Text ="耗时:"+ stp.ElapsedMilliseconds.ToString() + "ms";
- }
-
- private void button2_Click(object sender, EventArgs e)//直接发送图片
- {
- label1.Text = "";
- Stopwatch stp = new Stopwatch();
- string imgdr = Environment.CurrentDirectory + "\\images\\OK_00408.bmp";
- stp.Start();
- yolov5_sendbmp(imgdr);
- stp.Stop();
- label1.Text = "耗时:"+ stp.ElapsedMilliseconds.ToString() + "ms";
- }
-
- string[] coco;
- private void Form1_Load(object sender, EventArgs e)
- {
- Task.Run(() =>
- {
- coco = System.IO.File.ReadAllLines(Environment.CurrentDirectory + "\\coco.names");
- Result[] re = new Result[100];
- string imgdr = Environment.CurrentDirectory + "\\images\\OK_00002.bmp";
-
- yolov5_obb_trt(imgdr, engdr, re);//先载入一次,预热。
- Bitmap bp = (Bitmap)Image.FromFile(imgdr);
- DrawRect(bp, re);
- pictureBox1.Image = bp;
- this.BeginInvoke(new MethodInvoker(delegate ()
- {
- button1.Visible = true;
- button2.Visible = true;
- label1.Text = "载入完毕";
- }));
-
- });
- }
-
- private void button3_Click(object sender, EventArgs e)
- {
- richTextBox1.Clear();
- StringBuilder sb=new StringBuilder();
- for (int i = 0; i < 100; i++)
- {
- Result[] re = new Result[100];
- label1.Text = "";
- Stopwatch stp = new Stopwatch();
- string imgdr = Environment.CurrentDirectory + "\\images\\OK_00004.bmp";
- stp.Start();
- yolov5_obb_trt(imgdr, engdr, re);
- stp.Stop();
- sb.Append(stp.ElapsedMilliseconds.ToString()+"ms\r\n");
-
- }
- richTextBox1.AppendText(sb.ToString());
- }
-
-
- }
- }

结果是一样的。 RTX 2060 FP16推理速度, 15ms。
-------------------------------------------------------------------------------
完整代码如下
注意点:
1.修改包含目录和库目录。自己对应的。
2.dll需要覆盖,用自己的版本,我的tensorrt8.4 opencv4.5.5,改了opencv的话,注意附加依赖项。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。