
简介面向计算机视觉与深度学习方向的研究者与毕业生这份资源提供了基于YOLOv8的交通锥桶摆放合规性自动巡检系统完整项目适用于毕设、课程设计或大作业场景也可作为新手学习目标检测的进阶参考。压缩包共8个文件含3个Python源码分别负责模型训练、视频检测与可视化界面、3个PyTorch模型权重文件以及2个部署说明文档整体约15.91MB。项目附带完整数据集并已经过运行验证可输出核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果和标签分布图方便用于答辩评审与效果展示。已有36人学习下载配套部署说明与README文档齐全项目结构清晰、可直接使用适合需要快速落地演示或完成课设、毕设任务的用户。1. 交通锥桶摆放合规性巡检为什么需要YOLOv8而不是传统图像处理在高速公路养护、道路施工和大型活动交通组织中锥桶摆放是否符合规范直接决定后方来车能否提前变道。现实中这条巡检线往往靠人开车巡视或者蹲在监控墙前一帧帧看效率低且容易漏检。用YOLOv8做自动巡检核心不是“认出锥桶”这一件事而是把“识别”和“摆放规则判断”连起来检测出每个锥桶的像素位置再通过坐标换算判断间距、排列直线度、是否侵入作业区边界最后生成带截图和坐标的巡检记录。这套流程对毕设或课程设计来说正好覆盖了目标检测、图像坐标计算、GUI交互和部署四个模块比单纯训练一个模型更有完整度。适合的人群分两类一类是刚接触YOLOv8、想用现成数据集跑通训练到推理全流程的学生另一类是有一定检测基础、想往“检测后处理”方向拓展的工程师。下面按“模型原理→推理部署→界面实现→完整实操→进阶技巧”的顺序展开涉及的命令和代码都按可直接复制运行的标准来写。2. YOLOv8识别交通锥桶的原理与训练配置2.1 从C2f到HeadYOLOv8用于小目标检测的改动点很多教程直接给训练命令但不解释模型结构导致后面换数据集时不知道怎么改。YOLOv8相比YOLOv5最明显的结构变化是C3模块换成了C2f模块。C2f把输入特征图拆成两条路径一条走Bottleneck堆叠一条做shortcut连接最后拼接再经过卷积。这种设计让梯度回传路径更丰富对锥桶这种外观简单但尺度变化大的物体来说小目标特征不容易在前向传播中丢失。另一个关键改动是Head部分。YOLOv8用Decoupled Head把分类和回归分支拆开各自经过两层卷积后再输出。锥桶检测中经常出现“两个锥桶靠得很近”的情况耦合头容易在分类和回归之间互相干扰解耦头在这类场景下收敛更稳。如果你的巡检目标是更小的锥桶比如百米外拍摄的画面可以考虑后续替换成P2层输出或在Neck部分增加一层特征融合这就是常说的yolov8 head改进方向之一。实际使用时先确认你下载的yolov8版本。在ultralytics库中模型定义在ultralytics/nn/modules下可以用以下方式查看C2f的实现位置import inspect from ultralytics.nn.modules import C2f print(inspect.getsource(C2f))这段代码会直接打印C2f类源码方便你对照网络结构图加深理解。C2f的输入通道数由ch_in决定n参数控制Bottleneck数量训练时不需要手动修改但了解它有助于你阅读训练日志里的参数量信息。2.2 锥桶数据集的标注格式与目录组织训练自己的数据集前先把图片和标注文件按YOLO格式放好。每个标注文件是txt每一行代表一个目标格式为class_id x_center y_center width height注意这里的坐标是相对于图片宽高的归一化值不是像素坐标。比如图片宽1920、高1080一个锥桶中心点在(960, 540)宽100像素、高200像素对应的一行就是0 0.5 0.5 0.052083 0.185185标注工具推荐用LabelImg或LabelMe。如果你手里已经有一套完整数据集打开其中一个txt文件就能确认格式是否符合上面这种形式。目录标准结构如下dataset/ images/ train/ val/ labels/ train/ val/训练前写一个data.yaml内容如下path: D:/traffic_cone_dataset train: images/train val: images/val names: 0: traffic_conepath指向数据集根目录train和val是相对路径。类别名只写了一种如果你的场景里还要区分“标准锥桶”和“破损锥桶”可以继续扩展。这里必须保持一致txt文件里的类别ID要对应names列表里的顺序。2.3 训练命令与损失函数曲线解读训练用ultralytics命令行最省事。进入Python环境后执行yolo detect train datadata.yaml modelyolov8s.pt epochs100 imgsz640 batch8 device0参数含义data指向刚才写的data.yamlmodel选择预训练权重yolov8s.pt比n精度高比m速度快锥桶这种单类目标用s就够了imgsz640是训练分辨率锥桶占画面比例小可以调到800但显存占用会上升batch8根据显存调整6GB显存建议从4开始device0表示用第一张GPU卡没有GPU就改成cpu训练完成后在runs/detect/train目录下会生成results.png里面包含box_loss、cls_loss、dfl_loss三条损失曲线。判断训练是否正常不要只看loss有没有降到0要看val/box_loss是否在某轮后停止下降并且没有明显回升。如果val_loss在第80轮后持续上升而train_loss还在下降说明过拟合常见缓解手段是把epochs降到60或者给数据增强参数hsv_h、hsv_s减少扰动。2.4 检测效果不达标时的调参顺序很多人一上来就换大模型或堆数据其实锥桶检测的瓶颈通常不在模型容量。调参我一般按这个顺序走现象首选调整项说明漏检远处小锥桶提高imgsz到960或开启SAHI切片推理小目标在640下像素太少两个锥桶粘连误检调低NMS的iou阈值到0.4默认0.45对密集目标偏宽松夜间/逆光漏检增加数据增强中的亮度变换训练时用degrees0.2 translate0.1 scale0.5把路肩误检成锥桶增加背景负样本或调整cls_loss权重负样本要单独建images/background目录如果训练集本身只有几百张优先尝试第2项和第1项。调NMS阈值不需要重训只在推理阶段修改参数后面会讲到。3. 部署巡检系统从权重到可视化界面的完整链路3.1 环境准备与权重加载的两种方式部署阶段要保证训练环境和推理环境一致或兼容。先在目标机器上确认ultralytics版本pip install ultralytics python -c from ultralytics import YOLO; print(YOLO.__version__)从网上下载的源码包通常带有best.pt加载方式有两种from ultralytics import YOLO # 方式一直接加载训练好的权重 model YOLO(best.pt) # 方式二加载yaml结构预训练权重迁移学习用 model YOLO(yolov8s.yaml).load(yolov8s.pt)巡检系统部署只需要方式一。predict方法会返回包含boxes对象的Results通过results[0].boxes.xyxy拿到每个检测框的左上角和右下角坐标conf字段为置信度cls字段为类别ID。3.2 从摄像头或视频流读取帧并执行推理核心巡检循环代码如下import cv2 from ultralytics import YOLO model YOLO(best.pt) cap cv2.VideoCapture(test_video.mp4) # 也可以是摄像头索引0 while cap.isOpened(): ret, frame cap.read() if not ret: break results model(frame, conf0.35, iou0.45, imgsz640, verboseFalse) for box in results[0].boxes: x1, y1, x2, y2 box.xyxy[0].tolist() conf float(box.conf[0]) # 这里拿到的是像素坐标用于后续合规性判断 draw_cone_box(frame, (int(x1), int(y1), int(x2), int(y2)), conf) cv2.imshow(Traffic Cone Inspection, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()conf0.35是置信度阈值巡检场景里宁可有少量误报也别漏检所以设得比默认的0.25高一点。iou0.45是NMS交并比阈值数值越小重叠框越容易被抑制。这个参数在锥桶粘连时直接影响检测框数量调低到0.3可以避免两个锥桶被合并成一个框。3.3 可视化界面从临时窗口到PySide6控制面板OpenCV自带的imshow窗口只适合调试毕设或课程设计要交付一个操作界面。常见做法是使用PySide6配合线程分离推理和界面刷新避免视频卡顿。界面布局通常包含左侧视频显示区域右侧检测结果列表帧号、锥桶数量、平均置信度下方开始/停止巡检按钮、合规状态指示灯最小示例代码如下from PySide6.QtWidgets import QMainWindow, QLabel, QVBoxLayout, QPushButton, QWidget from PySide6.QtGui import QImage, QPixmap from PySide6.QtCore import QTimer import cv2 class ConeWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle(交通锥桶巡检系统) self.label QLabel() self.btn QPushButton(开始巡检) layout QVBoxLayout() layout.addWidget(self.label) layout.addWidget(self.btn) container QWidget() container.setLayout(layout) self.setCentralWidget(container) self.cap cv2.VideoCapture(0) self.timer QTimer() self.timer.timeout.connect(self.update_frame) self.btn.clicked.connect(self.toggle) def update_frame(self): ret, frame self.cap.read() if not ret: return # 这里插入detect逻辑 rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch rgb.shape qimg QImage(rgb.data, w, h, ch * w, QImage.Format_RGB888) self.label.setPixmap(QPixmap.fromImage(qimg)) def toggle(self): if self.timer.isActive(): self.timer.stop() else: self.timer.start(30) # 约33帧/秒 def closeEvent(self, event): self.cap.release() event.accept()这里用了QTimer定时从摄像头抓帧定时器间隔30毫秒即33帧每秒。推理如果耗时超过这个间隔界面会掉帧所以推理建议放在子线程主线程只负责显示。3.4 合规性判断坐标排序与间距计算检测到锥桶后怎么判断摆放是否合规常见规则是锥桶应沿车道线方向等间距排列相邻间距误差不超过20%。代码实现分三步import numpy as np def check_compliance(boxes, standard_spacing2000): boxes: 检测框列表每个元素为 [x1, y1, x2, y2] 返回是否符合标准以及不符合的锥桶编号 if len(boxes) 3: return False, [] # 取每个框底边中点因为锥桶底边才是实际接地位置 centers np.array([[(x1 x2) / 2, max(y1, y2)] for x1, y1, x2, y2 in boxes]) centers centers[np.argsort(centers[:, 0])] # 按x坐标排序 deviated [] for i in range(len(centers) - 1): dist np.linalg.norm(centers[i 1] - centers[i]) if abs(dist - standard_spacing) / standard_spacing 0.2: deviated.append(i 1) return len(deviated) 0, deviated代码逻辑说明先通过argsort按x坐标排序假设锥桶沿道路横向排列。距离用欧氏距离计算因为摄像机会有透视畸变纯x方向差值在远处会失真欧氏距离可以部分缓解。standard_spacing需要根据实际场景标定方法是量出真实间距再除以检测框在图像中的像素差得到像素/米比例。4. 在本地跑通完整巡检流程的实操步骤4.1 源码包目录结构与启动顺序拿到标题对应的源码包后先看目录组织。常见结构包含以下部分traffic_cone_inspection/ weights/ best.pt dataset/ images/ labels/ ui/ main_window.py video_thread.py utils/ compliance.py report.py demo.mp4 requirements.txt run.py启动前先装依赖pip install -r requirements.txtrequirements.txt里一般包含ultralytics、opencv-python、PySide6、numpy。装完后不要急着运行先单独验证权重文件能否推理python -c from ultralytics import YOLO; modelYOLO(weights/best.pt); print(model.names)输出{0: traffic_cone}这类字典说明权重加载正常。如果报错cannot import name YOLO一般是ultralytics版本过低或没有安装成功用pip install -U ultralytics升级。4.2 一键启动脚本中必改的三个参数run.py里通常有一段像这样的初始化代码if __name__ __main__: model_path weights/best.pt source demo.mp4 # 0表示摄像头 conf_thres 0.35 standard_spacing_px 200 app QApplication(sys.argv) window ConeWindow(model_path, source, conf_thres, standard_spacing_px) window.show() sys.exit(app.exec())部署到新机器时改这三个参数source默认是demo.mp4改成0才能使用笔记本摄像头。如果是网络摄像头填rtsp://192.168.1.64:554/stream1这样的地址。conf_thres实景中光线正常就保持0.35夜间检测建议降到0.25否则容易漏检。standard_spacing_px这个值由标定得到不要拍脑袋填。标定方法在画面中放置两个间距已知为2米的锥桶记录检测框中心点像素距离填入该值。4.3 常见报错与排查方向报错信息原因处理CUDA out of memory显存不足batch调小或把devicecpuFileNotFoundError: data.yaml路径写错检查data.yaml位置改为绝对路径QThread: Destroyed while thread is still running关闭界面时子线程未退出在closeEvent中先stop并waitAttributeError: NoneType object has no attribute xyxy模型没有检测到目标results[0].boxes为空先判断results[0].boxes is not Nonecv2.error: (-215:Assertion failed)视频路径错误或文件损坏换成demo.mp4测试或解码器改为opencv-mpeg4遇到QThread报错时推荐在video_thread.py的run方法里加一个while not self._stop_flag:这样关闭窗口时能立即退出循环而不是等当前帧推理完。5. 让巡检系统更实用的三个进阶技巧5.1 用ROI排除干扰区域实际监控画面里路肩、绿化带、临时围挡都可能被误检成锥桶。给模型划定一个矩形巡检区域只处理区域内的检测框def in_roi(box, roi(0, 200, 1920, 1000)): x1, y1, x2, y2 box cx, cy (x1 x2) / 2, (y1 y2) / 2 return roi[0] cx roi[2] and roi[1] cy roi[3]加上这一步后画面右侧固定出现的施工机械即使形状像锥桶也不会进入合规性判断。ROI坐标需要和视频分辨率匹配分辨率改了要同步调整。5.2 夜间与逆光场景的图像预处理交通锥桶巡检常发生在傍晚和夜间锥桶表面反光会导致检测框闪烁。在推理前做一次自适应直方图均衡化能显著提升夜间召回率import cv2 def preprocess_for_night(frame): lab cv2.cvtColor(frame, cv2.COLOR_BGR2LAB) l, a, b cv2.split(lab) clahe cv2.createCLAHE(clipLimit3.0, tileGridSize(8, 8)) l clahe.apply(l) return cv2.cvtColor(cv2.merge([l, a, b]), cv2.COLOR_LAB2BGR)将预处理函数插到检测代码的model(frame)之前即可。注意这会让推理耗时略有增加如果帧率不够可以把clipLimit降到2.0。5.3 输出结构化巡检报告除了界面展示巡检系统最后要能导出报告。在每次巡检结束后把检测结果和合规性判断写入CSV文件方便后续统计import csv from datetime import datetime def save_report(records, pathinspection_report.csv): with open(path, w, newline, encodingutf-8) as f: writer csv.writer(f) writer.writerow([timestamp, frame_id, cone_count, violation_count, violation_indices]) for r in records: writer.writerow([datetime.now().isoformat(), r[frame_id], r[cone_count], r[violation_count], r[violation_indices]])报告里可以再加一列“违规类型”比如“间距过小”“间距过大”这样区分“检测问题”和“摆放问题”时不用重新看画面。这个CSV文件用Excel或pandas都能打开配合截图保存函数就能组成一套可用于课程设计答辩的完整交付物。本文还有配套的精品资源点击获取