简介面向毕业设计场景的PythonYOLOv5路面桥梁裂缝检测识别项目源码与模型专为计算机相关专业学生设计可作为毕业设计、课程设计或期末大作业也适合目标检测初学者动手实战。项目经导师指导并获评99分代码完整、结构清晰即使初学者也能顺利跑通完整覆盖数据准备、模型配置、训练与推理等关键环节。整个压缩包共85个文件体积仅1.6MB文件类型以Python源码(.py)、模型配置(.yaml)、Shell脚本(.sh)为主另含Dockerfile和示例图片便于跨环境部署和快速测试。源码目录与官方YOLOv5框架保持一致并提供权重下载脚本可快速准备预训练模型直接运行检测流程。已有80人浏览学习对于需要高效完成毕业设计与答辩的学生是一份高含金量、可直接复用的参考资料文件组织清晰查阅方便。1. 这套 PythonYOLOv5 裂缝检测毕设真正值钱的地方不在“跑通”路面桥梁裂缝检测是目标检测里少见的“技术门槛不高但工程坑极多”的选题。用 Python 和 YOLOv5 做裂缝识别本质上是两件事一是把官方仓库在本地跑通、用自己的数据集训出一个能用的模型二是把“能用”变成“毕业答辩能讲清楚”。很多同学带着“高分毕设”的预期拿到这类项目包最容易踩的坑是——模型也能跑、图也能出但一到提问环节就被问住数据怎么标定的mAP 是怎么算出来的为什么小裂缝检不出来所以这篇笔记不打算复述“下载源码→安装依赖→训练→出结果”这种二手流程而是按我自己的落地习惯把环境、数据、训练、避坑、推理到交付这条线完整拆一遍重点放在参数怎么设、失败时看什么、以及哪些地方是翻车重灾区。这套方案适合三类人毕设选了裂缝检测但还没动手的手里已经有一套能跑通的源码但想换自己的数据集重训一遍的以及打算把 YOLOv5 部署到边缘设备做实时巡检、先拿路面桥梁裂缝当试点的。文章里的命令和脚本我都按 YOLOv5 官方仓库的结构来写你拿到项目包后按名对照即可不需要改架构。2. 先把环境焊死Python 版本、CUDA 与 torch 匹配是第一个分水岭2.1 为什么裂缝检测项目对环境版本“洁癖”这么重YOLOv5 对运行环境的要求其实不苛刻苛刻的是版本组合。官方在 requirements.txt 里写的都是“最低版本”但现实中 torch、torchvision、CUDA 三者的对应关系是硬约束。以目前最常用的组合为例Ultralytics 在 YOLOv5 v6.0 之后默认使用 torch 1.7 以上而大多数毕设项目包里的权重文件是用 torch 1.8 或 1.10 训练的。如果你直接装最新版 torch 2.x大概率会遇到两类问题一是权重文件能加载但算子行为有细微差异导致实测精度与 README 里的数据对不上二是某些自定义模块比如 Detect 层的 anchor 解码在新版接口下报错或者静默改变输出形状。所以我的习惯是“先锁版本再建环境”。在创建虚拟环境时直接把 python 版本钉在 3.83.10不要用 3.11 以上因为 torch 对 3.11 的支持在部分老版本上不完整编译扩展时会出现奇奇怪怪的报错而做毕设的同学往往没耐心在这上面耗。conda create -n crack_yolov5 python3.8 -y conda activate crack_yolov5 pip install torch1.12.1 torchvision0.13.1 --index-url https://download.pytorch.org/whl/cu113这里解释一下参数python3.8 是兼容性最稳的选择opencv-python 和 numpy 在 3.8 下都有多年验证过的编译产物torch1.12.1 搭配 cu113 是 Pascal/Ampere 架构显卡上最常见的一套组合如果你是 RTX 30 系卡这个版本直接能用。如果你的机器是纯 CPU 环境那 torch 换成 CPU 版本即可但训练速度会非常感人一个 epoch 跑十几分钟是常态这种情况我建议直接在云 GPU 环境上跑训练。2.2 验证环境的三条命令别等训练到一半才发现模型在 CPU 上爬环境装完后不要急着跑训练。先用三行命令确认核心组件是否正常这能帮你把“环境问题”和“代码问题”隔离开。python -c import torch; print(torch.__version__, torch.cuda.is_available()) python -c from models.common import DetectMultiBackend; print(model import ok) python -c import cv2; print(cv2.__version__)第一行最关键。如果输出True说明 CUDA 可用如果输出False说明你装的是 CPU 版 torch后面所有训练都会慢到怀疑人生。这里要特别提醒torch.cuda.is_available()返回False不一定是没装对 GPU 版也可能是 CUDA 驱动版本太低——用nvidia-smi看一眼驱动版本如果低于 460那驱动要先升级。第三行 cv2 版本建议在 4.5 以上理由是用cv2.imread读中文路径图片时4.5 以下版本容易出现空指针这个坑在后面数据准备阶段会专门讲。3. 把数据集变成 YOLO 能吃的格式转换脚本与四个边界坑3.1 裂缝数据集的结构差异VOC 标注 vs YOLO txt绝大多数公开的路面裂缝数据集比如 CFD、CrackForest原始标注是 VOC 格式的 XML 文件而 YOLOv5 训练需要的是归一化的 txt 标注。这两种格式的核心差异在于坐标系的表达方式VOC 用左上角和右下角的绝对像素坐标YOLO 用中心点坐标加宽高的归一化比例。新手最常见的翻车现场是用标注工具时默认导出 VOC 格式然后直接把 XML 目录丢给 YOLOv5 训练训练能跑起来但 loss 不降。原因是 YOLOv5 的Dataset类只认labels/目录下的 txt 文件找不到 txt 就会静默跳过该图片的标注等于模型一直在学“背景”自然不收敛。下面这个脚本可以把 VOC 的 XML 批量转成 YOLO 的 txtimport xml.etree.ElementTree as ET import os def voc2yolo(xml_file, class_names, output_dir): tree ET.parse(xml_file) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.iter(object): cls obj.find(name).text if cls not in class_names: continue cls_id class_names.index(cls) box obj.find(bndbox) x_min int(box.find(xmin).text) y_min int(box.find(ymin).text) x_max int(box.find(xmax).text) y_max int(box.find(ymax).text) x_center ((x_min x_max) / 2) / img_w y_center ((y_min y_max) / 2) / img_h w (x_max - x_min) / img_w h (y_max - y_min) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) out_path os.path.join(output_dir, os.path.basename(xml_file).replace(.xml, .txt)) with open(out_path, w) as f: f.write(\n.join(lines)) if __name__ __main__: class_names [crack] os.makedirs(labels/train, exist_okTrue) for xml in os.listdir(annotations/train): voc2yolo(os.path.join(annotations/train, xml), class_names, labels/train)这个脚本的逻辑是逐条解析 XML 里的 object 节点取出真实像素坐标后做归一化。参数说明class_names 顺序必须与最终训练时的 data.yaml 保持一致否则类别索引错位模型输出会“认识裂缝但画在错误类别上”输出坐标保留了 6 位小数目的是让训练时标签读取不丢失精度。脚本里每一行对应一个目标框如果一张图里有多条裂缝并列这个循环就会追加多行YOLOv5 的 dataloader 会按行解析这个格式本身不需要排序。3.2 转换后必做的两步校验用可视化和统计拦住脏数据转换脚本跑完不算完。我见过太多人转换后直接开训最后 mAP 只有 0.3回头查数据发现一半的 txt 是空文件。空 txt 的成因通常是 XML 里嵌套结构不同有些标注工具导出的 polygon 是四点坐标你的脚本只读 bndbox。所以转换之后要跑两步校验。第一步是统计校验直接数 txt 文件里每行的坐标值是否都在 [0,1] 区间如果有大于 1 的坐标说明某张图的size/width标签和实际图片尺寸不一致这是拍照后裁剪图片但没同步更新 XML 导致的。第二步是可视化校验把检测框画回原图人眼看一遍import cv2 with open(labels/train/0001.txt) as f: boxes [line.strip().split() for line in f.readlines()] img cv2.imread(images/train/0001.jpg) h, w img.shape[:2] for box in boxes: _, x_c, y_c, bw, bh map(float, box) x1 int((x_c - bw / 2) * w) y1 int((y_c - bh / 2) * h) x2 int((x_c bw / 2) * w) y2 int((y_c bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.imwrite(check_0001.jpg, img)这段代码把 txt 里的归一化坐标还原成像素坐标画框。注意我特意用了cv2.imread和cv2.imwrite而不是 matplotlib原因是 matplotlib 显示图片时会做色彩通道转换裂缝本身是暗色纹理通道错乱后很难判断框是否贴边。画框后如果发现框的边界和裂缝纹理明显错位优先怀疑标注时的人为误差这种情况不值得重训直接手动修正 txt 更省时间。3.3 边界坑一裂缝长宽比极端导致的锚框失配路面裂缝和常规目标人、车最大的区别在于形状极不规则。一条横向裂缝可能宽 800 像素、高只有 20 像素长宽比达到 40:1。YOLOv5 默认的锚框是按 COCO 数据集聚类出来的偏向方形目标。如果你用默认锚框训裂缝会出现“小裂缝检不出来、大裂缝只框住一半”的情况。解决方案是在训练命令里开启自动锚框计算--noautoanchor别加让 YOLOv5 在训练启动前用 k-means 重新聚类你的标注框聚类结果会在训练日志里打印。如果你发现聚类出来的锚框长宽比超过 20属正常现象不要惊讶如果你用的是自己改过的模型文件记得把聚类结果回填到 yaml 里否则每次启动都要重新聚类。3.4 边界坑二数据划分时图片和标注没对齐训练集、验证集、测试集的划分是另一个隐形杀手。YOLOv5 的目录结构默认是 images/train、images/val 和 labels/train、labels/val 对应。很多人划分时只复制了 images忘了同步复制 labels或者用随机脚本分配图片但标签文件顺序没跟着打乱。验证明细的方法是数文件数find labels/train -name *.txt | wc -l和find images/train -name *.jpg | wc -l两边数量必须一致。数量对上了还不够要抽查文件名对应关系因为同一张图的 jpg 和 txt 文件名必须完全同名后缀除外任何错位都会导致训练日志出现Image not found警告而 YOLOv5 对这个警告的处理是跳过该图片你不看日志根本发现不了。4. 训练与调参从官方权重热启动不要从零开始4.1 用 COCO 预训练权重做迁移学习少走十天弯路裂缝检测的训练策略和通用目标检测不太一样。如果你完全从零训练即随机初始化权重那么在小数据集通常只有几千张上至少要 300 个 epoch 才能收敛稳定而硕士毕设的时间往往等不起。正确做法是用 COCO 预训练权重热启动也就是冻结 backbone 前几层只训练 Detect 头。这也是 YOLOv5 官方推荐的迁移学习路径命令如下python train.py --data data/crack.yaml --weights yolov5s.pt --epochs 150 --batch-size 16 --img 640 --device 0 --workers 4参数说明--weights yolov5s.pt会下载 COCO 预训练权重你的项目包如果自带 yolov5s.pt 就直接指定本地路径--epochs 150是裂缝检测的合理起点不要小于 100因为裂缝的纹理特征需要较多 epoch 才能区分出“真裂缝”和“路面阴影”--batch-size 16对应 8GB 显存的下限如果你只有 6GB 显存降到 8同时把--workers降到 2否则数据加载会成为瓶颈。--img 640是训练分辨率这是速度和精度的平衡点裂缝检测不建议用 320因为细小裂缝在 320 分辨率下只有几个像素特征直接丢失。4.2 修改 data.yaml 的三个关键字段类别、路径、和实参变化训练前必须改 data.yaml 文件这是 YOLOv5 读取数据集的唯一入口。最基本的三个字段是train、val和nc类别数量。裂缝检测一般是单类nc: 1但如果你的数据集里区分了横向裂缝和纵向裂缝这里要写 2并且 class_names 也要同步改。这里有一个容易出错的地方data.yaml 里的路径可以是绝对路径也可以是相对路径相对路径是相对于执行train.py时的当前工作目录不是相对于 yaml 文件所在目录。所以如果你把数据放在项目根目录之外建议直接写绝对路径避免在服务器上换了个启动目录就找不到数据。另外一个值得调的是--hyp超参数文件。YOLOv5 默认的 hyp.scratch-low.yaml 偏向自然图像对裂缝这种低对比度纹理目标可以把hsv_h、hsv_s、hsv_v三个色彩增强参数调低因为裂缝的颜色基本是灰黑色过度的色彩扰动会让模型学到颜色相关性而不是纹理相关性。具体做法是复制一份 hyp 文件把hsv_h: 0.015改成hsv_h: 0.005这是我在裂缝场景下的常用配置既能保留几何增强的抗过拟合效果又不破坏灰度纹理的稳定性。4.3 训练过程中的四个关键信号loss、P/R、mAP 和权重保存节奏训练启动后不要只是盯着 loss 曲线。YOLOv5 的日志里有两列 lossbox_loss和cls_loss。裂缝检测的cls_loss应该迅速降到 0.01 以下因为只有单类分类任务很简单如果cls_loss在 50 个 epoch 后还在 0.05 以上徘徊先怀疑数据问题不要急着调参。另一个关键信号是P精确率和R召回率在验证集上的表现。裂缝检测的特殊性在于精确率高但召回率高才是好模型。如果 P 高 R 低说明模型“保守”宁可不检也不误检如果 R 高 P 低说明模型“激进”把路面纹理都当成裂缝。坦率地说工业场景更看重召回率因为漏检一条裂缝可能造成安全隐患但毕设答辩专家会追问“漏检率”所以你要在训练日志里找 P 和 R 的平衡点通常看 mAP0.5 在 0.85 以上就算合格。权重保存节奏也很重要。YOLOv5 默认只保存last.pt和best.ptbest.pt是按 mAP 最高的 epoch 保存的。裂缝检测建议再加一个--save-period 10参数每 10 个 epoch 保存一次检查点这样即使最后 mAP 因为过拟合下滑你还能回到中间的权重做推理。训练中断后用--resume last.pt继续训练这个参数很实用但注意 resume 时不要改--img否则数据集缓存会重新生成白白浪费时间。5. 避坑排查裂缝检测训练翻车的五个真实案例5.1 训练 Loss 正常但 mAP 为 0标签名与类别索引错位现象是训练日志里 loss 稳步下降P、R 曲线也都正常但验证集 mAP 始终为 0。原因是 data.yaml 里的names顺序和转换脚本里的class_names不一致比如转换脚本里 crack 是 0data.yaml 里 crack 却是 1导致模型输出的类别预测永远对不上标签。解决方法是打印预测结果看类别 index——在 val.py 里加一行print(det[:, 5])或者更轻量的是直接对比两个文件里的 names 字符串。这种情况最容易发生在你从别人项目里拿来数据集、只改了数据路径没检查类别映射的时候。5.2 小裂缝完全检不出来分辨率与锚框的双重瓶颈现象是验证集里大裂缝框得很准宽度小于 20 像素的细小裂缝直接漏检。原因有两层一是训练分辨率 640 下小裂缝的下采样特征图只有 20×20目标信号被背景噪声淹没二是锚框聚类对小目标分配不足。解决手段优先级先试--img 1280训练显存不够就用--batch-size 8换如果显存实在吃紧修改模型配置文件中的 anchors 数量把默认的 9 组改为 12 组增加对小目标的覆盖。注意改 anchors 后必须重新聚类直接在 yaml 里手写锚框值通常是徒劳的。5.3 训练到一半显存溢出多卡或半精度参数设置不当现象是 8GB 显存训练到 80 个 epoch 后 OOM。原因是 YOLOv5 默认会缓存整批图像做数据增强加上 AMP自动混合精度在部分显卡上会额外占用显存。解决方法是尽量不开--cache参数把--batch-size调小如果调小后速度太慢开启--amp但把--workers设为 0取消数据预加载显存峰值能降 1GB 左右。还有一点容易忽略如果屏幕开着 PyTorchTensorBoard 或者其他监控工具它们也会吃掉显存训练时关掉浏览器能救急。5.4 验证集 mAP 高但实拍视频效果差数据分布不一致现象是训练集和验证集都来自同一批公开数据集mAP0.5 达到 0.9但拿手机在桥底拍一段视频推理结果疯狂漏检。原因是公开数据集里的裂缝大多清晰、完整、光照均匀而实拍视频里有阴影、水渍、伸缩缝、钢筋裸露。解决方法是把 20% 的实拍图加入训练集另外调低置信度阈值从默认的 0.25 降到 0.15让模型“更愿意”检出来再用 NMS 的 IoU 阈值 0.45 压掉重叠框。实拍数据至少要 200 张起不要只加 50 张就期待质变。5.5 Detect 层输出有大量重复框NMS 阈值和类别置信度的配合现象是一张复杂背景图上同一个位置堆了五六个框框大小略有不同。原因是 NMS 的 IoU 阈值太低比如 0.3同一目标的不同尺度预测框无法被合并或置信度阈值太高导致多个低分框残留。解决方法是把--conf-thres 0.15 --iou-thres 0.5组合使用这个组合对裂缝这类细长目标比较友好。另外要检查是不是故意关闭了 NMS——YOLOv5 的 detect.py 在导出 TorchScript 时有个参数会隐藏 NMS 层如果你在部署时用了自定义推理脚本务必保持 NMS 开启。6. 用训练好的模型做推理验证从单张图到视频流的部署检查训练跑完后你的模型能不能交付不取决于 loss 曲线多漂亮取决于推理脚本能不能稳定出结果。官方仓库自带的 detect.py 是最稳妥的起点python detect.py --weights best.pt --source test_images/ --conf-thres 0.25 --iou-thres 0.45 --imgsz 640 --save-txt --save-conf这里--source可以接图片目录、单张图片、视频文件也可以接摄像头 ID比如 0。--save-txt会额外输出标注文件格式和训练标签一致方便你量化检测框的重合度--save-conf会同时写出置信度。我建议在交付前把--conf-thres从 0.25 调到 0.15 跑一遍全量测试图对比两次输出的框数量差异如果框数量暴涨说明模型在低置信度下有很多假阳性这时候应该看一下是不是训练数据里负样本太少而不是硬调阈值。如果项目需要接入实时视频流建议用下面的脚本做循环推理import cv2 import torch model torch.hub.load(ultralytics/yolov5, custom, pathbest.pt, force_reloadFalse) cap cv2.VideoCapture(bridge.mp4) while True: ret, frame cap.read() if not ret: break results model(frame, size640, conf_thres0.2, iou_thres0.5) frame results.render()[0] cv2.imshow(crack_detection, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这个脚本用torch.hub.load加载本地权重results.render()直接在原图画框并返回。注意size参数要和训练时的--img保持一致否则目标缩放比例不同导致检测精度下降。在 CPU 上跑这个推理每帧大约 300 到 500 毫秒只能达到演示级别如果想达到实时需要 GPU 或者把模型导出为 TensorRT 引擎。导出命令是python export.py --weights best.pt --include engine --device 0导出后速度能提升 2 到 3 倍这是毕设演示里一个不错的加分项。另外我自己的习惯是推理验证阶段一定要保留“坏例”。找一些远处带水渍的桥墩、晚上打光不均的路面把漏检误检的截图单独归档毕设论文的“失败案例分析”章节靠的就是这些素材它们比正面效果图更能体现你对问题的理解深度。常见做法是把这些坏例做成一张对比表标题写上“不同光照与纹理背景下的检出现状”答辩时放在 PPT 倒数第二页比空洞的“本系统鲁棒性良好”有说服力得多。回到标题本身这套 PythonYOLOv5 裂缝检测项目源码和模型固然是基础交付物但拿高分的决定性因素是你有没有把数据清洗、锚框适配、阈值平衡这些细节讲透。把上面这些参数和避坑经验走一遍哪怕最终精度没有冲到 0.95你也能在答辩时对每一个检测框的来历给出合理解释这比任何花哨的网络结构改动都更值得做。希望帮到你。本文还有配套的精品资源点击获取