红绿灯辅助系统

基于 LYTNetV2 ONNX 的实时交通信号灯识别 · 视障人士出行辅助 · WebSocket 实时处理

1. 系统架构

┌──────────────────────────────────────────────────────────────┐ │ 手机浏览器 (Chrome/Edge) │ │ 摄像头采集 → JPEG 帧 → WebSocket 发送 │ │ ← 识别结果 + TTS 语音播报 │ └────────────────────────┬─────────────────────────────────────┘ │ Socket.IO (WebSocket) ▼ ┌──────────────────────────────────────────────────────────────┐ │ Flask + Flask-SocketIO (app.py :5008) │ │ │ │ 每客户端独立识别线程 (_recognition_loop) │ │ │ │ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────┐ │ │ │Preprocessor│→│Color │→│LYTNetV2 │→│Digit │ │ │ │ CLAHE增强 │ │Detector │ │Classifier│ │Recognizer │ │ │ │ 光照归一化 │ │ HSV色彩 │ │ ONNX推理 │ │ 倒计时OCR │ │ │ └─────────┘ └────┬─────┘ └────┬─────┘ └──────┬──────┘ │ │ ▼ ▼ ▼ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ LightTracker (150帧保持) + DirectionDetector (箭头) │ │ │ │ GuidanceCalculator (偏离指导) + VoiceStrategy (播报) │ │ │ └──────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ emit("result") → 浏览器显示 + TTS 语音 │ └──────────────────────────────────────────────────────────────┘

系统通过手机摄像头实时采集交通灯图像,浏览器将 JPEG 帧通过 WebSocket 发送至 Flask 服务端。服务端执行多阶段识别流水线,将结果(灯色、方向、倒计时、瞄准指导)实时返回前端,并通过 TTS 语音播报。

2. LYTNetV2 ONNX 模型

模型名称LYTNetV2 (Light-weight YOLO-based Traffic light Network)
格式ONNX (Open Neural Network Exchange)
推理引擎OpenCV DNN (cv2.dnn.readNetFromONNX)
输入尺寸768×768 (resize + pad, 保持宽高比)
预处理BGR→RGB, /255.0 归一化到 [0,1], mean=[0,0,0], std=[255,255,255]
推理速度~30ms/frame (CPU, OpenCV DNN)
准确率94~98%
模型大小14.3 MB (lytnetv2.onnx)

分类类别

Class ID类别含义触发行为
0red红灯语音播报"红灯,请等待"
1green绿灯语音播报"绿灯,可以通行"
2none无信号灯保持HSV检测结果
3countdown_blank倒计时黑屏忽略
4countdown_green绿灯+倒计时逐秒播报倒计时(5秒内)

LYTNetV2 作为二级验证分类器:HSV 色彩检测初步定位信号灯区域 → 裁剪 ROI 四周扩展 60% → LYTNetV2 对裁剪区域分类 → 置信度 >40% 时采用模型结果覆盖 HSV 判定。有效过滤 HSV 的误检(如橙黄色广告牌、红色车尾灯)。

3. 识别流水线

