news 2026/1/21 12:43:16

[C#][winform]基于yolov11的道路路面坑洼坑洞检测系统C#源码+onnx模型+评估指标曲线+精美GUI界面

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[C#][winform]基于yolov11的道路路面坑洼坑洞检测系统C#源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】

在道路交通基础设施维护需求持续升级的背景下,道路坑洼坑洞检测工作面临严峻挑战。坑洼坑洞(pothole)不仅会加速车辆轮胎磨损、引发交通事故,还可能造成道路结构损伤,危及行车安全。传统人工巡检依赖经验判断,效率低且覆盖范围有限,难以应对复杂路网与突发灾害后的快速排查需求;早期基于传统图像处理的方法,受路面阴影、积水、相似纹理干扰,误检率高且无法精准定位微小坑洞,难以满足精细化养护要求。因此,研发高效、精准的道路坑洼坑洞智能检测技术,成为提升道路安全与运维效率的关键。

传统方法存在显著局限:人工目视检测受主观因素影响大,夜间或恶劣天气下漏检风险高;基于边缘检测或灰度阈值的算法难以区分坑洞与井盖、阴影等干扰物,对不规则形状坑洞的识别能力不足;普通深度学习模型在复杂光照条件下,对坑洞边缘特征提取能力弱,易受路面污渍、裂缝等噪声干扰。

基于YOLOv11的道路坑洼坑洞检测系统为道路养护带来革新。YOLOv11以卓越的实时性与多尺度特征融合能力为核心,可快速处理车载摄像头或无人机采集的路面图像,精准标注坑洞位置。通过改进骨干网络,增强对不同深度、形态坑洞的特征提取能力,无论是浅层裂缝还是深层凹陷均能准确识别;优化颈部网络的多尺度特征融合策略,提升对远距离小目标坑洞的检测精度;结合注意力机制与动态阈值调整,抑制路面反光、阴影等干扰因素,确保复杂场景下的高鲁棒性。该系统支持实时视频流分析,可快速生成坑洞分布热力图,为道路管理部门提供科学决策依据,推动道路养护向智能化、预防性方向升级。

【效果展示】

【训练数据集介绍】

数据集大约有一半为增强图片

数据集格式:YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的yolo格式txt文件)
图片数量(jpg文件个数):3940
标注数量(xml文件个数):3940
标注数量(txt文件个数):3940
标注类别数:1
标注类别名称:["pothole"]
每个类别标注的框数:
pothole 框数 = 10111
总框数:10111
使用标注工具:labelImg
标注规则:对类别进行画矩形框
重要说明:暂无
特别声明:本数据集不对训练的模型或者权重文件精度作任何保证,数据集只提供准确且合理标注

图片预览:

标注例子:

【测试环境】

windows10 x64系统
VS2019
netframework4.7.2
opencvsharp4.9.0
onnxruntime1.22.0

注意使用CPU推理,没有使用cuda推理因此不需要电脑具有nvidia显卡,无需安装安装cuda+dunn

【界面设计】

using DeploySharp.Data; using OpenCvSharp; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace FIRC { public partial class Form1 : Form { public bool videoStart = false;//视频停止标志 string weightsPath = Application.StartupPath + "\\weights";//模型目录 YoloDetector detetor = new YoloDetector();//推理引擎 public Form1() { InitializeComponent(); CheckForIllegalCrossThreadCalls = false;//线程更新控件不报错 } private void LoadWeightsFromDir() { var di = new DirectoryInfo(weightsPath); foreach(var fi in di.GetFiles("*.onnx")) { comboBox1.Items.Add(fi.Name); } if(comboBox1.Items.Count>0) { comboBox1.SelectedIndex = 0; } else { tssl_show.Text = "未找到模型,请关闭程序,放入模型到weights文件夹!"; tsb_pic.Enabled = false; tsb_video.Enabled = false; tsb_camera.Enabled = false; } } private void Form1_Load(object sender, EventArgs e) { LoadWeightsFromDir();//从目录加载模型 } public string GetResultString(DetResult[] result) { Dictionary<string, int> resultDict = new Dictionary<string, int>(); for (int i = 0; i < result.Length; i++) { if(resultDict.ContainsKey( result[i].Category) ) { resultDict[result[i].Category]++; } else { resultDict[result[i].Category] =1; } } var resultStr = ""; foreach(var item in resultDict) { resultStr += string.Format("{0}:{1}\r\n",item.Key,item.Value); } return resultStr; } private void tsb_pic_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png"; if (ofd.ShowDialog() != DialogResult.OK) return; tssl_show.Text = "正在检测中..."; Task.Run(() => { var sw = new Stopwatch(); sw.Start(); Mat image = Cv2.ImRead(ofd.FileName); detetor.SetParams(Convert.ToSingle(numericUpDown1.Value), Convert.ToSingle(numericUpDown2.Value)); var results=detetor.Inference(image); var resultImage = detetor.DrawImage(image, results); sw.Stop(); pb_show.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(resultImage); tb_res.Text = GetResultString(results); tssl_show.Text = "检测已完成!总计耗时"+sw.Elapsed.TotalSeconds+"秒"; }); } public void VideoProcess(string videoPath) { Task.Run(() => { detetor.SetParams(Convert.ToSingle(numericUpDown1.Value), Convert.ToSingle(numericUpDown2.Value)); VideoCapture capture = new VideoCapture(videoPath); if (!capture.IsOpened()) { tssl_show.Text="视频打开失败!"; return; } Mat frame = new Mat(); var sw = new Stopwatch(); int fps = 0; while (videoStart) { capture.Read(frame); if (frame.Empty()) { Console.WriteLine("data is empty!"); break; } sw.Start(); var results = detetor.Inference(frame); var resultImg = detetor.DrawImage(frame,results); sw.Stop(); fps = Convert.ToInt32(1 / sw.Elapsed.TotalSeconds); sw.Reset(); Cv2.PutText(resultImg, "FPS=" + fps, new OpenCvSharp.Point(30, 30), HersheyFonts.HersheyComplex, 1.0, new Scalar(255, 0, 0), 3); //显示结果 pb_show.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(resultImg); tb_res.Text = GetResultString(results); Thread.Sleep(5); } capture.Release(); pb_show.Image = null; tssl_show.Text = "视频已停止!"; tsb_video.Text = "选择视频"; }); } public void CameraProcess(int cameraIndex=0) { Task.Run(() => { detetor.SetParams(Convert.ToSingle(numericUpDown1.Value), Convert.ToSingle(numericUpDown2.Value)); VideoCapture capture = new VideoCapture(cameraIndex); if (!capture.IsOpened()) { tssl_show.Text = "摄像头打开失败!"; return; } Mat frame = new Mat(); var sw = new Stopwatch(); int fps = 0; while (videoStart) { capture.Read(frame); if (frame.Empty()) { Console.WriteLine("data is empty!"); break; } sw.Start(); var results = detetor.Inference(frame); var resultImg = detetor.DrawImage(frame, results); sw.Stop(); fps = Convert.ToInt32(1 / sw.Elapsed.TotalSeconds); sw.Reset(); Cv2.PutText(resultImg, "FPS=" + fps, new OpenCvSharp.Point(30, 30), HersheyFonts.HersheyComplex, 1.0, new Scalar(255, 0, 0), 3); //显示结果 pb_show.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(resultImg); tb_res.Text = GetResultString(results); Thread.Sleep(5); } capture.Release(); pb_show.Image = null; tssl_show.Text = "摄像头已停止!"; tsb_camera.Text = "打开摄像头"; }); } private void tsb_video_Click(object sender, EventArgs e) { if(tsb_video.Text=="选择视频") { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "视频文件(*.*)|*.mp4;*.avi"; if (ofd.ShowDialog() != DialogResult.OK) return; videoStart = true; VideoProcess(ofd.FileName); tsb_video.Text = "停止"; tssl_show.Text = "视频正在检测中..."; } else { videoStart = false; } } private void tsb_camera_Click(object sender, EventArgs e) { if (tsb_camera.Text == "打开摄像头") { videoStart = true; CameraProcess(0); tsb_camera.Text = "停止"; tssl_show.Text = "摄像头正在检测中..."; } else { videoStart = false; } } private void tsb_exit_Click(object sender, EventArgs e) { videoStart = false; this.Close(); } private void trackBar1_Scroll(object sender, EventArgs e) { numericUpDown1.Value = Convert.ToDecimal(trackBar1.Value / 100.0f); } private void trackBar2_Scroll(object sender, EventArgs e) { numericUpDown2.Value = Convert.ToDecimal(trackBar2.Value / 100.0f); } private void numericUpDown1_ValueChanged(object sender, EventArgs e) { trackBar1.Value = (int)(Convert.ToSingle(numericUpDown1.Value) * 100); } private void numericUpDown2_ValueChanged(object sender, EventArgs e) { trackBar2.Value = (int)(Convert.ToSingle(numericUpDown2.Value) * 100); } private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { tssl_show.Text="加载模型:"+comboBox1.Text; detetor.LoadWeights(weightsPath+"\\"+comboBox1.Text); tssl_show.Text = "模型加载已完成!"; } } }

【常用评估参数介绍】

在目标检测任务中,评估模型的性能是至关重要的。你提到的几个术语是评估模型性能的常用指标。下面是对这些术语的详细解释:

  1. Class
    • 这通常指的是模型被设计用来检测的目标类别。例如,一个模型可能被训练来检测车辆、行人或动物等不同类别的对象。
  2. Images
    • 表示验证集中的图片数量。验证集是用来评估模型性能的数据集,与训练集分开,以确保评估结果的公正性。
  3. Instances
    • 在所有图片中目标对象的总数。这包括了所有类别对象的总和,例如,如果验证集包含100张图片,每张图片平均有5个目标对象,则Instances为500。
  4. P(精确度Precision)
    • 精确度是模型预测为正样本的实例中,真正为正样本的比例。计算公式为:Precision = TP / (TP + FP),其中TP表示真正例(True Positives),FP表示假正例(False Positives)。
  5. R(召回率Recall)
    • 召回率是所有真正的正样本中被模型正确预测为正样本的比例。计算公式为:Recall = TP / (TP + FN),其中FN表示假负例(False Negatives)。
  6. mAP50
    • 表示在IoU(交并比)阈值为0.5时的平均精度(mean Average Precision)。IoU是衡量预测框和真实框重叠程度的指标。mAP是一个综合指标,考虑了精确度和召回率,用于评估模型在不同召回率水平上的性能。在IoU=0.5时,如果预测框与真实框的重叠程度达到或超过50%,则认为该预测是正确的。
  7. mAP50-95
    • 表示在IoU从0.5到0.95(间隔0.05)的范围内,模型的平均精度。这是一个更严格的评估标准,要求预测框与真实框的重叠程度更高。在目标检测任务中,更高的IoU阈值意味着模型需要更准确地定位目标对象。mAP50-95的计算考虑了从宽松到严格的多个IoU阈值,因此能够更全面地评估模型的性能。

这些指标共同构成了评估目标检测模型性能的重要框架。通过比较不同模型在这些指标上的表现,可以判断哪个模型在实际应用中可能更有效。

【使用步骤】

使用步骤:
(1)首先根据官方框架ultralytics安装教程安装好yolov11环境,并根据官方export命令将自己pt模型转成onnx模型,然后去github仓库futureflsl/firc-csharp-projects找到源码
(2)使用vs2019打开sln项目,选择x64 release并且修改一些必要的参数,比如输入shape等,点击运行即可查看最后效果

特别注意如果运行报错了,请参考我的博文进行重新引用我源码的DLL:[C#]opencvsharp报错System.Memory,Version=4.0.1.2,Culture=neutral,PublicKeyToken=cc7b13fcd2ddd51“版本高于所引_未能加载文件或程序集“system.memory, version=4.0.1.2, culture-CSDN博客

【提供文件】

C#源码
yolo11s.onnx模型(不提供pytorch模型)
训练的map,P,R曲线图(在weights\results.png)
测试图片(在test_img文件夹下面)

特别注意这里提供训练数据集

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/17 1:02:08

Langchain-Chatchat如何评估问答质量?指标体系构建

Langchain-Chatchat如何评估问答质量&#xff1f;指标体系构建 在企业知识管理日益智能化的今天&#xff0c;一个常见的困境是&#xff1a;员工每天要花数小时查找文档、邮件或内部系统中的信息&#xff0c;而客服面对客户提问时却常常无法快速调取准确答案。尽管大语言模型&am…

作者头像 李华
网站建设 2026/1/20 16:54:59

springboot在线教育系统(11528)

有需要的同学&#xff0c;源代码和配套文档领取&#xff0c;加文章最下方的名片哦 一、项目演示 项目演示视频 二、资料介绍 完整源代码&#xff08;前后端源代码SQL脚本&#xff09;配套文档&#xff08;LWPPT开题报告&#xff09;远程调试控屏包运行 三、技术介绍 Java…

作者头像 李华
网站建设 2026/1/20 23:49:53

测了多款AI自动生成PPT工具,真正能用的不到一半

告别PPT制作难题&#xff01;轻竹办公让汇报高效出彩在职场中&#xff0c;年终总结、项目汇报等工作如同一座座大山&#xff0c;压得职场人喘不过气来。为了一份完美的报告&#xff0c;我们常常熬夜修改&#xff0c;好不容易搭建好框架&#xff0c;内容却缺乏亮点&#xff1b;精…

作者头像 李华
网站建设 2026/1/17 19:13:59

springboot星之语明星周边产品销售网站的设计与实现(11529)

有需要的同学&#xff0c;源代码和配套文档领取&#xff0c;加文章最下方的名片哦 一、项目演示 项目演示视频 二、资料介绍 完整源代码&#xff08;前后端源代码SQL脚本&#xff09;配套文档&#xff08;LWPPT开题报告&#xff09;远程调试控屏包运行 三、技术介绍 Java…

作者头像 李华
网站建设 2026/1/20 13:45:41

毕设救星:Spring Boot + Neo4j 打造“医疗知识问答”——基于知识图谱的智能导诊平台

🏥 前言:为什么选“医疗问答”? 现在毕设题目里带个“智能”二字才好过。但真正的“医疗大模型”训练成本极高,且容易胡说八道。 “基于知识图谱的问答 (KBQA)” 是完美的替代方案: 准确性高:基于图谱查询,不会产生幻觉(医生说吃药 A,它绝不会说吃药 B)。 可视化强…

作者头像 李华
网站建设 2026/1/20 13:03:25

华为网络设备基本配置命令

1、恢复出出厂设置<Huawei>reset saved-configuration This will delete the configuration in the flash memory.The device configuratio ns will be erased to reconfigure.Are you sure? (y/n)[n]:yClear the configuration in the device successfully. <Huawe…

作者头像 李华