基于 YOLO11 的道路交通锥 视觉 识别系统
一套面向道路养护、施工管控与自动驾驶感知场景的交通锥(路锥 / 雪糕筒)识别方案,使用 YOLO11n + Streamlit 构建,稳定检出施工区、临时占道与隔离区的安全锥,辅助安全防护与作业区划设。
一、背景
1.1 行业痛点
交通锥(俗称"雪糕筒"“路锥”)是道路施工、临时占道与事故现场最常见的隔离物。围绕它的痛点很集中:
- 施工区锥桶巡检靠人眼:高速沿线一个标段几十公里、上百枚锥桶,人工巡查既慢又难量化"是否摆够、是否倾倒";
- 自动驾驶感知短板:锥桶是 corner case 之一——颜色高饱和、形状特殊、又常出现在非结构化场景,传统检测器对倾倒 / 遮挡场景误检率高;
- 事故现场态势难还原:交警 / 路政事后取证时希望快速统计锥桶分布,传统人工标注耗时耗力。
本 项目 用一个轻量、可部署到巡检车 / 路侧抓拍机 / 自驾感知模块的 YOLO11n 模型,把"识别路面上有几个锥桶、在哪里、姿态如何"做成开箱即用的能力。
数据集 规模 6000 张,来自真实交通场景,覆盖白天、夜晚、阴天、雨天,包含锥桶直立、倾倒、部分遮挡多种状态,按 YOLO 格式组织(train / valid / test ),单类 nc=1:['交通锥']。
视频演示与源码下载

包含: 📦完整项目源码 📦 预训练 模型权重
🗂️数据集
1.2 项目运行效果
Web 界面总览(道路橙 + 警示黄主题,符合交通行业视觉规范):


1.3 项目介绍
创新点 / 亮点
| 维度 | 说明 |
|---|---|
| 多场景泛化 | 训练集覆盖高速、城市道路、停车场,白天/夜晚/雨天/雾天均匀采样 |
| 多姿态适应 | 直立 / 倾倒 / 部分遮挡均参与标注,不再只对"标准锥桶"友好 |
| 单类专精 | 单类 nc=1,模型只学一件事,可大胆做小目标增强、负样本挖掘 |
| 多源接入 | 巡检车前视相机、施工区抓拍机、自驾感知模块都能复用 |
系统功能概览
- 单张图片识别:路面照片 → 标注图 + 锥桶数量 + 平均置信度
- 批量图片识别:整段路上传后输出全段锥桶分布
- 视频检测:行车记录仪 / 巡检车视频,逐帧检测 + 时间线
- 摄像头实时:直接接 RTSP / USB 摄像头,实时输出
技术栈
| 层级 | 技术选型 |
|---|---|
| 检测模型 | YOLO11n(Ultralytics) |
| Web 框架 | Streamlit |
| 图像处理 | OpenCV、Pillow |
| 数据 / 图表 | Pandas、Streamlit 原生图表 |
| 视频编解码 | imageio-ffmpeg |
| 部署 | Python 3.9+,本地 / 容器 / Jetson 边缘盒子 |
类别定义:nc=1,names=['交通锥']。