手机端每帧 JPEG (原始分辨率) │ ▼ ┌─ 服务端 _recognition_loop ──────────────────────────────┐ │ │ │ ① FrameController.get() 取帧 (跳过积压帧) │ │ │ │ │ ▼ │ │ ② Preprocessor (640×480) │ │ CLAHE 自适应直方图均衡 → 光照归一化 → BGR增强图 │ │ │ │ │ ▼ │ │ ③ ColorDetector (HSV 色彩空间) │ │ 红色 H[0~10]∪[170~180], S>80, V>80 │ │ 绿色 H[50~90], S>80, V>80 │ │ → raw_color, raw_roi (信号灯包围盒) │ │ │ │ │ ▼ │ │ ④ DirectionDetector (箭头方向) │ │ 对 ROI 做形态学分析 → 直行/左转/右转 │ │ │ │ │ ▼ │ │ ⑤ ROI 映射到原始高分辨率帧 │ │ sx = 原图W/640, sy = 原图H/480 → big_roi │ │ │ │ │ ▼ │ │ ⑥ DigitRecognizer (倒计时 OCR) │ │ 对 big_roi 做灰度+二值化+轮廓提取 → 数字识别 │ │ → countdown 倒计时秒数 │ │ │ │ │ ▼ │ │ ⑦ LYTNetV2 二级验证 │ │ ROI 四周扩展 60% → crop 768×768 → ONNX推理 │ │ conf>40% 时: 覆盖 HSV 的 color 结果 │ │ │ │ │ ▼ │ │ ⑧ LightTracker.update() │ │ 150帧 hold (5秒) + 2x expand_ratio │ │ 稳定追踪:短暂被遮挡/闪烁不丢失目标 │ │ │ │ │ ▼ │ │ ⑨ GuidanceCalculator.compute() │ │ ROI中心偏离画面中心的 dx/dy → left/right/up/down/center│ │ │ │ │ ▼ │ │ ⑩ VoiceStrategy.decide() │ │ 优先级: 绿灯倒计时5秒 > 红绿灯切换 > 方向引导 > 无信号 │ │ 去重: 相同内容 2~8秒内不重复播报 │ │ │ │ │ ▼ │ │ emit("result") → {color, direction, countdown, │ │ roi, guidance, speech_text, fps} │ └─────────────────────────────────────────────────────────┘

4. 核心代码

LYTNetV2 ONNX 推理

class LYTNetClassifier: INPUT_SIZE = 768 CLASSES = {0: "red", 1: "green", 2: "none", 4: "countdown_green"} def classify(self, image): # resize+pad → 768×768, BGR→RGB, /255 blob = self._preprocess(image) self.net.setInput(blob) outputs = self.net.forward() # OpenCV DNN, ~30ms probs = outputs[0].flatten() class_id = int(np.argmax(probs)) return {"class_name": CLASSES[class_id], "confidence": float(probs[class_id])}

识别主循环 (精简)

def _recognition_loop(sid): while not stop.is_set(): frame = buffer.get() # 取帧 enhanced = preprocessor.process(frame) # CLAHE color_result = color_detector.detect(enhanced) # HSV color = color_result["color"]; roi = color_result["roi"] if color and roi: direction = direction_detector.detect(frame, roi) # 箭头 countdown = digit_recognizer.recognize(orig, big_roi) # OCR # LYTNetV2 二级验证: ROI扩展60% → 裁剪 → ONNX crop = frame[y1:y2, x1:x2] lyt = lytnet.classify(crop) if lyt["confidence"] > 0.4: color = lyt["class_name"] # 模型覆盖HSV tracker.update(roi) # 追踪 guidance = guide.compute(roi) # 瞄准指导 speech = voice.decide(result, guidance) # TTS策略 emit("result", {"color": color, "direction": direction, "countdown": countdown, "guidance": guidance, "speech": speech, "fps": fps})

5. 模块详解

ColorDetector (HSV 色彩检测)

基于 HSV 色彩空间的初级检测器。红色: H[0,10]∪[170,180], S>80, V>80;绿色: H[50,90], S>80, V>80。输出包围盒+颜色标签。速度快但存在误检(广告牌、尾灯等)。

LYTNetClassifier (深度学习验证)

LYTNetV2 ONNX 模型,OpenCV DNN CPU 推理 ~30ms。对 HSV 检测到的 ROI 区域进行二次分类验证,conf>40% 时覆盖 HSV 结果。5 分类: red/green/none/countdown_blank/countdown_green。

DigitRecognizer (倒计时 OCR)

对原始高分辨率帧上映射的 big_roi 区域做灰度化+自适应二值化+轮廓提取,识别倒计时数字。HSV→原图坐标映射: sx=Worig/640, sy=Horig/480。

DirectionDetector (箭头方向)

对 ROI 区域做形态学分析,提取箭头轮廓,判断方向:直行(straight)/左转(left)/右转(right)。辅助视障用户区分不同方向的信号灯。

LightTracker (目标追踪)

hold_frames=150 (5秒) + expand_ratio=2.0。信号灯短暂被遮挡或闪烁时不丢失目标。追踪激活时限制 HSV 检测范围到上次 ROI 的扩展区域(2x),减少误检。

GuidanceCalculator (瞄准指导)

计算 ROI 中心偏离画面中心的偏移量。死区 25%,触发阈值 32%。输出: center/left/right/up/down,指导视障用户调整手机角度对准信号灯。

