☰
基于YOLOv8与YOLO11的混凝土裂缝检测系统实现与部署
2026/10/18 8:15:45 网站建设 项目流程

混凝土裂缝检测这件事,我前前后后折腾了快半年。最早接触这个需求是在一个结构健康监测的项目里:施工方要求定期巡检桥墩和楼板,光是整理现场拍回来的照片就让人头大——几千张图,裂缝形态各异,光照忽明忽暗,靠人眼一张张看,眼睛看花不说,漏判误判还得返工。后来我尝试用深度学习目标检测模型来替代人工筛查,在YOLOv8和YOLO11两代框架里各训练了一套混凝土裂缝检测模型,配合OpenCV做图像预处理和实时推理,总算是把整个流程跑通了。这篇博文就把这套系统的完整实现过程整理出来:从数据集标注、模型训练、参数调优,到OpenCV部署推理、常见坑避雷,想入坑混凝土缺陷检测的工程师和同学可以直接照着做。

1. 项目整体设计与思路拆解

1.1 为什么是YOLO框架,而不是传统的图像处理或分类模型

混凝土裂缝检测说白了就是一个“在图片里找到裂缝并框出来”的问题。早期尝试过传统OpenCV边缘检测(Canny、Sobel)加形态学处理,效果不稳定:背景里的钢筋、模板纹理、水泥浮浆都会产生大量干扰边缘,阈值参数换个场景就得重新调。后来试过分割模型(U-Net之类),精度不错但标注成本太高,每条裂缝都要逐像素描边,工期根本耗不起。

YOLO系列走的是“边界框回归”路线,标注只需画框框住裂缝,训练和推理速度快,非常适合工程现场的实时巡检场景。我选择同时试YOLOv8和YOLO11两个版本,主要出于三个考虑:一是对比两代模型在同一数据集上的精度和速度差异,看哪个更适合部署到边缘设备;二是YOLO11在轻量化模块上做了调整,想实测它在中低端显卡和Jetson这类板子上的表现;三是Ultralytics框架统一了训练和推理接口,换模型成本非常低,完全可以并行做实验。

1.2 技术方案选型:从数据到部署的整体设计

整个系统分成四条链路来搭:数据链路、训练链路、推理链路和展示链路。数据链路负责采集现场裂缝图片、标注并切分训练集验证集;训练链路跑YOLOv8和YOLO11的检测训练,输出best.pt权重文件;推理链路用OpenCV读取图片、视频或摄像头流,调用模型输出检测框;展示链路把检测结果绘制在原图上,支持实时显示和结果保存。

这里有个关键设计决定要在动工前想清楚:检测类别怎么定义。我一开始只设了“裂缝”一个类别,后来发现不同类型裂缝的修复方案完全不同——横向裂缝可能是温度应力造成的,纵向裂缝可能是沉降引起的,网状裂缝大概率是材料老化。所以我在第二版数据集里把类别扩成了“横向裂缝、纵向裂缝、网状裂缝”三类,虽然标注工作量上去了,但后续巡检报告的参考价值高了很多。如果你的项目只是做“有没有裂缝”的粗筛,单类别就够用了;如果要做缺陷分级,从一开始就分好类,否则后期重新标注训练的代价会很高。

2. 数据集准备:采集、标注与OpenCV预处理

2.1 数据从哪里来,怎么判断够不够用

混凝土裂缝数据集的来源一般有两条路:一条是现场采集,带上相机或手机去工地、桥梁、隧道拍实景;另一条是用公开数据集做补充(公开的路面裂缝数据集、混凝土桥梁裂缝数据集等)。现场采集时有一点要特别注意:不要只拍清晰的高清裂缝。真实工况里裂缝可能很小、很模糊、被阴影遮挡、背景杂乱,这些“难样本”如果数据集里不够,模型学了之后在真实场景基本不能用。我第一版模型就是在过度“干净”的数据上训练的,到了现场对着一堵粗毛坯墙各种漏检,后来补了一大批带噪声、反光和遮挡的图片进去,指标立刻好看了很多。

