☰
Python+YOLOv5路面桥梁裂缝检测实战:数据标注、训练与避坑指南
2026/10/7 13:57:27 网站建设 项目流程

简介:基于Python+YOLOv5的桥梁与路面裂缝检测识别项目,是一份可直接运行的毕业设计源码和模型包,面向计算机相关专业学生、毕业设计及课程设计人群,也适合零基础学习者用于项目实战练习。项目围绕基础设施裂缝检测这一现实任务,提供了从数据配置、模型训练到图片/摄像头实时推理的完整流程,结构清晰,代码可运行,并曾获导师认可、评审得分99分,可直接作为毕设底稿或课程作业。资源包共85个文件,以py源码、yaml配置、pyc编译文件为主体,辅以sh环境脚本、Dockerfile和多种裂缝示例图片,压缩包仅1.6MB,轻量易下载,便于快速部署。已有78人学习浏览,适合正在完成毕设或想快速跑通目标检测项目的读者。借助该方案可复现裂缝检测全流程,也能按需修改数据与参数,用于后续算法改进或论文实验。

1. 毕业设计选 Python+Yolov5 做路面桥梁裂缝检测:为什么这题看着简单,却每年都有人翻车

毕业设计要选 Python+Yolov5 做路面桥梁裂缝检测,几乎是计算机视觉方向最容易上手的目标检测题目。裂缝识别既有真实场景,又能用边界框和置信度直观展示,答辩时放一张裂缝被框出来的效果图,比讲一堆数学公式更能让评委点头。但这个项目并不是把源代码和模型下载下来就能交差的:Python 环境、数据标注、yolov5 超参数,每一处都能让人卡上一周。适合的人群很明确,想完整走一遍“采集数据 → 标注 → 训练 → 评估”流程的本科生,或者刚入门目标检测、想拿裂缝当落地场景的开发者。下面按我实际跑通这个方向的顺序写,照着做能省下不少反复摸索的时间。

2. 裂缝检测前先看懂 Yolov5:网络结构、模型选型与本地跑通 demo

2.1 看懂 yolov5 网络结构图:Backbone、Neck 与 Head 各管什么

很多人一开始就跳过网络结构,直接跑训练脚本,结果模型变成黑匣子,出了问题不知道去哪看。YOLOv5 的主体结构在任何一张 yolov5 网络结构图上都能看得很清楚,它由三块拼起来:Backbone 负责从原始图像里抽特征,Neck 负责把不同尺度的特征融合,Head 负责在最终特征图上输出预测框和类别概率。裂缝检测对这三块各有要求。Backbone 的深度决定了对细纹理的敏感度,Neck 的多尺度融合决定了对长短不一裂缝的适配度,Head 的锚框设计则决定了细小目标能不能被准确定位。

YOLOv5 的 Backbone 使用了 CSPDarknet 结构,把通道分成两部分,一部分经过卷积计算,另一部分直接跨层相连,用这种设计减少重复梯度计算,同时保留更多细节信息。路面桥梁裂缝在图像里往往是低对比度边缘,背景里有沥青颗粒、桥墩阴影、伸缩缝,这些都会干扰特征提取,所以 Backbone 的浅层特征对裂缝边界尤其重要。Neck 部分是 FPN 加 PANet 的组合,FPN 从高层往低层传语义信息,PANet 再自底向上补充空间细节,最后在 Head 端得到三个不同尺度的输出,分别负责小、中、大目标。裂缝的长宽比差异极大,一张图里可能同时存在几像素宽的细纹,也有横向贯穿几十厘米的长缝,这种跨度让单尺度输出完全失效。看网络结构图时,要理解的是为什么需要三个输出头,而不只是记住模块名字。

很多毕业设计的失败不是模型不好,而是压根不看结构就把源代码里的参数一顿乱改。改之前至少要在图上找到输入尺寸从哪里进入、三个预测层在哪些位置生成,这样后面调训练参数时,才知道改的是哪一个环节。

2.2 路面桥梁裂缝该选哪个模型:从 yolov5s 到 yolov5x 的取舍

YOLOv5 常见有 n、s、m、l、x 五档模型。用在哪决定选哪档。如果手里的显卡只有 4G 到 6G 显存,训练时间又只剩一两周,老老实实选 yolov5s;如果只做验证,CPU 推理也能跑,选 yolov5n 更轻松;如果桥梁远景图片里的裂缝只有十几个像素,显卡 10G 以上,可以考虑 yolov5m 或 yolov5l,但要接受训练时间翻倍的代价。

