当前位置: 欣欣网 > 码农

C# yolov8 TensorRT Demo

2024-05-30码农

效果


说明

环境

NVIDIA GeForce RTX 4060 Laptop GPU

cuda12.1+cudnn 8.8.1+TensorRT-8.6.1.6

版本和我不一致的需要重新编译TensorRtExtern.dll,TensorRtExtern源码地址:

https://github.com/guojin-yan/TensorRT-CSharp-API/tree/TensorRtSharp2.0/src/TensorRtExtern

Windows版 CUDA安装参考:

https://blog.csdn.net/lw112190/article/details/137049845

项目

代码

Form2.cs

using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using TensorRtSharp.Custom;
namespace yolov8_TensorRT_Demo
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
string imgFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
YoloV8 yoloV8;
Mat image;
string image_path = "";
string model_path;
string video_path = "";
string videoFilter = "*.mp4|*.mp4;";
VideoCapture vcapture;
VideoWriter vwriter;
bool saveDetVideo = false;

/// <summary>
/// 单图推理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
if (image_path == "")
{
return;
}
button2.Enabled = false;
pictureBox2.Image = null;
textBox1.Text = "";
Application.DoEvents();
image = new Mat(image_path);
List<DetectionResult> detResults = yoloV8.Detect(image);
//绘制结果
Mat result_image = image.Clone();
foreach (DetectionResult r in detResults)
{
Cv2.PutText(result_image, $"{r. class}:{r.Confidence:P0}", new OpenCvSharp.Point(r.Rect.TopLeft.X, r.Rect.TopLeft.Y - 10), HersheyFonts.HersheySimplex, 1, Scalar.Red, 2);
Cv2.Rectangle(result_image, r.Rect, Scalar.Red, thickness: 2);
}
if (pictureBox2.Image != null)
{
pictureBox2.Image.Dispose();
}
pictureBox2.Image = new Bitmap(result_image.ToMemoryStream());
textBox1.Text = yoloV8.DetectTime();
button2.Enabled = true;
}
/// <summary>
/// 窗体加载,初始化
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Load(object sender, EventArgs e)
{
image_path = "test/zidane.jpg";
pictureBox1.Image = new Bitmap(image_path);
model_path = "model/yolov8n.engine";
if (!File.Exists(model_path))
{
//有点耗时,需等待
Nvinfer.OnnxToEngine("model/yolov8n.onnx", 20);
}
yoloV8 = new YoloV8(model_path, "model/lable.txt");
}
/// <summary>
/// 选择图片
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click_1(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = imgFilter;
if (ofd.ShowDialog() != DialogResult.OK) return;
pictureBox1.Image = null;
image_path = ofd.FileName;
pictureBox1.Image = new Bitmap(image_path);
textBox1.Text = "";
pictureBox2.Image = null;
}
/// <summary>
/// 选择视频
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button4_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = videoFilter;
ofd.InitialDirectory = Application.StartupPath + "\\test";
if (ofd.ShowDialog() != DialogResult.OK) return;
video_path = ofd.FileName;
button3_Click(null, null);
}
/// <summary>
/// 视频推理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button3_Click(object sender, EventArgs e)
{
if (video_path == null)
{
return;
}
textBox1.Text = "开始检测";
Application.DoEvents();
Thread thread = new Thread(new ThreadStart(VideoDetection));
thread.Start();
thread.Join();
textBox1.Text = "检测完成!";
}
void VideoDetection()
{
vcapture = new VideoCapture(video_path);
if (!vcapture.IsOpened())
{
MessageBox.Show("打开视频文件失败");
return;
}
Mat frame = new Mat();
List<DetectionResult> detResults;
// 获取视频的fps
double videoFps = vcapture.Get(VideoCaptureProperties.Fps);
// 计算等待时间(毫秒)
int delay = (int)(1000 / videoFps);
Stopwatch _stopwatch = new Stopwatch();
if (checkBox1.Checked)
{
vwriter = new VideoWriter("out.mp4", FourCC.X264, vcapture.Fps, new OpenCvSharp.Size(vcapture.FrameWidth, vcapture.FrameHeight));
saveDetVideo = true;
}
else {
saveDetVideo = false;
}
while (vcapture.Read(frame))
{
if (frame.Empty())
{
MessageBox.Show("读取失败");
return;
}
_stopwatch.Restart();
delay = (int)(1000 / videoFps);
detResults = yoloV8.Detect(frame);
//绘制结果
foreach (DetectionResult r in detResults)
{
Cv2.PutText(frame, $"{r. class}:{r.Confidence:P0}", new OpenCvSharp.Point(r.Rect.TopLeft.X, r.Rect.TopLeft.Y - 10), HersheyFonts.HersheySimplex, 1, Scalar.Red, 2);
Cv2.Rectangle(frame, r.Rect, Scalar.Red, thickness: 2);
}
Cv2.PutText(frame, "preprocessTime:" + yoloV8.preprocessTime.ToString("F2")+"ms", new OpenCvSharp.Point(10, 30), HersheyFonts.HersheySimplex, 1, Scalar.Red, 2);
Cv2.PutText(frame, "inferTime:" + yoloV8.inferTime.ToString("F2") + "ms", new OpenCvSharp.Point(10, 70), HersheyFonts.HersheySimplex, 1, Scalar.Red, 2);
Cv2.PutText(frame, "postprocessTime:" + yoloV8.postprocessTime.ToString("F2") + "ms", new OpenCvSharp.Point(10, 110), HersheyFonts.HersheySimplex, 1, Scalar.Red, 2);
Cv2.PutText(frame, "totalTime:" + yoloV8.totalTime.ToString("F2") + "ms", new OpenCvSharp.Point(10, 150), HersheyFonts.HersheySimplex, 1, Scalar.Red, 2);
Cv2.PutText(frame, "video fps:" + videoFps.ToString("F2"), new OpenCvSharp.Point(10, 190), HersheyFonts.HersheySimplex, 1, Scalar.Red, 2);
Cv2.PutText(frame, "det fps:" + yoloV8.detFps.ToString("F2"), new OpenCvSharp.Point(10, 230), HersheyFonts.HersheySimplex, 1, Scalar.Red, 2);
if (saveDetVideo)
{
vwriter.Write(frame);
}
Cv2.ImShow("DetectionResult", frame);
// fortest
// delay = 1;
delay = (int)(delay - _stopwatch.ElapsedMilliseconds);
if (delay <= 0)
{
delay = 1;
}
//Console.WriteLine("delay:" + delay.ToString()) ;
if (Cv2.WaitKey(delay) == 27)
{
break; // 如果按下ESC,退出循环
}
}
Cv2.DestroyAllWindows();
vcapture.Release();
if (saveDetVideo)
{
vwriter.Release();
}
}
}
}

















