数据量方面,单类别“裂缝检测”大概需要多少张呢?我的实践经验是:单类别检测任务,清晰标注的图片数量在1500到3000张区间比较稳妥;如果是三类裂缝任务,建议每类至少800张,总数据量保持在3000张以上。数据太少模型容易过拟合,太多则标注成本太高,不必盲目追求量。数据增强可以在一定程度上弥补数量不足的问题,Ultralytics框架默认开启了Mosaic、翻转、亮度扰动等增强策略,实际训练中即使只有800张原图也能跑出可用的模型,但前提是原图的多样性要足够。

2.2 标注工具与YOLO格式转换:一张图看懂标注文件结构

标注工具我用的是LabelImg,它支持直接导出YOLO格式的txt文件,操作逻辑就是打开图片、画框、选择类别、保存,非常简单。标注完的文件目录结构长这样:

crack_dataset/ ├── images/ │ ├── train/ # 训练集图片 │ └── val/ # 验证集图片 ├── labels/ │ ├── train/ # 训练集标签txt │ └── val/ # 验证集标签txt └── crack.yaml # 数据集配置文件

每个txt文件对应一张图片,里面每一行是一个目标框,格式为:

class_id x_center y_center width height

注意这里的x_center、y_center、width、height都是归一化坐标,即像素值除以图片宽度和高度,取值在0到1之间。我最开始写了一个转换脚本时忘了归一化,直接把像素坐标写进去,训练时模型loss一直不收敛,查了老半天才发现Format不对。如果你用的是Roboflow等在线标注平台,导出时会自动转好格式,用LabelImg时就要特别注意。

标注训练集和验证集的比例建议8:2或9:1,我习惯比例是8:2。还有一个容易忽略的点:同一场景、同一角度、同一光照下拍的连续照片不要同时分进训练集和验证集,否则验证集和训练集太相似,验证指标虚高,到了真实场景就露馅了。通常的做法是先按场景分组,再把不同场景的图片随机分配到两个集合。

2.3 OpenCV预处理:提升训练效果的关键步骤

虽然深度模型理论上可以学习各种光照变化,但在训练前用OpenCV做一遍基础预处理,能有效减少数据中的噪声干扰,让模型把注意力集中在裂缝本身的纹理特征上。我在实际项目里主要做了两步:

第一步是灰度化与对比度增强。裂缝在灰度图像中的特征是“局部暗纹理”,和周围混凝土的灰度差异是核心判别依据。使用OpenCV的CLAHE(对比度受限自适应直方图均衡)来增强局部对比度,比直接用全局直方图均衡效果好得多,因为光照不均匀时全局均衡会把暗部细节继续压暗。核心代码只有几行:

import cv2 img = cv2.imread("raw_crack.jpg") # 读取原始图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转灰度 clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) enhanced = clahe.apply(gray) # 自适应直方图均衡 cv2.imwrite("enhanced.jpg", enhanced)

第二步是去噪。工地上拍的照片难免有噪点,用双边滤波可以在去除噪声的同时保留边缘纹理,不像高斯滤波那样会把裂缝边缘磨糊。数据增强阶段的双边滤波我设置的是d=5、sigmaColor=50、sigmaSpace=50,实测既去了噪,又没伤到裂缝细节。

关于预处理有一个重要提醒:训练和推理阶段的预处理逻辑要尽量保持一致。如果你在训练前对图片做了CLAHE,那么推理阶段的输入图片也应该走一遍CLAHE,否则图像分布不一致会导致推理效果掉点。最好把预处理封装成一个共用的函数,训练和推理同时调用,避免两边各写各的。

2.4 数据增强:在不增加标注量的前提下扩充数据

Ultralytics框架在训练时默认开启了一系列数据增强,包括Mosaic(四图拼接)、随机翻转、缩放、色域变换等。这些参数是数据增强策略的核心,位于训练配置文件中。我一般会在默认配置的基础上做两处调整。

一是Mosaic增强的概率。Mosaic把四张图拼成一张,对提升小目标(细长裂缝)检测很有帮助,但它会在每轮epoch中随机组合图片,导致淡化了单张图片的原始分布,如果训练集本身规模不大,最后几个epoch建议关闭Mosaic,让模型在更接近真实分布的图片上“收尾收敛”。Ultralytics提供了参数控制,我通常在前90%的epoch保持Mosaic开启,最后10%的epoch关闭。