二、设计框架
系统架构
┌────────────────────────────────────────────────────────────┐
│ 接入终端:巡检车前视相机 │ 施工区抓拍机 │ 自驾感知模块 │
└──────────────────────┬─────────────────────────────────────┘
│ HTTP / RTSP / 文件上传
┌──────────────────────▼─────────────────────────────────────┐
│ Streamlit App (app/streamlit_app.py) │
│ · 模式路由(单图 / 批量 / 视频 / 摄像头) │
│ · 行业品牌渲染(project.yaml 驱动) │
│ · 结果分析图 / 明细表 / 导出包 │
└──────────────────────┬─────────────────────────────────────┘
│ model.predict(conf=0.25, iou=0.7)
┌──────────────────────▼─────────────────────────────────────┐
│ YOLO11n 推理引擎 │
│ Backbone (C2f + SPPF) → Neck (FPN + PAN) → Decoupled Head │
│ + DFL(分布式回归) → NMS │
└──────────────────────┬─────────────────────────────────────┘
│ result.boxes (cls, conf, xyxy)
┌──────────────────────▼─────────────────────────────────────┐
│ 后处理:单类汇总 → DataFrame → 数量统计 / 置信度分布 │
└────────────────────────────────────────────────────────────┘
YOLO11 网络结构
- Backbone:连续
Conv + C2f下采样 5 次 + 末端SPPF多尺度池化 - Neck:
FPN+PAN双向特征金字塔,对远处小锥桶和近距离大锥桶同时友好 - Head:解耦头 + DFL(分布式回归),对倾倒锥桶这种非典型长宽比定位更稳
- 损失:BCE(分类)+ CIoU + DFL(回归)
检测流程:图像/帧 → letterbox 缩放至 imgsz=640 → 推理 → 置信度过滤(conf=0.25)→ NMS(iou=0.7)→ 单类汇总 → 前端渲染。
三、代码结构(核心 50 行 + 解析)
项目结构:
道路交通锥识别/
├── app/streamlit_app.py # Streamlit Web 入口
├── configs/project.yaml # 业务配置(行业 / 场景 / UI)
├── model/best.pt # YOLO11n 训练权重
├── scripts/ # 训练 / 评测 / 导出脚本
├── 安全锥路锥雪糕筒检测数据集/ # 数据集(train/valid/test)
└── 安全锥路锥雪糕筒目标检测train_CH_yolo11n/ # 训练产物
核心 50 行(精简版):
from pathlib import Path
import pandas as pd
import streamlit as st
import yaml
from ultralytics import YOLO
PROJECT_ROOT = Path(__file__).resolve().parent.parent
CONFIG_PATH = PROJECT_ROOT / "configs" / "project.yaml"
MODEL_PATH = PROJECT_ROOT / "model" / "best.pt"
APP_CFG = yaml.safe_load(open(CONFIG_PATH, "r", encoding="utf-8"))
APP_META = APP_CFG.get("app", {
})
INFER = APP_CFG.get("inference", {
})
DEFAULT_CONF = float(INFER.get("conf", 0.25))
DEFAULT_IOU = float(INFER.get("iou", 0.7))
@st.cache_resource(show_spinner=False)
def load_model(model_path: str) -> YOLO:
return YOLO(model_path) # 全局缓存,避免反复加载
def infer_image(model: YOLO, image_path: Path, conf: float):
result = model.predict(str(image_path), conf=conf, iou=DEFAULT_IOU, verbose=False)[0]
annotated = result.plot() # 自带画框 + 类名 + 置信度
rows = []
if result.boxes is not None:
for box in result.boxes:
cls_id = int(box.cls.item())
rows.append({
"class_id": cls_id,
"class_name": result.names[cls_id], # '交通锥'
"confidence": round(float(box.conf.item()), 4),
"x1": float(box.xyxy[0][0]), "y1": float(box.xyxy[0][1]),
"x2": float(box.xyxy[0][2]), "y2": float(box.xyxy[0][3]),
})
return annotated[:, :, ::-1], pd.DataFrame(rows) # BGR -> RGB
# ---------------- Streamlit 主流程 ----------------
st.set_page_config(page_title=APP_META.get("title"), layout="wide")
model = load_model(str(MODEL_PATH))
conf = st.sidebar.slider("置信度阈值", 0.05, 0.95, DEFAULT_CONF, 0.05)
mode = st.radio("输入类型", ["单张图片", "批量图片", "视频", "摄像头"], horizontal=True)
if mode == "单张图片":
uploaded = st.file_uploader("上传路面图片", type=["jpg", "png", "jpeg"])
if uploaded is not None:
tmp = Path("/tmp") / uploaded.name
tmp.write_bytes(uploaded.getvalue())
annotated, df = infer_image(model, tmp, conf)
col1, col2 = st.columns(2)
col1.image(uploaded.getvalue(), caption="原图", width="stretch")
col2.image(annotated, caption="检测结果", width="stretch")
st.metric("识别锥桶数量", int(len(df)))
if not df.empty:
st.metric("平均置信度", f"{df['confidence'].mean():.2%}")
st.dataframe(df, width="stretch")
逐段解析
yaml.safe_load(project.yaml)把inference.conf / inference.iou / app.title全部抽到配置层,调超参不用改代码,巡检 SaaS 多租户场景极友好。@st.cache_resource缓存YOLO(path):Streamlit 每次交互都会重跑脚本,缓存避免 200ms 级的模型加载开销,让单图响应稳定在 50ms 量级。model.predict一行完成"预处理 + 推理 + NMS",返回Results,.plot()直接生成带标注框的 ndarray,免去手画 cv2 矩形的工作量。result.boxes迭代得到cls / conf / xyxy,组成 DataFrame:单类项目里class_name永远是交通锥,但保留字段是为了未来扩展(如增加"倾倒锥桶"、"破损锥桶"子类)。st.radio+if/elif路由四种输入模式,模型一次加载、四个入口共享。摄像头 / 视频模式只需复用infer_image,把帧 ndarray 灌进去即可。
四、训练效果
训练采用 YOLO11n 预训练权重 微调 ,epochs=200, imgsz=640, batch=16, patience=50(实际跑到 113 epoch 触发早停)。best.pt 对应的最佳指标:
| 指标 | 数值 |
|---|---|
| Precision (B) | 0.786 |
| Recall (B) | 0.691 |
| mAP@0.5 | 0.747 |
| mAP@0.5:0.95 | 0.398 |

