ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

基于YOLOv5的桥梁裂缝检测实战:从数据标注到模型部署

基于YOLOv5的桥梁裂缝检测实战:从数据标注到模型部署 简介一项基于Python与YOLOv5的桥梁路面裂缝检测识别项目提供可直接运行的源码并附有模型权重下载脚本面向计算机、土木工程等专业的学生可满足毕业设计、课程设计及期末大作业需求也适合目标检测初学者作为实战参考。资源采用ZIP压缩包形式总计85个文件包含Python源码、YOLOv5配置参数、Shell辅助脚本、Dockerfile容器部署文件以及用于验证的示例图片压缩包整体大小仅1.58MB轻巧便携。项目源码已经本地编译并通过验证评审得分高达98分难度适中内容覆盖数据配置、模型搭建、训练与推理等核心环节目录中包含models、utils、data、runs等模块结构清晰便于学习者对照调试。目前已有179人学习对于希望快速掌握裂缝自动检测流程或需要完成相关课业任务的学习者而言是一份高质量且易于上手的参考资料。1. 凌晨四点在桥底拍完最后一张裂缝照片我决定用YOLOv5重做检测凌晨的桥检车上头顶是横梁脚下是施工缝手里的相机一晚上拍回几千张混凝土表面照片。这些照片里有的是结构性裂缝有的是养护不到位导致的水渍纹还有的只是模板接缝的影子。靠人眼一张张去分真正干活的时间会被拖到天亮而传统阈值分割和边缘检测在阴影和粉尘面前又脆弱得离谱。这就是我后来把路面桥梁裂缝检测从纯视觉方法切换到深度学习的原因选来选去最终落到一套基于Python和YOLOv5的源码模型上。YOLOv5在通用目标检测里名气大但真正让它适合裂缝识别的是单阶段推理速度和可调的输入分辨率。桥梁裂缝目标细长、背景脏、尺度变化大YOLOv5的FPN结构能从不同尺度捕捉小目标。配上源码模型从数据标注、训练到部署每一步都看得见摸得着。这个方向适合两类人一类是有标注数据但不知道怎么用的检测工程师另一类是刚学Python不久、想拿真实项目练手的学生。接下来我就按自己跑通一版裂缝检测的流程把数据准备、训练参数、踩坑记录和部署验证一起讲明白。2. 裂缝检测数据准备从现场照片到YOLOv5能直接吃下的数据集2.1 裂缝数据长什么样分辨率、光照和标注风格裂缝检测和一般的行人检测有个明显差别裂缝在图像里通常只占很小一块面积而且形态是细长条一条两米长的裂缝在640×640的画面里可能只有60×5像素。如果现场照片分辨率很高比如4000×3000直接缩放到640细小裂缝几乎会被压没。常见做法是先对原图做切片把大图切成若干640×640的块保留裂缝的原始像素密度再喂给网络。我一般会写一个滑窗切片脚本重叠率设10%左右避免裂缝正好被切在边缘。光照问题更麻烦。桥梁底面光照不均有些裂缝在阴影里有些在强反光里。YOLOv5的数据增强里有HSV抖动但对这种真实场景帮助有限最可靠的办法是在采集数据时尽量覆盖不同时刻、不同角度。标注风格方面裂缝检测有两种主流一种是框标注框住裂缝的明显可见段另一种是分割掩码标出每一个裂缝像素。做目标检测项目用框标注就够了但要注意框的紧致程度。框太大会把背景纹理包进来框太小裂缝断点太多模型反而学不到整体结构。经验值是标到裂缝可见段的外接矩形稍微往外扩2到3个像素保证框内裂缝连续。2.2 用LabelImg做框标注的要点标注工具我常用LabelImg虽然界面老一点但胜在轻量、格式直接。启动后先选PascalVOC格式后面再转成YOLO的txt。裂缝标注有个容易犯的错一条裂缝分成好几段有人会一段标一个框。这种做法会导致同一目标被拆成多个碎片训练时锚框匹配非常混乱。正确思路是如果裂缝在视觉上是连续一条线即使中间有一点被阴影遮挡也应尽量用一个框覆盖完整段只要框的长宽比别太极端就行。YOLOv5对长条目标是有能力处理的但框的长宽比超过20比1时锚框效果会明显下降。标注完记得检查两个地方一是是否有标签名称拼写错误比如“crack”和“crackk”混用二是是否出现了空标签文件。空标签文件在实际中很常见可能是手误点了一下“Save”没标任何框。这些空txt文件在训练时会影响数据加载需要清理。我习惯在标注结束跑一个python脚本把所有空的label文件列出来直接删除同时把对应的图像从训练集里移除。2.3 数据划分脚本train/val/test按目录摆放YOLOv5的data配置只需要图片路径标签文件会自动去同名目录找。标准目录结构是这样的dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/注意images和labels的根目录必须同级且训练集和验证集里的图片文件名一一对应否则YOLOv5会报“label not found”。写一个划分脚本把原始图片和标注后的txt按比例随机分配。这里要注意随机数种子避免每次运行结果不一样后面复现训练时对不上。import random import shutil from pathlib import Path random.seed(42) img_src Path(original_images) # 现场裁剪后的图片 label_src Path(original_labels) # LabelImg导出的txt需先转成YOLO格式 train_ratio 0.7 val_ratio 0.2 # test_ratio用剩余比例 images list(img_src.glob(*.jpg)) assert images, 没有找到图片文件请检查目录路径 # 先打乱再按比例切分 random.shuffle(images) total len(images) train_idx int(total * train_ratio) val_idx int(total * (train_ratio val_ratio)) splits {} splits[train] images[:train_idx] splits[val] images[train_idx:val_idx] splits[test] images[val_idx:] for split, img_list in splits.items(): img_out Path(dataset/images) / split label_out Path(dataset/labels) / split img_out.mkdir(parentsTrue, exist_okTrue) label_out.mkdir(parentsTrue, exist_okTrue) for img in img_list: shutil.copy(img, img_out / img.name) label_file label_src / (img.stem .txt) if label_file.exists(): shutil.copy(label_file, label_out / label_file.name) else: print(f警告: {img.name} 没有对应的txt文件已跳过标签)逻辑说明脚本先固定随机种子保证每次运行划分结果一致。切分时把图片路径列表按比例切成三段分别拷贝到对应目录。关键点是“label_file.exists()”的判断它会把缺失标签的图片单独提示出来避免训练时因为标签缺失而静默忽略该图。参数方面train_ratio和val_ratio需要根据数据量调整如果总图片数少于200张建议把val_ratio降到0.1否则验证集太小评估指标波动很大。2.4 数据增强怎么加才不会让细裂缝学歪YOLOv5默认的增强已经很强但对裂缝这种细长目标有些增强要谨慎。比如旋转角度默认hyp里有degrees0可以试着开到5到10度。注意裂缝不像车辆方向是有物理意义的桥梁横缝和纵缝代表不同受力状态标注时类别区分可能就是这个。如果旋转角度太大横缝转成斜缝类别就乱了。翻转增强fliplr和flipud可以开但要注意裂缝位置在桥梁墩柱上可能有左右对称性一般没问题。尺度增强scale对裂缝很关键。裂缝尺度本身就细如果scale设得太大有些裂缝会被缩成几个像素小目标检测基本失效。我一般把scale控制在0.4到0.6之间让网络在不同尺度下都能看到清晰的裂缝纹理。另一项是mosaic增强默认开启它会拼四张图对提高小目标泛化能力有帮助但mosaic会把四张图的上下文混在一起训练周期较长。如果数据集只有几百张建议mosaic一直开着因为裂缝样本本身太少靠增强扩充是唯一出路。如果已经训练了50轮还是过拟合再考虑关闭mosaic做微调。3. 环境搭建与训练用YOLOv5训练自己的裂缝检测模型3.1 conda yolov5环境搭建和依赖安装先说环境。YOLOv5要求Python版本3.8以上PyTorch 1.8以上。用conda建独立环境是最稳的避免和系统的其他Python项目冲突。网上很多“conda yolov5”教程会直接让你pip install -r requirements.txt但如果你是在国内网络一定要先配好pip镜像否则下载大依赖包时容易超时。conda create -n yolov5 python3.9 -y conda activate yolov5 pip install torch1.13.1 torchvision0.14.1 --index-url https://download.pytorch.org/whl/cu117 pip install -r requirements.txt逻辑说明第一条命令创建名为yolov5的虚拟环境指定Python 3.9第二条命令激活环境第三条安装CPU或GPU版PyTorch这里用的是CUDA 11.7对应的版本你在操作时需要用nvidia-smi查自己机器的CUDA版本再选择对应的PyTorch。最后一条安装YOLOv5的依赖包包含numpy、opencv、matplotlib等。参数说明requirements.txt里有一个坑它会自动安装最新版opencv-python如果你本机已经有摄像头权限问题建议装opencv-python-headless替代。训练前我需要检查GPU是否可用python -c import torch; print(torch.cuda.is_available())如果输出True说明GPU正常。如果输出False也可以继续用CPU训练但裂缝数据集至少几百张CPU训练会非常慢。真没有GPU建议把img size降到480batch size降到8先用小模型试跑通再去云上租卡训练。3.2 数据配置文件与yaml写法YOLOv5训练前要准备两个yaml文件一个是数据集配置文件描述图片路径和类别一个是模型配置文件描述网络结构。对新手来说模型配置直接用默认的yolov5s.yaml或yolov5m.yaml不用改。数据集配置必须自己写它长这样# bridge.yaml train: dataset/images/train val: dataset/images/val nc: 2 names: [crack, seam]这段配置最简单。train和val指向图片目录YOLOv5会自动识别同级的labels目录。nc是类别数这里假设两种裂缝和施工缝。names是类别名字列表顺序必须和标注txt里的类别ID一致。不要小看这个顺序LabelImg导出的txt第一列是0还是1取决于你给标签分配ID的顺序。如果names写反了训练出的模型不会报错但推理结果会张冠李戴。3.3 训练命令与关键超参数数据准备好了环境也通了接下来就是训练。我的标准命令python train.py \ --data bridge.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --cache各参数说明--data指向刚才写好的bridge.yaml--weights用yolov5s.pt做预训练权重YOLOv5会从官方仓库下载也可以第一次训练不指定用COCO预训练会大大加快收敛对裂缝这种目标也算迁移学习--img设为640这个值不能拍脑袋需要去看数据集中裂缝的宽度。如果裂缝在切片后宽度只有几个像素可以把img设到800或960对小目标更友好但显存占用会明显增加--batch设为16在24GB显存的显卡上img640时16是安全的。如果显存只有8GBbatch要降到4或2否则会报CUDA out of memory--epochs设为100但配合早停实际会在60轮左右停止。注意epochs不是越多越好裂缝数据集普遍很小训练太久会过拟合到背景纹理上。还有一个隐藏参数是--hyp用来指定超参数文件。默认的是data/hyps/hyp.scratch.yaml里面包含学习率、权重衰减、增强系数等。我经常改的只有三个lr0: 0.01 weight_decay: 0.0005 mosaic: 1.0lr0是初始学习率数据量大可以保持0.01但裂缝这种小数据集我降到0.005防止前几轮loss发飘。weight_decay控制正则化0.0005是默认值如果验证集mAP已经在乱跳可以试着调到0.001压制过拟合。3.4 怎么看训练曲线和早停训练过程中会生成runs/train目录里面有每轮的结果。主要看两个文件results.png和weights/。results.png里有损失曲线和mAP曲线。我习惯重点看val/box_loss和val/cls_loss如果两个loss在缓慢下降说明训练正常如果train_loss还在降val_loss已经开始震荡上升就是过拟合信号需要立刻调早停参数。早停参数是--patience。默认值是100意味着100轮内没有提升就停止。对裂缝检测我把它设成20因为小数据集从第30轮开始mAP就趋于平稳再等太长没有意义。看权重文件时best.pt是验证集mAP最高的权重last.pt是最后一轮的权重。如果训练中断可以用--resume last.pt继续。这个“后悔药”对长训练特别有用不要傻傻从头开始。另外如果数据集中裂缝数量特别少网络可能提示“WARNING: no labels found in train path”这时候要回头检查labels目录下的txt内容是否为空或者图片和标签的stem是否一致。4. 避坑裂缝检测训练与推理的5个高频翻车现场4.1 边界框偏移标注了整条裂缝却只识别出一小段现象训练完成后在测试图上推理框只框住了裂缝的一小段而不是完整裂缝。有时候一段裂缝被标出了四五个框看起来像是把一条线切碎了。原因锚框匹配机制。YOLOv5使用固定锚框默认锚框是为通用目标设计的长宽比最大接近5比1。裂缝框长宽比经常超过10比1锚框和真实框的IoU太低网络只能勉强匹配到部分区域导致输出框严重不完整。解决在训练时使用--noautoanchor参数的选项。YOLOv5默认会在开始训练前自动重新聚类锚框但因为有预训练权重它可能不会完全重算。我一般先关闭自动锚框用--noautoanchor跑一个短迭代输出新的锚框结果然后拷贝到yolov5s.yaml里再正式训练。这一步对裂缝检测几乎是必须的能有效降低边界框偏移。另外把标注时的框适当拉长尽量包住裂缝两端能改善长宽比问题。4.2 把细小裂缝当背景模型过拟合到纹理上现象训练集上识别很准到了验证集很多细小裂缝直接被漏掉但一些明显的模板接缝却全被检测出来。看热力图模型关注的是粗糙纹理区域而不是裂缝的连续性。原因裂缝样本太少背景纹理太强。混凝土表面的气孔、模板纹、砂眼都和裂缝在灰度上有相似性。网络在有限样本下选择了一条捷径学习背景特征而不是裂缝的边缘断裂特征。解决增加负样本。从现场多拍一些完全没有裂缝的混凝土表面加入训练集标签为空文件网络被迫学习“没有裂缝”的样本。另一个做法是数据增强里提高HSV的颜色扰动强度让模型更依赖灰度梯度而不是绝对颜色。还有个小技巧是在训练时把--cls类别损失权重提高一点让模型在类别判断上更保守宁可少检也不误检。注意漏检和误检是一对矛盾单靠参数调整已经到瓶颈了最有效还是补充标注数据。4.3 显存不足batch size和img size怎么搭配现象训练开始几秒直接报错“RuntimeError: CUDA out of memory”。有人立刻把batch size降到1结果发现loss仍然波动很大训练极不稳定。原因只调batch不调img size。YOLOv5的内存占用大约与图片面积成正比另外多尺度训练会在每个epoch随机切换640、704等尺寸显存峰值出现在最大尺寸时。如果batch size 4配合img 960峰值占用可能是batch 16配合img 640的好几倍。解决先把img size降到640然后用一个经验公式显存总大小除以2大约能跑的batch size。比如16GB显存batch size可以设88GB显存batch size设4。如果还想再小就要用--cache参数把数据预加载到显存但这一步会额外占用显存。另一个能救急的办法是开启梯度累积也就是--batch 64加--accumulate 4的写法但YOLOv5没有直接的accumulate参数需要手动改源码或使用nohup分割训练。这里提醒一句真的不要长期用batch 1训练BN统计量都算不准模型会像喝醉了一样收敛不稳定。4.4 预测结果错位多类别标成单类别现象模型推理时输出框位置很准但框里的内容分类错。比如把结构性裂缝的框标成了“施工缝”或者反过来。更隐蔽的是同一张图同一个位置两次推理返回的类别不同。原因检查数据标注时发现有人用LabelImg把class name设置成1和2而不是0和1。YOLO格式要求类别ID从0开始。如果txt里写的是1和2而配置文件的nc2网络会把1当正常类2当越界类训练时产生“IndexError”不报但权重更新混乱。解决写个脚本批量修正所有txt类别ID统一减1并打印类别分布。另外验证集里的类别分布如果很不均衡比如裂缝有2000个框施工缝只有20个框网络会把施工缝当异常噪声推理时就乱猜。这种情况要么多补施工缝的样本要么用--weight参数给不同类别分配损失权重。4.5 模型跑起来了但检测速度慢瓶颈在预处理现象训练好的模型在检测图片时单张耗时可能200毫秒感觉不快。有人就认为是模型结构太复杂马上换小模型或做剪枝。但后来用torch.profiler一查发现80%的时间花在图像缩放和颜色转换上。原因YOLOv5的detect.py会内置letterbox也就是等比例缩放填充。如果输入图片特别大比如4000×3000第一步缩放就要花费大量CPU时间尤其你用CPU推理时特别明显。GPU推理中瓶颈也会在数据预处理上。解决推理前在代码里手动把图片缩放到与训练时一致的尺寸再做归一化避免detect脚本里重复的resize。另一个方式是导出TensorRT或ONNX让推理引擎接管预处理。实际项目中一般会先用--source指定一个视频看FPS如果FPS低先检查预处理不要急着换模型。另外--half参数可以启用FP16推理显存减半速度提升也很明显前提是GPU支持FP16。5. 部署与验证把YOLOv5裂缝模型跑在图片和视频上5.1 本地推理命令与置信度参数选择训练完best.pt就是最终的产物。推理命令很简单python detect.py --source test_images/ --weights runs/train/bridge/weights/best.pt --conf-thres 0.35 --img 640这里--source可以是图片文件夹也可以是一个视频文件。--conf-thres是置信度阈值我习惯先设0.35如果测试图上有明显漏检再往下降如果一堆误检框就往上升。裂缝检测和行人检测不一样漏检比误检更危险因为现场的裂缝需要被记录和复核宁可多框一些疑似区域。推理结束后输出图片会保存到runs/detect目录打开看一遍不要只看数值因为mAP指标无法反映一些细小的视觉误差。5.2 导成ONNX模型做更轻量的部署如果要在边缘设备或手机上部署YOLOv5支持导出ONNXpython export.py --weights runs/train/bridge/weights/best.pt --include onnx --opset 11导出成功后会生成best.onnx。移植到其他推理框架时记得把输出层的维度顺序理解清楚。YOLOv5的原始输出是三个尺度的feature map每个尺度有num_anchors×(5num_classes)个预测。用ONNX跑推理时要把这三个输出拼起来再做NMS不要直接拿输出当最终结果。很多踩坑贴都是卡在NMS这一步。5.3 切片检测用小图检测微小裂缝最后分享一个我常用的验证技巧对原图先做切片推理。把一张2000×2000的测试图切成9个800×800的块重叠50像素分别检测再把结果映射回原图。这一步能验证模型的真实小目标能力也适合在采集端直接用来处理大分辨率相机图。切片后的检测精度通常比直接缩放高不少代价是推理次数增加。如果现场只关心局部细节这个技巧非常实用。我在桥检车上就是这么干的把相机连到电脑边拍照边切片检测当场标出可疑区域效率比回去再处理高很多。说回习惯我现在每次训练完都会先跑一遍切片验证再考虑是否调优。这比看训练曲线可靠得多。视觉模型往往在小数据集上表现很好但放到不同光照和角度的现场就会露馅。希望你也能把这个步骤当成默认动作希望帮到你。本文还有配套的精品资源点击获取
返回列表