二是针对裂缝这种长条形目标,增加旋转和小角度仿射变换的强度范围。裂缝可能在任意方向上,不加旋转会导致模型对斜向裂缝的泛化能力差。我设置的旋转范围是±30度,缩放在0.5到1.5倍之间,实测对斜裂缝和远近尺度变化的效果提升明显。

3. 环境搭建与模型训练完整实操

3.1 训练环境准备:硬件需求和依赖安装

训练YOLOv8/YOLO11检测模型,硬件门槛其实没有想象中那么高。我的开发机配置是:一块中端显卡(8GB显存)、i5级别CPU、32GB内存。在这个配置下,用YOLOv8n和YOLO11n参数量较小的模型,batch size设为16,imgsz设为640,显存占用大约在4GB到5GB左右,跑100个epoch大概需要4到6个小时。如果只有CPU,也能训练,但一个epoch可能要十分钟以上,建议先用小模型和低分辨率把流程跑通。

依赖安装直接用pip,简单直接:

pip install ultralytics opencv-python

这里提醒一个常见问题:ultralytics库升级很频繁,不同大版本之间的API可能有变化,把ultralytics版本固定在一个稳定版本上(我用的版本是8.3.x,那个版本下YOLO11已经支持),免得跑着跑着因为版本兼容性问题报错。如果担心Python环境混乱,用conda建一个独立虚拟环境最好。

3.2 数据集配置文件:crack.yaml怎么写

在工程目录下新建一个crack.yaml,内容如下:

path: D:/crack_dataset # 数据集根目录,建议用绝对路径 train: images/train # 训练集图片目录,相对于根目录 val: images/val # 验证集图片目录 nc: 1 # 类别数量,如果你的缺陷分三类就写3 names: 0: crack # 类别名称,按顺序排列

这里有一个很容易踩的坑:path路径里不要有中文和空格。有些跑在Windows上的项目把数据集放在“D:/混凝土检测/裂缝数据”这样的目录下,结果训练时读取图片路径报错,排查半天才发现是中文路径编码问题。稳妥起见,数据集根目录用纯英文名称。

3.3 YOLOv8训练实操:命令、参数与日志解读

配置文件准备好后,在命令行中切换到工作目录,执行训练命令:

yolo task=detect mode=train model=yolov8n.pt data=crack.yaml \ epochs=100 batch=16 imgsz=640 device=0 patience=15 \ project=runs_v8 name=crack_yolov8n

逐项说明这几个参数的含义(这些是从实际踩坑中总结出来的):

  • model=yolov8n.pt:n代表nano版本,是YOLOv8里参数量最小、速度最快的模型。首次训练建议先用nano跑通全流程,确认数据和配置没问题后,再换m或l版本提高精度。
  • epochs=100:训练轮数。不要盲目加多,epoch越多过拟合风险越大,一般50到200轮都能收敛。配合patience早停机制(15轮验证集指标不再提升就自动停止),反而比自己硬定epoch数量要科学。
  • batch=16:批大小。显卡显存不够就调小到8或4,但batch太小会显著影响收敛速度和稳定性。
  • imgsz=640:输入图片尺寸,YOLO系列的标准输入大小。对裂缝来说,640分辨率的输入对小裂缝的检出是底线,如果原图分辨率很高(比如4000万像素相机拍的照片),直接缩到640会丢失细微裂缝信息,建议先滑窗裁剪再缩放。
  • patience=15:早停耐心值,15轮验证集mAP不涨就提前结束训练,省时间。

训练过程中终端会打印每个epoch的loss值和验证指标,关键指标看这几个:box_loss(边框回归损失,数值持续下降则说明模型在学习定位裂缝)、cls_loss(分类损失,下降说明类别判别在学习)、mAP50(IoU阈值为0.5时的平均精度,达到0.6以上通常就可用)、mAP50-95(更严格的综合指标,需要追求更高精度时再重点关注)。训练结束后,best.pt和last.pt会保存在runs_v8/crack_yolov8n/weights/目录下,best.pt是验证集表现最好的权重,后面部署推理全部用best.pt。