YoloV8.cs

using OpenCvSharp;
using OpenCvSharp.Dnn;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using TensorRtSharp.Custom;
namespace yolov8_TensorRT_Demo
{
public class YoloV8
{
float[] input_tensor_data;
float[] outputData;
List<DetectionResult> detectionResults;
int input_height;
int input_width;
Nvinfer predictor;
string[] class_names;
int class_num;
int box_num;
float conf_threshold;
float nms_threshold;
float ratio_height;
float ratio_width;
public double preprocessTime;
public double inferTime;
public double postprocessTime;
public double totalTime;
public double detFps;
public String DetectTime()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine($"Preprocess: {preprocessTime:F2}ms");
stringBuilder.AppendLine($"Infer: {inferTime:F2}ms");
stringBuilder.AppendLine($"Postprocess: {postprocessTime:F2}ms");
stringBuilder.AppendLine($"Total: {totalTime:F2}ms");
return stringBuilder.ToString();
}
public YoloV8(string model_path, string classer_path)
{
predictor = new Nvinfer(model_path);
class_names = File.ReadAllLines( classer_path, Encoding.UTF8);
class_num = class_names.Length;
input_height = 640;
input_width = 640;
box_num = 8400;
conf_threshold = 0.25f;
nms_threshold = 0.5f;
detectionResults = new List<DetectionResult>();
}
void Preprocess(Mat image)
{
//图片缩放
int height = image.Rows;
int width = image.Cols;
Mat temp_image = image.Clone();
if (height > input_height || width > input_width)
{
float scale = Math.Min((float)input_height / height, (float)input_width / width);
OpenCvSharp.Size new_size = new OpenCvSharp.Size((int)(width * scale), (int)(height * scale));
Cv2.Resize(image, temp_image, new_size);
}
ratio_height = (float)height / temp_image.Rows;
ratio_width = (float)width / temp_image.Cols;
Mat input_img = new Mat();
Cv2.CopyMakeBorder(temp_image, input_img, 0, input_height - temp_image.Rows, 0, input_width - temp_image.Cols, BorderTypes.Constant, 0);
//归一化
input_img.ConvertTo(input_img, MatType.CV_32FC3, 1.0 / 255);
input_tensor_data = Common.ExtractMat(input_img);
input_img.Dispose();
temp_image.Dispose();
}
void Postprocess(float[] outputData)
{
detectionResults.Clear();
float[] data = Common.Transpose(outputData, class_num + 4, box_num);
float[] confidenceInfo = new float[ class_num];
float[] rectData = new float[4];
List<DetectionResult> detResults = new List<DetectionResult>();
for (int i = 0; i < box_num; i++)
{
Array.Copy(data, i * ( class_num + 4), rectData, 0, 4);
Array.Copy(data, i * ( class_num + 4) + 4, confidenceInfo, 0, class_num);
float score = confidenceInfo.Max(); // 获取最大值
int maxIndex = Array.IndexOf(confidenceInfo, score); // 获取最大值的位置
int _centerX = (int)(rectData[0] * ratio_width);
int _centerY = (int)(rectData[1] * ratio_height);
int _width = (int)(rectData[2] * ratio_width);
int _height = (int)(rectData[3] * ratio_height);
detResults.Add(new DetectionResult(
maxIndex,
class_names[maxIndex],
new Rect(_centerX - _width / 2, _centerY - _height / 2, _width, _height),
score));
}
//NMS
CvDnn.NMSBoxes(detResults.Select(x => x.Rect), detResults.Select(x => x.Confidence), conf_threshold, nms_threshold, out int[] indices);
detResults = detResults.Where((x, index) => indices.Contains(index)).ToList();
detectionResults = detResults;
}
internal List<DetectionResult> Detect(Mat image)
{
var t1 = Cv2.GetTickCount();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Preprocess(image);
preprocessTime = stopwatch.Elapsed.TotalMilliseconds;
stopwatch.Restart();
predictor.LoadInferenceData("images", input_tensor_data);
predictor.infer();
inferTime = stopwatch.Elapsed.TotalMilliseconds;
stopwatch.Restart();
outputData = predictor.GetInferenceResult("output0");
Postprocess(outputData);
postprocessTime = stopwatch.Elapsed.TotalMilliseconds;
stopwatch.Stop();
totalTime = preprocessTime + inferTime + postprocessTime;
detFps = (double)stopwatch.Elapsed.TotalSeconds / (double)stopwatch.Elapsed.Ticks;
var t2 = Cv2.GetTickCount();
detFps = 1 / ((t2 - t1) / Cv2.GetTickFrequency());
return detectionResults;
}
}
}