我通常会先拿 yolov5s 和输入尺寸 640 跑一轮 baseline。这个组合在 6G 显存的笔记本上,batch-size 设 16 勉强能跑,速度也够。跑完看 mAP,如果漏检多再换更大的模型或调高 imgsz。不要一开始就上 yolov5x,那是典型的拿资源换虚荣心,训练时间可能长到让毕设日期告急。imgsz 是另一个容易被忽略的入口参数,640 适合车载摄像头拍的路面,1280 适合无人机拍的桥面,但显存占用会按面积增长,小显存基本碰不了。所以模型档位和输入尺寸要一起规划。

这里有一条血泪经验:先做小模型跑通全流程,再换大模型做对比,这是最稳的节奏。很多失败案例都是第一天就在最大模型上调参,结果连一次完整训练都没跑起来。

2.3 先把环境跑通:Python 安装、依赖安装与第一条 detect.py 命令

无论拿到的是哪个版本的 YOLOv5 源代码,第一步一定是先跑通推理 demo,再碰训练。这一步能帮你确认 Python、PyTorch 和 CUDA 是否兼容,也能让你提前感受模型输出长什么样。用虚拟环境管理项目依赖,可以避免把系统 Python 环境搞乱。常见做法是先创建 conda 环境,再按 requirements.txt 装依赖:

conda create -n yolov5 python=3.8 -y conda activate yolov5 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install -r requirements.txt

参数说明:Python 版本不用追最新,3.8 到 3.10 都可以;torch 的安装源要根据 CUDA 版本选择,如果只是 CPU 推理,就装 CPU 版能省不少空间;requirements.txt 在 YOLOv5 项目根目录下,里面是 opencv-python、pandas、matplotlib 这类依赖。装完先别急着训练,用一张裂缝图片跑推理:

python detect.py --weights yolov5s.pt --source 001.jpg --conf-thres 0.25 --save-txt

这里关键参数有三个。--weights指定模型权重文件,第一次运行会自动下载官方预训练权重;--conf-thres是置信度阈值,0.25 是偏低的值,能看到更多候选框,用来熟悉输出可以,用来做正式统计则要调回 0.4 左右;--save-txt会把每个框的类别、中心坐标、宽高和置信度写进 txt,方便后面做裂缝数量统计。如果机器没有 NVIDIA 显卡,detect.py 默认会用 GPU,启动后会报错,这时在命令末尾加--device cpu,PyTorch 就会用 CPU 推理,速度慢一点但流程能通。CPU 推理一张 640 的图大概要 1 到 3 秒,是正常现象。权重下载如果网络连接不畅,可以直接找已经下载过的同学拷贝一个 yolov5s.pt 放进项目根目录,代码检测到文件已存在就不会再去下载。

源代码管理这件事也很重要,我习惯从第一天就把项目纳入版本管理,每跑完一版训练就提交一次。runs/train/exp目录会按编号自增,再把对应的训练命令和超参数写进备注文件,否则过两周你根本分不清哪个权重是哪次实验产的。这一步属于典的后悔药机制,毕设答辩前尤其关键。

3. 把路面桥梁裂缝做成自己的数据集:采集、标注与划分脚本

3.1 裂缝数据集的两个来源与版权边界

裂缝检测的训练数据有两个主要来源:公开数据集和自采照片。公开裂缝数据集常见的有 CrackForest、Crack500、DeepCrack 这一类,多来自城市道路和混凝土墙面,标签形式有语义分割也有手工框。作为训练素材,它们质量高、量大,可以直接用来做预训练。但它们的场景和桥梁裂缝差异不小:路面裂缝大多在平整沥青背景上,桥梁裂缝常有混凝土纹理、模板接缝和锈迹,直接把公开数据训练出来的模型拿去检测桥梁图片,漏检率会明显上升。

所以我常用的做法是公开数据做底料,自采数据做精调。先拿公开数据集跑一轮,让模型学会裂缝的基本纹理特征,再在自己拍摄的几十张桥梁、道路照片上做二次训练。这样标注工作量能控制在两到三天内,模型在答辩现场面对陌生人拍的图片时也不至于完全失效。还有一条要注意的是版权,公开数据集的引用规则各不相同,毕设论文要在数据集来源一节写清楚名称和出处,这是评委容易追问的点。

自采照片时要尽量覆盖白天、阴影、干燥、湿润、近距离、远距离这些条件。不要只拍大裂缝,真实场景里的细小裂缝才是模型能否落地的关键。如果条件允许,多拍一些带阴影、带水渍、带桥梁伸缩缝的图片,这部分负样本在后面排查误检时非常有用。

