用YOLOv8+Jetson Nano实时检测闯红灯预警

比利时校车事故中,尽管道口信号正常,但司机闯红灯导致4死5伤。这类悲剧并非孤例——全球每年约135万人死于交通事故,其中闯红灯占行人死亡原因的30%以上(WHO 2023)。现有交通监控大多依赖事后录像回放,但若能实时识别闯红灯行为并现场预警,或许能挽回一些生命。

本文带你用YOLOv8和一块Jetson Nano(成本约500元),搭建一个能运行在路口的实时闯红灯检测系统。读完你将掌握:

  • 如何用YOLOv8检测车辆、行人和红绿灯状态
  • 如何定义虚拟“停止线”判断违规
  • 在边缘设备上实现低延迟推理(<100ms)并驱动声光报警
  • 部署时容易踩的坑及应对方案

1. 产品Demo效果展示

JETSON_NANO_ON_POLE_CAMERA

系统启动后,摄像头实时采集路口画面。当信号灯为红色时,若检测到车辆越过预先标定的停止线,程序会:

  1. 在画面上框出违规车辆并标注“VIOLATION”
  2. 通过GPIO控制蜂鸣器发出警报声
  3. 在终端/日志记录违规时间、车辆类别和ID

实测在Jetson Nano上,YOLOv8n模型(640x640输入)推理速度约45ms/帧,加上预处理和后处理,整体延迟在80-100ms,满足实时预警需求。

2. 技术选型(模型/框架/部署方案)

组件 选型 理由
模型 YOLOv8n 官方预训练,nano版本最快(Jetson Nano上45ms),精度足够检测车/人/灯
框架 Ultralytics + ONNX Runtime 推理速度比PyTorch快2倍,双核CPU下也能跑
设备 Jetson Nano 4GB (B01) 成本低($150),有GPIO,社区成熟
摄像头 USB免驱摄像头(1080p) 即插即用,实测640x480输入足够
报警 蜂鸣器模块 + 继电器 通过Jetson GPIO 5V控制
信号灯状态 颜色阈值 + 位置区域 简单可靠,不依赖模型,避免模型误判红绿灯(YOLO对交通灯小目标检出率低)

为什么不用纯模型检测红绿灯? 我在测试中发现,YOLOv8官方权重对远距离小目标(如路口红绿灯)的召回率不足40%。改用HSV颜色空间提取红色/绿色区域,配合固定ROI,准确率可达95%以上。

3. 核心代码实现(关键片段)

3.1 红绿灯状态判定

python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
import cv2
import numpy as np

def get_traffic_light_state(frame, roi_box=(300, 50, 100, 120)):
    """
    从frame中截取红绿灯区域(可根据实际场景标定)
    roi_box: (x, y, w, h) 相对于画面左上角
    返回: 'red', 'green', 'yellow', 'unknown'
    """
    x, y, w, h = roi_box
    roi = frame[y:y+h, x:x+w]
    hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
    
    # 红色有两个区间(H 0-10, 160-180)
    red_mask1 = cv2.inRange(hsv, (0, 70, 50), (10, 255, 255))
    red_mask2 = cv2.inRange(hsv, (160, 70, 50), (180, 255, 255))
    red_mask = red_mask1 | red_mask2
    green_mask = cv2.inRange(hsv, (40, 70, 50), (80, 255, 255))
    
    red_pixels = cv2.countNonZero(red_mask)
    green_pixels = cv2.countNonZero(green_mask)
    
    if red_pixels > 100 and red_pixels > green_pixels:
        return 'red'
    elif green_pixels > 100:
        return 'green'
    elif red_pixels > 10 or green_pixels > 10:
        return 'yellow'
    return 'unknown'

3.2 停止线定义与违规判断

python
1 2 3 4 5 6 7 8 9 10
# 停止线定义为图像坐标系中的一条水平线 y = stop_line_y
STOP_LINE_Y = 350  # 根据实际视角标定