3.4 YOLO11训练实操与模型对比

YOLO11是Ultralytics在2024年推出的新一代目标检测框架,它吸收了此前YOLO系列的经验,在轻量化和特征提取效率上做了改进。从官方提供的预训练模型看,YOLO11n的参数量比YOLOv8n更少,理论上推理速度更快。但理论归理论,实际跑一跑才知道在我们混凝土裂缝数据上表现如何。

训练YOLO11的命令和YOLOv8几乎完全一致:

yolo task=detect mode=train model=yolo11n.pt data=crack.yaml \ epochs=100 batch=16 imgsz=640 device=0 patience=15 \ project=runs_11 name=crack_yolo11n

跑完之后把两个模型的验证结果放在一起对比。我拿一组真实测试数据(包括100张白天拍摄、50张阴天拍摄、50张带阴影遮挡的图片)做了对比测试,结论是:YOLO11n在正常光照下的mAP50和YOLOv8n差距不大,但在阴天和低对比度场景下,YOLO11n的漏检率明显更低;推理速度方面,在相同显卡上YOEO11n每帧处理时间比YOLOv8n缩短了大约15%。如果你部署的设备性能比较紧张,YOLO11是更好的选择。

一个非常关键的经验:不要只看最佳验证指标就决定用哪个模型,要拿一批训练集和验证集之外的现场实测图片做盲测。验证集毕竟只是原始数据切出来的,数据分布和现场真实情况有差异。我之前两个模型验证mAP都差不多,但在现场实际拍摄的视频里测试,一个模型对暗部裂缝漏检严重,另一个就好很多。你的最终选择应该以盲测结果为准,而不是训练日志里那一串数字。

3.5 训练过程中的资源监控和中断恢复技巧

训练跑了很久突然中断是件让人崩溃的事。Ultralytics框架在训练过程中会持续保存权重,如果是中途断电或电脑重启,可以用resume参数从上次保存的状态继续训练:

yolo task=detect mode=train model=runs_v8/crack_yolov8n/weights/last.pt \ resume=True

平时训练时我习惯用GPU-Z或nvidia-smi监控显存占用和温度。显存占用超过硬件上限的90%说明batch或imgsz设大了,需要调小。显卡温度超过80℃时最好检查散热,否则训练到一半出现CUDA out of memory或者driver reset,前面跑的epoch全部作废。

4. 推理部署与检测系统集成

4.1 用训练好的模型做图片检测

训练完成后,对单张图片推理最简单的方式是使用命令行:

yolo task=detect mode=predict model=runs_v8/crack_yolov8n/weights/best.pt \ source=test_images/conf=0.25 device=0 save=True

不过工程化部署还是写Python脚本更灵活。用Ultralytics的Python API进行推理:

from ultralytics import YOLO model = YOLO("runs_v8/crack_yolov8n/weights/best.pt") results = model.predict("test_01.jpg", conf=0.3, iou=0.5) for r in results: boxes = r.boxes for box in boxes: cls_id = int(box.cls[0]) # 类别ID conf = float(box.conf[0]) # 置信度 xyxy = box.xyxy[0].tolist() # 左上角右下角坐标 print(f"类别: {cls_id}, 置信度: {conf:.2f}, 坐标: {xyxy}")

其中conf参数是置信度阈值,预测框的置信度低于这个值就会被过滤掉。裂缝检测场景由于“难样本”比较多,阈值不宜设得太高,0.25到0.35比较合适;如果设成0.5,很多真裂缝会被漏掉。iou参数是NMS(非极大值抑制)的IoU阈值,控制重叠框的合并力度,默认0.5就够用。

这里有一个实际优化经验:如果一张大图上有很多细小裂缝,直接缩放成640推理会把小裂缝漏掉。我采用的方案是先做滑窗切图:把原图切成512×512或640×640的块,每个块单独推理,最后把结果坐标换算回原图坐标拼接起来。推理时间会成倍增加,但对小目标裂缝的召回率提升非常明显。

