一个 WinForms YOLOv8 目标检测小实用的工具

  1. 点按钮 加载模型

  2. 点按钮 选图 → 检测 → 画框 → 把结果直接显示在主窗体的 PictureBox 里

  3. 类别只有“1”、“2”两个;4. 全程用System.Drawing + SixLabors.ImageSharp混合绘图,已解决所有命名冲突。

【功能拆解】

模块作用
字段yolov8(可空引用) + mylabel = {"1","2"}
button2_Click手动加载模型;路径取 best1.onnx(与 exe 同目录)。
button1_Click打开图片:弹出 OpenFileDialog,把文件路径交给 showimg
ToImageSharp把 System.Drawing.Image → ImageSharp.Image<Rgb24>
showimg核心流程
资源清理Dispose 旧图,避免句柄泄漏。

安装的NuGet 包:

完整代码:

using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Windows.Forms;
using Yolov8Net;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
namespace NetOnnx08
{
public partial class Form1 : Form
{
public IPredictor yolov8;
string[] mylabel = { "1", "2" };//模型分类标签
public Form1()
{
InitializeComponent();
}
//public void Form1_Load(object sender, EventArgs e)
//{
//    //加载模型
//    try
//    {
//        yolov8 = YoloV8Predictor.Create("best1.onnx", mylabel);
//        if (yolov8 != null)
//        {
//            toolStripStatusLabel1.Text = ("模型加载成功\r\n");
//        }
//    }
//    catch (System.Exception ex)
//    {
//        MessageBox.Show(ex.Message);
//    }
//}
public void button1_Click(object sender, EventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog();
//dialog.Multiselect = true;//该值确定是否可以选择多个文件
dialog.Title = "请选择文件";
dialog.Filter = "图像文件(*.jpg;*.jpeg)|*.jpg;*.jpeg";
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string file = dialog.FileName;
toolStripStatusLabel1.Text = file;
toolStripStatusLabel2.Text = "检测成功!";
showimg(dialog);
}
}
public static SixLabors.ImageSharp.Image
ToImageSharp(System.Drawing.Image source)
{
if (source == null) throw new ArgumentNullException(nameof(source));
using var ms = new MemoryStream();
source.Save(ms, ImageFormat.Png);
ms.Position = 0;
return SixLabors.ImageSharp.Image.Load(ms);
}
public void showimg(OpenFileDialog dialog)
{
string imgpath = dialog.FileName;
Image image = System.Drawing.Image.FromFile(imgpath);
Form form = new Form();
form.Text = dialog.SafeFileName + " " + image.Width + "x" + image.Height;
PictureBox pictureBox = new PictureBox();
pictureBox.Parent = form;
//格式转换
SixLabors.ImageSharp.Image img = ToImageSharp(image);
//图像预测
var predictions = yolov8.Predict(img);
// Draw your boxes
//using var graphics = Graphics.FromImage(image);
foreach (var pred in predictions)
{
var originalImageHeight = image.Height;
var originalImageWidth = image.Width;
var x = Math.Max(pred.Rectangle.X, 0);
var y = Math.Max(pred.Rectangle.Y, 0);
var width = Math.Min(originalImageWidth - x, pred.Rectangle.Width);
var height = Math.Min(originalImageHeight - y, pred.Rectangle.Height);
////////////////////////////////////////////////////////////////////////////////////////////
// *** Note that the output is already scaled to the original image height and width. ***
////////////////////////////////////////////////////////////////////////////////////////////
// Bounding Box Text
string text = $"{pred.Label.Name} [{pred.Score}]";
using (Graphics graphics = Graphics.FromImage(image))
{
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
// Define Text Options
Font drawFont = new Font("consolas", 11, FontStyle.Regular);
SizeF size = graphics.MeasureString(text, drawFont);
SolidBrush fontBrush = new SolidBrush(Color.Black);
Point atPoint = new Point((int)x, (int)y - (int)size.Height - 1);
// Define BoundingBox options
Pen pen = new Pen(Color.Yellow, 2.0f);
SolidBrush colorBrush = new SolidBrush(Color.Yellow);
// Draw text on image
graphics.FillRectangle(colorBrush, (int)x, (int)(y - size.Height - 1), (int)size.Width, (int)size.Height);
graphics.DrawString(text, drawFont, fontBrush, atPoint);
// Draw bounding box on image
graphics.DrawRectangle(pen, x, y, width, height);
}
}
////用pictureBox弹窗来显示
//pictureBox.Width = image.Width;
//pictureBox.Height = image.Height;
//pictureBox.Image = (Bitmap)image.Clone();
//form.AutoSize = true;
//form.Show();
//image.Dispose();
// 1. 清空旧图
if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
pictureBox1.Image = null;
}
// 3. 直接赋给 PictureBox
//pictureBox1.Image = new System.Drawing.Bitmap(ms);
pictureBox1.Image = (Bitmap)image.Clone();
// 4. 自适应/原图大小任选其一
pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;   // 自适应
// pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize; // 原图大小
}
public void button2_Click(object sender, EventArgs e)
{
try
{
string modelPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "best1.onnx");
if (!File.Exists(modelPath))
{
MessageBox.Show($"模型文件不存在:{modelPath}");
return;
}
// 25 个类别示例
string[] labels = { "1", "2"};
yolov8 = YoloV8Predictor.Create(modelPath, labels);
if (yolov8 != null)
{
toolStripStatusLabel2.Text = "模型加载成功";
}
}
catch (Exception ex)
{
MessageBox.Show("模型加载失败: " + ex.Message);
}
}
}
}

【优点】

  • 不弹额外窗口,所有结果在主界面实时可见。

  • 已显式区分 System.Drawing.ImageSixLabors.ImageSharp.Image,彻底消除“不明确的引用”。

  • 支持任意 jpg/jpeg/bmp 图片。


【可改进的小提示】

  1. pictureBox1.Image 的创建/释放封装成方法,减少重复代码。

  2. 如果类别多,可把 string[] labels 改成读取外部 txt,避免硬编码。

  3. 若图片非常大,可把 pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize 并放在 Panel.AutoScroll 里实现滚动查看。

posted @ 2025-08-24 19:17  yjbjingcha  阅读(12)  评论(0)    收藏  举报