def is_vehicle_crossing_line(bbox, line_y):
    """
    bbox: (x1, y1, x2, y2) 目标检测框
    return True 如果车辆底部中心越过停止线
    """
    bottom_center_y = (bbox[1] + bbox[3]) // 2
    return bottom_center_y > line_y

3.3 主循环(YOLOv8推理 + 违规检测)

python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
from ultralytics import YOLO
import cv2

model = YOLO('yolov8n.pt')  # 使用ONNX可加速
cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()
    if not ret:
        break
    
    # 1. 检测红绿灯状态
    light = get_traffic_light_state(frame)
    
    # 2. 对全图进行YOLO推理(只关注vehicle类:car, bus, truck, bicycle, motorcycle)
    results = model(frame, classes=[2,3,5,6,7], conf=0.5)
    
    if light == 'red':
        for box in results[0].boxes.xyxy:
            x1, y1, x2, y2 = map(int, box)
            if is_vehicle_crossing_line((x1,y1,x2,y2), STOP_LINE_Y):
                # 违规!画框、报警、记录
                cv2.rectangle(frame, (x1,y1), (x2,y2), (0,0,255), 3)
                cv2.putText(frame, "VIOLATION", (x1,y1-10), ...)
                gpio_trigger_buzzer()  # 通过Jetson GPIO控制
                log_violation(frame, time.time())
    
    cv2.imshow('Traffic Monitor', frame)
    if cv2.waitKey(1) == ord('q'):
        break

4. 项目结构和配置

text
1 2 3 4 5 6 7 8
traffic-alert/
├── config.py          # 红色灯ROI、停止线Y坐标、置信度阈值等
├── traffic_light.py   # 颜色检测
├── detector.py        # YOLOv8推理封装
├── violation_check.py # 违规判断 + 报警
├── main.py            # 主循环
├── requirements.txt   # ultralytics, opencv-python, numpy, gpiozero
└── run.sh             # 启动脚本

requirements.txt: 强烈推荐将YOLOv8导出为ONNX格式,减少PyTorch依赖,部署体积从2.5G降到100M。

5. 上线要注意的坑

① 光照变化
晴天/阴天/夜间,红绿灯HSV值漂移严重。解决方案:动态自适应阈值(每帧取ROI局部直方图),或加入夜间模式——检测红灯的圆形轮廓+闪烁频率(欧洲红灯常亮,不闪烁)。

② 误报与漏报
行人闯红灯如果也触发警报,可能会让驾驶员麻木。我建议对行人降低警报优先级(只记录不蜂鸣),对机动车严格拦截。另外停止线标定需要现场测量,不同摄像机角度需重新标定。

③ 延迟与帧率
Jetson Nano在640x640输入下推理45ms,但I/O和绘制框会额外增加。可启用NVIDIA TensorRT优化(需将模型转为engine),推理能降到15ms。实测使用model.export(format='onnx')再加载ONNX,速度提升30%。

④ 供电与稳定性
路口的工业级电源(12V)搭配降压模块,Jetson Nano建议使用5V/4A直流供电,避免USB供电不足导致降频。添加看门狗定时器(WDT),防止程序卡死后不报警。

⑤ 法规与隐私
欧盟GDPR要求监控视频必须模糊人脸或车牌。可在detector.py中添加后处理:对行人检测框添加cv2.GaussianBlur,或只保存违规证据。

个人观点

纯视觉方案永远存在“黑天鹅”——比如太阳直射使红灯褪色、雾霾遮挡摄像头。如果想落地,必须融合雷达或地磁传感器做冗余。但作为开发者,用几百块的成本跑通一个能用的原型,本身就是技术和社会的胜利。比利时事故中,如果公交车上装了这个系统(哪怕只给驾驶员震动提醒),结果或许不同。技术不能弥补所有人为失误,但至少能多一次提醒。

现在打开IDE,照着本文代码,你也能在桌上搭一个小型路口监控。它不完美,但点亮LED那一刻,你就在用技术对抗悲剧。