简介:一份基于Python与Yolov5实现的路面桥梁裂缝检测识别项目源代码与模型,面向具备一定深度学习基础的学生、研究人员及工程技术人员,可用于毕业设计、课程设计或快速构建检测原型。资源共49个文件,涵盖yaml配置、Python脚本、预训练模型及Dockerfile等,其中yaml用于模型结构与训练参数配置,py文件包含检测与训练调用逻辑,模型权重及示例图片便于直接验证效果,压缩包仅1.98MB,轻量易部署。已有98人浏览学习。项目经过编译验证,可直接运行,省去环境搭建与从零训练的时间;附带安装指南、使用手册和模型训练说明,帮助理解架构与二次开发。重点覆盖不同场景下裂缝形态、大小与位置识别,兼顾准确率与效率,适合作为高性价比的学习与落地参考。
1. 路面桥梁裂缝检测这个方向,为什么最终落在 Python + YOLOv5 上
土木结构物的表观病害检测,在本科和硕士毕业设计里一直是高频选题。原因很直接:混凝土桥墩、路面、隧道衬砌上的裂缝,靠人工巡检既慢又危险,而用摄像头采集图像后交给目标检测模型处理,恰好能把计算机视觉和工程安全两个方向串起来。基于 Python + YOLOv5 的路面桥梁裂缝检测识别项目,本质就是一套“图像输入 → 模型推理 → 框出裂缝位置和类别 → 输出坐标结果”的完整流程,交付物是一份能跑的源代码外加可复用的模型权重。
对这个方向感兴趣的人,多半是有三类诉求:一是毕业设计需要从头到尾讲清楚原理和实验;二是实验室或工程团队要快速搭一套裂缝巡检原型;三是想训练自己的裂缝数据集但不知道从哪下手。无论哪一种,YOLOv5 都是目前最稳妥的入口。它不像分割模型那样对标注精度要求苛刻,也不像更重的双阶段检测器那样吃显存,训练和部署都相对友好。下面从原理、环境、数据、训练、排错到部署验收,把这条路完整讲透。
2. 裂缝检测为什么选 YOLOv5:网络结构、推理链路与迁移学习
2.1 单阶段检测器如何定位一条裂缝
目标检测这个任务要回答两个问题:目标在哪,目标是什么。裂缝在图像里表现为细长的暗色纹理,背景是水泥砂浆、沥青或者混凝土表面,对比度往往很低,而且现场照片里经常有阴影、水渍、伸缩缝这些容易混淆的东西。YOLOv5 属于单阶段检测器,它把“找位置”和“判类别”合并成一次前向传播,图像被划分成多个网格单元,每个网格负责预测若干个候选框,再通过置信度和类别概率筛选出最终结果。
它能在裂缝场景立住,靠的是三个结构设计。骨干网络采用 CSPDarknet,把特征提取拆成两条通路,一部分走梯度流,一部分做跨阶段拼接,这样在参数量不大的情况下保住特征表达力。颈部用 PANet 做多尺度融合,底层高分辨率特征和顶层语义特征反复融合,让模型既能看清裂缝这种小尺度目标,又不丢失全局上下文。检测头在三个不同尺度的特征图上输出预测,分别对应大、中、小目标。裂缝在照片中往往只占几十个像素宽度,小目标预测分支是否有效,直接决定了检测召回率。
2.2 从图像到检测框的完整推理链路
一次推理的流程是这样走的:输入图像先做 letterbox 缩放,保持宽高比并填充到模型要求的尺寸,比如默认的 640×640;然后进入网络得到原始预测张量;最后经过 decode 和 NMS 后处理输出最终的框。很多人只关注模型本身,却忽略后处理参数对结果的影响,这其实是新手最容易翻车的地方。
conf-thres 是置信度阈值,低于这个值的框直接丢弃。裂缝检测里我一般会把它设在 0.25 到 0.35 之间,太低会放进来大量背景误检,太高又会漏掉浅裂缝。iou-thres 是 NMS 阶段判断两个框是否重叠的阈值,默认 0.45。裂缝框之间往往有大量重叠,如果这个值设得过高,一个裂缝会被拆成多个框,影响最后的坐标统计。这两个参数在训练后评估阶段一定要重新用验证集扫一遍,不能直接沿用 COCO 上的默认习惯。
2.3 为什么可以直接复用 COCO 预训练权重
刚接触目标检测的人常有一个疑问:我要检测裂缝,但 COCO 数据集里没有裂缝这一类,那 COCO 预训练权重还有意义吗?答案是意义很大。YOLOv5 的预训练权重在 ImageNet 和 COCO 上学到的是通用的纹理、边缘、形状特征,这些底层表征对裂缝这种暗纹理目标同样适用。迁移学习的做法是保留骨干网络的权重,只把最后一层类别数从 COCO 的 80 改成自己的类别数,重新初始化检测头,然后冻结或者小学习率微调骨干层。
这套毕业设计源码包里通常已经包含一个在通用数据集上预训练好的 yolov5s.pt 或者自定义裂缝权重,拿到手之后不要直接拿去检测所有现场图片,要先确认它的类别定义和你的场景是否匹配。如果你要检测的是横向裂缝、纵向裂缝、龟裂三类,而权重里只放了一类 crack,那输出框的类别名就对不上。检测识别项目里,“模型能不能用”和“模型适不适用你的业务定义”是两回事,这个边界必须在动手前想清楚。
3. 跑通环境与源码:conda 安装、依赖注入与最小推理
3.1 用 conda 创建独立的 Python 环境
Python 版本冲突是这类项目最常见的第一道坎。YOLOv5 官方要求 Python 3.8 以上,我自己习惯用 3.9。不要直接拿系统自带的 Python 裸跑,因为你机器上可能已经装过 TensorFlow、OpenCV 或者其他包,版本稍微不一致就容易出现兼容性问题。这里用 conda 隔离环境是成本最低的后悔药。
# 创建 python 3.9 独立环境 conda create -n yolov5 python=3.9 -y conda activate yolov5创建完成之后先确认 Python 版本和 pip 可用,再进入下一步安装 PyTorch。如果机器是 NVIDIA 显卡且显存不低于 4GB,建议安装 GPU 版 PyTorch;如果只有 CPU,也可以跑,只是训练速度会慢很多,验证功能没问题。
# 查看 Python 版本 python --version pip --version3.2 安装 PyTorch 与 YOLOv5 依赖
PyTorch 的安装必须用官方索引,否则容易装上 CPU 版或者版本不匹配的 CUDA 版。下面这段以 CUDA 11.8 为例,如果你的显卡驱动较新,也可以装 cu117 或 cu121 对应版本。
pip install torch==2.0.1 torchvision==0.15.2 --index-url https://download.pytorch.org/whl/cu118装完后不要急着跑训练,先进 Python 里验证一下 CUDA 是否可用。这一步只要几十秒,却能省掉后面几个小时的排查时间。经常有人 pip 安装成功但 torch.cuda.is_available() 返回 False,原因多半是驱动太旧或者装成了 CPU 版。
import torch print(torch.__version__) print(torch.cuda.is_available()) # 输出 True 才说明 GPU 版本生效确认 PyTorch 没问题后,进入 YOLOv5 源码目录安装其余依赖。requirements.txt 里包含了 opencv-python、pandas、matplotlib、seaborn、ultralytics 等一整套包,直接执行即可。如果网络环境不理想,可以把 pip 源切换成国内镜像。
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple3.3 用一张裂缝图片验证推理链路
源码和依赖都就绪后,不要急着训练,先用自带的权重跑一次推理。这样可以最快验证整个链路是否通畅——数据读入、模型加载、前向传播、后处理、画框存图,任何一环出错都会在这里暴露。
python detect.py --weights yolov5s.pt --source data/images/bus.jpg --conf-thres 0.25 --iou-thres 0.45运行结束后在 runs/detect/exp 目录下会生成标注好检测框的结果图。如果这一步能出框,说明你的环境已经具备继续训练和开发的能力;如果报错,九成是依赖缺失或权重路径不对。建议把报错信息复制到搜索引擎,直接搜最后一行的错误类型,比自己瞎猜定位快得多。
3.4 跑通阶段常见的三个报错
第一个是 ModuleNotFoundError,提示缺少某个模块,比如 pandas 或 seaborn。原因是 requirements.txt 没有装全,或者安装时被中断。解决方法是重新执行 pip install -r requirements.txt,检查输出里有没有 skipped 或 error 字样。
第二个是 OSError: [Errno 2] No such file or directory,通常出现在权重或配置文件路径写错。解决方法是先确认当前工作目录,用绝对路径引用 weights 和 data 配置,避免相对路径在不同终端下产生歧义。
第三个是 RuntimeError: CUDA out of memory。这个最让人头疼,因为它不一定是显存真的不够,可能是 batch size 太大或者推理时图像尺寸设得过高。缓解办法是把 batch-size 调小到 1 或 2,把 --imgsz 从 640 降到 512,再不行就临时换 CPU 推理验证代码逻辑,等优化完再回到 GPU。
4. 训练自己的裂缝数据集:标注、增强与小目标切图
4.1 数据集目录结构要在一开始就定好
YOLOv5 训练要求的数据目录有严格约定,很多人在标注完后才回头改目录,浪费时间还容易出错。标准结构是 images 和 labels 两个主目录,下面按 train、val 划分。所有 txt 标签文件名必须和对应图片名一致,标签内容每行是“类别id 归一化中心x 归一化中心y 归一化宽 归一化高”。
crack_dataset/ images/ train/ val/ labels/ train/ val/划分数据集时不要用随机切割,要按拍摄场景划分。也就是说,同一座桥、同一条路段的照片只能进 train 或只能进 val,否则模型会在验证集上“作弊”,mAP 虚高,实际部署就露馅。这个细节在毕业设计答辩时经常被评委追问,提前处理好会成为加分项。
4.2 用 LabelImg 标注并输出 YOLO 格式
LabelImg 是这类任务最常用的标注工具,它支持直接输出 YOLO 格式的 txt 文件。标注前先在设置里把默认保存格式改成 YOLO,否则默认输出 PASCAL VOC 的 xml,到时候还要多一步转换。标注时框要贴着裂缝轮廓,不要太松,尤其是裂缝两端的细微部分,这直接影响模型的边界回归精度。
标注完成后写一个脚本检查标签是否合法:标签里的坐标必须是 0 到 1 之间的浮点数,宽高不能为负,类别 id 不能超出 names 列表。一个非常隐蔽的问题是某些标注工具在空标注目标时仍然会生成一行全 0 的标签,这会让模型在训练时学习“全图都是目标”,导致预测框奇大无比。
import os # 扫描标签文件,检查非法坐标和空标签 label_dir = "crack_dataset/labels/train" for f in os.listdir(label_dir): if not f.endswith(".txt"): continue lines = open(os.path.join(label_dir, f)).read().strip().splitlines() for line in lines: parts = line.split() if len(parts) != 5: print(f"格式错误: {f} -> {line}") continue cls, x, y, w, h = parts x, y, w, h = map(float, [x, y, w, h]) if not (0 < x < 1 and 0 < y < 1 and w > 0 and h > 0): print(f"坐标非法: {f} -> {line}")这段脚本虽然简单,但能在训练前拦截大部分标注错误。标注质量比标注数量更重要,几百张干净的数据永远好过几千张充满噪声的数据。
4.3 裂缝场景的数据增强策略
YOLOv5 在训练时默认启用 mosaic、平移、缩放、HSV 扰动等增强手段,但默认超参是面向 COCO 通用目标设置的,直接用在裂缝上并不最优。裂缝具有方向任意性,桥梁腹板上的竖向裂缝和路面上的横向裂缝方向完全不同。默认 hyp 里 fliplr 是 0.5 即水平翻转,但 flipud 即垂直翻转默认是 0,对裂缝检测来说建议打开,因为相机角度变化后裂缝方向的翻转是很常见的现场情况。
hsv_h 和 hsv_s 这两个色相和饱和度扰动对裂缝作用有限,因为混凝土和沥青表面本身就是低饱和度的,真正影响大的是 hsv_v 亮度扰动。裂缝和背景的对比度受光照影响极大,阴影里的裂缝和阳光直射下的裂缝差异明显,把 hsv_v 适当调大有助于模型学习更鲁棒的特征。
4.4 小裂缝检测难,用滑窗切图缓解
路面裂缝在整体照片中经常是细长条,占比小,属于典型的小目标问题。直接把整张 1920×1080 的图像缩放到 640×640,裂缝可能只剩几个像素宽,特征几乎丢光。常见做法是训练前把大图切成 512×512 或 640×640 的滑窗块,相邻窗口之间保留约 20% 的重叠,避免裂缝被切在边缘。推理时对同一场景的若干滑窗分别检测,再把结果映射回原图坐标进行合并。
import cv2 # 滑窗切图:将大图切成 512x512 的块,重叠 128 像素 def slide_cut(img_path, save_prefix, win=512, stride=384): img = cv2.imread(img_path) h, w = img.shape[:2] idx = 0 for y in range(0, h - win + 1, stride): for x in range(0, w - win + 1, stride): crop = img[y:y + win, x:x + win] cv2.imwrite(f"{save_prefix}_{idx}.jpg", crop) idx += 1 # 补切边缘部分,防止裂缝正好落在窗口外 if (h - win) % stride != 0: cv2.imwrite(f"{save_prefix}_edge_bottom.jpg", img[h - win:h, 0:w]) if (w - win) % stride != 0: cv2.imwrite(f"{save_prefix}_edge_right.jpg", img[0:h, w - win:w])切图之后要同步转换标注框的坐标,这部分逻辑在代码里是最容易出错的。核心思路是:原图框的坐标减去切图窗口的左上角偏移,再换算成归一化坐标。曾经有人切完图没有改标注坐标,训练时模型学到的框位置全是错的,mAP 一直为 0,排查了很久才发现是坐标没跟着切。每次改完数据流程,先挑 20 张图可视化验证一遍标注框和图像是否对齐,再开始训练。
5. 训练与调参:train.py 最小命令、超参数与高频排查
5.1 从拿到源码包到跑起训练的最小命令
这是整个项目性价比最高的一步。进入 YOLOv5 根目录,先写一个 data.yaml 指定训练集和验证集路径、类别数和类别名,再执行 train.py。不要试图在一开始就把所有参数调到完美,第一轮训练的目的是验证数据链路是否通畅、损失是否下降。
# crack.yaml train: crack_dataset/images/train val: crack_dataset/images/val nc: 2 names: ['horizontal_crack', 'vertical_crack']python train.py --data crack.yaml --weights yolov5s.pt --epochs 100 --batch-size 8 --imgsz 640训练结束后结果保存在 runs/train/exp 目录下,包含 best.pt、last.pt、PR 曲线、混淆矩阵以及每轮的 loss 曲线。这里要注意:epochs 不是越大越好,要结合验证集 mAP 的变化来判断。如果训练到第 60 轮时 mAP 已经不再上升,后面 40 轮基本属于白跑,还增加了过拟合风险。best.pt 是根据验证集指标自动挑选的权重,正常流程里最后部署用的是 best.pt 而不是 last.pt。
5.2 超参数:哪些值得改,哪些属于玄学
YOLOv5 的超参数写在 data/hyps/hyp.scratch-low.yaml 里,训练时可以用 --hyp 指定。新手最容易犯的错误是看什么参数都像重要参数,结果一顿乱改后模型反而变差。根据我的实操经验,影响最大的三个是 mosaic、mixup 和 lr0。
mosaic 默认 1.0,它对小目标检测有显著提升,因为拼接图里目标尺度变化更大。但如果你训练过程里发现 loss 震荡剧烈,可以降到 0.8 试试。mixup 默认是 0,裂缝这类目标形态差异较小,不建议开太高,0.2 足够,开大了会让模型学到的特征变模糊。lr0 初始学习率默认 0.01,迁移学习场景下我一般调到 0.005,更稳,尤其是当你的数据集只有几百张时,学习率太大会让预训练权重被快速破坏。
fliplr 和 flipud 这两个翻转参数,前面提过,做路桥裂缝检测时建议打开 flipud。这是为数不多值得改的默认超参之一,因为多数项目默认为 0,而裂缝的方向在现实中是无约束的。
5.3 显存不足:低配置机器怎么把训练跑起来
很多同学的机器只有 4GB 或 6GB 显存,跑 batch-size 8 就会爆显存。不要急着换机器,先按下面这个顺序逐级降低资源占用:把 batch-size 改到 4,再改到 2;把 --imgsz 从 640 改到 512;换更小的模型,把 yolov5s 换成 yolov5n;开启 --amp 半精度训练。如果这样还爆,就把 --workers 设为 0,关闭数据预加载进程,减少额外的显存开销。
# 低显存配置下的训练示例 python train.py --data crack.yaml --weights yolov5n.pt --epochs 100 --batch-size 2 --imgsz 512 --amp这里存在一个平衡问题:imgsz 降得太低,裂缝这种小目标会丢失细节;batch-size 太低又会导致 BN 层统计不稳定。我的经验是优先换小模型,而不是一味降低图像尺寸。yolov5n 的参数量只有 yolov5s 的大约四分之一,检测速度更快,在裂缝这种前景不算复杂的任务里精度差距并不会太大。
5.4 训练看什么指标:别只盯着 loss 曲线
训练过程中终端每轮会输出 box_loss、obj_loss、cls_loss 和 mAP 指标。很多人只关心总 loss 有没有下降,但真正决定模型能不能用的是 mAP50 和 mAP50-95。如果 loss 一直在降但 mAP 不涨,先检查是不是验证集图片和训练集高度重合;如果 mAP 在某个 epoch 后突然大幅回落,说明学习率没有按期衰减导致震荡,调低 lr0 并增加 warmup 轮数。
训练结束后打开 runs/train/exp 里的 results.png,这是一张包含四个子图的综合曲线。如果 precision 高但 recall 低,说明模型倾向于只检测高置信度的目标,漏检多,应降低 conf-thres 或增加数据中裂缝的多样性;如果 recall 高但 precision 低,说明误检多,应检查标注是否把水渍、伸缩缝、阴影也当成裂缝标进去了。
5.5 常见问题排查:现象、原因、解决
现象一:训练正常结束但 mAP 为 0。原因通常是标注文件与图片不匹配,比如图片是 JPG 而标签文件名后缀写成了 jpg 大小写不一致,或者数据增强里把标签文件也做了翻转但坐标没同步。解决方法是先用上一章提供的脚本扫描标签,再画出 20 张增强后的训练图确认标注框位置正确。
现象二:预测框把整张图框住。原因是存在大量“裂缝占满整张图”的训练样本,比如特写照片里裂缝横贯全图,模型学到的是“这整块区域都是目标”。解决方法是删除这类样本或切图时把大裂缝切成小段,让目标尺度分布更均匀。
现象三:训练到一半 loss 变成 nan。原因是学习率过高或某张图片的分辨率异常导致梯度爆炸。解决方法是调低 lr0 到 0.001,同时检查数据里有没有损坏的图片文件,比如零字节图片或格式错误的 JPG。
现象四:训练集 loss 很低但验证集 mAP 上不去。这是过拟合的典型特征。解决方法按效果排序是:增加更多多样化数据、降低模型复杂度换 yolov5n、增加 mixup 与 mosaic 的增强力度、调低 epoch 并早停。
6. 从评估到部署:mAP 验证、批量推理与模型导出
6.1 用 val.py 验证训练结果,别靠肉眼
训练完成后,用验证集做一次系统评估。val.py 会输出 precision、recall、mAP50、mAP50-95,以及各类别的单独指标。这里有个容易被忽略的细节:部署时的图片尺寸和验证时的 imgsz 尽量保持一致。如果用 640 训练、640 验证,但部署时输入 1280 的大图,性能会受影响,因为模型没有见过更大尺度的特征分布。
python val.py --data crack.yaml --weights runs/train/exp/best.pt --imgsz 640 --conf-thres 0.25 --iou-thres 0.45保存好这份评估结果,它是你后续调参的基线。每次改超参或加数据后都重跑一次,对比 mAP 曲线,才能知道改动到底是正向还是负向。纯靠肉眼在不同测试图上对比检测效果,很容易被个别视觉效果好的图误导。
6.2 批量推理:对文件夹、视频和摄像头统一处理
detect.py 支持传入图片文件夹、视频文件和摄像头,这是把项目从离线演示推向实际使用场景的关键一步。批量检测时建议把 --project 参数改成有意义的目录名,并把 --name 设为当前模型的短描述,避免生成一堆 exp1、exp2 很难对应回实验结果。
python detect.py --weights runs/train/exp/best.pt --source test_images/ --conf-thres 0.3 --iou-thres 0.45 --project logs --name crack_run1 --save-txt加上 --save-txt 后,每张检测图会额外生成一个同名的 txt 文件,里面是检测框的坐标和置信度信息,方便后续做裂缝统计或坐标记录。这部分输出格式和训练标签格式一致,都是归一化坐标,如果后续要计算裂缝的实际长度,需要再结合标定信息换算成像素距离或者物理距离。
6.3 导出 ONNX 和 TensorRT 模型:部署到边缘设备的前提
训练好的 PyTorch 权重直接部署到 Jetson 或嵌入式设备上效率不高。常见做法是先用 export.py 导出成 ONNX,再在目标设备上转成 TensorRT 引擎。导出时要关注 opset 版本,裂缝检测项目通常不需要太高级的算子,opset 11 或 12 就够。
python export.py --weights runs/train/exp/best.pt --include onnx --opset 12导出后的 onnx 文件可以用 onnxruntime 在 CPU 上做快速推理验证,这个过程和 PyTorch 推理结果可能会有细微差异,主要来自上采样和填充方式的不同。如果发现导出后 mAP 明显下降,优先检查输入图像的预处理是否一致,包括 letterbox 的填充颜色和缩放方式。TensorRT 的优化收益很大,推理时间通常能比 PyTorch 快 3 到 5 倍,但转换过程对算子和动态尺寸支持有限制,第一版建议先固定输入尺寸 640×640,跑通后再考虑动态尺寸。
6.4 验证模型是否真的可用的一个小技巧
模型做完了,mAP 数字也不错,但到了现场照片上还是可能翻车。我习惯在部署前做一轮“盲测”:把训练集、验证集之外的现场原始照片按场景分类,对同一张图分别用训练时的 conf-thres 0.25、0.5、0.7 三档跑推理,导出预测结果并标记出所有 false positive。看这些误检集中在哪些部位,如果是伸缩缝和裂缝同时出现,说明训练数据里缺少这类负样本;如果是阴影误检,需要增加阴影下的正样本。这一步能让你对手里的模型边界有清晰认知——它擅长什么、怕什么,比一个漂亮的 mAP 数字更有实用价值。
用这套方法和流程,我自己前前后后做过市政路面和桥梁巡检两个场景的裂缝检测,最大的体会是:数据整理的规范和训练参数的克制,比花哨的模型改动能带来更稳定的效果提升。不要一开始就想着改网络结构,先把默认模型在干净数据上跑出可靠的基线,再逐步优化。希望这份经验能帮你少走一些弯路,祝顺利。
本文还有配套的精品资源,点击获取