
简介基于YOLOv5的裂缝检测项目包面向深度学习、图像识别方向的本科生与开发者适用于毕业设计、课程设计及期末大作业场景可作为目标检测入门的完整范例也可用于建筑物、道路、桥梁等基础设施表面裂缝的自动检测与定位。压缩包共51个文件、约2MB资源以YAML配置和Python脚本为主同时包含Shell权重下载脚本、Dockerfile容器化配置、说明文档与示例图片覆盖模型构建、权重获取、实时/图片检测及部署等关键环节。目前已有49人学习浏览。项目内置摄像头视频流检测与静态图片检测两套入口并给出模型仓库配置和训练权重下载路径便于直接复现裂缝识别流程目录按模型、数据、权重、运行记录划分修改数据集即可扩展应用是一份完整可操作的深度学习实践参考。1. 裂缝检测为什么值得用 YOLOv5 重做一遍混凝土表面的裂缝在公路、桥梁、隧道、大坝这类基础设施巡检里是最常见也最要命的外观缺陷。过去靠人工目视或者回看图片效率低、标准不统一一个裂缝有没有、多长多宽两个人看结果可能都不一样。这几年土木行业用视觉做结构健康监测第一关就是要把裂缝从背景里干净地抠出来。而这个「设计」通常并不复杂——用 YOLOv5 训练一个裂缝检测模型输入一张混凝土表面照片框出每一条裂缝的位置和置信度再配合像素级后处理就能给巡检系统提供稳定的目标候选。相比语义分割YOLOv5 这类目标检测方案不需要像素级标注几百张图就能出效果迭代快也好部署到树莓派或 Jetson 这类边缘设备上跑实时检测。做这个项目的人身份很杂土木研究生想把裂缝识别写进论文检测公司想拿它替换人工初筛也有搞工业视觉的半路转过来试水。共通点是都想尽快有一个「能跑、能看效果、能交代」的模型。YOLOv5 恰好是这里面最省心的一个选项——源码成熟、文档齐全、社区方案多训练自己的数据集也就跑几条命令的事。但真正落地时数据、超参、后处理这几个环节一个都不省心这篇就把从环境配置到部署的完整路径走一遍重点讲清楚哪些地方是玄学、哪些是可以直接照抄的参数。2. 先搭环境再攒数据conda 虚拟环境与标注格式转换2.1 为什么推荐 conda 而不是裸装 PyTorchYOLOv5 的依赖集中在 PyTorch 生态里版本匹配是个老问题。PyTorch 的 CUDA 版本、torchvision 的对应关系、numpy 的版本下限哪一个不对都能让训练在第一步就翻车。最稳的做法是用 conda 建一个独立虚拟环境把 Python、CUDA、PyTorch 的版本一次性锁死。虽然命令行里看起来只多了三步但它解决了「把系统搞坏」和「项目之间互相污染」这两个最实际的痛点。conda create -n crack_yolov5 python3.8 -y conda activate crack_yolov5 pip install torch2.1.0 torchvision0.16.0 --index-url https://download.pytorch.org/whl/cu118这里 Python 选 3.8 是和 YOLOv5 官方推荐的运行环境对齐实测在 3.8 下依赖最顺不需要改任何源码。PyTorch 2.1.0 配 CUDA 11.8 这个组合对大多数显卡都友好从 RTX 3060 到 4090 都能直接跑。如果机器上 CUDA 版本是 12.x也可以换成 cu121 的轮子命令结构一样只改最后的 cu 后缀。装完基础框架之后进到 YOLOv5 源码目录用 requirements.txt 补齐剩余依赖。这一步需要能访问 GitHub先把仓库 clone 下来再安装git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txtrequirements.txt 里有几个关键依赖值得单独确认opencv-python 负责图片读写matplotlib 用在训练曲线绘制pandas 用在评测结果汇总。这些如果装失败通常原因是网络问题换国内镜像源再装即可。注意不要用 conda 直接装 opencvconda 源里的 opencv 版本经常和 PyTorch 的 tensor 操作产生隐式冲突用 pip 装反而干净。2.2 裂缝数据集从哪里来开源数据集与自采补强做裂缝检测网上最常用的公开数据集是 CrackDataset也叫 CFD里面是几百张混凝土路面裂缝图片分辨率在 544×384 左右单张图里通常只有一条裂缝背景以路面为主。还有 DeepCrack 这个标注到像素级的数据集做语义分割时常用如果做 YOLOv5需要把像素级掩码转成 bounding box 标注OpenCV 的 boundingRect 就能干这件事。import cv2 import numpy as np import os mask_dir path/to/masks save_dir path/to/labels_txt os.makedirs(save_dir, exist_okTrue) for mask_name in os.listdir(mask_dir): mask_path os.path.join(mask_dir, mask_name) mask cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE) _, binary cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY) contours, _ cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) txt_path os.path.join(save_dir, mask_name.replace(.png, .txt)) with open(txt_path, w) as f: for contour in contours: x, y, w, h cv2.boundingRect(contour) # YOLO 格式class x_center y_center width height全部归一化到 0~1 f.write(f0 {x/mask.shape[1]:.6f} {y/mask.shape[0]:.6f} f{w/mask.shape[1]:.6f} {h/mask.shape[0]:.6f}\n)这段代码做的事很简单遍历掩码图用 findContours 找出裂缝连通域对每个连通域求外接矩形然后写成 YOLO 的 txt 标注。YOLO 的标签格式是「类别 中心点x 中心点y 宽 高」全部除以图片宽高做归一化这样不同分辨率的图片可以混在一起训练不需要统一尺寸。用公开数据集有一点必须清醒CFD 的图片背景非常单一拍的都是干净路面没有阴影、没有反光、没有苔藓。真实巡检场景比这个脏得多。所以我在做这类项目时会在现场用手机补拍 200~300 张带各种干扰的裂缝照片用 labelImg 手动框选再和公开数据集混在一起训练。这与直接用公开数据集训出来的模型相比误检率能降不少。2.3 目录结构与路径配置这一步错了后面全白搭YOLOv5 对数据集的读取依赖一个简化的目录约定images 和 labels 两个文件夹训练集和验证集放在同级的 train、val 子目录里。标签文件名必须和图片文件名一致扩展名从 .jpg 换成 .txt。这个对应关系一旦错位训练时 loss 会异常eval 时 mAP 会惨不忍睹。crack_data/ ├── images/ │ ├── train/ │ │ ├── crack_001.jpg │ │ └── crack_002.jpg │ └── val/ │ ├── crack_100.jpg │ └── crack_101.jpg └── labels/ ├── train/ │ ├── crack_001.txt │ └── crack_002.txt └── val/ ├── crack_100.txt └── crack_101.txt之后要写一个 data.yaml 文件告诉 YOLOv5 数据在哪、有几个类别。我见过太多人在这一步栽跟头最常见的问题是路径用了 Windows 反斜杠或者类别数写错。YAML 文件别看简单写错一个缩进训练直接报错。train: crack_data/images/train val: crack_data/images/val nc: 1 names: [crack]train 和 val 指向的是 images 目录YOLOv5 会自动去对应的 labels 目录找同名 txt 文件。nc 是类别数这里只有裂缝一个类。names 列表里每一项和 txt 文件里第一个数字对应0 就对应 names[0]也就是 crack。如果后续要加「剥落」「蜂窝麻面」等类别nc 和 names 同步加就行。3. 开始训练超参数与命令行的真实匹配关系3.1 训练命令怎么看不是越大的模型越好YOLOv5 提供了 n/s/m/l/x 五个规格的预训练权重从 yolov5n 到 yolov5x模型参数量和计算量依次递增。裂缝本身是细长结构但目标检测框并不要求像素级贴合所以这个任务里模型大小对精度的影响远不如数据质量大。我的经验是优先用 yolov5s它速度和精度都不差训练时间也可控如果基线模型 mAP 已经到 90% 以上不需要换成更大的模型把精力放在后处理上价值更大。python train.py \ --data crack_data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --device 0 \ --project runs/crack_train \ --name exp1如果显卡显存只有 8Gbatch 16 img 640 是上限了再大就会爆显存。要观察训练是否正常看每个 epoch 输出的 P、R、mAP50 这几个指标。正常训练时从第二个 epoch 开始 mAP50 会明显上升P 和 R 的曲线会有波动但整体趋势向上。如果跑了大几十个 epochmAP50 还在 0.1 以下基本可以断定是数据或标注出了问题不是训练轮数不够。这里有一个经常被忽略的细节YOLOv5 在--data文件里如果指定了train和val的绝对路径那命令行里就不要再用相对路径启动 train.py否则容易因为工作目录不一致导致找不到文件。建议保持一致性把 crack_data 放在 yolov5 源码目录旁边路径写绝对路径省得排查半天。3.2 三个必调参数imgsz、batch、epochs 之间的平衡训练自己的数据集时最值得调的参数不是学习率而是训练尺寸、batch 大小和 epoch 数。YOLOv5 的默认学习率对于这个项目已经够用但上游的超参数调不好训练过程和结果会完全失控。训练尺寸 imgsz 直接影响模型对裂缝的感知能力。裂缝这种细长目标占比小如果图片压缩到 320 或太小裂缝可能只有几个像素宽模型很难学出特征如果开到 1280训练时间和显存占用成倍增长而 mAP 的提升可能不到 2%。640 是一个普遍合理的起点如果裂缝在图片里占比例很小比如细小龟裂可以试试 960。batch 大小关系到梯度估计的稳定性。batch 太小梯度噪声大loss 曲线像锯齿batch 太大训练时间短但显存容易爆。batch 16 对于裂缝检测来说足够如果显存有余量上调到 32 对收敛略有帮助但边际效益递减。epochs 的选择要看早停机制。YOLOv5 里设置了--patience参数控制早停默认是 100意思是 100 个 epoch 内模型质量不提升就停止。我在裂缝数据集上训练通常 60 到 80 个 epoch 就能稳定出结果设置 100 是为了让它有充分的空间来微调。有的同学训练时急着看结果设 30 个 epoch 就停了这种模型往往还没到最佳点最终部署时会有蛮高的误检率。python train.py \ --data crack_data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 32 \ --epochs 120 \ --patience 20 \ --cache ram \ --workers 4加上--cache ram会把训练图片预加载进内存第一次训练之前会有一个准备阶段但后续每个 epoch 的读取速度快一大截。这个参数在机械硬盘环境下尤其有价值代价是内存占用跟着上去16G 内存的机器也能扛住 640 尺寸的数据集但 32G 内存会更轻松。workers 设 4 足够设置成 8 在 Windows 上会偶尔报 DataLoader worker 的错原因不明我一般不开那么高。4. 评测模型mAP、混淆矩阵与置信度阈值的取舍4.1 看懂 val 输出mAP50、mAP50-95、P、R 都意味着什么训练结束后YOLOv5 会在 runs/crack_train/exp1 里生成一堆文件weights 目录下是最好的权重 best.pt 和最后一轮的 last.pt还有混淆矩阵、F1 曲线、PR 曲线等图表。给项目交代成果之前先看 val 输出的这几个数字。mAP50 的含义是预测框和真实框的 IoU 大于 0.5 时算命中然后综合所有类别求平均精度。对于裂缝检测项目mAP50 是最核心的指标因为裂缝检测最终要送后处理预测框不完全贴合没关系能框中就行。mAP50-95 更严格对 IoU 要求更高裂缝这类细长目标在这个指标上会偏低不用过度纠结。Pprecision和 Rrecall的曲线趋势比最终数值重要。如果 P 高 R 低说明模型保守宁可漏检也不误检如果 R 高 P 低说明模型激进很多框都是误检。具体调 F1 的最优置信度阈值时YOLOv5 会给出 F1-Confidence 曲线但实际部署时不一定要选 F1 最好的点要看业务需求巡检场景里漏检比误检更危险那就把置信度阈值调低接受更多误检如果是自动化系统直接触发警报就把阈值调高减少打扰。4.2 后处理NMS 参数与置信度阈值的配合逻辑YOLOv5 的推理输出是一堆原始预测框每个框带坐标、置信度和类别。后处理的本质是过滤和合并这些框其中最核心的是 NMS非极大值抑制的两个参数IoU 阈值和置信度阈值。NMS 不是 YOLOv5 独有的概念做目标检测的人都绕不开。它的思路是同一目标周围会出现多个预测框先把置信度高的框留下把与之重叠度高IoU 大的框删掉逐次迭代。裂缝这种长条形目标相邻预测框之间天然有高重叠所以 NMS 的 IoU 阈值对裂缝检测的影响比对普通目标检测更敏感。import torch from models.experimental import attempt_load model attempt_load(runs/crack_train/exp1/weights/best.pt, map_locationcpu) model.eval() results model(img_tensor, augmentFalse, conf_thres0.25, iou_thres0.45)detect.py 里默认的 conf_thres 是 0.25iou_thres 是 0.45。需要按项目实际效果调。裂缝项目里我通常会调高 NMS 的 IoU 阈值到 0.5 到 0.6因为裂缝的预测框长宽比很极端默认的 0.45 会吞掉一些并排排列的细长框片段导致一条裂缝被切成长度不一的几段。调高阈值可以保留更多的候选框交给业务层再判断。cli 工具直接推理时建议不要用 detect.py 直接跑验证集而是用 val.py 拿指标然后再对特定图片跑 detect.py 看可视化效果这样指标和眼见都能对齐。python detect.py \ --weights runs/crack_train/exp1/weights/best.pt \ --source crack_data/images/val \ --conf-thres 0.25 \ --iou-thres 0.5 \ --save-txt \ --save-conf--save-txt会把每个图片的检测结果存成 txt--save-conf会在 txt 里带上置信度。这两个参数是做工程交付时非常关键的对方如果要把检测结果接进巡检系统最稳定的接口形式就是这种 txt——坐标、置信度、类别全都有系统那边解析起来没有障碍。4.3 模型轻量化对比yolov5s 和 yolov5n 的实测权衡树莓派 5、Jetson Nano 这类设备跑 YOLOv5是热词里经常出现的方向。但它们算力比 PC 差一个量级模型文件大小和推理速度必须单独考虑。yolov5n 是 YOLOv5 家族里最小的模型参数量只有 yolov5s 的五分之一到六分之一在树莓派 5 上用 CPU 推理单张图大约 1~2 秒而 yolov5s 要 3~5 秒。如果只是让设备拍一张分析一张不追求视频实时性yolov5n 已经完全够用。但注意小模型意味着特征提取能力弱。如果训练数据里有大量小裂缝yolov5n 很容易漏检。我的经验是先拿 yolov5s 训练看 mAP 是否达标再拿同样的数据跑 yolov5n 对比。如果两者 mAP50 差距在 3% 以内部署时选 yolov5n 没有心理压力如果差距超过 5%最好别为了「部署快」牺牲检出率换 yolov5s 再想办法加速。5. 裂缝检测常见问题排查这几类坑几乎人人会踩5.1 反光把水泥墙面误检成裂缝现象是模型在亮面瓷砖或反光水渍处输出高置信度框没有裂缝的地方被检测出裂缝。原因是裂缝数据集中此类样本太少模型把「高亮边缘」学成了「裂缝特征」。解决办法分两步一是训练数据里加入反光、水迹、污渍图片作为负样本labels 目录里的 txt 为空文件让模型学「这些不是裂缝」二是后处理里对 RoI 区域做灰度统计裂缝区域灰度一般低于周围背景如果框内亮度方差太小或者整体亮度太高直接丢弃。5.2 阴影边缘为什么疯狂误检建构筑物表面常常有遮挡物投下的阴影阴影边缘和裂缝在图像上很相似——都是暗色长条。模型学到的是纹理特征而非物理特征所以阴影会触发误检。解决思路是负样本增强时把带阴影的墙面照片大量加进去让模型见过足够多「看起来像裂缝但不是裂缝」的案例。训练后用错检样本做 hard negative mining把误检图加入训练集重新微调一轮效果比单纯调阈值表面。5.3 训练时 loss 一张嘴就是 nan这个报错很吓人但通常根因就两三个标注 txt 里有坐标超出图片边界比如归一化坐标大于 1、图片本身损坏导致读取失败、batch 里混入了灰度的单通道图。排除方法先写一个小脚本检查所有 txt 里的坐标值是否在 0~1 区间再检查图片是否都能被 cv2.imread 正常读出最后在 train.py 里加--workers 0排除读图线程的问题。5.4 树莓派上部署后推理速度慢到不可用如果部署目标是树莓派 5在 CPU 上跑 YOLOv5 的瓶颈不在模型推理而在图像预处理和 NMS 后处理。OpenCV 的 resize 和归一化在树莓派上很耗时但可以通过改用 libyuv 或直接缩小输入图片来缓解。另外要在导出模型时加上--simplify和--dynamic参数把不必要的算子删掉。5.5 细小裂缝的 mAP 很高但实际很多漏检mAP 是数据集的镜像。如果验证集里裂缝都比较粗大模型自然对龟裂、早期裂缝不敏感。检查方法是对验证集做分层统计——把裂缝按像素宽度分成粗、中、细三档分别算各档的 recall。细裂缝档 recall 通常最低。解决办法不是调参而是收集更多细裂缝的样本做难例挖掘同时训练时加上马赛克增强让模型在不同尺度下看到裂缝不同粗细的形态。6. 部署裂缝检测模型从 PyTorch 权重到边缘设备上的实时推理这一步是把训练好的模型真正跑起来的环节常见的部署路径是先把 PyTorch 权重导出成 ONNX 格式再转换成 TensorRT 或直接在 ONNX Runtime 上推理。对于树莓派 5 这类 ARM 设备ONNX Runtime 比直接跑 PyTorch 快很多是更实际的方案。python export.py \ --weights runs/crack_train/exp1/weights/best.pt \ --include onnx \ --opset 12 \ --imgsz 640导出 ONNX 后要注意确认输入输出的形状。输入是 1×3×640×640输出是 1×25200×85。其中 25200 表示三个特征层80×80、40×40、20×20的预测框总数85 表示 4 个坐标 1 个置信度 80 个类别概率。因为裂缝数据集只有一个类别最后 80 个类别概率实际上是冗余的导出时可以用--simplify裁剪计算图让模型文件更小、推理更快。python export.py \ --weights best.pt \ --include onnx \ --simplify \ --opset 12如果是部署到树莓派 5 上做实验onnxruntime 的 ARM 版本直接用 pip 安装pip install onnxruntime然后写推理脚本重点是把后处理里的 NMS 用 ONNX Runtime 提供的非极大值抑制算子来实现这样整体流程都在运行时内部完成不用逐条在 Python 里循环。import onnxruntime as ort import numpy as np import cv2 session ort.InferenceSession(best.onnx) input_name session.get_inputs()[0].name img cv2.imread(test_crack.jpg) img cv2.resize(img, (640, 640)) img img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, HWC to CHW img np.ascontiguousarray(img, dtypenp.float32) / 255.0 img np.expand_dims(img, axis0) outputs session.run(None, {input_name: img})推理速度在树莓派 5 上通常在 1 秒到 2 秒之间取决于输入分辨率和设备散热状态。如果要做视频流检测需要调整到每 5 帧取一帧不然 CPU 温升会导致降频反而更慢。跑通 ONNX 推理之后整个裂缝检测系统就成形了后续可以尝试把 ONNX 进一步转 TensorRT 压缩延迟或者叠加一个连通域分析计算裂缝的像素宽度——这一步的目标检测给的是框真正评估裂缝严重程度还是要看像素级的几何指标。部署验证有一个建议不要只拿最好看的测试照片看效果要拿现场的真实照片看特别是在逆光、阴影、雨天环境下的照片。模型训得再好落地效果始终要去现场看。我自己吃过这个亏——实验室里 mAP 漂亮拿去桥墩上一拍太阳一照阴影里的柱子全是红框。后来学乖了每次训练都在验证集里强制混入现场拍的「硬样本」才把误检压下来。这个习惯后来救了我所有的部署项目希望帮到你。本文还有配套的精品资源点击获取