
简介这是一份基于Python与YOLOv5的路面桥梁裂缝检测识别项目源于导师指导下的高分毕业设计评审分99分适合计算机相关专业学生用于毕业设计、课程设计或期末大作业也适合希望动手实践YOLO目标检测的初学者。整套资源以zip压缩包形式提供共85个文件大小仅1.6MB包含23个Python源文件、23个YAML配置文件、Shell脚本、Dockerfile及示例图像其中py文件负责模型定义、训练与推理yaml文件用于配置网络结构和数据集sh脚本用于获取预训练权重Dockerfile可快速搭建一致运行环境。代码库按模型、工具、数据、脚本等模块组织提供图片与摄像头两种推理脚本方便对图片或摄像头画面进行裂缝识别同时附有多个YOLOv5模型配置与权重下载脚本可灵活切换不同检测规模。目前已有80人学习/下载对有课程设计或毕业设计需求、想直接运行并二次开发的初学者较为友好。1. 路面桥梁裂缝用PythonYolov5检测识别这套毕设方案先解决三个被低估的问题混凝土路面和桥梁检测是结构检测的必修项裂缝一旦漏检轻则影响耐久性重则危及结构安全。人工巡检效率低、主观性强因此很多毕业设计选PythonYolov5路面桥梁裂缝检测识别这个方向——数据集可获取、模型可训练、源码能直接跑通看起来是一条稳妥路径。但一个反直觉的事实是这类项目的难点不在模型精度而在三个被低估的环节——数据标注的一致性、细长裂缝的漏检控制、最终评估口径的严谨性。如果这三件事没想清楚哪怕源码包和预训练权重都准备得很顺利最后收获的也只是“模型能跑但答辩站不住”的结果。这篇笔记顺着这个标题把环境搭建、训练调参、常见翻车点走一遍新手能照着复现熟手也能对照检查自己的参数设置。2. Yolov5落地面裂检测先看模型机理网络结构、检测输出与三个对比选型理由2.1 路面和桥梁裂缝检测到底在检测什么裂缝检测和行人检测这类常规目标检测任务有一个本质区别裂缝不是“一团独立物体”而是背景上的局部断裂纹理。沥青路面的裂缝往往呈现黑色细长条水泥混凝土桥梁的裂缝则可能伴随渗水痕迹、泛碱区甚至长期车辆磨损后的黑色车辙带这些干扰物在视觉上和裂缝高度相似。任务定义一旦不清晰标注和评估就会出现系统性偏差。从任务形态看裂缝检测既可以用目标检测框来做也可以用语义分割来做。毕设和多数现场巡检系统采用Yolov5检测框有几个实际原因裂缝框只需要表达“这里有一处缺陷”不需要逐像素抠出裂缝形态标注成本大幅低于分割标注后续统计裂缝数量、大致长度时通过检测框的宽高比和坐标就能近似估算。分割方案比如U-Net能给出更精细的形态但训练样本需求大而且对桥梁上密集的网状裂缝分割标注能把人标到崩溃。我一般会把裂缝按形态粗分为三类来建类横向缝、纵向缝、网状/块状缝。如果你的数据集里已经有现成标签先看一眼类别之间的数量是否悬殊——常见翻车是横缝占了八成纵缝和网状缝的召回率惨不忍睹。2.2 Yolov5的结构、推理流程与检测头输出Yolov5的源码结构有几个关键模块跑裂缝检测前至少要清楚它们各自干什么。Backbone部分负责提取特征U版Yolov5用的是CSPDarknet结构加上SPP模块扩大感受野让网络能同时看到较大范围的背景纹理Neck部分采用PANet结构自顶向下和自底向上的特征融合路径交叉进行目的是让浅层的高分辨率特征和深层的语义特征互相补充Head部分在三个不同尺度上输出预测结果。以小目标为主的裂缝检测需要特别关注的是P2/浅层特征——很多漏检就发生在模型完全依赖Deep层语义特征、丢失了细裂缝的空间细节。推理时的工作流也要心里有数。输入图片先做letterbox缩放保持宽高比并填充边缘避免形变破坏裂缝的几何形态接着进入网络得到三个尺度的原始预测张量每个张量的通道数由公式(类别数 5) * 3决定5对应center_x, center_y, width, height, objectness最后做NMS按类别过滤重叠框。这里有个裂缝场景特有的坑NMS对细长裂缝框特别敏感如果长宽比极端的两个框中心接近NMS很容易把其中一个当成冗余框抹掉导致联网状裂缝漏检。检测头的输出从代码层面看是经过解码后的归一化坐标。以detect.py为例开启--save-txt后每一行文本的前几个数字就是归一化的中心点和宽高乘以原图尺寸才能还原真实像素位置。这个还原关系如果不搞清楚后续统计裂缝位置、计算占比时很容易算错而且错得悄无声息。2.3 与Faster R-CNN、SSD、Yolov8的对比为什么这张牌打起来最顺手常见对手是两阶段检测器Faster R-CNN或其变种如经典的Cascade R-CNN和单阶段的SSD再新一点还有Yolov8、YoloX。Faster R-CNN的RPN 两阶段级联在密集小目标上确实能捡回不少召回但训练速度、显存占用和部署成本对本科毕设并不友好。一个 200 张裂缝图的训练集在同样的1050显卡上Faster R-CNN要跑到 3 至 4 个小时一轮Yolov5s只要不到 1 小时而且调参涉及的先验框、NMS策略、候选框采样逻辑比Yolov5复杂得多——排查问题时的难度成倍上升。SSD的优势是快但对小目标先天弱势裂缝这种宽高比极端、像素占比小的目标在SSD的单尺度特征上很容易被当成背景。Yolov8的问题不是精度而是封装程度。它的训练接口更“一体化”许多底层改了要绕好几层代码对新手来说像黑匣子Yolov5的代码结构相对直白从数据加载、损失函数到NMS都能在utils/目录下对应到具体文件。答辩时老师问“你的检测框怎么来的”你能直接指出model/yolo.py里的解码逻辑这一点比“我用现成框架跑的”有说服力得多。3. 跑通最小项目Python环境搭建与源码目录的每一个关键开关3.1 Python环境与依赖安装先把torch和CUDA对应关系锁死拿到源码包后的第一步不是急着跑train.py而是先顺一遍Python环境。Yolov5的官方requirements.txt通常会列出一组依赖版本但源码包经过多次迭代依赖清单不一定和你的显卡驱动匹配。常见做法是先建独立虚拟环境避免把系统Python搞乱。我常用的环境是 Python 3.8 搭配 PyTorch 1.10 及以上如1.10.2与 CUDA 11.3这个组合在NVIDIA 20/30系显卡上都能稳定跑。如果你手里是没有独显的机器或Mac纯CPU也能训练只是速度慢几倍建议把--batch-size调小到4以内。建环境和装依赖的典型命令如下# 1. 用conda建独立环境python版本建议3.8/3.9/3.10 conda create -n crack_detect python3.8 -y conda activate crack_detect # 2. 先装torch全家桶再装项目其余依赖 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu113 # 3. 进入源码目录安装requirements里的剩余依赖 cd yolov5-master pip install -r requirements.txt第一步创建的虚拟环境让依赖隔离避免系统里其他项目的包版本冲突第二步指定cu113索引是为了让torch与CUDA 11.3配套如果版本错配运行时会报CUDA error: no kernel image available for execution on the device第三步的requirements.txt里会装上 numpy、opencv、matplotlib、tensorboard 等运行训练和可视化的基础库。装完先跑一个自检命令python -c import torch; print(torch.cuda.is_available())输出True再继续。这个检查是后面所有训练的前提免得在开了GPU的代码里浪费一整晚才发现CPU在硬扛。3.2 源码目录结构与关键文件不看会跑错U版Yolov5的核心代码文件并不多但作为毕设你需要知道每个目录在项目里扮演什么角色。models/下的yolov5s.yaml、yolov5m.yaml等文件是模型结构定义它们不是权重只是描述网络层数和通道数的配置utils/里是数据加载、损失计算、指标评估、增强策略这些工具方法data/下放数据集配置文件weights/一般放预训练权重或你自己的训练结果。很多第一次跑的人会犯的错是把权重文件放到models/里然后--weights models/yolov5s.pt报错找不到模块。权重文件默认放在项目根目录或weights/结构定义文件才在models/。还有一个常见坑源码包里的runs/目录是训练输出包括每次的日志、权重和检测结果图如果你连续训练多次注意runs/train/expN的编号递增别总是盯着runs/train/exp看还以为自己没训练出结果。我想强调的是不要在拿到源码包后马上就改代码。先原样跑通一次推理或训练确认环境无误再逐步增加自己的数据集和改动这个顺序能省大量排查时间。3.3 用预训练权重跑一次检测detect.py参数逐项说明拿到一个能用的模型文件如yolov5s.pt后先验证推理链路。detect.py是推理入口常用命令长这样python detect.py --weights yolov5s.pt \ --source data/images/bridge_01.jpg \ --conf-thres 0.25 --iou-thres 0.45 \ --img-size 640 \ --save-txt --save-conf --project runs/detect/ --name demo_crack用途说明--weights指定权重路径可以是官方预训练权重也可以是你之后自己训练的best.pt--source可以是单张图片、视频文件甚至摄像头传文件夹可以批量推理--conf-thres是置信度阈值低于该值的预测将被丢弃调低它能找回更多潜在的裂缝区但同时也引入误检--iou-thres是NMS的IoU阈值它控制两个重叠框的去留对裂缝这种长条目标一般控制在0.4到0.5之间比较稳妥--img-size是推理时letterbox缩放到的大小针对桥梁裂缝这种细节目标建议直接用960代价是显存占用上升--save-txt会把每个目标的类别、置信度和归一化坐标写进txt文件--save-conf则额外把置信度数值写入--project与--name指定输出目录。跑完会在输出目录看到带检测框的图片和同名txt文件。如果这时候画出来的框全是“一把梭”——一个大框套住半张图大概率是阈值太低或模型过拟合了背景而不是参数出了问题。先不要急着换模型把--conf-thres提到0.5再看筛选出真正的裂缝框这一步也是毕设里经常被问到的“后处理逻辑从哪里体现”。4. 训练自己的裂缝检测模型数据集协调、YOLO格式转换与五个必调超参数4.1 裂缝数据集准备从现场图到可用训练集的三个原则如果是毕设多数人拿到的都是已有的裂缝图片集但“有图”和“能训练”之间隔着挖掘整理。第一个原则是宁少勿偏图片数少但覆盖多种光照、拍摄角度的训练集比全是清晰正光图片的大数据集更可靠。第二个原则是控制类别边界路面裂缝和桥梁裂缝如果只是拍摄对象不同、形态相似没有必要拆成两个类除非你确实需要区分“部位”来支撑后续维护决策。第三个原则是加入负样本没有裂缝的干净路面、有水渍和阴影的混凝土面各放一部分标注为背景。这能大幅减少模型把阴影当裂缝的翻车概率。数据增强方面Yolov5训练时默认开启Mosaic增强把多张图拼成一张喂给网络。对裂缝这种长条形目标Mosaic在早期能提升抗干扰能力但要注意如果拼图时把裂缝截断或让两个长裂缝交叉标注框会被强行合并反而引入错误标签。因此如果你用的是自己的数据建议把训练配置里的mosaic系数保持在0.5左右不要为了增强而增强。4.2 标注与YOLO格式一行txt的坐标陷阱标注工具我一般用LabelImg它导出的是Pascal VOC的XML格式需要再转成YOLO的txt格式。YOLO格式每行对应一个目标内容为class_id center_x center_y width height所有值都归一化到0到1之间。随手截一个真实标注中可能出现的错误例子# 标签文件 bridge_001.txt类别0为横向裂缝 0 0.318759 0.245871 0.076599 0.024489 0 0.703214 0.658112 0.054821 0.011935每一行前一个数字是类别ID后面四个是归一化坐标。这里最容易出错的点是width和height是“框的宽和高”不是“右侧坐标减左侧坐标再取绝对值”那么简单。如果写反了宽高或者忘了归一化而直接写了像素值训练出来的模型会在验证时mAP极低且框的位置整体偏移。一个稳妥的转换习惯是先把XML里的xmin, ymin, xmax, ymax读出来再统一用(xmin xmax) / 2 / img_width计算中心点x坐标用(xmax - xmin) / img_width计算宽度所有坐标和尺寸都除以对应的图片宽或高严格区分分母。同时做一步数据校验对每个txt文件读一遍检查所有值是否都在0到1之间mAP在某个点突然崩塌八成是这类低级问题。4.3 训练启动命令与超参数怎么调才不玄学数据准备完成后需要写一个数据配置文件data/crack.yaml。内容示例如下# 数据配置train/val路径按自己实际的目录写 train: data/crack/train.txt # 训练集图片路径列表 val: data/crack/val.txt # 验证集图片路径列表 nc: 2 # 类别数例如横向缝纵向缝 names: [horizontal, vertical]train和val既可以是图片目录也可以是包含图片路径的txt文件两种写法Yolov5都认nc必须和你标注txt里的最大类别ID1一致如果标注时用了ID 0和1那么nc: 2names列表顺序要和标注ID严格对应否则训练出来类别名错乱。训练启动命令是python train.py --data data/crack.yaml \ --weights yolov5s.pt \ --img 640 --batch 16 --epochs 100 \ --device 0 --workers 4 \ --patience 20 --cache各参数在裂缝场景下的选择逻辑--img是训练时的输入分辨率如果想提高小裂缝召回调到960但显存占用会翻倍--batch直接受显存限制8G显存选--img 640 --batch 16通常是安全的显存溢出就降到8--epochs结合下面--patience使用我一般设100起步配合早停让模型自己决定几轮收敛--workers是数据加载线程数在Windows下超过4偶发假死Linux上可以调到8--cache会把图片一次性读入内存显著减少每次epoch的等待时间但前提是训练集总大小小于内存容量--patience 20表示连续20个epoch验证mAP没有提升就自动停止这是防过拟合的后悔药。训练过程中.pt会保存为last.pt每轮结束的最新状态和best.pt验证集表现最好的权重。要断点续训执行python train.py --data data/crack.yaml --weights runs/train/exp/weights/last.pt --resume runs/train/exp--resume接训练输出目录它会自动读取该目录下配置和上次的epoch状态继续跑而不是从头再来。能否成功续训的关键是不要手动改这个目录里的opt.yaml里面的参数和命令行参数冲突时训练会直接从旧配置启动。想要改参数就老实新建一次训练。4.4 训练日志解读loss降得漂亮不代表mAP好看训练日志里最少有两个数要盯box_loss和val/obj_loss另外留意集中输出的[email protected]。裂缝数据集下有一条血泪经验box_loss持续下降[email protected]却不动甚至下跌多半是模型在过拟合刷训练集而不是真正学懂了裂缝形态。意思是它对训练图里的光照分布和背景记熟了换到新图就失灵。每轮epoch结束Yolov5会在日志里打印类似P:0.713 W:0.862 mAP.5:0.622这样的指标。mAP是多个数据集共同评估的结果对于裂缝这类长条形、尺度变化大的目标建议看mAP.5IoU0.5时算作命中而不是mAP.5:.95。因为.5:.95对框的位置偏差极其敏感同一批裂缝框人眼看着已经框到裂缝上但 IoU 达不到0.75指标被误杀。想用更严苛的指标来支撑毕设结论也先确认你的数据集能承受这个标准否则答辩时被质疑指标虚高更被动。5. 裂缝检测项目必踩的坑过拟合、小目标漏检与评估失真5.1 现象训练后mAP不错但验证集图片上满屏红框现象是模型在训练集表现极佳在验证集却满图框甚至把没有任何裂缝的水泥纹路全框出来。原因通常是训练时conf-thres设置过低或数据增强过度让模型学到了背景纹理的细节而不是裂缝的结构。解决方法是先看验证集预测时的阈值把--conf-thres提到0.3以上再检查增强配置里的fliplr0.5是否把纵向裂缝翻转成横向标注产生物理上虚假的样本。此类问题用负样本图跑一遍预测能快速定位是过拟合还是标签混乱。5.2 现象细长裂缝漏检而粗裂缝框得挺好桥面细小裂缝只有1到2像素宽下采样到深层特征图上可能只剩一个点自然丢失。解决思路有三条一是直接提高训练与推理分辨率--img 960甚至1280二是对原图做切图推理把一张大图切成512大小的小图块分别检测再合并结果这个做法能显著提高召回代价是推理时间翻倍三是标注时要对长裂缝分段标注不要把一整条几十厘米的裂缝框成一个极大长条框而是按可视段拆成多个框这既适合检测任务也减轻NMS对长宽比极端框的压制。如果这三条都做了还漏检再看锚框Yolov5默认锚框并不适配极长条目标可以在标注数据上运行utils/autoanchor.py重新聚类出自己的锚框再写回模型配置。5.3 现象训练刚跑几步就报CUDA out of memory这个报错多数是显存容量撞墙。连续跑几次都被中断不是代码问题是配置和显卡不匹配。常见处理把--batch从16降到8或4把--img从960降到640关闭--cache因为把数据缓存进内存在某些版本里会连带占用更多显存临时缓冲再不行就启用混合精度训练加--amp一般能把显存占用压低三到四成。如果整机内存不够先把workers调小避免数据加载进程抢占系统内存。这类问题在裂缝数据集上特别频繁因为图片多是现场拍摄的高分辨率照片一张就接近十MB预处理开销不小。5.4 现象测试集指标高一到现场新图就失灵这是割裂较严重的一类翻车模型的指标是在“自己人”数据集上测出来的而现场巡检的图片亮度、拍摄角度、相机型号全变了。裂缝检测里常见的误检是阴影、伸缩缝、水渍被识别为裂缝因为这些区域的局部对比度和真实裂缝很接近。解决常用两板斧一是负样本补数据把没有裂缝的桥梁、路面图片按10%左右的比例混进训练集二是推理前做一次统一预处理固定缩放到同一亮度范围减少相机型号带来的分布偏移。我自己会在训练集里故意加入一些过曝和欠曝的裂缝样本这比加入更多正常光照图对泛化能力的提升更明显。5.5 现象打印的mAP挺高但保存的文本检测框数量对不上detect.py里--save-txt保存的是NMS之后、置信度大于--conf-thres的目标框它和画面里画出来的框应该是一一对应的。对不上通常有两个原因第一你同时开了--save-conf却没有解析最后一列置信度导致多读少读第二输出的txt里坐标是归一化的如果你直接拿像素坐标去画框得到的框位置就会偏。建议统一用结果图旁边的txt做后处理不要用Python另读一遍原始预测张量。分析裂缝统计时以txt里保存的坐标为准根据框的宽高比区分横向缝和纵向缝再按置信度过滤一次才算把检测输出用扎实了。6. 从“会跑”到“能答辩”自己做一张结果统计卡并解释清楚置信度的含义做毕业设计最常被问的一句话是“你的系统到底比人工目检好在哪”。如果只甩两张对比图老师很难信服。这里我分享一个实用习惯写一段脚本把检测结果统一汇总成表让每个裂缝框、置信度、类别都有据可查。import os, glob def parse_detect_txt(txt_path, img_w, img_h): boxes [] with open(txt_path, r) as f: for line in f: parts line.strip().split() # 格式class_id cx cy w h [conf] cls_id int(parts[0]) cx, cy float(parts[1]), float(parts[2]) w, h float(parts[3]), float(parts[4]) conf float(parts[5]) if len(parts) 5 else -1 # 还原为像素坐标 x1 int((cx - w / 2) * img_w) y1 int((cy - h / 2) * img_h) x2 int((cx w / 2) * img_w) y2 int((cy h / 2) * img_h) boxes.append((cls_id, x1, y1, x2, y2, conf)) return boxes # 示例遍历某个检测输出目录 for txt in glob.glob(runs/detect/demo_crack/labels/*.txt): boxes parse_detect_txt(txt, 1920, 1080) print(f{os.path.basename(txt)}: {len(boxes)} 个裂缝框)这段代码把Yolov5保存的归一化坐标还原成像素框再按文件统计数量。你可以在此基础上继续统计横向缝和纵向缝的比例、平均置信度、每张图的拍摄位置——这些数据凑成一张统计表再配合几张现场图答辩时就能把“检测结果可解释”说清楚。最后从实施角度强调两件事第一最终报告里写清楚你的conf-thres默认值和调整后的值因为置信度阈值对裂缝检测的数量影响极大不写阈值直接写“检测出872条裂缝”会被当作无效结论第二保留训练日志和验证集预测结果图它们是模型训练的原始证据。我在这个项目上吃过亏当时只留了最后结果图被追问训练过程中的mAP曲线时拿不出东西临时补跑又是好几天。现在做任何模型迭代都习惯把每次训练的results.png和opt.yaml归档这是最便宜的后悔药。裂缝检测没有想象中难但把每个环节的坑填平比追求一次跑通更有价值希望这些经验对你有用。本文还有配套的精品资源点击获取