3.2 用 LabelImg 标注裂缝并导出 YOLO 格式 txt

有了图片之后,最花时间的就是标注。目标检测标注工具里,LabelImg 因为轻量和稳定,一直是首选。用 pip 直接安装:

pip install labelimg labelimg

启动后,在菜单里把标注格式从 PascalVOC 切换到 YOLO,再打开图片文件夹。框选裂缝时用矩形框,不要太贪心把大块背景包进去。裂缝是细长目标,标注框应该贴着裂缝边缘,宽度尽量覆盖裂缝实际占用的像素区域,否则模型学到的是一个框里大部分是路面,定位自然不准。类别名统一写 crack,毕设阶段不要一上来分 road_crack 和 bridge_crack 两个类,样本少的时候多分类会严重拉低精度。

保存后每张图片会生成一个同名 txt 文件,内容类似:

0 0.487307 0.318269 0.438462 0.159615

这一行五个数字对应类别 id、中心 x、中心 y、宽、高,前四个都是 0 到 1 的归一化坐标。值得强调的是,YOLO 格式里没有像素坐标,直接把像素值写进去会导致训练时所有边界都越界,模型完全学不出来。标注完一定要抽查几行 txt,看到大于 1 的数就回去改。这个细节可以说是裂缝标注里最容易发生的低级错误,但绝大多数报错都会让你怀疑到模型代码头上,实际是标签的问题。

3.3 训练集/验证集/测试集划分:一份不会串包的 Python 脚本

标注完成后,下一步是把图片按比例切成训练集、验证集和测试集。这一步看着简单,实际操作里最常犯的错是图片和 txt 对不上。如果一张图没有对应标签文件,训练时 yolov5 会报警告甚至跳过样本;如果标签文件名不一致,数据加载会漏样本。我习惯写一个脚本,用文件名作为匹配键来划分:

import random, shutil from pathlib import Path random.seed(2024) # 固定种子,保证每次划分结果可复现 dataset = Path("dataset/raw") # 原始图片目录 out = Path("dataset") split = {"train": 0.8, "val": 0.1, "test": 0.1} for img in dataset.glob("*.jpg"): label = dataset / (img.stem + ".txt") if not label.exists(): continue # 有图无标注的,直接跳过,别硬塞进训练集 mode = random.choices(list(split), weights=list(split.values()))[0] (out / mode / "images").mkdir(parents=True, exist_ok=True) (out / mode / "labels").mkdir(parents=True, exist_ok=True) shutil.copy(img, out / mode / "images" / img.name) shutil.copy(label, out / mode / "labels" / label.name)

这个脚本的逻辑很简单:遍历原始图片,强制要求同名 txt 存在,缺失就跳过;然后按比例用随机抽取的方式决定这张图进哪个集合。random.seed(2024)的作用是让每次运行结果一致,这样论文里写的训练集和测试集划分,答辩时还能复核。目录结构上,YOLOv5 默认要求图片放 images,同名标签放 labels,所以脚本里在目标目录下又按 train、val、test 分层。最后检查三个目录下的文件数量,大致 8:1:1 即可。

这里还有一个很隐蔽的坑:如果同一条裂缝被裁剪成多块,这些图片会被随机划分到 train 和 val,导致验证集和训练集高度相似,mAP 虚高,答辩时一换新图片就露馅。所以我后来会按来源批次分组划分,同一批拍摄的图片要么全进训练,要么全进验证,避免数据串包。处理小数据集时,这比简单随机划分重要得多。

4. 用 YOLOv5 训练自己的裂缝数据集:命令、超参数与迁移学习

4.1 修改数据配置文件 data.yaml:路径和类别的三处坑

训练之前要先准备一个数据描述文件,YOLOv5 约定俗成叫data.yaml。内容不多,但三处细节容易出错:

train: dataset/train/images val: dataset/val/images test: dataset/test/images nc: 1 names: ["crack"]

第一处是路径。建议用相对路径,从项目根目录出发,不要写带盘符的绝对路径,换一台电脑就得改一遍。第二处是 train 和 val 的地址,YOLOv5 会自动找同级 labels 目录,也就是说配置里只需要写dataset/train/images,它会自动对应dataset/train/labels,所以千万不能把标签和图片放到同一个目录里。第三处是nc要和names数量一致,如果标注时写了多个类别,这里也要同步改,类别数不一致会让训练报维度错误。

如果启动训练时提示AssertionError: train: No labels found in ...,第一反应不是去改 Python 代码,而是检查dataset/train/labels是否存在、txt 文件名是否和图片一致。这个提示算是我见过最多的 YOLOv5 数据问题,占了数据集报错的一半还多。