说明:当前 mAP@0.5 ≈ 0.75,模型仍在迭代中。从误差分布看,主要瓶颈在三个方向:
- 远距离小目标:高速场景下 50m 外的锥桶在 640×640 输入里只有几像素,需要更高分辨率(imgsz=1280)或 P2 检测头;
- 倾倒 / 重度遮挡:长尾样本不足,模型偶尔把倾倒锥桶判成背景;
- 夜间反光:夜间锥桶反光条会让模型把多个连续锥桶 NMS 误合为一个。
下一阶段优化方向:
- imgsz 提到 1280 + 加入 P2 高分辨率检测头,专治远距离小目标;
- 使用 Mosaic + Copy-Paste 增强长尾倾倒样本;
- 训练时混合一定比例的夜间增强数据,缓解光照域差;
- 升级到 YOLO11s 后量化部署到 Jetson Orin Nano,平衡精度与推理速度。
由于本阶段 mAP 尚未达到放出 PR / 混淆矩阵的内部阈值(≥ 0.85),暂仅展示训练 loss / 指标随 epoch 的总览图。从曲线看,box / cls / dfl loss 平稳下降,P/R 在中后段趋于平台期,未出现过拟合震荡,整体走势健康。
五、项目总结
做对了什么
- 一份代码 + 一份
project.yaml,可同时跑高速养护、城市施工、自驾感知三种业务,配置即业务。 - 数据集采集时刻意覆盖了天气、光照、姿态长尾,模型即使没到 SOTA,泛化能力也比"晴天直立锥桶"训练集强不少。
- Streamlit 多模式入口让算法成果能直接给前线交警 / 路政人员演示,缩短从"训练完模型"到"业务方能看见效果"的链路。
还能怎么做
- 接入巡检车 GPS + 时间戳,把锥桶检测结果落到地图上做"全路段锥桶库存表",回答"今天 K78 处少了几枚锥桶"这种业务问题。
- 上时序跟踪(ByteTrack)把单帧锥桶串成"事件",识别"锥桶被车撞倒"瞬间,配合视频取证做交通事故快速复盘。
- 量化到 INT8 部署到 Jetson Orin Nano,单帧推理 < 20ms,可直接装到巡检车前视相机里,离线也能跑。
- 加入"车 / 人 / 锥桶"多类同框,识别施工区是否有违规闯入。
一句话总结
YOLO11n + Streamlit 给智慧交通领域提供了一个开箱即用、可配置化、可边缘部署的交通锥识别底座,无论是高速养护 SaaS、自驾感知补丁,还是事故现场快速取证,都能在它上面拼装出自己的业务闭环。