4.2 OpenCV读取摄像头和视频实时检测

要搭一个“混凝土缺陷检测系统”,通常还需要处理视频流。这里就要用到OpenCV来读取视频或摄像头画面,逐帧送入YOLO模型推理,再把检测框画在帧上。

用OpenCV读取摄像头并配合YOLO实时检测的完整代码:

import cv2 from ultralytics import YOLO model = YOLO("runs_v8/crack_yolov8n/weights/best.pt") cap = cv2.VideoCapture(0) # 0表示默认摄像头,视频文件则传文件路径 # cap = cv2.VideoCapture("site_video.mp4") while True: ret, frame = cap.read() if not ret: break results = model.predict(frame, conf=0.3, imgsz=640, verbose=False) for r in results: boxes = r.boxes for box in boxes: x1, y1, x2, y2 = map(int, box.xyxy[0].tolist()) conf = float(box.conf[0]) cls_id = int(box.cls[0]) cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), 2) label = f"crack {conf:.2f}" cv2.putText(frame, label, (x1, y1 - 8), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) cv2.imshow("Crack Detection", frame) if cv2.waitKey(1) & 0xFF == ord("q"): break cap.release() cv2.destroyAllWindows()

这段代码里有个值得注意的点:model.predict(frame, verbose=False)。默认情况下predict会输出大量日志信息,在实时视频流里每条都打印会拖慢速度,关掉verbose后帧率立刻提升。此外,OpenCV的waitKey(1)的1毫秒间隔保证了画面显示的流畅度。

如果检测速度和帧率上不去,可以从两个方向优化。第一是模型版本降级:把yolov8n或yolo11n作为实时部署选择,它们比m、l版本快很多,精度损失在裂缝场景里通常可以接受。第二是推理时用单张图片而非列表:接口支持传入列表做batch推理,可以累积帧到一定数量再批量推理,省去部分预处理开销。

4.3 集成一个简单的检测系统界面

现场工程师不会去看命令行输出,做一个简单的可视化界面很重要。我用Tkinter写了一个极简检测工具:左边是实时画面,右边是检测日志与统计信息(总检测数、平均置信度、当前fps)。核心逻辑就是把上面那套OpenCV逐帧检测代码包进一个类里,然后用Tkinter的Label显示图像帧。这类小工具不需要多复杂,能实时展示检测框、保存截图、导出检测报表就够了。

在实际部署时还有一个冷门但很实用的功能:检测结果自动存档。检测到裂缝时,自动把当前帧和检测框坐标保存成json或csv,这个文件后续可以直接导入Excel做巡检台账。裂缝的位置坐标、置信度、检测时间都有记录,评审会上报告一拉就出来,比手填表单可靠多了。

5. 常见问题与排查技巧实录

5.1 问题速查表:训练和部署阶段最常见的坑

我在整个项目中踩过的坑整理成一张表,按场景分类列出来,你如果遇到类似问题可以直接对着查:

问题现象可能原因解决方案
loss一直不下降标签格式错误(坐标未归一化)检查txt中坐标值是否在0~1之间
loss下降后快速回升学习率过大调低lr,可设为0.001或0.005
验证mAP很低(<0.3)数据量不足或类别标注错误增加数据量,检查是否有错标漏标
训练时CUDA out of memorybatch或imgsz超出显存batch调小、imgsz降到480或使用nano模型
检测时裂缝断断续续图片过曝或缩太小增强处理后推理,或用滑窗切图
边框框偏了(框到一半裂缝)标注框不够紧贴目标提高标注精度,框尽量紧贴裂缝外接矩形
实时检测帧率低模型太大或预处理耗时换nano模型、降低输入分辨率、关掉日志
训练集验证集都好、现场盲测差数据分布和现场不一致增加现场实拍难样本,重新训练

5.2 训练loss不收敛的排查经验

Loss不收敛是初学者最常遇到、也最打击信心的问题。有一次我训练自己的数据时,loss在0.3左右死活降不下去,后来我详细复盘了整个流程,发现是漏做归一化的低级错误——标签坐标直接用像素值写进txt,模型怎么学都达不到预期。所以排查顺序非常重要:

