
简介面向计算机相关专业学生的PythonYoloV5路面桥梁裂缝检测识别项目提供毕业设计级完整源代码、预训练模型及配套配置适合正在完成课程设计、期末大作业或希望积累目标检测实战经验的学习者。项目由导师指导完成评审得分99分代码结构完整、可直接运行即使基础薄弱也能按照现有工程完成环境配置和推理调试。压缩包共85个文件组成上以Python源码.py、YAML配置文件、模型下载/训练Shell脚本、测试图像以及Dockerfile为主其中Python代码对应检测入口、模型定义与工具函数YAML文件用于模型超参和数据集配置Shell脚本可快速获取预训练权重方便复现实验。整体体积仅1.6MB模块按检测入口、模型定义、数据配置、工具函数等划分明确结构紧凑、便于局部修改和二次开发。当前已有80人参与学习从数据准备、模型推理到结果可视化均有覆盖可作为毕业设计、课程设计或期末大作业的高分参考实现。1. 为什么拿 PythonYolov5 做路面桥梁裂缝检测先把毕设的底牌看清毕业设计如果锁定“PythonYolov5 路面桥梁裂缝检测识别”这个组合核心优势在于Yolov5 有相当成熟的训练和推理闭环源代码管理、模型导出都有现成路径不存在“造轮子”导致的失控风险而路面和桥梁裂缝这类目标背景干扰少、纹理特征集中是目标检测领域少有的容易出效果、展示性也强的场景。你把它做成一个能上传图片就输出裂缝框的小系统评委一眼就能看懂你的工作内容和工程能力。整条链路按“原理→环境→数据→训练→踩坑→推理验证”的次序展开下面一步步说清楚。2. 裂缝检测不是图像分类Yolov5 目标检测原理与选题理由2.1 分类、分割与检测的边界裂缝任务为什么选检测而不是分割做裂缝识别常被问“为什么不用语义分割”。这个问题背后其实是任务边界没分清分割要逐像素给裂缝轮廓理论上能给出更精细的裂缝形态但代价也很直接——标注成本翻好几倍得用多边形或多段线描线训练难度也更高稍微欠拟合就出现大面积漏检。而目标检测只需要一个矩形框把裂缝主体框住标注工具用 LabelImg 就能完成训练完输出的是“在哪里、什么类别、置信度多少”对毕设答辩来说信息量完全足够。任务类型输出形式标注成本毕设展示性图像分类整图标签最低只能答“有无裂缝”目标检测矩形框 坐标 置信度中直观且可量化语义分割像素级 mask最高视觉精细但训练难我一般会建议选目标检测的另一个理由是可解释性。分割结果是一张 mask 图评委很难直观判断“为什么这里算裂缝”检测框则自带坐标和置信度能清楚展示模型关注的位置。桥梁裂缝通常是细长的线条矩形框在视觉上会框住裂缝的延伸范围也能方便地统计裂缝数量或密度分布。对毕设而言检测方案在“效果可视化”与“工程量可控”之间是最均衡的。还有一类方案是图像分类但那只能回答“这图有没有裂缝”无法回答“裂缝在哪”在桥梁检测里基本不够用。所以最终选择 Yolov5 目标检测路线不是因为分割做不到而是因为检测在毕设的交付周期内能稳定出好结果。先想明白这一点后面所有流程才有依据。2.2 Yolov5 网络结构里的三个关键件Backbone、Neck、HeadYolov5 的网络结构图在网上很好找但真正决定裂缝检测效果的只有三个部分。Backbone 用 CSPDarknet 做特征提取连续卷积和下采样把输入图片逐渐抽象成高层语义特征Neck 用 PANet 结构把高层语义和底层纹理做多尺度融合让网络同时保留“裂缝是细线”的空间细节和“这是桥面还是路面”的上下文Head 则是三个不同尺度的检测头分别负责小目标、中目标和大目标的框回归与分类。对路面桥梁裂缝来说最麻烦的其实是细小裂缝。如果裂缝宽度只有几个像素经过多次下采样后在高层特征图上可能只剩一两个像素的响应。好在 Yolov5 的三个检测头里大尺寸特征图那一路就是专门用来召回小目标的。这也是为什么训练时--img 640甚至--img 1280会比小分辨率好很多分辨率上去了细小裂缝占的像素比例才够高。后处理也是 Yolov5 的一个重要环节。网络输出的是大量冗余候选框需要经过置信度阈值过滤和 NMS非极大值抑制去重。我调试时会特别关注 NMS 的 IoU 阈值默认 0.45在裂缝密集区域容易出现两个框互相压制这时候把阈值调到 0.3或者遇到裂缝边缘不完整时调高到 0.5要根据实际效果权衡。这个参数直接决定最终画出来的框是干净还是糊成一片。2.3 数据标注格式YOLO txt 格式与 COCO json 之间的坑复现这个项目时遇到的第一道坎往往是数据集格式不匹配。网上公开的路面裂缝数据集不少是 COCO 格式标注存成 json而 Yolov5 训练要的是每个图片对应一个同名 txt 文件每行是class x_center y_center width height全部归一化到 0~1。换算不复杂但有几个细节容易翻车。import os import json def coco_json_to_yolo_txt(json_path, img_dir, out_dir): with open(json_path, r, encodingutf-8) as f: coco json.load(f) # 建立 image_id 到图片信息的映射避免重复读图 img_map {img[id]: img for img in coco[images]} if not os.path.exists(out_dir): os.makedirs(out_dir) for ann in coco[annotations]: img img_map[ann[image_id]] # 注意宽高必须取 json 里记录的原始值不要自己重新读图 w, h img[width], img[height] # COCO 的 bbox 是 [x, y, width, height]左上角为原点 x, y, bw, bh ann[bbox] x_center (x bw / 2.0) / w y_center (y bh / 2.0) / h bw_norm bw / w bh_norm bh / h # 类别 id 从 0 开始COCO 数据集如果从 1 开始要减 1 cls_id ann[category_id] - 1 txt_path os.path.join(out_dir, os.path.splitext(img[file_name])[0] .txt) with open(txt_path, a, encodingutf-8) as f: f.write(f{cls_id} {x_center:.6f} {y_center:.6f} {bw_norm:.6f} {bh_norm:.6f}\n) # 用法示例把 COCO 标注转成 YOLO 格式 coco_json_to_yolo_txt(annotations.json, images, labels)这段代码的关键第一是拿到图片的宽高后直接使用 json 里记录的原始值而不是自己重新读图第二是保存归一化坐标时保留 6 位小数如果只保留到 2 位小裂缝的框会抖动得很明显第三是一个图片有多条标注时用追加模式写文件不要覆盖前一条。如果你重复运行这段脚本记得先清空 out_dir否则同一个文件的标注会重复追加。如果你用的是 LabelImg它默认生成的也是 YOLO txt 格式但类别名称需要预先在classes.txt里定义好。这里还有个小坑LabelImg 的 class id 从 0 开始和 Yolov5 一致但有些标注工具后台从 1 开始转的时候一定要检查一遍否则类别错位会让训练完全跑偏。3. 从零跑通环境Python 安装、Yolov5 克隆与数据集目录组织3.1 Python 与 PyTorch 安装先定 CUDA 再装框架不少人在 Python 安装教程这一步就卡住了。我的建议是先把 CUDA 定下来再装 PyTorch最后装 Yolov5 的依赖。Python 版本建议选 3.8~3.11不要一上来就用 3.12太新的版本会让部分依赖在编译环节出问题。装好 Python 后建一个虚拟环境把 Yolov5 的依赖隔离进去后面换项目不至于互相污染。确定 GPU 环境时在命令行执行nvidia-smi能看到驱动支持的 CUDA 版本然后按这个版本来装 PyTorch。比如驱动支持 CUDA 11.8就用pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118如果只是 CPU 机器直接pip install torch torchvision也能跑但训练速度会让人失去耐心我建议至少有一块入门级 GPU哪怕 4G 显存也比 CPU 强。装完以后用一条命令验证环境python -c import torch; print(torch.__version__, torch.cuda.is_available())看到True说明 CUDA 可用后面训练才会走 GPU。这里还有一个容易忽略的点如果torch.cuda.is_available()返回 False大概率是 PyTorch 版本和驱动不匹配或者装成了 CPU 版重新按 CUDA 版本装一遍即可。3.2 获取 Yolov5 代码库与预训练模型Yolov5 的代码结构相当简练train.py、detect.py、models、data 一目了然。我不建议自己重新实现一个检测框架直接 clone 官方仓库是最稳妥的源代码管理上也最透明出了问题一搜就是成堆的解答。常见做法是git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txtrequirements.txt 里的依赖以 numpy、opencv-python、matplotlib、pyyaml、tqdm 为主。装的时候如果遇到 opencv 版本冲突把 requirements.txt 里的 opencv-python 改成opencv-python-headless再装可以省掉一堆 GUI 库的麻烦。预训练权重不需要手动满网找第一次运行 train.py 或 detect.py 时脚本会根据--weights指定的名字自动下载比如 yolov5s.pt。下载慢就自己想办法放到位放到当前目录即可脚本会在当前目录查找。3.3 组织数据集目录images 与 labels 的一一对应关系数据目录组织是老生常谈但翻车率最高。Yolov5 训练时读的是--data指定的 yaml 文件里的train和val路径它会在这些路径下找同名图片和同名 txt。我习惯把目录建成这样datasets/crack/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── crack.yaml这里最容易踩的坑图片是 001.jpg 时标注必须是 001.txt前缀完全一致扩展名无所谓。还有train 和 val 两个目录里千万不要有同名的图片否则验证时会串数据mAP 虚高。另外如果某个 txt 文件是空的训练时会把这张图当成背景如果你的裂缝图没有标注模型就学不到这条裂缝还会给背景类制造噪声。我还会在训练前写个小脚本检查标注和图片是否一一对应。把下面的代码存成 check_data.py 跑一遍能快速定位问题文件import os for split in [train, val]: img_dir fimages/{split} lab_dir flabels/{split} imgs {os.path.splitext(f)[0] for f in os.listdir(img_dir)} labs {os.path.splitext(f)[0] for f in os.listdir(lab_dir)} print(split, 缺少标注的图片:, sorted(imgs - labs)[:5]) print(split, 空标注文件数:, sum(1 for f in os.listdir(lab_dir) if os.path.getsize(os.path.join(lab_dir, f)) 0))这段脚本的输出里如果“缺少标注的图片”不为空说明有图片没有对应的 txt如果“空标注文件数”不为零说明存在背景图或漏标。这两种情况都要先处理再训练否则后面调参没有任何意义。数据切分我一般按 7:2:1 随机切但切的时候避免同一座桥或同一条路的连续帧同时落到训练集和验证集否则验证分数虚高。4. 训练自己的裂缝模型yolov5 超参数、训练命令与结果评估4.1 数据集配置文件先写 crack.yaml训练入口是 train.py但它不直接认文件夹而是要一个 yaml 配置文件。这个文件告诉 Yolov5 数据集在哪、有几类、类名是什么。裂缝检测一般只有一个类别crack配置文件内容如下# datasets/crack/crack.yaml path: datasets/crack # 数据集根目录相对于 yolov5 根目录 train: images/train val: images/val nc: 1 names: [crack]这里有几个细节。path字段在 Yolov5 7.0 以后是必需的它相当于一个公共前缀下面的train和val都相对于它来写。nc和names必须一致类别顺序决定了训练时 class id 的映射不能随意改动。如果你想把“无裂缝”也作为一类那nc设为 2names写成[background, crack]但通常不需要显式建模背景Yolov5 会把没有目标的图片当作负样本处理。4.2 train.py 关键参数epoch、batch-size、img-size、weights最基本的训练命令只需要一行python train.py \ --data datasets/crack/crack.yaml \ --weights yolov5s.pt \ --epochs 100 \ --batch-size 16 \ --img 640 \ --device 0参数说明--weights加载预训练权重。yolov5s.pt 是在 COCO 上预训练的小模型导入后可以把 Backbone 里学到的通用特征迁移到裂缝检测上比从零训练收敛快很多。这里也回答了“为什么要用源代码模型”这个问题模型不只是最终交付物更是训练的起点。--epochs单类目标 100 个 epoch 基本够用如果数据量不足 500 张50 个 epoch 也可能收敛。关键看验证集 mAP 是否还在上升。--batch-size受显存限制。16 在 8G 显存下跑 640 分辨率比较稳显存不够就降到 8 或 4。--img训练尺度。裂缝是小目标起步建议 640显卡扛得住就上 1280细小裂缝的召回会有肉眼可见的改善。训练过程中会自动生成runs/train/exp目录每个 epoch 的权重都存下来最终模型在exp/weights/best.pt。训练完我一般会紧接着跑一条验证命令python val.py --data datasets/crack/crack.yaml --weights runs/train/exp/weights/best.pt --img 640val.py 会输出每个类别的 precision、recall、mAP50、mAP50-95。对裂缝这类目标mAP50 比 mAP50-95 更容易好看答辩时可以两个都提但心里要清楚 mAP50-95 对框定位精度的要求更高。4.3 超参数调节yolov5 超参数文件里真正值得动的三个yolov5 超参数一般写在data/hyps/hyp.scratch.yaml里新手建议从默认值开始不要一上来就大改。真正值得调的我一般看三个lr0初始学习率、mosaic数据增强、fl_gamma焦点损失 gamma。学习率默认 0.01 在迁移训练时往往偏大裂缝数据集如果只有几百张建议调到 0.005 甚至 0.001否则 loss 在最开始几个 epoch 会震荡得很厉害。mosaic把四张图拼成一张能让小目标更鲁棒但如果你的裂缝样本本身密集mosaic 会让框与框之间互相重叠、标注混乱这种情况关掉反而更好。还有一个容易被忽略的参数是--patience它配合早停机制使用验证集 mAP 连续多轮不提升训练就提前终止。我一般设为 30不至于在无效训练上浪费电费。遇到 loss 曲线很漂亮但验证 mAP 上不去的“玄学”情况第一步不是加数据而是检查验证集里有没有和训练集重叠的图片这个问题比超参数更能解释奇怪的结果。4.4 训练过程监控从 loss 曲线到混淆矩阵训练跑起来以后不要只看终端打印。Yolov5 会在 runs/train/exp 下生成results.png里面有 Box_Loss、Cls_Loss、mAP 曲线这是判断训练状态的第一手资料。如果 loss 在降但验证集 recall 一直很低说明很多裂缝没有被检出来。这时翻出confusion_matrix.png看背景类是不是被大量预测为裂缝如果是说明假阳性太多需要提高置信度阈值或增加负样本。我也会在训练结束后打开val_batch0_pred.jpg这种可视化文件Yolov5 会把预测框画在原图上。真正用来答辩的展示图往往是从这一批可视化里挑出来的。但要注意一个“自我欺骗”模型经过阈值过滤后可视化结果通常看着都不错真正反映水平的是整个验证集的 mAP所以答辩 PPT 上贴成功图的同时最好也拿出一张漏检图分析一下原因反而显得工作更扎实。5. 裂缝检测避坑指南从数据标注到训练推理的五个常见问题这里把跑这个项目最常见的翻车现场列出来每一条都是我实际调试时遇到过的。5.1 现象训练 loss 一直不掉在初始值附近震荡很多人会在第一个 epoch 结束时发现 Box_Loss 高得离谱。原因往往是标注格式错了比如把中心点坐标写成了左上角坐标或者归一化时用了像素值而不是比例。Yolov5 对非法坐标通常不会直接报错而是把 loss 计算成极大值表现出来就是 loss 曲线完全不动。解决的办法是先随机抽查 3~5 个标注 txt把坐标反算回像素坐标画框对照原图看一眼框是不是贴住了裂缝。另外预训练权重没加载成功时日志里会有警告这等于从零开始训练loss 会明显偏高也要先排除。5.2 现象细小裂缝完全检不到recall 接近 0路面桥梁裂缝的宽度往往只有几个像素训练时统一缩放到 640很多裂缝在输入图上已经不足 4 像素宽。原因不是模型能力不够而是目标太小特征在下采样过程中丢掉了。解决思路有几个一是把--img提到 1280让目标在图上变大二是在数据增强时关闭mosaic和mixup因为它们会让小目标更模糊三是选模型时用 yolov5s 而不是 yolov5nnano 版参数量小对极端小目标的拟合能力偏弱。我实际跑下来img 从 640 升到 1280细小裂缝的 recall 能提升 10 个点以上代价是训练时间大约翻倍。5.3 现象GPU 显存溢出训练中断显存溢出时最先要看的是--batch-size但很多人会忽略--img的影响。分辨率从 640 升到 1280显存占用是平方级增长的batch size 减一半都不一定补得回来。还要注意不要习惯性开启--cache这个参数会把图片预加载进内存或显存对小显存环境更不友好。显存实在不够时把 batch size 降到 4同时加--accumulate 4让梯度累积 4 步再更新等效 batch size 还是 16但显存压力小得多。另外--workers也不要设太大数据加载线程过多会把 CPU 内存打满很多人把“内存不足”误判成显存问题。5.4 现象训练集 mAP 很高验证集 mAP 低很多这是过拟合的典型特征。裂缝数据集如果只有两三百张图模型很容易把训练集里的背景细节背下来。解决思路按性价比排序先检查 train 和 val 是否有图片重叠然后增加数据增强比如随机旋转和 HSV 扰动再考虑从 yolov5s 换到 yolov5n 减小模型容量最后才是加数据。我还见过一种情况验证集里某些图是从训练视频里连续抽帧出来的相邻帧几乎一样这也会让人误以为模型很好反过来验证集和训练集场景差异太大分数又会虚低。所以数据切分时最好按“桥面/路面”这种场景来划分而不是完全随机。5.5 现象推理时框偏移明显置信度极低训练没问题但用 detect.py 推理时发现框的位置不对。最常见的原因是推理时的--img分辨率和训练时不一致。训练用了 1280推理用 640模型看到的特征尺度完全不同输出自然不可靠。解决办法是让推理分辨率和训练分辨率接近最好是同一个值且保持 32 的倍数。另一个原因是图片里裂缝太多NMS 后互相压制可以打开--agnostic-nms对单类模型来说这个参数会减少误删。还有一个容易忽略的点手机拍摄的图片 Exif 里带旋转信息OpenCV 读图不会自动纠正方向框就会整体偏 90 度或 180 度需要在读图后根据 Exif 先旋转再做推理。6. 让模型真正用起来detect.py 推理、性能指标与量化部署方向训练完拿到 best.pt 只是第一步毕设要演示还得把它接到新的输入上做推理。Yolov5 的 detect.py 是最直接的入口python detect.py \ --weights runs/train/exp/weights/best.pt \ --source data/images --img 640 \ --conf 0.25 --iou 0.45 \ --save-txt --save-conf这条命令会遍历data/images下的图片在runs/detect/exp下生成带框图片、txt 结果文件和置信度。--conf是置信度阈值裂缝检测一般设 0.25 比较合适低于这个值会漏掉细小裂缝高于这个值则容易漏检--save-conf会在 txt 里输出每个框的置信度恰好可以拿来统计裂缝数量或计算框的面积占比作为裂缝严重程度的量化指标去展示。再往后走一步就是模型导出。官方代码库里的 export.py 可以导出 ONNX 或 TensorRT 引擎。如果毕设里想强调工程能力我建议至少导出 ONNX然后用 ONNX Runtime 写一个几十行的推理脚本彻底脱离 Yolov5 的 Python 依赖做成一个 web 接口。我平时还会用 export.py 导出成 TensorRT 的 .engine 文件在 NVIDIA 显卡上把推理延迟压到几十毫秒。像 RK3568 这类 ARM 板卡上跑 Yolov5一般也是先导出 ONNX再转成 rknn 模型量化到 INT8 后可以实时处理视频流这一步在边缘计算相关的毕设方向里是很加分的。最后说一个我自己的教训最早做裂缝检测时总以为“模型精度高等于答辩稳”于是把所有精力都花在刷 mAP 上忽略了推理链路。后来发现评委真正感兴趣的是你能不能输入一张图立刻输出一个带框带坐标带置信度的结果甚至是一个实时视频的检测窗口。所以后来的习惯是训练大约花 80% 时间剩下 20% 一定留给导出和推理链路的打通。模型精度决定你分数的下限而“能不能用起来、能不能演示”往往决定分数的上限。把数据切分做对、标注格式查一遍、训练参数选稳再配上完整的推理可视化链路这个 PythonYolov5 的路面桥梁裂缝检测毕设拿高分是水到渠成的事。希望这些实战细节能帮到你。本文还有配套的精品资源点击获取