简介:一套基于YOLOv8的路面、桥梁与墙体裂缝识别Python项目,面向计算机视觉学习者、深度学习初学者及需要完成课程设计或毕业设计的开发者,源码已在本地编译通过,评审分95分以上,内容经助教老师审定,难度适中,适合直接运行与二次学习。项目以26个yaml配置、21个py脚本及18个pyc编译文件为主体,辅以png/jpg/jpeg示例图片用于效果展示,2个md文档用于说明,压缩包共78个文件约2.55MB,结构紧凑,便于快速定位模型配置、训练预测与输出结果,已有130人学习使用。通过该项目可掌握YOLOv8在裂缝检测场景中的数据组织方式、模型配置参数、检测脚本调用流程及可视化输出方法,配有可直接运行的代码与示例图,便于对照复现和修改拓展。无论是想快速搭建裂缝识别原型,还是理解目标检测工程落地细节,这份打包齐全的资料都能提供明确参考。
1. 裂缝识别课题:拿到手先分清是作业还是工程
路面、桥梁、墙体裂缝识别这几年成了 CV 方向的高频课题,原因很现实:传统人工巡检要搭架子、封路、靠人眼量缝宽,成本高而且不同人量出来的结果能差一倍。YOLOV8 做裂缝检测的套路已经比较成熟,GitHub 上相关源码包不少,但绝大多数人下载后卡在同一个地方——能跑通 demo,却训不出能用的模型。这个课题的源码和文档说明,核心价值不是那几万行代码,而是把「采集→标注→训练→评估→部署」这条链路的坑提前标出来了。适合谁做?想做毕设、课程设计的在校生,或者单位里需要快速验证「深度学习能不能用于结构巡检」的工程师。看完你会发现,真正决定项目高分的不是模型改得多花哨,而是数据处理和评估环节是否经得起追问。
2. 搭建 YOLOV8 环境:CPU 版 Ubuntu 20.04 的完整命令与依赖取舍
2.1 用 conda 在 Ubuntu 20.04 上搭 CPU 版环境:5 条命令一次过
很多裂缝识别源码包默认你有一块 NVIDIA 显卡,但实际做课题的人里相当一部分只有办公电脑,GPU 是奢望。CPU 版环境不是不能跑,而是要把依赖版本钉死,否则装完 import 就报错。以下命令在 Ubuntu 20.04 + Python 3.9 下验证过。
# 创建独立环境,避免把系统 Python 搞乱 conda create -n crack python=3.9 -y conda activate crack # 安装 CPU 版 PyTorch,注意一定要带 cpu 标识 pip install torch==2.0.1 torchvision==0.15.2 --index-url https://download.pytorch.org/whl/cpu # 安装 ultralytics 包(YOLOV8 的官方实现) pip install ultralytics==8.0.200 # 验证环境是否可用 python -c "from ultralytics import YOLO; print(YOLO.__name__)"这段命令的核心逻辑是「先固定 PyTorch 全家桶,再装 ultralytics」。--index-url指定 CPU 版 PyTorch 的下载源,如果不加,pip 默认会拉 CUDA 版,装完在无显卡机器上照样能跑但体积大 2GB 且推理会警告。ultralytics 8.0.200 这个版本号建议锁住,升级到 8.1 之后部分回调函数的参数名变了,老源码包里的训练脚本可能直接报TypeError。
后面需要验证推理是否能跑通,用官方预训练权重做一次最小推理:
# 下载 yolov8s.pt 并用一张测试图走完整推理流程 yolo predict model=yolov8s.pt source='https://ultralytics.com/images/bus.jpg' device=cpudevice=cpu参数是 CPU 版环境的关键——不写这个参数,ultralytics 会尝试调用 CUDA,失败后回退 CPU 虽然不报错,但会打印一堆警告干扰判断。跑通后runs/detect/predict目录下会出现带边框的 bus.jpg,说明环境没问题。
2.2 源码包目录结构:先读文档再跑代码,省掉三小时排错
拿到源码包第一件事不是运行main.py,而是花十分钟把目录结构看清。常见做法是源码包会区分detect(检测)、train(训练)、utils(工具脚本)三个目录,文档说明里通常会有一张环境依赖表。先检查requirements.txt里有没有版本号,如果写的是ultralytics>=8.0.0这种开区间,建议按源码包里 README 的版本来。
关于是否在 Windows 上搭建:源码包文档如果写的是 Ubuntu 20.04,就不要在 Windows 上硬跑,因为路径分隔符、cv2.imread读中文路径、multiprocessing的 spawn 模式都会成为额外变量。我一般会先在 Ubuntu 上把代码跑通,再迁到 Windows 做可视化展示。用 VSCode 连远程服务器或 WSL 都是可接受的方式,关键是别让「环境问题」和「代码问题」混在一起排查。
3. 裂缝数据集的构建:Labelme 标注转 YOLO 格式的完整脚本与四个边界坑
3.1 裂缝图像采集:不是拍得越多越好,而是每类裂缝都要有「代表性样本」
裂缝识别的数据采集有个容易被忽略的原则:裂缝在图像里通常只占很小面积,背景占了 95% 以上。如果直接拿手机去拍,拍 1000 张照片里可能只有 200 张是有效裂缝样本,其余都是「疑似裂缝」的阴影、水渍、苔藓。采集阶段要做的是控制变量——固定拍摄距离(一般 0.5~1 米)、固定光照方向(侧光能凸显裂缝纹理)、覆盖不同表面材质(混凝土、沥青、砖墙、金属桥梁构件)。
更关键的是裂缝形态的多样性。细裂缝(宽度 1~3mm)、网状裂缝、横向裂缝、纵向裂缝、断裂带,这五类在检测难度上完全不同。如果源码包自带数据集,先看它的类别分布;如果自建数据集,每个类别至少 300 张是底线,低于这个数模型基本学不到类间差异。采集时把图像分辨率统一到 1280×720 或 1920×1080,不要一会儿横拍一会儿竖拍——标注框的宽高比分布会变得很奇怪,影响锚框匹配。
3.2 Labelme 标注到 YOLO txt 的转换:坐标归一化的标准做法
Labelme 标注出来的是 JSON 文件,里面记录的是多边形顶点坐标,而 YOLO 训练需要的是归一化的中心点坐标和宽高,类别编号从 0 开始。转换脚本是数据集处理的核心,以下代码解决「多边形转矩形框」和「归一化」两个问题。
import json import os import glob def convert_labelme_to_yolo(json_path, save_dir, class_names): """ 将 Labelme 的 JSON 标注转换为 YOLO 格式的 txt 文件 class_names: ['crack'],如果有多个类别,按列表顺序编号 """ with open(json_path, 'r', encoding='utf-8') as f: data = json.load(f) img_w = data['imageWidth'] img_h = data['imageHeight'] # 获取图像文件名,txt 与图像同名 img_name = os.path.basename(data['imagePath']).split('.')[0] save_path = os.path.join(save_dir, img_name + '.txt') lines = [] for shape in data['shapes']: label = shape['label'] if label not in class_names: continue class_id = class_names.index(label) # 取多边形所有顶点的最小外接矩形 points = shape['points'] xs = [p[0] for p in points] ys = [p[1] for p in points] x_min, x_max = min(xs), max(xs) y_min, y_max = min(ys), max(ys) # 转成 YOLO 需要的 xywh 归一化格式 x_center = (x_min + x_max) / 2 / img_w y_center = (y_min + y_max) / 2 / img_h box_w = (x_max - x_min) / img_w box_h = (y_max - y_min) / img_h # 过滤掉过小的框,这些通常是误标注 if box_w < 0.001 or box_h < 0.001: continue lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}") with open(save_path, 'w') as f: f.write('\n'.join(lines)) # 批量转换 json_files = glob.glob('labelme_json/*.json') os.makedirs('yolo_labels', exist_ok=True) for jf in json_files: convert_labelme_to_yolo(jf, 'yolo_labels', ['crack'])这段脚本有三个参数值得注意。box_w < 0.001的过滤条件是为了剔除标注时手抖产生的点状框;class_names用列表索引确定类别 ID,顺序不能随意改动,训练和推理必须用同一份列表;归一化保留 6 位小数,因为在 1920×1080 的图像上一个像素的偏差约等于 0.0005,6 位精度足够区分。
转换完后必须做一次可视化抽检,找 10 张图把标注框画出来叠在原图上,确认没有「框与裂缝整体错位」的问题。这一步很多教程不会提,但它能直接暴露转换脚本的 bug。
3.3 数据增强:裂缝识别的特殊处理与样本均衡
YOLOV8 自带数据增强(随机翻转、马赛克、仿射变换),但裂缝识别有两个特殊问题自带增强解决不了——细长目标和高背景相似度。细长裂缝经过随机旋转 90 度后,宽度和长度比例会改变,模型可能学到错误的长宽比先验;墙壁上的裂缝和阴影在灰度特征上极其相似,纯几何增强反而增加误检。
常见做法是叠加形态学增强:用 OpenCV 对原图做形态学梯度运算,生成突出纹理边缘的辅助图,与原图合并成双通道输入,或者直接做 MixUp。但源码包的训练脚本通常不包含这个逻辑,需要自己写预处理。稳妥的做法是先只用 YOLOV8 自带增强跑一版,记录基线 mAP,再叠加形态学增强对比效果——不要让多个变量同时改变,否则无法定位是哪个操作带来的提升。
样本不均衡是另一个高频问题:横向裂缝可能只有 80 张,纵向裂缝有 500 张。用class weights或者对少数类做过采样(复制样本并加轻微噪声)都能缓解。ultralytics 支持在data.yaml里指定每个类别的权重,但实现方式是修改损失函数的cls系数,效果不如在数据层面做均衡直观。
4. YOLOV8 裂缝分割与检测训练:数据 YAML 配置、损失函数曲线判读与调优边界
4.1 训练数据集的目录组织与 YAML 文件:这步错了训练直接报 0 个样本
很多人在这一步翻车。YOLOV8 不直接读文件夹里的图片列表,而是要求你给一份 YAML 文件,里面写清楚训练集和验证集的图片路径以及类别名。官方支持「图片路径 + 同名字的 txt 标签文件」这种组织方式,但也允许在 YAML 里直接指定标签文件夹。以下是用 LabelImg/Labelme 产出数据后组织训练集的常规做法。
# 数据集目录推荐结构 # crack_data/ # ├── train/ # │ ├── images/ # │ │ ├── crack_001.jpg # │ │ └── ... # │ └── labels/ # │ ├── crack_001.txt # │ └── ... # ├── val/ # │ ├── images/ # │ └── labels/ # └── data.yaml# data.yaml path: /absolute/path/to/crack_data train: train/images val: val/images nc: 1 names: ['crack']path建议写绝对路径,特别是用 VSCode 远程开发时,相对路径会因工作区不同而解析失败。train和val指向的是图片目录,ultralytics 会去同级的labels目录里找对应 txt。nc: 1表示只有一个类别,如果源码包文档里说有「裂缝、剥落、露筋」三个类别,这里就要改成3,names列表也要同步。
训练前验证数据是否被正确加载有一个快速方法:
# 用 train 模式跑一个 batch,观察是否正常加载图片 yolo train data=data.yaml model=yolov8n.pt epochs=1 batch=8 device=cpu如果显示0 images found,检查train/images路径是否正确、图片后缀是不是.jpg而非.jpeg.png;如果显示All labels are empty,检查 txt 文件名是否与图片名完全一致,包括大小写。这一步只花两分钟,但能排除 50% 以上的训练启动失败原因。注意model=yolov8n.pt会先下载预训练权重,无外网环境需要手动把.pt文件放到weights目录或指定本地路径。
4.2 训练命令里的关键参数:跑一轮之前先看清这张表
裂缝识别场景不大,数据集一般 1000~5000 张,训练参数有很强的参考范围。以下参数表是在 CPU 环境(i7-12700 + 32GB 内存)和低端 GPU(GTX 1660 Ti)上都验证过可跑的配置。
| 参数 | 推荐值 | 说明 |
|---|---|---|
model | yolov8s.pt | 裂缝是小目标,n模型感受野可能不够,s是性价比起点 |
imgsz | 640 | 裂缝图像源分辨率高,但直接 1280 训练显存会炸,先用 640 跑通 |
batch | CPU: 8 / GPU: 16 | CPU 上 batch 超过 8 会导致每个 epoch 时间翻倍,收益甚微 |
epochs | 100 | 裂缝数据集规模不大,100 轮足够收敛,再长容易过拟合 |
patience | 20 | 早停轮数,20 轮没提升就停 |
cache | True | 数据集小可以开,把图片加载到内存,CPU 训练速度能快 30% |
device | cpu或0 | CPU 环境不写这个参数会卡在 CUDA 检查 |
启动训练的标准命令是:
yolo train data=data.yaml model=yolov8s.pt epochs=100 batch=8 imgsz=640 device=cpu patience=20 cache=Truepatience=20是个值得调的值——如果前 80 轮 loss 一直在降,但第 81 轮开始验证集 mAP 不再提升,20 轮的耐心窗口刚好能在第 100 轮前自动停止,省掉不必要的等待。cache=True在数据集 2GB 以内时强烈建议开,CPU 训练瓶颈在磁盘 IO,把图片缓存进内存后每个 epoch 能省 30%~40% 时间;但如果内存只有 16GB,建议关掉,否则可能触发 Linux OOM Killer。
4.3 损失函数曲线的判读:三个典型轨迹分别说明什么
源码包文档里通常会附带训练日志,热搜词里「yolov8画损失函数曲线图」说明很多人想搞清楚怎么看这个图。YOLOV8 训练结束后会在runs/train/exp目录下生成results.png,包含train/box_loss、train/cls_loss、train/dfl_loss以及验证集对应曲线。判读要诀是:
第一,box_loss持续下降但val/box_loss在某个 epoch 后反弹,这是过拟合信号。裂缝背景复杂,模型在训练集上死记背景纹理,验证集上表现下降。此时优先加weight_decay(ultralytics 默认 0.0005,可调到 0.001),或者直接降低训练轮数。第二,cls_loss下降缓慢。裂缝只有一个类别,理论上 cls 损失应该很小。如果这条曲线波动剧烈,先查数据——是不是标注框重叠率太高、同一个裂缝被标了多遍。第三,所有 loss 曲线呈锯齿状但整体向下,这是正常现象,batch size 越小锯齿越明显,不用慌张。判断训练是否成功看两点:val/box_loss是否低于 0.05,推理测试图上能否稳定框出肉眼可见的裂缝(而不是墙面纹理)。
5. 裂缝识别的 5 个高频坑:现象、定位与绕开方式
5.1 训练集 mAP 很高,但新场景图片基本漏检
这是裂缝识别课题最常见的翻车现场。现象是验证集上 mAP 能到 0.85,换一批现场拍摄的照片,检测框要么只框住裂缝的一部分,要么直接没输出。
原因大概率是过拟合到训练集的拍摄条件。裂缝图像的灰度分布受光照、湿度影响极大,训练集里的裂缝和现实场景的对比度差距超过模型泛化范围。
解决思路有三个层次。第一层是数据层面,收集更多不同光照、不同材质的新样本补进训练集;第二层是增强层面,增加 HSV 色彩抖动和随机亮度的强度,ultralytics 的hsv_h、hsv_s、hsv_v参数默认值是 0.015、0.7、0.4,裂缝场景可以把hsv_v调到 0.6;第三层是接受现实——把检测结果的置信度阈值从 0.25 降到 0.15,漏检换误检,看哪个更能接受。
5.2 细长裂缝被框成「一节一节」而不是一个整体
现象是 YOLO 框出的检测框只覆盖裂缝的某一段,一条 30cm 长的裂缝被输出 5 个互相重叠的小框。原因在于 YOLO 的锚框机制对长宽比极端的目标不友好,把一条细长裂缝回归成一个完整框的难度远高于回归成几段短框。
解决需要分两步走。第一步是训练侧,把imgsz从 640 提升到 960 或 1280,分辨率越高,细裂缝在特征图上的响应越完整;第二步是后处理侧,对输出的检测框做合并——把中心距小于框宽度 1.5 倍且角度相近的框合并成一个长框。后者用 OpenCV 写一个 NMS 变体即可实现,这段逻辑源码包不一定带,是加分项。
5.3Segmentation fault崩溃:多进程 DataLoader 是元凶
训练到一半进程直接消失,终端只报段错误,没有 Python traceback。这通常发生在num_workers大于 0 时,OpenCV 在多进程环境下读取图片偶发崩溃,尤其是图片编码不标准(手机拍摄的微信传输图片常是这种)。
处理方式是把workers显式设为 0:
yolo train data=data.yaml model=yolov8s.pt epochs=100 batch=8 device=cpu workers=0代价是数据加载变慢,但换来稳定。如果想保留多进程,把图片统一离线转成标准 JPEG:
import cv2 import glob # 将非标准编码的图片统一转为标准 JPEG for img_path in glob.glob('crack_data/**/*.jpg', recursive=True): img = cv2.imread(img_path) cv2.imwrite(img_path, img, [cv2.IMWRITE_JPEG_QUALITY, 95])重新写一遍文件会去掉 EXIF 信息和异常色彩空间,OpenCV 再读就不会出问题。
5.4 正样本太少,训练直接不收敛
裂缝图像里常见「大量无裂缝背景图」被人工筛选为负样本,但如果负样本占比超过 90%,模型会倾向把所有区域都预测为背景,就算有裂缝也输出不了检测框。看训练日志会发现cls_loss一直卡在某个值不动,box_loss下降也很慢。
解决核心是重新平衡正负样本比例。把无裂缝背景图的数量压到总样本的 30% 以内,甚至先完全去掉背景图,只保留裂缝图训练一版,确认能收敛后再逐步加入背景图做误检抑制。裂缝识别的正样本难采集,多拍多标才是根治办法。
5.5 推理阶段单张耗时过高:CPU 上每张图要 2 秒
CPU 推理慢是课题答辩时最容易被追问的点。YOLOV8s 在 CPU 上处理一张 640×640 图像大约要 1~3 秒,现场演示如果一张一张跑,观众会失去耐心。
应急方案是换轻量模型。用yolov8n.pt替换yolov8s.pt,推理时间能降到 0.5~1 秒,mAP 会掉 3~5 个点,但课题展示完全够用。进阶方案是模型转换后用 OpenVINO 跑推理,ultralytics 自带导出:
yolo export model=best.pt format=openvino device=cpu导出后的 IR 模型在 CPU 上比 PyTorch 原生推理快 2~3 倍,代价是安装openvino-dev包。如果是 RK3588 这类嵌入式板子供部署,需要先导出 ONNX 再转 RKNN,中间涉及算子兼容性排查,这个放到下一章展开。
6. 裂缝识别模型的部署与验证:ONNX 导出、嵌入式移植和效果评估口诀
6.1 把最佳权重导出为 ONNX:给 RK3588 等硬件留好后路
训练完的best.pt只在 PyTorch 环境里能跑,工业落地需要转成开放格式。ONNX 是绕不开的中转站,热词里「hi3516cv610 yolov8模型转换与部署实战」「rk3588部署yolov8」都指向这条链路。导出命令:
yolo export model=best.pt format=onnx opset=12导出后用 ONNX Runtime 做一次精度验证,确保推理结果与 PyTorch 原版一致。这段验证代码可以直接复用:
import onnxruntime as ort import cv2 import numpy as np from ultralytics import YOLO # 原模型推理 pt_model = YOLO('best.pt') pt_result = pt_model('test_crack.jpg', conf=0.25) # ONNX 模型推理 ort_session = ort.InferenceSession('best.onnx') img = cv2.imread('test_crack.jpg') img_resized = cv2.resize(img, (640, 640)) input_tensor = img_resized.transpose(2, 0, 1).astype(np.float32) / 255.0 input_tensor = np.expand_dims(input_tensor, axis=0) outputs = ort_session.run(None, {'images': input_tensor})注意 ONNX 输出的原始张量是(1, 84, 8400),84 是4 个框坐标 + 80 个 COCO 类别概率,如果自定义数据集只有裂缝一个类别,需要自己改类别索引映射。对 RK3588 的部署,先用 ONNX 做算子兼容性筛查,再转 RKNN,遇到不支持的算子(如部分版本的DCNv2)优先考虑在导出时加dynamic=False固定输入尺寸。这一步纯粹是实践活,没有捷径。
6.2 效果评估的「三条线」口诀:精确定位、最小缝宽、误检率
训练结束后需要一套能讲给评审听的效果评估结论,而不是只报 mAP。我习惯用三条线来验证裂缝识别模型的水平。第一条是定位精度线:把模型检测框和人工标注框做 IoU,取 IoU 均值,阈值 0.5 是及格,0.7 是良好。第二条是最小缝宽线:准备几张已知缝宽(1mm、3mm、5mm)的标定图,看模型在哪个宽度以下开始漏检——这个数字直接决定能否用于实际巡检。第三条是误检率线:在干净的混凝土背景图上测试,统计每百张图出现假阳性检测框的数量,低于 5 个才算可用。这三条线跑完,课题里「模型效果」这部分的论述就有了硬支撑,源码包里如果附带了评估脚本,直接复用;没有,就按上面思路写一个几十行的测试脚本,属于加分项。
部署时的一个习惯分享一下:我习惯把置信度阈值设成 0.3,NMS 的 IoU 阈值保持默认 0.45,这两个值不动,只调输入分辨率。因为裂缝检测场景里,调错阈值导致漏检的后果比误检严重得多——漏掉一条裂缝等于埋下安全隐患,误检顶多多派一次人工复核。这个取舍原则在项目答辩和实际使用中能站得住脚。
做这个课题最大的收获是明白了「模型只占四成功夫,数据与评估占六成」。源码包的价值在于帮你跳过环境搭建和训练脚本的重复劳动,但数据整理和评估逻辑必须自己弄懂,否则换个数据集还是不会用。希望这篇笔记能帮你在裂缝识别这个方向上少走几步弯路。
本文还有配套的精品资源,点击获取