简介:基于YOLOV8实现的路面、桥梁与墙体裂缝识别Python项目,面向深度学习学习者与计算机视觉开发者,适用于结构表面缺陷检测、智能巡检等场景。项目源码已本地编译可运行,评审分95分以上,难度适中,内容经助教审定,适合作为课程设计、毕业设计或工程落地的参考基线。压缩包共78个文件,仅2.55MB,包含21个Python核心脚本、26个YAML模型与训练配置、18个pyc编译文件、5个PNG、4个JPEG、2个JPG图像样本及2个Markdown说明文档,模型配置、训练代码、测试图片和文档笔记一一对应,目录结构清晰。目前已有130人学习下载。通过学习能够掌握YOLOv8从数据准备、模型训练到预测可视化的完整流程,代码中附带的输出截图和预测脚本可辅助快速理解检测效果的调参与评估方法。
1. YOLOV8裂缝识别:一套能跑通的路面桥梁墙体检测源码
做结构巡检的人对裂缝检测都不陌生,传统办法靠肉眼贴着墙看,或者拿着裂缝测宽仪一点点量,效率低而且主观性很强。用深度学习做裂缝识别这几年很热,YOLOV8是其中综合性价比最高的方案之一——检测速度快、训练配置简单、源码生态成熟。这份资源就是一个基于Python和YOLOV8的路面、桥梁、墙体裂缝识别项目,压缩包里带了完整源码、文档说明和测试图片,解压后本地编译就能跑。我拆完这套资源后的感受是:它不是一个只丢给你一堆代码的黑匣子,而是从推理脚本到训练流程都给全了,适合正在做毕业设计、课程项目或者结构检测相关课题的人直接拿去做二次开发。
2. 源码构成与推理实测:detect_predict.py 怎么把权重变成裂缝框
2.1 压缩包里的源码脉络:从目录结构看项目分工
拿到压缩包先别急着运行,花两分钟把目录结构过一遍。这个项目用的是Ultralytics YOLOV8标准工程结构,核心脚本是根目录下的detect_predict.py,images目录里放了测试图片,包括墙面裂缝、路面裂缝的实拍图,还有screenshot目录存了运行截图,方便你对比预测前后的效果。整个项目的运行入口很集中,不像有些开源项目散落一堆脚本找不到主文件。
Python-Yolov8-crack-recogntion-for-road-bridge-wall-main/ ├── detect_predict.py # 推理脚本,加载模型并预测 ├── ultralytics/ # YOLOV8核心库目录 ├── images/ # 测试图片(路面、桥梁、墙体裂缝) ├── screenshot/ # 运行效果截图 ├── yolov8_out/ # 预测结果输出目录 └── requirements.txt # 依赖清单detect_predict.py是这份资源的主入口,它做的事情说起来很简单:加载训练好的YOLOV8权重,读入一张图片,经过模型前向推理输出目标框,再把框画到原图上保存。实际工程里这套逻辑可以被包装成API接口,也可以接进无人机巡检的实时视频流。我一般会先跑通这个脚本确认环境没问题,再去看权重文件和训练配置,因为推理能跑通说明整个依赖链是完整的。
2.2 一条命令跑通推理:detect_predict.py 的运行与输出
这套源码在Python 3.8以上的环境里都能跑,核心依赖是ultralytics、torch、opencv-python。安装依赖后直接在项目根目录执行下面的命令:
pip install -r requirements.txt python detect_predict.py如果你只是想快速验证,也可以不安装requirements.txt里的全部依赖,只装ultralytics和opencv-python,因为推理阶段用到的核心库就这两个。运行结束后,程序会在yolov8_out目录下生成带检测框的结果图。第一次跑通看到裂缝被框出来的那一刻,整个项目就算立住了。
这里有个参数需要留意:脚本里的model_path变量指向权重文件。如果资源里附带的是best.pt,那它通常是在某个裂缝数据集上训练出来的;如果只有yolov8n.pt这种官方预训练权重,那检测效果就只是COCO80类里的通用能力,并不专门针对裂缝。我第一遍拆这个项目的时候,先看的是detect_predict.py里模型加载部分的代码,确认权重路径指对了,再跑推理。
# detect_predict.py 核心推理逻辑(简化版) from ultralytics import YOLO # 加载模型权重 model = YOLO("best.pt") # 换成项目里实际的权重文件路径 # 对单张图片进行推理 results = model.predict( source="images/1.png", # 输入图片路径 conf=0.25, # 置信度阈值,低于此值的检测框会被过滤 save=True, # 保存标注后的结果图 project="yolov8_out", # 输出目录 name="exp", # 输出子目录名 exist_ok=True # 允许覆盖已有结果 ) # 打印检测到的目标信息 for result in results: boxes = result.boxes if boxes is not None: for box in boxes: print(f"类别: {result.names[int(box.cls)]}, " f"置信度: {float(box.conf):.2f}, " f"坐标: {box.xyxy.tolist()}")代码逻辑分三段:第一段初始化YOLO实例并加载权重;第二段调用predict方法做前向推理,source参数可以传图片路径、文件夹路径甚至视频流;第三段遍历results对象读取检测框数据。conf参数控制置信度阈值,默认0.25意味着模型对某个区域是裂缝的把握低于25%时就丢弃,调高它会减少误检但可能漏掉细小裂缝,调低则相反。
2.3 预测结果长什么样:置信度、类别与坐标的读取逻辑
YOLOV8的预测结果封装在results对象里,很多人第一次接触时不知道从哪里取坐标。result.boxes里存了检测框的全部信息:xyxy是左上角和右下角坐标,xywh是中心点和宽高,conf是置信度,cls是类别索引。裂缝识别项目通常只训练一个类别"crack",所以cls基本都是0。
# 手动遍历检测框并过滤低置信度结果 for result in results: for box in result.boxes: conf = float(box.conf[0]) if conf < 0.5: # 只保留高置信度结果 continue x1, y1, x2, y2 = [int(v) for v in box.xyxy[0].tolist()] cls_id = int(box.cls[0]) label = result.names[cls_id] print(f"{label} {conf:.3f} ({x1}, {y1}) -> ({x2}, {y2})")实际做巡检项目时,这个遍历逻辑会改成把坐标写入CSV或者数据库,方便后续统计裂缝位置和数量。我习惯把置信度阈值从0.25提到0.4以上做路面裂缝检测,因为路面背景纹理复杂,低置信度的框大多是把沥青颗粒误判成了裂缝。
3. 训练自己的裂缝数据集:标注、yaml 与参数调优
3.1 裂缝数据从哪来:拍摄规范与 Labelme 标注
资源自带的模型能覆盖常见场景,但换一个工地、换一种光照条件,检测效果可能就掉了。这时候你需要用自己的数据训练模型。裂缝数据集的核心痛点是标注一致性——同样一条裂缝,不同人画框的标准差别很大,模型学出来的特征就飘。
我一般用Labelme做标注,它对裂缝这种不规则目标比较友好。每张图片里所有的裂缝都要框出来,判断标准是:肉眼能明显分辨的裂缝必须框,宽度小于2像素的微裂缝建议框,因为模型要学的就是这些早期损伤信号。图片分辨率统一缩放到1280×720左右再标注,原始尺寸太大的话,框的坐标在缩放后会错位。
# 安装并启动 Labelme pip install labelme labelme标注完成后每个图片会对应一个同名JSON文件,里面记录了多边形顶点坐标和类别名。Labelme导出的JSON是COCO格式的polygon,不能直接喂给YOLOV8训练,需要先转成YOLO的txt格式——每行一个目标,格式是"class_id x_center y_center width height",四个值都是相对于图片宽高的比例。
3.2 从 JSON 到 YOLO 格式:标注转换脚本
转换脚本是训练前必须写的一段代码。Labelme的JSON里存的是多边形顶点,YOLO需要的是外接矩形框。这里有个细节:裂缝往往是长条形的,外接矩形会框进大量背景,但YOLOV8的anchor机制能适应这种长宽比,直接用外接矩形就行,不需要额外做旋转框处理。
# json2yolo.py 将 Labelme 标注转换为 YOLO 格式 import json import os from glob import glob def convert_labelme_to_yolo(json_path, output_dir, class_names): with open(json_path, 'r', encoding='utf-8') as f: data = json.load(f) img_w = data['imageWidth'] img_h = data['imageHeight'] # 获取图片文件名并构造输出 txt 路径 base_name = os.path.splitext(os.path.basename(json_path))[0] txt_path = os.path.join(output_dir, base_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'] x_min = min(p[0] for p in points) y_min = min(p[1] for p in points) x_max = max(p[0] for p in points) y_max = max(p[1] for p in points) # 转换为归一化的 YOLO 格式坐标 x_center = (x_min + x_max) / 2 / img_w y_center = (y_min + y_max) / 2 / img_h width = (x_max - x_min) / img_w height = (y_max - y_min) / img_h lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}") with open(txt_path, 'w') as f: f.write('\n'.join(lines)) # 使用示例 class_names = ['crack'] # 类别列表,顺序决定了 class_id json_files = glob('labels_json/*.json') os.makedirs('labels_txt', exist_ok=True) for jf in json_files: convert_labelme_to_yolo(jf, 'labels_txt', class_names) print(f"转换完成,共处理 {len(json_files)} 个文件")这段代码的核心逻辑是从JSON的shapes字段里取出每个目标的类别和多边形顶点,遍历所有顶点求出外接矩形的左上角和右下角,再转换成归一化坐标。class_names的顺序很重要,训练时yaml文件里names列表的顺序必须和这里完全一致。如果漏掉某个label没写进class_names,对应的框就被静默丢弃了,训练时你会困惑为什么有些图片没有标注文件。
转换完检查一下txt文件内容是否正常。我习惯随机打开几个txt,看看坐标值是否都在0到1之间、有没有空文件——空文件说明原图的标注全部被过滤了,这个问题要提前发现,不然训练时模型在这些图上看不到任何目标。
3.3 训练配置与启动:crack.yaml 和训练参数详解
YOLOV8用yaml文件描述数据集配置,包括训练集和验证集路径、类别数量、类别名称。文件夹结构建议按YOLO的标准格式组织:
dataset/ ├── images/ │ ├── train/ # 训练图片 │ └── val/ # 验证图片 └── labels/ ├── train/ # 训练标注 txt └── val/ # 验证标注 txtcrack.yaml内容如下:
# crack.yaml 数据集配置文件 path: ./dataset # 数据集根目录 train: images/train # 训练图片相对路径 val: images/val # 验证图片相对路径 nc: 1 # 类别数量,裂缝只算一类 names: ['crack'] # 类别名称列表训练命令可以直接指定yaml文件路径:
yolo train data=crack.yaml model=yolov8n.pt epochs=100 imgsz=640 batch=8这里每个参数都值得细说。model=yolov8n.pt表示用YOLOV8nano的预训练权重做初始化,nano是最小的变体,显存占用低,适合在消费级显卡上训练。如果显卡是RTX 3060以上的级别,可以换yolov8s.pt,精度会高一截。epochs是训练轮数,裂缝检测这种单一类别任务100轮足够,再多就容易过拟合。imgsz是训练时输入图片的尺寸,640是速度和精度的常规平衡点;如果裂缝很细,可以试试800甚至960,但显存占用会明显增大。batch是批大小,默认8,显存不够就降到4或者2。
训练过程中关注两个指标:box_loss和cls_loss。box_loss是检测框的回归损失,cls_loss是分类损失。正常情况下两者都持续下降,如果cls_loss降不下去,先查数据集里有没有空标注文件或者类别标错的图。
4. 推理脚本二次开发:置信度、NMS 与批量检测
4.1 置信度与 NMS:两个参数决定漏检和误检的平衡
YOLOV8后处理阶段有两个参数直接影响输出质量:置信度阈值conf和NMS的IoU阈值iou。conf决定一个检测框保留还是丢弃,iou决定两个重叠的框是否合并。对于裂缝检测,这两个参数需要联动调,单独调一个效果有限。
from ultralytics import YOLO model = YOLO("best.pt") # 高精度模式:严格过滤低置信度,NMS 也设严 results = model.predict( source="images/", conf=0.5, iou=0.45, save=True, project="yolov8_out", name="high_precision", exist_ok=True ) # 高召回模式:多保留可疑框,NMS 放宽 results = model.predict( source="images/", conf=0.2, iou=0.6, save=True, project="yolov8_out", name="high_recall", exist_ok=True )判断用哪个阈值,取决于场景。桥梁定检时裂缝漏检的后果比误检严重,我会把conf放到0.3以下,让模型把疑似区域都标出来,人工再复查;如果是自动化流水线做初筛,误检会浪费人力,conf提到0.6更合适。NMS方面,裂缝这种细长目标之间很少有大面积重叠,iou设0.45到0.5就够用,不需要调太高。
4.2 批量检测文件夹:把单图推理改成目录遍历
实际巡检不是一张张图手动跑,而是面对一个目录下成千上万的图片。detect_predict.py的predict方法已经支持传入文件夹路径,直接指定source为目录就能自动遍历全部图片。但如果你想在批量模式下加一些自定义逻辑——比如跳过已经检测过的图片、把结果汇总成报表——就需要自己写循环了。
# batch_predict.py 批量检测并汇总结果 from ultralytics import YOLO import os import csv model = YOLO("best.pt") img_dir = "inspection_images" output_csv = "detection_results.csv" results_data = [] img_extensions = ('.jpg', '.jpeg', '.png', '.bmp') for img_name in os.listdir(img_dir): if not img_name.lower().endswith(img_extensions): continue img_path = os.path.join(img_dir, img_name) results = model.predict( source=img_path, conf=0.3, save=True, project="yolov8_out", name="batch_run", exist_ok=True ) # 统计该图片中的裂缝数量 for result in results: num_cracks = len(result.boxes) if result.boxes is not None else 0 results_data.append([img_name, num_cracks]) print(f"{img_name}: 检测到 {num_cracks} 条裂缝") # 写入 CSV 报表 with open(output_csv, 'w', newline='', encoding='utf-8') as f: writer = csv.writer(f) writer.writerow(['图片名', '裂缝数量']) writer.writerows(results_data)这个脚本把逐张图片的检测结果汇总成CSV,方便后续导入Excel做统计。os.listdir遍历目录时依赖文件扩展名过滤,遇到大小写混合的.jpg和.JPG时用lower()做了统一。批量跑的时候建议把save参数设为False,先只收集结果,等筛选出重点图片再单独保存标注图,否则几千张图跑完磁盘空间会很紧张。
4.3 视频流与实时检测:cap 读帧的改造思路
结构巡检里视频检测也很常见——无人机沿着桥梁飞一圈,录一段视频,回来逐帧分析。YOLOV8的predict方法传视频路径就能直接检测,但帧率可能跟不上;更好的方案是用OpenCV逐帧读取,再喂给模型。
# video_predict.py 视频逐帧裂缝检测 import cv2 from ultralytics import YOLO model = YOLO("best.pt") video_path = "bridge_inspection.mp4" cap = cv2.VideoCapture(video_path) fps = cap.get(cv2.CAP_PROP_FPS) width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 初始化视频写入器 out = cv2.VideoWriter( "bridge_inspection_result.mp4", cv2.VideoWriter_fourcc(*'mp4v'), fps, (width, height) ) frame_count = 0 while cap.isOpened(): ret, frame = cap.read() if not ret: break # 每隔 3 帧检测一次,控制耗时 if frame_count % 3 == 0: results = model.predict(source=frame, conf=0.3, verbose=False) annotated_frame = results[0].plot() else: annotated_frame = frame out.write(annotated_frame) frame_count += 1 cap.release() out.release() print(f"处理完成,共 {frame_count} 帧")逐帧检测的耗时瓶颈在模型推理上。这里每隔3帧检测一次,中间两帧直接复用原画面,巡检视频中裂缝在连续帧中的位置变化不大,这种做法能省掉三分之二的推理时间。如果你对实时性要求更高,可以把模型换成yolov8n.pt并用TensorRT加速。
5. 避坑与常见问题:环境、显存与预测结果排查
5.1 ultralytics 版本升级导致 API 不兼容
现象:代码报错AttributeError: module 'ultralytics' has no attribute 'YOLO',或者train参数解析失败。
原因:ultralytics库更新很快,不同版本之间API有差异。旧版本用model.predict()传参,新版本改成了model.predict()支持更多参数但部分旧写法不兼容;装成最新版反而把老接口废掉了。
解决:按照requirements.txt里锁定的版本安装,不要用pip install ultralytics直接装最新版。我一般先建虚拟环境再装依赖,这样不同项目之间版本不会互相污染。
python -m venv venv venv\Scripts\activate # Windows # 或 source venv/bin/activate # Linux/Mac pip install -r requirements.txt如果已经装了新版想降级,先卸载再装指定版本:pip uninstall ultralytics && pip install ultralytics==8.0.20。
5.2 训练时显存溢出,程序直接崩溃
- 现象:训练刚开始几十秒就报OutOfMemoryError,或者CUDA error: device-side assert triggered。
- 原因:batch size设太大、imgsz设太大,或者显卡显存不够。裂缝数据集里的原图经常是几千万像素的航拍图,直接训练必爆显存。
- 解决:先看显卡型号,RTX 3060 12G的情况下batch=8、imgsz=640是安全的。如果还不够,batch降到2,imgsz降到480。改参数后模型精度会受一点影响,但至少能跑完训练。还有个办法是开启梯度累积,Ultralytics的train方法里没有直接暴露这个参数,可以通过设置batch=2配合accumulate参数缓解。
5.3 标注框太小导致训练不收敛
- 现象:训练几十轮后loss还在高位波动,验证集mAP@0.5不到0.1。
- 原因:裂缝本身是细长目标,标注框的面积可能只占整张图的千分之一甚至更少。YOLO系列对微小目标的检测天生吃力,框太小会让正负样本极度不平衡。
- 解决:训练时把imgsz调大,让目标在输入图像中占据更多像素。原始图是1920×1080的话,imgsz设960或1280,模型能看到更多细节。数据侧可以裁切——把大图切成多个512×512的小图再训练,裂缝在切分后相对尺寸会大很多。这是裂缝检测项目里最有效的手段。
5.4 推理结果全空白,一张裂缝都没框出来
- 现象:程序正常运行,也生成了输出图,但图上没有任何检测框。
- 原因:首先是权重不对,加载的模型没有见过裂缝数据;其次是置信度阈值太高,微弱裂缝的置信度普遍低于0.5;再就是推理图片的色调和训练集差异大。
- 解决:用项目自带的测试图片跑一遍,确认模型本身没问题;然后调低conf到0.1看看有没有框;最后检查输入图片是不是有严重的曝光问题,过曝或过暗的图片可以先用OpenCV做直方图均衡化再送进模型。
5.5 CPU 推理慢到没法用
- 现象:一张720p的图片在CPU上跑yolov8s要1秒多,视频检测基本是幻灯片效果。
- 原因:没有调用GPU推理,或者用的是s/l这种大模型。
- 解决:先确认torch.cuda.is_available()是否为True,如果环境没有CUDA版torch,重装:pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118。然后把推理模型换成yolov8n.pt,速度能快三四倍。检测时把imgsz从默认640降到480,推理耗时进一步缩短。
6. 进阶验证:从指标曲线到 ONNX 平台迁移
6.1 用混淆矩阵和 PR 曲线验证模型真实水平
只看mAP数字很容易被误导。模型训练完后,我会跑一次model.val()生成混淆矩阵和PR曲线,这两张图比总分更能说明问题。对于裂缝检测,特别注意一下precision和recall的走势——PR曲线下的面积大但曲线头部掉得快,说明模型对高置信度的裂缝识别好,对模糊裂缝识别差,这时候应该关注数据侧的标注质量而不是盲目调参。
from ultralytics import YOLO # 加载训练好的模型,在验证集上评估 model = YOLO("runs/train/exp/weights/best.pt") metrics = model.val(data="crack.yaml", split="val") # 打印关键指标 print(f"mAP@0.5: {metrics.box.map50:.4f}") print(f"mAP@0.5:0.95: {metrics.box.map:.4f}") print(f"精确率: {metrics.box.mp:.4f}") print(f"召回率: {metrics.box.mr:.4f}")6.2 导出 ONNX 提升部署效率
训练好的模型如果要部署到无人机机载电脑或者边缘设备,ONNX格式是比PyTorch更通用也更快的中转格式。导出过程一行代码,但导出的参数要选对。
# 导出 ONNX 模型 model = YOLO("best.pt") model.export(format="onnx", imgsz=640, opset=12)导出的best.onnx可以用ONNX Runtime跑,在CPU上比PyTorch原模型快30%左右,在RK3588这类NPU设备上可以直接用板端推理框架加载。导出后务必用onnxruntime验证一下和PyTorch推理结果是否一致,常见问题是opset版本太高导致某些算子不兼容。
从那以后我每次训练完模型,都强制走一遍导出ONNX + onnxruntime验证 + 样本图片对比的流程,这套组合拳帮我避免过好多次部署现场的翻车事故。裂缝识别这个项目从跑通到落地,最关键的还是把数据工作做扎实——这一行走到位了,模型效果不会差。希望帮到你。
本文还有配套的精品资源,点击获取