ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLO11+PyQt5道路裂缝检测系统实战:从数据集到GUI部署

YOLO11+PyQt5道路裂缝检测系统实战:从数据集到GUI部署 简介基于YOLO11深度学习的道路裂缝检测系统配套PyQt5图形界面可直接对道路裂缝图像进行识别与定位适合计算机、人工智能、通信工程、自动化等专业的学生用于毕业设计、课程设计或实战项目演示。资源共825个文件包含Python源码、PyQt5界面文件以及370多张已标注的道路裂缝数据集其中JPG图片与TXT标签配套使用另有训练好的YOLO11模型权重、评估指标曲线、安装使用教程和演示图片视频整体约386.87MB解压后即可运行体验。已有186人学习下载适合希望快速跑通深度学习目标检测流程或在此基础上做功能扩展的开发者。包内代码经训练测试运行通过模型针对单类别“裂缝”设计准确率高同时提供UI布局文件、配置文件与训练缓存等辅助材料可帮助理解界面搭建、数据标注、模型训练与评估的完整链路方便直接用于课设、毕设或进一步改造。1. 道路裂缝检测为什么绕不开YOLO11这个系统能帮你省下什么路面裂缝巡检到今天仍大量靠人眼。一个人沿路走一天看不了几公里裂缝藏在阴影和积水反光里漏检几乎是必然。把YOLO11深度学习检测封装进PyQt5桌面界面让系统自己盯图找裂缝正是这套方案要做的事Python源码、界面、370多张标注数据、训练好的权重全部备齐装好依赖直接跑这就是“开箱即用”的含义。为什么值得信370多张图配预训练权重迁移学习足够训出一个能用的检测器。适合道路养护信息化工程师、做视觉课题的研究生、想完整看一遍落地方案的开发者。读完你会清楚模型选型理由、训练参数怎么设以及GUI集成真正的坑在哪。2. 从网络结构到数据集YOLO11选型理由与370张图的准备细节2.1 YOLO11到底改了什么为什么裂缝检测普遍选它YOLO11是Ultralytics在YOLOv8之后推出的检测模型名字跳过了9和10因为那两位被其他团队用了。它最大的结构变化是用C3k2模块替换了v8的C2f。C3k2沿用了CSP的拆分思想把特征分成两条路径一条直连通路保留细节一条经过瓶颈层提取高级语义最后拼接。相比C2fC3k2在同样通道数下计算量更小这对实时检测有直接好处——桌面工具要的是“点一下马上出结果”不是转圈等三秒。对裂缝这类目标anchor-free是比结构升级更关键的改变。YOLOv5需要预设一组锚框尺寸比如常见的高矮胖瘦几个固定框。裂缝的长宽比极端一条横向裂缝可能宽300像素、高只有8像素如果预设锚框里没有这种形状训练时模型要从错误起点去拟合很容易发散。YOLO11沿用anchor-free思路直接从特征图每个位置预测目标是否存在、中心偏移和宽高不再被锚框形状限制对细长缺陷的适应性明显更好。型号选择上YOLO11按计算量分n、s、m、l、x五档各挡位的差异不是算法逻辑而是通道数和深度型号速度精度建议使用场景yolo11n最快基础CPU推理、实时预览yolo11s较快中等桌面工具默认yolo11m中等较好离线批处理yolo11l/x慢最好服务器离线分析370张图这个量级建议先上n。n模型参数最少训练快、不容易过拟合跑通全流程后再换s刷精度。直接上x不是不行但你会在等待训练的过程中把耐心耗尽而且数据量撑不起大模型的容量精度未必比s高。2.2 370多张标注数据这个量级怎么组织才不翻车370多张图对目标检测来说属于小样本但配合预训练权重够用。关键在数据组织。这套系统用的是YOLO格式标注每张图片对应一个同名txt文件放在labels目录每行记录一个目标“类别序号 中心x 中心y 宽度 高度”坐标都归一化到0到1之间。举个例子一条横向裂缝的标注行0 0.4832 0.2567 0.1245 0.0398含义是类别0裂缝目标中心点位于图片宽度方向的48.32%、高度方向的25.67%目标宽度占整张图宽度的12.45%高度只占3.98%。注意这个框很扁是正常的。裂缝天然是细长目标别为了让标注框“规整”而拉大它拉大的框会把路面纹理也包进去模型学到的是“这一片区域大量纹理都算裂缝”误报直接起飞。目录结构建议按Ultralytics的约定来方便命令行直接调用datasets/road_crack/ ├── images/ │ ├── train/ # 训练图片约300张 │ └── val/ # 验证图片约70张 ├── labels/ │ ├── train/ # 与训练图片同名的txt │ └── val/ ├── crack.yaml # 数据配置 └── README.md370多张的常见划分是8:2训练集和验证集要按路面段分开而不是随机打乱。比如同一条路同一个裂缝的连续照片一张进训练、一张进验证验证指标会虚高到0.9换一段完全没见过的路立刻跌到0.3。这种“见光死”我在实际项目里遇到不止一次。这个量级必须靠数据增强补足。YOLO11默认开Mosaic四张图拼一张模型能同时看到多个裂缝局部对尺度变化更不敏感。颜色扰动方面裂缝对比度低、受光照影响大把饱和度扰动调到0.5到0.8比较合适。翻转只做水平翻转——垂直翻转会让路面裂缝变成悬空线条物理上不成立强行加只会让模型学出错误的空间先验。另外如果之前装过labelme它自带的PyQt5版本可能和当前项目冲突常见做法是把标注环境和使用环境分开用conda单独建一个环境装labelme别拖垮主训练环境。2.3 标签和YAML训练前必须检查的三个位置训练失败的原因大部分出在数据格式而不是网络结构。我每次拿到数据集固定查三个位置。第一空标签文件。标注工具偶尔会生成内容为空的txt训练时Ultralytics会报“No labels found”直接退出。检查命令find datasets/road_crack/labels -name *.txt -size 0 -print有输出就删掉空文件并同步把对应图片从images目录移走否则图有标签无模型会白学一张图。第二类别编号越界。crack.yaml里nc写1、names写[crack]所有标签第一列的编号必须全是0。如果出现1或更大的数字说明这批数据混入了别的类别或者标注工具用了默认的预置类别没改。训练时类别通道对不上loss曲线会是锯齿状怎么调都压不下去。第三图片和标签配对。YOLO格式要求jpg主文件名与txt完全同名Windows下复制文件常自动生成“图片(1).jpg”标签对不上模型等于在学“图里有内容但没有监督信号”。对完整性的检查可以用一段脚本ls images/train | sed s/\.[^.]*$// | sort /tmp/names_img.txt ls labels/train | sed s/\.[^.]*$// | sort /tmp/names_lab.txt diff /tmp/names_img.txt /tmp/names_lab.txt输出为空说明配对正常有输出就逐个处理。这三个位置在第一次训练前查完后面基本不会因为数据问题返工。另外crack.yaml里的路径建议写绝对路径或相对ultralytics运行目录的路径否则换台机器训练报“dataset not found”的几率很高。# crack.yaml path: ./datasets/road_crack # 数据集根目录 train: images/train # 训练图片相对路径 val: images/val # 验证图片相对路径 nc: 1 # 类别数这里只有裂缝一类 names: [crack] # 类别名必须和标注编号一致3. 训练到评估环境配置、训练命令与指标曲线怎么读3.1 环境配置跑通YOLO11的最小安装训练YOLO11需要的东西其实不多Python、PyTorch、Ultralytics库以及可选的NVIDIA显卡驱动。强烈建议用conda建独立环境别把依赖装进系统级Python。这套项目自带安装教程换到任何一台机器要复现按下面三步走。conda create -n yolo11 python3.10 -y conda activate yolo11 pip install ultralytics pyqt5 opencv-pythonpython3.10是当前生态兼容性最好的版本之一PyTorch和PyQt5都有现成轮子不会编译报错。没有GPU也能跑CPU训练370张图需要几小时到十几个小时推理则完全够用有N卡就先把CUDA工具包装好再用GPU版PyTorch。装完验证一步python -c from ultralytics import YOLO; mYOLO(yolo11n.pt); print(len(m.names))第一次运行会自动下载yolo11n.pt权重网络通畅的情况下等一会儿就好。如果这步能打印出类别数量说明训练链路已经通了。还要验证PyQt5跑一行python -c from PyQt5.QtWidgets import QApplication; import sys; appQApplication(sys.argv); print(pyqt ok)能输出pyqt okGUI环境就绪。这里有个常见坑PyQt5和底层Qt5库版本不一致时import正常但一创建窗口就闪退或段错误。遇到这种情况把PyQt5和PyQt5-Qt5卸载后一起重装让版本对齐。3.2 训练命令与参数调节370张图的推荐设置数据准备完毕训练就是一条命令的事。以yolo11n为起点推荐这样的设置yolo detect train datacrack.yaml modelyolo11n.pt epochs150 batch16 imgsz640 device0逐项说明。data指向前一节的crack.yamlmodel用官方预训练权重迁移学习的起点别用随机初始化那在370张图上基本训不出来epochs设150裂缝这种低对比度目标收敛慢50轮通常不够200轮开始有过拟合风险batch看显存8GB显存用16没问题显存不够降到8或4CPU训练建议4imgsz默认640如果图中裂缝偏细长可以试736代价是训练时间明显变长device0指第一块GPUCPU就写cpu。训练过程的终端输出每轮打印一行重点看box_loss和cls_loss是否在下降。有没有更直观的判断有loss降但mAP不升多半是标注框位置或类别错误loss完全不降检查是否忘了把model参数改成预训练权重或者数据增强开得太大模型学不过来。数据增强参数值得单独调一下。默认的全开增强对370张小样本偏激进我一般这样收敛yolo detect train datacrack.yaml modelyolo11n.pt epochs150 batch16 imgsz640 hsv_h0.02 hsv_s0.7 hsv_v0.3 mosaic0.8hsv_h是色调扰动幅度裂缝颜色差异本身不大0.02够用设太大会出现蓝色裂缝这种假样本hsv_s饱和度扰动0.7让模型适应阴天、背光、积水反光下的低饱和画面hsv_v亮度扰动0.3模拟早晚光照差异。mosaic0.8意思是八成训练轮次执行四图拼接留两成用原图回归防止模型过度依赖拼接特征。3.3 评估指标曲线mAP50、PR曲线和混淆矩阵怎么读训练结束runs/detect/train/下会生成一组评估图和权重文件best.pt和last.pt。对裂缝检测重点看四张图。PR曲线是第一个要看的。横轴召回率纵轴精确率曲线越靠右上说明“既要漏得少、又要错得少”兼顾得越好。裂缝检测的典型问题是曲线后半段掉得快——置信度阈值调低时模型开始把路面纹理、伸缩缝、油污都当成裂缝框出来召回率上去了精确率崩了。曲线包围面积对应的就是mAP面积小说明模型没有真正学会“裂缝是什么”。results.png把训练过程画在一起包含box_loss、cls_loss、mAP50、mAP50-95。看两个点mAP50是否在后期还在爬升还在爬就把epochs往上加验证集loss是否在某个节点掉头向上掉头就说明过拟合开始early stopping会帮你停在最佳权重附近但如果你关闭了patience就要自己盯。混淆矩阵对两类任务最有用。裂缝是正类背景是负类矩阵里“背景被预测为裂缝”那一格的比例直接反映误报水平。数值高就两个处理方向提高检测置信度阈值暂时压制误报或者给数据集补一些无裂缝的路面负样本让模型见过更多“长得很像裂缝但其实是纹理”的图。F1曲线是调阈值用的。训练好的模型会输出每个框一个0到1的置信度F1曲线帮你找precision和recall的平衡点。工程上我习惯让召回率优先——漏检一条裂缝的代价比误报大得多所以置信度阈值通常定在0.3到0.4配合后面GUI里的面积过滤来压误报。3.4 验证新图best.pt的第一轮实测指标再好不如拿一批从未见过的路面图跑一遍。验证命令yolo detect predict modelruns/detect/train/weights/best.pt source./test_road/ conf0.3 saveTruesource指向一张图或一个目录都行saveTrue会把画好框的结果存到runs/detect/predict/下。这一步主要看三件事真实路面上能不能检出裂缝单张图推理耗时多少误报长什么样。如果检测结果里有一堆小方框套在纹理上说明模型对“裂缝”的定义学宽了回到3.2调高conf到0.5再看看。如果该检出的裂缝漏了一半说明召回不够把conf降到0.2同时检查是不是标注框本身画得太紧。验证通过后这个best.pt就是要接进GUI界面的那个模型文件。4. 用PyQt5把模型变成桌面工具GUI的设计与推理线程4.1 GUI功能拆解图片、视频和参数面板这个系统的界面价值在于让不懂命令行的人也能用模型。常见做法是三区域布局。左侧是操作面板放“打开图片”“打开视频”“开始检测”按钮加一个置信度滑条中间是显示区QLabel控件承载图像检测框直接画在图上底部放结果列表显示每次检测的目标数、平均置信度、是否报警窗口底部再加状态栏显示模型加载状态和推理耗时。PyQt5实现这个界面不复杂QMainWindow作为主窗口QPushButton做按钮QSlider做阈值调节QLabel显示图像QListWidget列检测结果。界面代码量不大真正的难点不在控件摆放而在怎么让模型推理不卡住界面。控件类型作用btn_open_imageQPushButton打开单张图片btn_open_videoQPushButton打开视频文件slider_confQSlider调节置信度阈值label_displayQLabel显示检测结果图list_resultQListWidget列出检测框详情statusbarQStatusBar显示模型状态和耗时布局用QVBoxLayout和QHBoxLayout组合左侧面板用固定宽度显示区用伸缩因子占满剩余空间窗口缩放时图像跟随放大。这里有个设计点值得说模型加载要在窗口初始化时完成不要每次点检测都重新load。加载一个YOLO模型需要几百毫秒到几秒如果放在按钮回调里用户每点一次就卡一次体验很差。正确做法是在初始化时加载一次模型之后所有检测请求复用同一个模型对象。4.2 推理线程为什么不能在主线程跑模型PyQt5的事件循环跑在GUI主线程界面刷新、按钮点击都在这条线程上调度。如果在按钮回调里直接调用model.predict()CPU或GPU推理的这段时间里事件循环被占住界面表现为“假死”——按钮按了没反应窗口拖不动严重时系统会提示程序未响应。解决方法是把推理放进QThread子线程推理完成后通过信号把结果传回主线程更新界面。下面是核心骨架import cv2 import numpy as np from PyQt5.QtCore import QThread, pyqtSignal from ultralytics import YOLO class DetectWorker(QThread): result_ready pyqtSignal(object) # 返回绘制后的图像 frame_ready pyqtSignal(object) # 视频逐帧画面 progress pyqtSignal(int) # 视频处理进度 def __init__(self, model_path, conf0.35, parentNone): super().__init__(parent) self.model YOLO(model_path) # 窗口初始化时加载一次 self.conf conf self.mode image self.source def run(self): if self.mode image: frame cv2.imread(self.source) results self.model.predict(frame, confself.conf, imgsz640) plotted results[0].plot() # YOLO自带画框返回BGR图像 self.result_ready.emit(plotted) elif self.mode video: cap cv2.VideoCapture(self.source) total int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) count 0 while cap.isOpened(): ret, frame cap.read() if not ret: break res self.model.predict(frame, confself.conf, imgsz640) plotted res[0].plot() count 1 self.frame_ready.emit(plotted) self.progress.emit(int(count / total * 100)) cap.release()说明几个关键点。self.model YOLO(model_path)放在init而不是run里模型只加载一次。self.mode和self.source由主线程在启动线程前赋值run里根据模式分流。res[0].plot()是Ultralytics封装好的画框方法直接在原图上画矩形、标签和置信度返回BGR格式的numpy数组省去手工绘制。主线程那边接收信号更新界面from PyQt5.QtGui import QImage, QPixmap def show_result(self, plotted): h, w, ch plotted.shape img QImage(plotted.data, w, h, ch * w, QImage.Format_BGR888) self.label_display.setPixmap(QPixmap.fromImage(img))QImage直接包装numpy数组的内存不再做复制。最后一个参数QImage.Format_BGR888要和OpenCV的BGR通道顺序对应如果换成RGB格式裂缝图上所有颜色都会红蓝互换第一次做GUI集成的人几乎都踩过这个坑。4.3 可视化与导出画框、阈值和结果保存检测框画出来了展示只是第一步。工程上常用三个补充。第一个是置信度过滤。界面滑条的值在启动每次检测时传给predict的conf参数。滑条设0.2时漏检少但误报多设0.6时误报少但可能漏细裂缝。建议区间0.25到0.5默认0.35这个组合在370张图训练出的模型上表现比较平衡。第二个是结果导出。检测完可以让用户选择保存检测图也可以生成一份CSV报告逐条记录文件名、目标数、每个框的坐标和置信度路面养护单位要的往往不是一张图而是一张可以进台账的表格import csv import datetime def export_csv(self, rows, path): with open(path, w, newline) as f: writer csv.writer(f) writer.writerow([时间, 文件, 类别, 中心x, 中心y, 宽, 高, 置信度]) for r in rows: writer.writerow([datetime.datetime.now(), r[file], r[cls], round(r[x], 4), round(r[y], 4), round(r[w], 4), round(r[h], 4), round(r[conf], 3)])第三个是面积过滤。裂缝检测常见误报是细小纹理被框成一小条置信度还不低。可以在画框前算一下框的像素面积设置一个最小面积阈值比如小于2000像素的框直接丢弃。这个不是模型的事是后处理的事但对桌面工具的“可用感”提升非常明显。5. 这套系统最容易翻车的位置踩坑记录与排查5.1 数据集与标注相关的坑现象一训练能跑起来loss曲线也正常下降但验证集mAP一直在0.2附近徘徊模型几乎什么都检不出来。原因最常见是标注框和真实裂缝贴合度太差或者标注框过小。370张图里如果有几十个宽度只有两三个像素的框模型很难从这些目标上学到有效特征反而把注意力放在“模糊小方块”上。解决用可视化脚本把标注框画回图上逐个看一遍。框小于10像素的样本直接删掉或重新标注成更完整的裂缝段。规则很简单宁可少一个目标不要错一个目标。现象二模型在训练图上效果很好换一段真实路面检测误报框暴增。原因训练集背景太“干净”。370张图里如果全是柏油路面裂缝模型没学过人行道、标线、伸缩缝、雨水箅子周围的纹理遇到没见过的背景就想框一下这是背景负样本不足导致的典型问题。解决从真实路面段补充50到100张无裂缝图片标注文件为空txt作为负样本加入训练。注意空txt要放得进去同时别让前面2.3的find空文件脚本把它们误删。现象三标签txt和图片存在但训练时报“found no labels”。原因多数情况是大小写不一致比如图片叫IMG_001.JPG、标签叫img_001.txtUltralytics按文件名匹配时找不到对应关系。Linux下这个问题是致命的。解决统一把文件名转成小写再配对或者用2.3节的diff脚本查一轮改完再启动训练。5.2 训练与评估相关的坑现象一启动训练立刻报CUDA out of memory或者CPU训练慢到无法接受。原因batch和imgsz超出硬件能力。imgsz640直接决定了显存占用翻倍到1280显存占用是四倍不是两倍。解决batch降到4或2imgsz保持640还不行的就用devicecpu配合小batch跑。对370张图来说CPU训练慢但能出结果唯一代价是时间。现象二best.pt和last.pt的指标差很多best的mAP很高但实际检测很差。原因验证集和训练集有重叠片段前面强调的“按路面段划分”没做好验证指标失真。解决重新划分数据集验证集换成模型完全没见过的路段。如果项目已训练完至少再准备一个独立的测试集目录用3.4节的predict命令单独验一次别信训练日志。现象三PR曲线形状怪异比如召回率到0.4附近曲线垂直下坠。原因标注样本里缺少某一类形态的裂缝。比如训练集全是横向裂缝模型看到纵向裂缝时召回率骤降曲线就表现为在某个位置断崖式下跌。解决回看数据分布缺哪些形态就补哪些补完重新训练。这个现象本身是好事它帮你发现数据的结构性缺口。5.3 PyQt5与推理集成的坑现象一点“开始检测”后窗口无响应过几秒才恢复。原因模型推理直接跑在了GUI主线程。这在图片检测时还能忍视频检测时窗口直接假死因为每一帧推理都占住事件循环。解决用4.2的QThread方案把predict放进子线程信号回传界面。这是GUI集成里最值得注意的一条。现象二图像显示颜色不对裂缝变成蓝色路面变成橙黄色。原因OpenCV读图是BGR通道顺序QImage默认按RGB解释。不转换直接显示红蓝通道互换所有画面都偏色。解决构造QImage时用QImage.Format_BGR888或在赋值前用cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)转一次对应QImage.Format_RGB888。两种方式都行但要在同一套代码里统一别一个界面里混着用。现象三程序启动时模型加载要好几秒用户以为卡死或崩溃。原因没有加载提示。YOLO模型初始化时会创建网络、加载权重n模型零点几秒s模型一两秒在机械硬盘上更久。解决在窗口初始化时先设置状态栏“正在加载模型…”加载完成再更新状态并把“开始检测”按钮disable到加载完成再enable。这个细节对交付体验影响很大。6. 让检测系统更可靠的三个进阶技巧切图、导出与泛化验证6.1 小裂缝用切图推理路面裂缝很多是细长条整图640输入时一条宽8像素的裂缝在特征图里只剩一两个像素模型很容易漏。常见做法是切图推理把原图切成四块或九块每块单独过模型再把框坐标映射回原图。切图尺寸建议与训练尺寸一致用640重叠率设10%到20%避免裂缝恰好落在切图边界被切断。坐标映射公式很简单原图x等于块内x加块起始xy同理。这样裂缝在局部图中的占比变大检出率明显提升代价是推理次数变多在桌面工具里做成一个“高精度模式”开关就行。6.2 导出ONNX不依赖训练框架的部署方案给用户交付时对方环境不一定能装PyTorch。用Ultralytics导出ONNX再接入GUI可以把运行依赖压到只保留onnxruntime和OpenCVyolo export modelruns/detect/train/weights/best.pt formatonnx imgsz640导出后用onnxruntime替换YOLO类推理速度在CPU上往往更快也绕开了PyTorch版本兼容问题import onnxruntime as ort import numpy as np session ort.InferenceSession(best.onnx) input_name session.get_inputs()[0].name outputs session.run(None, {input_name: preprocessed_image}) # outputs 包含框坐标、置信度、类别需在导出时保留NMS逻辑注意preprocessed_image要做letterbox、归一化、转float32、加batch维度格式与训练时保持一致否则输出坐标会偏移。6.3 泛化验证换一批路面图考验模型交付前我习惯准备一个“陌生验证集”不同路面类型沥青、水泥、不同天气晴天、阴天、雨后、不同设备拍的图各放几张手动统计漏检和误报在GUI里逐张过一遍。这一步往往是发现模型真实水平的时候比训练日志上的mAP可信得多。指标合格再交付不合格就回去补数据或调阈值。我的习惯是把这个验证集留在项目里和训练集分开管理。每次换模型、调参数都拿同一批陌生图测试结果可对比进步可量化翻车概率也会明显降下来。希望这套思路和前面几章的细节能帮到你把这些坑提前排掉你的道路裂缝检测系统会少走很多弯路。本文还有配套的精品资源点击获取
返回列表