4.2 train.py 训练命令拆解:yolov5 超参数这么设才不玄学

配置文件就绪后,进入训练环节。核心命令如下:

python train.py \ --data data.yaml \ --weights yolov5s.pt \ --epochs 100 \ --batch-size 16 \ --imgsz 640 \ --workers 4 \ --device 0

--weights yolov5s.pt是迁移学习的核心,官方预训练权重在大规模公开数据上见过大量真实物体,能提供一个不错的起点,比随机初始化训练少花很多个 epoch 才能收敛。--batch-size是显存敏感参数,6G 显存设 16 已经接近极限,12G 可以设 32;batch 太小会导致 BN 统计量不稳,直观表现就是 loss 抖成心电图。--workers在 Windows 下别超过 2,设 4 或 8 极容易出现 DataLoader 崩溃,这不是代码问题,是 Windows 多进程加载的经典冲突。--device 0指定 GPU 索引,只有一张卡默认就是 0;没有 GPU 就改成 cpu,同时把 batch 降到 4 到 8。

超参数不用全部在命令行传,YOLOv5 把它放在data/hyps/目录下的 yaml 文件里,不同版本文件名略有差异。训练时 train.py 会读入,改这个文件就相当于改超参数。对裂缝检测这个任务,我最常动的是下面三项:

超参数默认值我常用的值为什么
lr00.010.005数据集小,学习率低一点更稳
mosaic1.00.5细长裂缝在马赛克拼图里容易被裁掉
fliplr0.50.5左右翻转对裂缝也有效,保持默认即可

注意,一次只改一个超参数做对比实验,才有资格写进毕业设计的实验分析表。不要同时把 lr、mosaic、fliplr 全改了,最后模型涨了一点,根本不知道是哪个改动起了作用。这个做法在写论文时尤其重要,单变量原则能让实验结果叙述干净很多。

4.3 迁移学习与数据增强:让细裂缝不漏检的进阶操作

常规训练跑完,如果漏检都集中在细裂缝,建议先用冻结策略做两段式训练。常见做法是先冻结 Backbone 前十几层,让模型在保留通用纹理特征的前提下,只更新 Neck 和 Head 的参数:

python train.py --data data.yaml --weights yolov5s.pt --epochs 30 --freeze 10

跑完 30 个 epoch 后,再不加--freeze继续训练 70 个 epoch。这样做的原因是,小数据集上直接微调所有层,模型很容易把裂缝过拟合到背景纹理上;先冻结主干让浅层特征保持稳定,再解冻全网络去学习裂缝特有的边缘组合,收敛过程会平稳很多。

数据增强方面,mosaic对裂缝检测是一把双刃剑。它能把四张图拼成一张,提升训练效率,但裂缝本来就是细长线条,拼图时每张图被缩小一半,裂缝可能直接缩到几个像素,标注框也容易超出拼接边界。所以我通常把mosaic从默认 1.0 降到 0.5,样本量小时这比牺牲精度换多样性划算。如果还是漏检,再把--imgsz提到 1280 重跑一版。代价是训练时间几乎翻倍,一般只作为冲刺手段。

5. 裂缝检测避坑与排查:训练不收敛、漏检错检、显存不足的翻车现场

5.1 训练 loss 不降和 NAN:先查标签,再查学习率

现象:训练日志里 loss 曲线像心跳一样震荡,几十个 epoch 过去精度还在原地踏步;或者某一步突然输出 NAN,模型权重随之报废。

原因分两类。一是数据问题,最常见的有标签文件为空、坐标越界、图片里根本没有裂缝但标签却写了目标;二是超参数问题,初始学习率太高或者 batch-size 太小,BN 层统计量在批次间来回横跳。遇到 NAN 还有一个隐蔽原因:PyTorch 和 numpy 版本不匹配,老版本 YOLOv5 代码对新版 numpy 兼容性差,推理时直接算崩。

解决:先写个小脚本统计整个数据集的标签文件,确认没有越界和空标签;然后把学习率调低 50%,batch-size 尽量大过 8;最后再看依赖版本,把 numpy 固定在稳定版本。如果标签是手工编辑过的,千万别靠肉眼检查,用程序把所有 txt 的值打印一遍,这一步成本最低,收益最直接。

5.2 细裂缝漏检、阴影误检:从标注框和背景样本两方面治

现象:模型对粗裂缝框得很准,但对细小裂缝完全没反应;反过来,对桥墩阴影、路面湿润反光框出大量假阳性,一下框十几个,看着像模像样,实际全是误检。

