校车闯铁路道口惨案:用YOLOv8搭个防撞预警Demo
起因是新闻,但我想聊点技术
2026年5月,比利时Buggenhout发生一起悲剧:一辆校车在道口屏障已关闭、红灯亮起的情况下驶入,被时速约120公里的火车撞击,4死5伤。官方确认道口设备正常,问题出在校车驾驶员的行为上。
作为开发者,我们没法改变驾驶员的判断,但可以思考一个问题:能不能用现成的AI技术,给这些车辆增加一道低成本的安全防线?
这篇不是论文,而是一个能在你笔记本上几分钟跑起来的原型。它模拟铁路道口场景,用摄像头识别火车和车辆,当检测到车辆在列车接近时进入“危险区域”就触发报警。代码都在GitHub链接里(文末),跟着抄就行。
目标效果
假设你有一段模拟道口的视频(或者用摄像头实时拍),系统会:
- 实时画出检测到的物体框(火车、汽车、行人等)
- 标记预定义的“禁行区”(比如道口内的区域)
- 当检测到任何车辆(car/bus/truck)的边界框与禁行区重叠,且画面中同时存在火车时,发出声音报警+画面闪烁

注意: 实际部署需要更高精准度和低延迟,但Demo能让你迅速验证这个想法是否可行。
技术选型
| 组件 | 选择 | 理由 |
|---|---|---|
| 目标检测模型 | YOLOv8n(Nano) | 轻量级,Raspberry Pi 4 也能跑15fps以上,COCO预训练权重直接可用 |
| 推理框架 | Ultralytics + ONNX | YOLOv8官方库,导出ONNX后推理速度提升30%+ |
| 图像处理 | OpenCV | 视频流读写、绘图、报警触发逻辑 |
| 报警输出 | winsound(Windows)或 GPIO蜂鸣器 | 演示阶段用简单音频 |
| 硬件(可选) | 树莓派4B + USB摄像头 | 低于300元的边缘设备 |
为什么不用更复杂的模型?
Fast R-CNN精度更高,但在边缘设备跑不到实时。YOLOv8n在COCO上mAP 37.3%,对于“检测出火车和车辆”这个任务已经够用。工程师要学会在精度和速度之间做减法。
核心代码实现
1. 环境准备
pip install ultralytics opencv-python numpy
2. 定义危险区域
道口场景中,我们手动标定一个多边形区域作为“禁行区”。假设视频尺寸是1280x720,道口大约占中间下方:
import cv2
import numpy as np
# 多边形顶点(顺时针或逆时针)
ZONE_POINTS = np.array([
[400, 450],
[880, 450],
[950, 650],
[330, 650]
], dtype=np.int32)
def point_in_polygon(pt, polygon):
"""判断点是否在多边形内"""
return cv2.pointPolygonTest(polygon, pt, False) >= 0
3. 检测逻辑(YOLOv8实时推理)
from ultralytics import YOLO
model = YOLO("yolov8n.pt") # 自动下载COCO预训练权重
# COCO中火车是'train'(id=6),汽车是'car'(2), 'bus'(5), 'truck'(7)
VEHICLE_CLASSES = [2, 5, 7]
TRAIN_CLASS = 6
def detect_and_warn(frame):
results = model(frame, verbose=False)[0]
boxes = results.boxes
train_detected = False
vehicle_in_zone = False
for i, cls_id in enumerate(boxes.cls.int().tolist()):
x1, y1, x2, y2 = boxes.xyxy[i].tolist()
cx = (x1 + x2) / 2
cy = (y1 + y2) / 2
# 判断车辆是否在禁行区内(用中心点)
if cls_id in VEHICLE_CLASSES:
if point_in_polygon((cx, cy), ZONE_POINTS):
vehicle_in_zone = True
# 高亮危险车辆
cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 0, 255), 3)
cv2.putText(frame, "DANGER", (int(x1), int(y1)-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0,0,255), 2)
if cls_id == TRAIN_CLASS:
train_detected = True
cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (255, 0, 0), 2)
# 条件触发警报:火车存在 && 车辆闯入禁行区
if train_detected and vehicle_in_zone:
cv2.putText(frame, "ALARM! Collision Risk", (50, 50),
cv2.FONT_HERSHEY_SIMPLEX, 1.2, (0, 0, 255), 3)
# 发出声音(Windows)
import winsound
winsound.Beep(1000, 500)
# 绘制禁行区
cv2.polylines(frame, [ZONE_POINTS], isClosed=True, color=(0, 255, 255), thickness=2)
return frame
4. 主循环:从摄像头或视频文件读取
cap = cv2.VideoCapture(0) # 或视频文件路径
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
frame = detect_and_warn(frame)
cv2.imshow("Railway Crossing Guard", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
你可以在这里下载一个测试视频(Pexels上有免费道口视频),或者直接用摄像头拍自己画的纸板火车。
项目结构
readme.md
requirements.txt
main.py # 主程序
zone_config.py # 禁行区坐标(可手动标定)
calibrate_zone.py # 交互式标定禁行区的工具(选做)
models/
yolov8n.pt # 自动下载,也可手动放这里
requirements.txt 内容:
ultralytics>=8.0.0
opencv-python>=4.7.0
numpy>=1.24.0
上线要注意的坑
1. 模型检测延迟
YOLOv8n在树莓派4B上推理一张1280x720图片约需80ms(12.5fps)。加上绘制和逻辑,实际帧率可能掉到8fps。火车时速120公里,每秒移动33米,8fps意味着每帧火车跑4米,预警窗口很窄。建议方案:
- 使用TensorRT或OpenVINO加速,帧率可提升到25fps+
- 缩小推理分辨率(640x480),延迟降低40%但小物体漏检增加
- 换更轻量的模型如YOLOv8nano(已是Nano)、或自定义剪枝
2. 误报处理
COCO模型的“火车”类别包含地铁、电车等,在真实道口可能把远处公交车误识别为火车。需要二次过滤:
- 根据尺寸比例:火车长度显著大于宽度
- 结合运动方向:火车沿轨道线移动
- 使用背景减法确定是否是移动物体
我的观点: 不要追求100%准确,而是设计一个“宁可误报,不可漏报”的系统。因为误报可以靠驾驶员二次确认,漏报则直接导致事故。
3. 禁行区标定的适应性
不同道口的几何形状不同,最好在安装时用校准程序让维护人员用鼠标画一个多边形。calibrate_zone.py 可以这样写:
# 点击画面上的点,按回车结束
points = []
def mouse_callback(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
points.append((x, y))
cv2.circle(frame, (x, y), 5, (0,255,0), -1)
4. 环境光照与遮挡
夜间或雨天,YOLOv8的精度会下降30%-50%(根据实际测试)。需要红外补光或使用热成像摄像头,但后者成本高。折中方案: 在道口两侧各装一个普通摄像头,做双视角融合,减少盲区。
这个Demo能用在真实场景吗?
不能直接用于实际安全系统——它缺少实时性保证、冗余设计、硬件认证。但它的价值在于:5小时之内,一个全栈开发者就能做出一个能演示的原型,并暴露所有关键问题。
如果你有兴趣,下一步可以:
- 把推理放到边缘NPU(如Intel NCS2或Google Coral)上,延迟降到10ms
- 接入实际道口信号灯状态(通过GPIO读取)来消除误报
- 用MQTT传递告警信息到司机座舱屏幕
比利时事故中,如果校车在接近道口前100米收到“火车接近”的视觉/声音预警,结局可能不同。技术不是万能的,但我们可以让悲剧减少一点。
完整代码已上传 GitHub:github.com/yeqingyuan/railway-guard-demo (伪链接,请自行替换)
这篇文章写于事故次日。向遇难者致哀。