c# 调用tensorrt c++ dll 推理yolov7 ,win10, cuda11.4.3 ,cudnn8.2.4.15,tensorrt8.2.1.8。
1.首先需要生成自己的engine文件。
#include "config.h"
#include "model.h"
#include "cuda_utils.h"
#include "logging.h"
#include "utils.h"
#include "preprocess.h"
#include "postprocess.h"
#include <chrono>
#include <fstream>
#include "yolov7dll.h"
using namespace nvinfer1;
const static int kOutputSize = kMaxNumOutputBbox * sizeof(Detection) / sizeof(float) + 1;
static Logger gLogger;
void deserialize_engine(std::string& engine_name, IRuntime** runtime, ICudaEngine** engine, IExecutionContext** context) {
std::ifstream file(engine_name, std::ios::binary);
if (!file.good()) {
std::cerr << "read " << engine_name << " error!" << std::endl;
assert(false);
}
size_t size = 0;
file.seekg(0, file.end);
size = file.tellg();
file.seekg(0, file.beg);
char* serialized_engine = new char[size];
assert(serialized_engine);
file.read(serialized_engine, size);
file.close();
*runtime = createInferRuntime(gLogger);
assert(*runtime);
*engine = (*runtime)->deserializeCudaEngine(serialized_engine, size);
assert(*engine);
*context = (*engine)->createExecutionContext();
assert(*context);
delete[] serialized_engine;
}
void prepare_buffer(ICudaEngine* engine, float** input_buffer_device, float** output_buffer_device, float** output_buffer_host) {
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(kInputTensorName);
const int outputIndex = engine->getBindingIndex(kOutputTensorName);
assert(inputIndex == 0);
assert(outputIndex == 1);
// Create GPU buffers on device
CUDA_CHECK(cudaMalloc((void**)input_buffer_device, kBatchSize * 3 * kInputH * kInputW * sizeof(float)));
CUDA_CHECK(cudaMalloc((void**)output_buffer_device, kBatchSize * kOutputSize * sizeof(float)));
*output_buffer_host = new float[kBatchSize * kOutputSize];
}
void infer(IExecutionContext& context, cudaStream_t& stream, void** buffers, float* output, int batchSize) {
// infer on the batch asynchronously, and DMA output back to host
context.enqueue(batchSize, buffers, stream, nullptr);
CUDA_CHECK(cudaMemcpyAsync(output, buffers[1], batchSize * kOutputSize * sizeof(float), cudaMemcpyDeviceToHost, stream));
CUDA_CHECK(cudaStreamSynchronize(stream));
}
IRuntime* runtime = nullptr;
ICudaEngine* engine = nullptr;
IExecutionContext* context = nullptr;
float* device_buffers[2];
float* output_buffer_host = nullptr;
cudaStream_t stream;
int Init(std::string engine_name)
{
cudaSetDevice(kGpuId);
// Deserialize the engine from file
deserialize_engine(engine_name, &runtime, &engine, &context);
CUDA_CHECK(cudaStreamCreate(&stream));
cuda_preprocess_init(kMaxInputImageSize);
// Prepare cpu and gpu buffers
prepare_buffer(engine, &device_buffers[0], &device_buffers[1], &output_buffer_host);
return 0;
}
void detect_yolov7_trt(cv::Mat img, std::string engine_name, Result* stu)
{
std::vector<cv::Mat> img_batch;
// cv::Mat img = cv::imread(img_dir2);
img_batch.push_back(img);
// Preprocess
cuda_batch_preprocess(img_batch, device_buffers[0], kInputW, kInputH, stream);
// Run inference
infer(*context, stream, (void**)device_buffers, output_buffer_host, kBatchSize);
// NMS
std::vector<std::vector<Detection>> res_batch;
batch_nms(res_batch, output_buffer_host, img_batch.size(), kOutputSize, kConfThresh, kNmsThresh);
// Draw bounding boxes
for (size_t i = 0; i < img_batch.size(); i++) {
auto& res = res_batch[i];
cv::Mat img = img_batch[i];
for (size_t j = 0; j < res.size(); j++) {
stu[j].classid = res[j].class_id;
float l, r, t, b;
float r_w = kInputW / (img.cols * 1.0);
float r_h = kInputH / (img.rows * 1.0);
if (r_h > r_w) {
l = res[j].bbox[0] - res[j].bbox[2] / 2.f;
r = res[j].bbox[0] + res[j].bbox[2] / 2.f;
t = res[j].bbox[1] - res[j].bbox[3] / 2.f - (kInputH - r_w * img.rows) / 2;
b = res[j].bbox[1] + res[j].bbox[3] / 2.f - (kInputH - r_w * img.rows) / 2;
l = l / r_w;
r = r / r_w;
t = t / r_w;
b = b / r_w;
}
else {
l = res[j].bbox[0] - res[j].bbox[2] / 2.f - (kInputW - r_h * img.cols) / 2;
r = res[j].bbox[0] + res[j].bbox[2] / 2.f - (kInputW - r_h * img.cols) / 2;
t = res[j].bbox[1] - res[j].bbox[3] / 2.f;
b = res[j].bbox[1] + res[j].bbox[3] / 2.f;
l = l / r_h;
r = r / r_h;
t = t / r_h;
b = b / r_h;
}
stu[j].l = l;
stu[j].r = r;
stu[j].t = t;
stu[j].b = b;
}
}
}
const void yolov7_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_yolov7_trt(img, engine_name, stu);
}
const bool yolov7_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_yolov7_trt(img, engine_name, stu);
return 0;
}
3.最后用c# 调用。代码如下。
c#调用yolov7tensorrtc++dll,推理-C#文档类资源-CSDN文库https://download.csdn.net/download/vokxchh/87402320
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("yolov7-trt.dll", CallingConvention = CallingConvention.Cdecl,CharSet = CharSet.Ansi)]
extern static bool yolov7_trt(string imgdr,string engdr,[Out] Result[] re);//发送路径
[DllImport("yolov7-trt.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static bool yolov7_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 result;//class_id
public float l;
public float r;
public float t;
public float b;
}
public static string engdr = Environment.CurrentDirectory + "\\yolov7-fp32.engine";
public Bitmap DrawRect(Bitmap bmp, Result[] re)
{
Graphics gg = Graphics.FromImage(bmp);
Pen p = new Pen(Brushes.Red);
foreach (var i in re)
{
if (i.r == 0&& i.b == 0) { break; }
gg.DrawRectangle(p, i.l, i.t, i.r - i.l, i.b - i.t);
Font drawFont = new Font("Arial", 8, FontStyle.Bold, GraphicsUnit.Millimeter);
SolidBrush drawBush = new SolidBrush(Color.Red);
gg.DrawString(coco[(int)i.result], drawFont, drawBush, i.l, i.t);
}
gg.Dispose();
return bmp;
}
Result[] yolov7_sendbmp(string path)//发送图片
{
Result[] re = new Result[30];
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
{
yolov7_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[30];
label1.Text = "";
Stopwatch stp = new Stopwatch();
string imgdr = Environment.CurrentDirectory + "\\samples\\bus.bmp";
stp.Start();
yolov7_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 + "\\samples\\zidane.bmp";
stp.Start();
yolov7_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[30];
string imgdr = Environment.CurrentDirectory + "\\samples\\dog.bmp";
yolov7_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 = "载入完毕";
}));
});
}
}
}
可以 传入路径 或者 图片bitmap。实现推理。
以下增加置信率。请下载这个版本!
//
------------------------------------------------------------------------------------------------------------
以下用c++ 直接调用dll,推理,大致代码。 main.cpp
#include <iostream>
#include <windows.h>
struct Result
{
float classid;
float conf;
float l;
float r;
float t;
float b;
};
#pragma comment(lib, "yolov7-trt.lib")
extern "C" __declspec(dllimport) const bool yolov7_trt(const char* img_dir, const char* eng_dir, Result * stu);
int main()
{
char szFilePath[MAX_PATH + 1] = { 0 };
GetModuleFileNameA(NULL, szFilePath, MAX_PATH);
(strrchr(szFilePath, '\\'))[0] = 0;
std::string path = szFilePath;
std::string path1= path + "\\samples\\bus.bmp";
std::string path2 = path + "\\yolov7-fp16.engine";
const char* img_dir = path1.c_str();
const char* eng_dir = path2.c_str();
Result stu1[100];
yolov7_trt(img_dir, eng_dir,stu1);
for (size_t j = 0; j < 100; j++)
{
if (stu1[j].conf>0.5)
std::cerr << stu1[j].classid << " " << stu1[j].conf << " " << stu1[j].l << " " << stu1[j].r << " " << stu1[j].t << " " << stu1[j].b << std::endl;
}
system("pause");
}