原因:细裂缝在 640 输入下只占几个像素,下采样后特征图保留不住细节;阴影误检则说明训练集里缺少“没有裂缝但有阴影”的负样本,模型只能从颜色深这一点硬猜。换句话说,模型成了黑匣子,判断依据是不是真裂缝,只能通过数据和测试反推。

解决:第一,把包含细裂缝的图片裁剪成 640 的小块再训练,相当于变相提高 imgsz;第二,增加背景负样本,把检测中误检的图片不添加任何标签直接放进训练集图片目录,大部分 YOLOv5 默认配置会把它们当作没有目标的图片参与训练,帮助模型学习“这张图里没有裂缝”的输出;第三,推理时把--conf-thres从 0.25 提到 0.4 到 0.5,牺牲少量召回保住展示效果,毕设答辩现场宁可漏检几个,也好过满屏红框。

5.3 显存不足、训练卡死与 Windows 进程崩溃

现象:训练开始不久就报CUDA out of memory;或训练脚本启动后卡在 DataLoader,日志一动不动;还有一种是跑着跑着 worker 进程直接退出。

原因:显存不足主要是--batch-size和--imgsz组合超出显存上限;卡住和进程退出在 Windows 上多数是--workers设置过高导致,PyTorch 在 Windows 下的多进程数据加载本来就比 Linux 脆弱,加上数据集路径里有中文,还可能触发编码异常。

解决:遇到CUDA out of memory先把 batch-size 折半,再不行就把 imgsz 降到 480,或者加--cache ram把图片缓存到内存,减少显存里解压图片的开销。遇到 DataLoader 卡死,就把--workers设为 0,强制单进程加载。项目路径里不要出现中文字符,目录名和文件名统一用英文,这个习惯能避开大量奇怪的编码问题。

另外,训练中断时不用从头再来。YOLOv5 会在runs/train/exp下保存last.pt,重新训练时把--weights指向last.pt,它会从断点继续。这是做毕设最需要的后悔药,别等翻车了才想起来保存中间权重。

5.4 样本太少和类别不均衡:几十张图怎么救

现象:自采数据只有几十张图,训练很快收敛,验证集 mAP 很高,但一到测试集就崩盘,典型的过拟合。

原因:标注样本量不够,模型把背景纹理也背下来了。加上裂缝目标细长,目标框占整图比例低,类别不均衡会让模型倾向预测背景,导致漏检。

解决:先使用公开裂缝数据集做预训练,再用自己的几十张图微调,这是最有效的方法;微调时使用数据增强,包括旋转、平移、亮度扰动,但注意不能对裂缝做随机裁剪,否则会把目标切碎。如果公开数据集也找不到,就至少保证每张图里都有裂缝目标,训练集中不含目标占比太重,然后把训练轮数降低并把学习率调低,减少模型记忆背景的可能。

6. 答辩前把模型收拾体面:mAP 验证、PR 曲线与结果导出技巧

6.1 用 val.py 算 mAP 并导出可视化结果

训练完成后,不要只在训练日志里看一个漂亮数字,要跑一遍验证脚本拿到标准指标:

python val.py --data data.yaml --weights runs/train/exp/weights/best.pt

它会在终端打印 Precision、Recall、mAP@0.5、mAP@0.5:0.95 四项指标,同时在runs/val/exp里生成 PR 曲线、混淆矩阵和测试图的预测示例。答辩前我会把best.pt和last.pt各验一次,两者差很多说明训练还没收敛,就把 epochs 加到 150 再跑一版,没必要舍不得时间。

真正给答辩加分的,是用测试集跑一批现场实拍图的检测结果。挑 6 到 8 张你之前没参与标注的图片,放进 source 目录执行 detect.py,把框出裂缝的结果图整理成一页 PPT。评委看到模型在自己没见过的图上还能准确定位,比任何指标都有说服力。如果推理时裂缝框总是断成几截,可以适当把置信度阈值降到 0.35,推理完成后用形态学后处理把相邻框合并,这是我做演示时常用的保留技巧。

最后说一个个人习惯:我当年做毕设时,总喜欢在最后一周反复换权重和数据集,结果答辩前夜发现最关键的权重文件忘了保存对应 epoch 版本,只能灰头土脸用旧权重。从那以后,每次训练都用统一格式记录日期、模型档位、imgsz、batch、epochs、mAP,再和权重文件一起打包。这种习惯比任何调参技巧都管用。希望你不用走我这条弯路,希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询