简介:基于YOLOv8的基建裂缝目标检测系统,是一份面向计算机视觉、人工智能、自动化等专业学生与从业者的毕设级Python项目。资源以裂缝检测为核心,覆盖从数据集准备、模型训练到结果评估的完整流程,代码经调试可运行,适合作为课程设计、大作业或毕业设计的起点,也可供入门者系统学习YOLOv8目标检测。资源压缩包共849个文件,解压后大小约666MB,其中包含329个jpg图像样本、298个txt标签与158个xml标注文件,用于训练与验证;另有23个pt模型权重可直接加载推理,以及py脚本、yaml配置、results.csv训练日志等辅助文件。目前已有144人学习下载。除源码外还附有文档说明与数据集,目录结构清晰,训练缓存与结果文件可帮助快速复盘调参过程,适合在现有基础上修改类别或场景,实现自定义裂缝检测功能。
1. 为什么基建裂缝检测绕不开YOLOv8:先看这份资源解决什么问题
基建裂缝检测这类任务,最头疼的不是"能不能检出来",而是"裂缝这种细长目标,背景又脏,到底怎么稳定检出"。混凝土表面的网状裂缝、桥梁箱室里的细微裂缝,光照一变化就和背景混在一起,传统图像处理算法阈值分割半天,换个现场就失效。基于YOLOv8的基建裂缝目标检测系统就是冲着这个场景来的:用深度学习目标检测的思路,把裂缝当成一个窄长的框目标来训练和推理,Python源码、数据集、文档说明一套配齐,拿到手就能顺着跑出训练和推理结果。适合刚入门目标检测的在校生做课程设计,也适合现场检测工程师想快速验证深度学习方案在裂缝识别上的可行性。下面按我从解压到复现的顺序,把这套资源能干什么、坑在哪讲清楚。
2. 从压缩包到第一次跑通推理:源码结构与权重加载
2.1 拿到压缩包后先看什么
这套资源解压后的典型结构是一个python工程,加上dataset目录和文档说明。第一次打开别急着跑train.py,先把文件清单过一遍。常见布局是:
crack_yolov8/ ├── dataset/ │ ├── train/ │ │ ├── images/ │ │ └── labels/ │ └── val/ │ ├── images/ │ └── labels/ ├── weights/ │ └── best.pt ├── data/ │ └── data.yaml ├── train.py ├── detect.py └── requirements.txt我的习惯是先读data.yaml和train.py。这两个文件直接决定了训练集指向哪里、类别名是什么、训练配置长什么样。很多新手拿到源码后直接运行报错,九成是路径不对或者data.yaml里的路径没有改成自己的绝对路径。weights目录下如果有best.pt,说明作者已经把训练好的权重放进来了,可以跳过训练阶段先跑推理,验证环境通不通。
2.2 环境依赖:Python版本、ultralytics与CUDA的选型
这套代码基于ultralytics框架,YOLOv8的官方实现就在这个库里。requirements.txt里一般会写ultralytics、opencv-python、torch、torchvision这几项。环境搭建有两条路:GPU和CPU。如果你手上只有普通笔记本,ubuntu20.04搭建yolov8环境cpu版本完全可行,推理一张图几秒钟,训练小数据集也能凑合;如果有NVIDIA显卡,优先装CUDA版的PyTorch。
创建虚拟环境再做安装,避免把系统Python搞乱:
conda create -n crack python=3.9 -y conda activate crack pip install ultralytics==8.0.100 opencv-python pip install torch==2.0.1 torchvision==0.15.2 --index-url https://download.pytorch.org/whl/cu118逻辑说明:ultralytics是YOLOv8的官方训练推理库,把模型定义、训练循环、数据加载都封装好了,detect.py和train.py里大量直接引用这个库。torch版本要和CUDA版本匹配,这里指定cu118是兼容CUDA 11.8的预编译包,如果你用CPU,去掉--index-url参数装默认版即可。
参数说明:Python版本建议3.8到3.10之间,太新的Python版本可能导致部分依赖库没有预编译wheel。torch和torchvision版本必须对应,2.0.1配0.15.2是官方校验过的一组对应关系,混搭容易在导入模型时触发torchvision::nms相关报错。
2.3 用预训练权重跑通一次推理
环境装好后,先别碰训练,直接跑推理验证链路。命令行方式最省事:
python detect.py --source dataset/val/images/IMG_0234.jpg --weights weights/best.pt --conf 0.25 --iou 0.45 --imgsz 640 --save-txt如果detect.py不是标准的ultralytics封装,也可以直接用库的API写推理脚本:
from ultralytics import YOLO model = YOLO('weights/best.pt') results = model.predict(source='dataset/val/images/', conf=0.25, iou=0.45, imgsz=640, save=True, save_txt=True) print(results[0].boxes.xyxy.cpu().numpy())逻辑说明:model.predict接收图片路径或目录,内部自动完成预处理、推理、后处理NMS。results里打印出的坐标是xyxy格式,也就是每个裂缝框的左上角和右下角像素坐标。save=True会把带标注框的结果图写到runs/detect目录。save_txt=True让推理结果以YOLO格式txt保存,方便后续批量分析。
参数说明:conf是置信度阈值,裂缝检测我一般不会拉到0.5以上,因为裂缝这类低纹理目标的正检置信度天然偏低;iou是NMS的IoU阈值,调大一点能减少重叠框;imgsz是输入网络的尺寸,640是速度和精度的常用折中点,检测细小裂缝时如果显存够,可以试试1280。
2.4 数据集格式:YOLO的txt标注到底长什么样
这套资源里带的数据集,标注文件是txt格式,每个txt对应一张同名图片。打开看一眼就能明白:
0 0.428125 0.53125 0.03671875 0.015625 0 0.56328125 0.474609375 0.02421875 0.01875逻辑说明:每一行代表一个目标,第一个数字是类别id,后面四个数字是归一化后的中心点x、中心点y、框宽w、框高h,四个值都是相对图片宽高的比例,取值在0到1之间。这里类别id为0对应的就是裂缝。YOLO格式要求图片里的每个目标都写进txt,没有标注框的图片就放一个空txt或者不放txt。
和VOC的XML或COCO的JSON不同,YOLO的txt没法直接看出像素尺寸,所以检查标注是否正确时,最可靠的方式是把框画回原图肉眼检查。我一般会写几行代码验证一遍:
import cv2 img = cv2.imread('dataset/val/images/IMG_0234.jpg') h, w = img.shape[:2] with open('dataset/val/labels/IMG_0234.txt') as f: for line in f: cls, xc, yc, bw, bh = map(float, line.split()) x1 = int((xc - bw / 2) * w) y1 = int((yc - bh / 2) * h) x2 = int((xc + bw / 2) * w) y2 = int((yc + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.imwrite('check_label.jpg', img)逻辑说明:这段代码把txt里的归一化坐标换算回图片像素坐标,然后画框保存。跑完后打开check_label.jpg,重点看框是不是紧贴着裂缝边缘。如果框明显偏大或者偏小,说明标注质量有问题,这种数据拿去训练,模型学的就不是"裂缝边缘",而是"裂缝周围的一片区域"。
参数说明:cls这个值在资源和你的任务里通常都是0,但如果之后你自己用labelme标注多类别裂缝类型,这里会变成0、1、2这样的递增编号,data.yaml里的names列表顺序和这里要严格对应。
3. YOLOv8网络结构与推理参数:改动这三处,裂缝检出率才稳
3.1 检测头换成anchor-free后,裂缝目标检测发生了什么变化
YOLOv8相比YOLOv5最核心的变化是把anchor-based检测头换成了anchor-free。anchor-based需要预设一组宽高比各异的先验框,YOLOv5的默认anchor是COCO数据集聚类出来的,适合普通物体,但裂缝的宽高比极端,动辄几十比一,预设anchor经常匹配不上。YOLOv8直接在特征图每个位置预测目标中心点所在位置和宽高偏移,省去了anchor聚类这一步。
对基建裂缝这种细长目标来说,这是实打实的收益。我拿YOLOv5s和YOLOv8s在同一批桥梁裂缝图上对比过,YOLOv8对细裂缝尾部的召回明显更高,尤其裂缝延伸到阴影区域时,anchor-free的检测头更不容易因为IoU匹配不上而漏检。这也就是为什么这套源码选择YOLOv8而不是其他版本的原因之一。
模型结构上,YOLOv8用了C2f模块代替YOLOv5的C3。C2f在残差连接里引入了更多梯度流分支,参数量略微增加,但特征复用能力更强。对裂缝这种需要细节纹理特征的目标,深层特征图多一层梯度流,对小目标的敏感度是会高一些的。YOLOv8按深度和宽度系数分成n、s、m、l、x五档,这套资源里的源码通常默认用yolov8s起步,算力充足时换yolov8m会再涨两三个点的mAP。
3.2 推理参数怎么配:conf、iou、imgsz对裂缝检出的实际影响
说到推理参数,需要先明确裂缝检测和通用目标检测的差异。COCO数据集上0.5的置信度阈值很常见,但裂缝目标边缘模糊、对比度低,网络输出的objectness分数普遍低一截。我实际跑下来,裂缝检出的置信度分布集中在0.2到0.6区间,如果按默认conf=0.25,漏检率还凑合;拉到0.5,肉眼可见地少了一截裂缝。
from ultralytics import YOLO model = YOLO('weights/best.pt') results = model.predict( source='dataset/val/images/', conf=0.15, iou=0.5, imgsz=1280, save=True, classes=[0], max_det=300 )逻辑说明:conf降到0.15是为了把低置信度的裂缝框也保留下来,代价是误检增多,所以后面要配合classes过滤和max_det限制。我一般用两个配置跑不同场景:快速巡检用conf=0.25、imgsz=640,追求召回再用conf=0.15、imgsz=1280。
参数说明:iou=0.5用于NMS,裂缝框之间重叠程度通常不高,0.5到0.6都行。imgsz影响最大,小目标检测在640输入上的特征图分辨率有限,裂缝可能只占几个像素,放大到1280后特征明显丰富。max_det限制每张图最多输出的框数量,防止在纹理复杂背景上出现大量噪声框。
3.3 结果可视化与指标计算:别只看loss,要看mAP和PR曲线
训练或推理完之后,不能只盯着命令行里的loss数字。ultralytics在验证阶段会输出一张混淆矩阵和PR曲线,位置一般在runs/detect/val或者runs/train/exp目录。我每次都会把PR曲线打开看一眼:曲线越贴近右上角,说明模型在低置信度区间的表现越好。对裂缝检测来说,PR曲线右下段的形态尤其关键,因为实际使用中我们必须在高召回和低误检之间找平衡点。
如果这份源码里没有自动生成PR曲线,也可以手动验证一次,把测试集全部跑一遍,统计不同置信度下的精确率和召回率:
import numpy as np from ultralytics import YOLO model = YOLO('weights/best.pt') all_conf = [] for img_path in image_list: r = model.predict(source=img_path, conf=0.05, verbose=False)[0] for box in r.boxes: all_conf.append(float(box.conf[0])) thresholds = np.arange(0.05, 0.95, 0.05) for t in thresholds: keep = sum(c >= t for c in all_conf) print(f'conf={t:.2f}, 保留框数={keep}')逻辑说明:这段代码用很低的conf阈值把所有候选框都保留下来,然后统计不同置信度阈值下会输出多少个框。这个"框数量-置信度"曲线虽然粗糙,但能直观反映你的模型在哪个区间输出是稳定可靠的。如果0.2以下的框占比很高,说明模型对裂缝和背景纹理的区分度不够,需要回到训练阶段调数据。
参数说明:r.boxes.conf是每个检测框的置信度张量,verbose=False关掉逐张图打印,避免刷屏。image_list是你要测试的图片路径列表,可以用glob.glob('dataset/val/images/*.jpg')生成。
4. 训练自己的裂缝数据集:数据划分、训练命令与调参细节
4.1 数据集划分与data.yaml配置
这套资源自带的数据集可以直接训练,但如果你要换一批现场图,就得自己处理数据集。先做划分,train和val按8比2,test单独留一部分看最终效果。整理成这样的目录结构:
dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/然后写data.yaml,这是train.py的第一个入口:
path: /home/user/crack_yolov8/dataset train: images/train val: images/val test: images/test nc: 1 names: 0: crack逻辑说明:path是数据集根目录的绝对路径,train、val、test写相对于path的目录。nc是类别数,这里是1,只有裂缝一类。names列表里0对应crack,顺序一定要和标注txt里的类别id一致。很多复现翻车就是names顺序和标注对不上,模型学了半天其实在学"猜谜"。
参数说明:path建议写绝对路径,写相对路径时一定要在train.py同级目录启动Python,否则会找不到数据集。如果之后增加"网状裂缝"和"线性裂缝"两个类,nc改成2,names里加一个1对应的类别名,标注txt里的类别id也要相应修改。
4.2 训练命令与超参数说明
数据准备好后,直接训练。我这里给的是通用命令,实际使用以这份源码里的train.py为准,但核心参数都一致:
python train.py --data data.yaml --weights yolov8s.pt --epochs 100 --batch-size 16 --imgsz 640 --device 0如果没有GPU,把--device 0改成--device cpu,但训练时间会长很多。如果train.py就是启动ultralytics的封装脚本,也可以用等价的API方式:
from ultralytics import YOLO model = YOLO('yolov8s.pt') model.train( data='data.yaml', epochs=100, batch=16, imgsz=640, device=0, patience=20, cache=True, lr0=0.01, augment=True )逻辑说明:model.train会先加载COCO预训练权重,然后用你的数据集做迁移学习。epochs设100是因为裂缝数据集通常只有几百到几千张图,太少学不出纹理特征,太多容易过拟合,后面用patience做早停兜底。batch是每批图片数,根据显存调整;cache=True把图片缓存到内存里,小数据集下能显著加快读取速度。
参数说明:patience=20意思是连续20个epoch验证集指标没有提升就自动停止训练,这是防止过拟合的后悔药。lr0=0.01是初始学习率,迁移学习场景下一般不要超过0.01,否则预训练权重会被快速破坏。augment=True启用Mosaic、翻转、色彩抖动等内置数据增强,裂缝这种细长目标我建议保留,因为现场光照变化大,增强能提升泛化能力。
4.3 训练过程怎么看:loss曲线与过拟合判断
训练时命令行会持续输出box_loss、cls_loss、dfl_loss等指标。不要只看train_loss下降就开心,重点看val的指标曲线。ultralytics训练结束后会在runs/train/exp目录生成results.png,这张图里有每类loss和mAP50、mAP50-95的变化曲线。
我判断训练状态的方法很简单:train_loss持续下降、val_loss同步下降,说明模型在正常学习;train_loss还在降但val_loss开始反弹,就是过拟合信号。裂缝数据集通常不大,过拟合很常见,表现为训练集上框得很准,一到新图就漏检。遇到这个情况,优先做三件事:增加数据增强强度、调低batch让BN层统计更稳定、用早停保存最优权重。ultralytics默认只保存best.pt和last.pt,过拟合发生时last.pt通常不如best.pt。
另外强烈建议用torchinfo之类的工具看一眼模型参数量:
pip install torchinfofrom ultralytics import YOLO from torchinfo import summary model = YOLO('yolov8s.pt').model summary(model, input_size=(1, 3, 640, 640))逻辑说明:summary会打印每一层的输出尺寸和参数量,帮助你确认当前模型是yolov8s还是nano。有时候误以为自己在跑大模型,实际加载的权重是nano版本。裂缝检测界面上,yolov8s和yolov8n的精度差距在几个点,但文件大小和推理速度差别明显。
5. 裂缝检测排查避坑:五条翻车记录与解决顺序
5.1 踩坑记录:现象、原因、解决
第一条,运行train.py报FileNotFoundError: No such file or directory: 'data.yaml'。现象是脚本在main函数一进来就崩,原因很直接:data.yaml的path写的是相对路径,而你启动python的目录不是项目根目录。解决方式是改成绝对路径,或者在命令行里先cd /home/user/crack_yolov8再跑命令,这个坑我踩过三次,后来养成了习惯:每次拿到新源码,先修改data.yaml的path和weights路径,再执行任何训练命令。
第二条,推理结果全是框在背景纹理上,裂缝根本没标出来。现象是输出图里很多无意义的小框,精确率极低。原因通常是训练集里的负样本太少,模型分不清裂缝和暗色污渍。解决方式是数据集中加入一批完全没有裂缝的背景图,并且给这些图放一个空标注txt。YOLO训练逻辑会把这些图作为负样本参与loss计算,帮助模型学会抑制背景输出。
第三条,训练中爆显存CUDA out of memory。现象是epoch跑到一半程序被杀。原因常见两个:batch过大,或者cache=True在显存不足时反而把图片缓存到显存里。解决方式是batch从16降到8,cache=True改成cache='disk',imgsz从640降到480。如果还是爆,把worker数调低,减小数据加载进程对显存的额外占用。
第四条,验证集mAP很高,实测现场图效果很差。现象是val指标到了0.9,新场景检出率只有一半。原因几乎是数据集拍摄条件和现场差异太大,训练集裂缝都是近距离大裂纹,现场是远景细裂缝。解决方式是用现场图补充数据集,或者用第6章说的方式接到现场摄像头采集一轮数据重新微调,单靠调参数救不回分布差异。
第五条,用labelme标注后转成YOLO格式,训练时类别错乱。现象是loss波动剧烈,推理结果把裂缝检成类别2之类不存在的id。原因是labelme JSON转YOLO txt的脚本里,class_id没有按data.yaml的names顺序映射,比如names里0是crack,但脚本硬编码成1。解决方式是每转一批数据就抽样检查txt第一列的数值范围,确保最大值小于nc,并且和names索引一一对应。
5.2 小目标裂缝漏检率高的排查顺序
如果你发现模型对细小裂缝总是漏检,按这个顺序排查。第一步,看图里裂缝的最小宽度占图片宽度的比例,如果裂缝只有几个像素,那先降低imgsz的损失,推理和训练都改成1280。第二步,检查训练集里细裂缝样本是不是太少,YOLOv8对训练集中小目标的占比很敏感,低于10%基本学不好,需要用小图裁剪的方式把细裂缝放大再送进训练集。第三步,看损失曲线里dfl_loss有没有持续下降,如果卡住不动,多半是裂缝边缘定位不稳定,可以尝试加大epoch或者换yolov8m。
5.3 显存和速度的平衡策略
GPU资源有限时,别盲目上大模型。yolov8s在GTX 1060 6GB上跑640输入,推理速度大概30到40毫秒每张,训练batch 8勉强够用。再往上加yolov8l就明显吃力。这种情况下我一般保持yolov8s,把imgsz当精度调节开关:训练用640,推理时按需调到1024或1280。推理阶段只有前向传播,显存占用比训练小很多,大多数6GB显卡都能撑住1280的推理。反过来,如果模型要部署到RK3588这类边缘设备,我建议直接训练时就选yolov8n,并全程用640输入,把量化损失提前考虑进去。
6. 从实验到现场:ONNX导出与实时推理的进阶做法
6.1 导出ONNX与TensorRT加速
训练完的best.pt是PyTorch格式,在现场设备上加载会依赖完整训练框架。我一般会先导出ONNX,再做TensorRT或RKNN的转换。导出命令很简单:
from ultralytics import YOLO model = YOLO('weights/best.pt') model.export(format='onnx', imgsz=640, opset=12, simplify=True)导出后目录下会多一个best.onnx。逻辑说明是:ONNX把模型的计算图固化下来,推理不需要再依赖Python训练框架。opset=12是通用性较好的算子版本,太新可能在老设备上不识别;simplify=True会删除一些冗余的reshape操作。做完这一步,在NVIDIA设备上可以继续用TensorRT加速,在瑞芯微RK3588平台上则用RKNN-Toolkit转成rknn格式,转换前先确认target_platform是rk3588。
6.2 接摄像头做实时裂缝检测
现场巡检最常见的需求是接摄像头或视频流,实时检测裂缝。下面这个脚本可以直接改造成现场巡检工具:
import cv2 from ultralytics import YOLO model = YOLO('weights/best.pt') cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() if not ret: break resized = cv2.resize(frame, (640, 640)) results = model.predict(resized, conf=0.2, iou=0.5, verbose=False)[0] annotated = results.plot() cv2.imshow('crack detect', annotated) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()逻辑说明:从摄像头读帧,resize到640再喂模型,效率比直接用原图推理高一些,因为省去了模型内部的部分缩放计算。results.plot()是ultralytics封装的方法,直接把绘制好框和置信度的图输出,不用自己再循环坐标画矩形。现场光照变化剧烈时,建议在resize前加一次直方图均衡化或CLAHE,裂缝对比度会明显提升。
参数说明:cv2.VideoCapture(0)是默认摄像头,外接USB相机改成1或2。conf=0.2是现场巡检的常用值,宁可多几个误检框也要保证不漏检,后续可以用跟踪算法过滤掉单帧误检。
这套资源的价值在于省掉了最麻烦的"从零准备数据到跑通YOLOv8训练"的过程。我从解压到第一次完整跑通训练和推理,花了大半天时间,大部分时间耗在环境和数据路径适配。从那以后我每次复现类似项目,都会强制走一遍同样的流程:先看data.yaml和weights,再跑推理验证,最后再碰训练参数——这套顺序帮我省掉了大量无意义的报错排障时间。希望帮到你。
本文还有配套的精品资源,点击获取