第一步检查标签文件。随机挑几个txt文件,看坐标是否在0到1之间,类别ID是否小于配置中的nc值。这个检查写一个小脚本批量扫一遍,几秒钟就能把所有标注文件查完。

第二步检查数据增强配置。如果旋转范围设得过大(比如±180度),边框会严重失真,模型学到的是“扭曲的裂缝”,自然无法收敛。旋转范围控制在±30度左右比较合适。

第三步检查网络结构是否适配数据规模。裂缝数据量少时,直接训练yolov8l这样的大模型,很容易过拟合而mAP上不去;换成nano或small版本,参数少了,反而更容易在小数据集上收敛。

5.3 漏检误检的优化思路:置信度、数据补充和后处理

模型跑起来了,但现场效果不好,漏检多、误检也多,这时候优先调整哪块?我的经验是先看置信度分布:把一批现场图片推理一遍,输出置信度的直方图。其实裂缝检测的漏检大多是轻度漏检,模型输出了0.1、0.2的低置信度框,被阈值卡掉了。此时把conf从0.5降到0.2,召回率往往能大幅提升,误检也不会增加太多——因为裂缝特征还是相对鲜明的,误伤的主要是那些纹理复杂的混凝土气泡区域。

如果降低阈值之后误检仍然很多,就要回数据中心补数据了。把误检图片加入训练集,对误检区域标注成“背景”或者标注成额外的干扰类别(比如“气泡”“划痕”),让模型去区分这些易混物。加了这种负样本后,误检率会有立竿见影的下降。

后处理层面,可以结合OpenCV做二次确认,用来过滤明显不合理的检测框。比如裂缝通常是细长条状,宽高比常常大于5:1,如果一个检测框接近正方形,那大概率是误检;同理,检测框面积过小(比如只有几十个像素)也可能是噪声。写一个简单的规则过滤这类框,能再减少一部分误检,但要注意别把真正的小裂缝也过滤掉了。

5.4 换到YOLO11时遇到的兼容性问题

YOLO11刚发布时,我把YOLOv8的代码换到YOLO11,一开始确实碰到过一些问题:

  • 预训练权重兼容性:YOLO11的backbone结构变化导致旧版本YOLOv8权重不能直接加载到YOLO11模型上。必须用官方预训练权重yolo11n.pt作为起点,不要尝试用yolov8n.pt凑合用。
  • onnx导出:如果要把模型导出成onnx格式部署,YOLO11的导出命令多了几个新参数,而且旧版onnx库版本太低会导出报错。升级onnxruntime到1.17以上,问题基本就解决了。
  • Python版本:yolo11对Python版本有最低要求,在Python 3.8的环境里装不上最新ultralytics,建议用Python 3.9及以上版本。

如果你部署时不方便使用ultralytics自带的推理接口,选择把best.pt转成onnx后用onnxruntime推理,转换命令是:

yolo export model=best.pt format=onnx imgsz=640 opset=12

这样部署时就不再依赖ultralytics库依赖环境,只要有onnxruntime就能跑,体积和加载速度都更友好。实际项目里我最终就是用的onnx版本部署到边缘设备上,省了不少环境配置的麻烦。

结语

做混凝土裂缝检测这个项目,我最深的一点体会是:别把模型当黑盒,也别指望一个调好的模型能通吃所有工地场景。不同光照、不同墙体材质、不同拍摄距离下,模型的输出差异非常明显,前期数据层面多花力气,比后期反复调参有效得多。到现在我的工作流已经固定成:现场采集数据、OpenCV预处理、LabelImg标注、YOLOv8和YOLO11并行训练、跑盲测选型、openvino或onnx部署。后续想往缺陷分级和自动生成巡检报告的方向扩展,技术上都是现成的,关键看你对业务场景的理解够不够深了。

最后再分享一个小技巧:训练时记得把每个epoch的验证集检测结果可视化存档(一行配置就能实现),空闲时翻看一下模型在不同轮次输出的检测框变化,你很容易就能看出模型是什么时候开始学会检测细裂缝的——这个过程对理解模型行为非常有帮助,比盯着loss曲线直观多了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询