VoiceStrategy (语音播报策略)

优先级: ①绿灯≤5秒逐秒倒计时 ②红绿灯状态切换 ③方向+倒计时 ④偏离指导 ⑤无信号提示。去重: 相同内容 2~8秒内不重复播报。间隔: ≥0.8秒。

FrameController (帧控)

缓冲队列管理,自动跳过积压帧(取最新帧),防止处理延迟累积。配合 FPSMeter 实时统计处理帧率。

6. 技术亮点

HSV + LYTNetV2 双阶段检测

HSV 快速初筛 (轻量) → LYTNetV2 ONNX 深度验证 (精确)。兼顾速度与准确率,有效过滤尾灯、广告牌等误检源。

150 帧追踪保持

信号灯短暂被遮挡(行人/车辆经过)不丢失目标。追踪激活时 HSV 检测范围限制在上次 ROI 的 2x 扩展区域,减少全局误检。

双分辨率流水线

HSV/LYTNet 使用 640×480 (速度优先),OCR 使用原始高分辨率 (精度优先)。ROI 坐标自动映射 (sx, sy),兼顾速度与 OCR 可读性。

WebSocket 实时通信

Socket.IO 双向通信: 浏览器→服务端发送 JPEG 帧,服务端→浏览器推送识别结果+语音文本。每客户端独立线程+独立追踪器,支持多用户并发。

自适应语音播报

智能去重+优先级调度: 绿灯倒计时 ≤5秒时逐秒播报,红绿灯切换即时播报,偏离指导按需播报。相同内容不重复、不同内容不冲突。

ONNX 跨平台推理

LYTNetV2 转为 ONNX 格式,OpenCV DNN 推理无需 PyTorch/TensorFlow。CPU 推理 ~30ms,支持 Ubuntu/Windows/macOS 跨平台部署。

7. 技术栈

类别技术说明
Web 框架Flask + Flask-SocketIOHTTP路由 + WebSocket 实时双向通信
深度学习LYTNetV2 ONNX + OpenCV DNN14MB模型, CPU推理~30ms, 94~98%准确率
图像处理OpenCV (cv2)CLAHE增强, HSV色彩空间, 形态学, 轮廓提取
数值计算NumPyJPEG解码, 矩阵运算, 坐标映射
语音合成Edge-TTS / 浏览器 Web Speech APITTS 文本转语音, 前端播放
前端原生 HTML/CSS/JS + Socket.IO Client摄像头采集, Canvas渲染, 语音播报
部署Ubuntu 22.04 + systemd + nginxHTTPS 反向代理, 开机自启

8. 部署架构

用户手机 Chrome │ 摄像头 + WebSocket ▼ https://cdqtech.online/traffic/ │ ▼ ┌─────────────────────────────────────────┐ │ nginx (124.221.224.40:443) │ │ location /traffic/ { │ │ proxy_pass http://127.0.0.1:5008/; │ │ proxy_http_version 1.1; │ │ proxy_set_header Upgrade ...; │ │ proxy_set_header Connection ...; │ │ } │ └────────────┬────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────┐ │ systemd: traffic-assist.service │ │ WorkingDirectory=/data/traffic-assist │ │ ExecStart=venv/bin/python app.py │ │ Port: 5008 (Flask + Socket.IO) │ └────────────┬────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────┐ │ /data/traffic-assist/ │ │ ├── app.py Flask 主程序 │ │ ├── lytnet_classifier.py LYTNetV2 ONNX│ │ ├── lytnetv2.onnx 14MB 模型权重 │ │ ├── color_detector.py HSV 色彩检测 │ │ ├── digit_recognizer.py 倒计时 OCR │ │ ├── direction_detector.py 箭头方向检测 │ │ ├── preprocessor.py CLAHE 预处理 │ │ ├── tracker.py 目标追踪 │ │ ├── guidance_calculator.py 瞄准指导 │ │ ├── voice_strategy.py 语音播报策略 │ │ ├── frame_controller.py 帧控管理 │ │ ├── tts_generator.py TTS 语音合成 │ │ └── static/ 前端静态文件 │ └─────────────────────────────────────────┘