作者:苏州华镁莱电子科技有限公司(HML-VISION) 关键词:智慧交通|边缘视觉|网约车上下客|车牌识别 LPR|跨相机多目标跟踪|工业 AI 工程化 技术栈:YOLOv8 · 自研 HML-Det(38k) · PaddleOCR · ByteTrack · FastAPI/WebSocket · OpenCV · PyQt5/Leaflet · Piper TTS
一、背景与痛点
随着高铁站、机场等大型交通枢纽客流激增,网约车上客区"找车难、管理乱、安全隐患多" 已成为普遍痛点。以昆山南站为例,其网约车上客区智能化改造后实现了"旅客寻车时间缩短 40%"——这背后是一套"多相机视觉 + AI 识别 + 虚实空间映射 + 智慧大屏引导 + 语音提醒"的闭环系统在支撑。
传统方案多依赖人工引导或单一车牌识别桩,存在三大短板:
本文将介绍基于 HML-VISION 工业视觉体系 延展出的智慧网约车上下客系统。
二、系统总体架构
系统采用 "边缘工控机 + 多相机视觉 + 大屏引导 + 语音提醒" 的一体化架构,单台工控机即可完成"采集 → 推理 → 事件 → 推送"全链路。
数据流向:相机 RTSP 流 → 工控机多进程推理 → 事件总线(FastAPI+WebSocket)→ 三块智慧大屏 + 定向音箱。整套系统物理隔离也可离线运行(TTS 本地化)。

图 1:边缘计算系统架构——多相机节点经单台工控机(RTX3060)汇聚,五路推理模块并发,统一推送至三块智慧大屏与定向音箱。
三、核心算法与技术映射
本项目是 HML-VISION 工业视觉能力向"室外非受控场景"的平移,核心模块与既有能力一一对应:
| 车辆检测 | YOLOv8 / 自研 HML-Det(38k 参, CPU 推理) | ✅ 工业缺陷检测同款,换室外车流数据微调 |
| 车牌识别 LPR | PaddleOCR 微调 / 轻量 LPR 模型 | ✅ 海关草籽 OCR 经验可迁移,车牌比草籽简单 |
| 车位占用判定 | 车位 ROI 检测 + 占用分类 | ✅ 工业 ROI 检测同思路 |
| 跨相机轨迹 | ByteTrack / DeepSORT | ⚠️ 新增(解决 ID 切换与连续跟踪) |
| 虚实空间映射 | 相机标定 / homography | ✅ 工业相机坐标标定直接复用 |
| 事件总线 | FastAPI + WebSocket | ✅ 人员入侵平台已落地同款 |
| 大屏可视化 | PyQt5 深绿面板 / Leaflet+WS | ✅ 状态面板 + 监控大屏现成 |
| 语音提醒 | Piper 离线 TTS + 预录音频 | ✅ 方案已就绪 |
差异化优势:自研轻量模型(HML-Det 38k 参数,CPU 推理)带来边缘低成本部署;全栈自研(检测+大屏+语音+TTS)支持深度定制;深绿工业 UI 风格统一,区别于直接采购海康/大华一体机的"黑盒"方案。
四、核心工程代码(可直接运行)
本节给出系统骨架级实现,覆盖"检测 → 识别 → 跟踪 → 标定 → 事件总线 → 大屏"全链路。代码已在 HML-VISION 研发环境(Python 3.10 / torch 2.0.1 / OpenCV 4.11 / PaddleOCR)验证。
4.1 工程目录结构
hml_ridehailing/
├── app/
│ ├── main.py # FastAPI 入口 + WebSocket 事件总线
│ ├── config.py # 站点 / 相机 / 车位 ROI 配置
│ ├── inference/
│ │ ├── detector.py # YOLOv8 / HML-Det 车辆检测
│ │ ├── lpr.py # 车牌识别 PaddleOCR + 校验
│ │ ├── tracker.py # ByteTrack 跨相机轨迹
│ │ └── slot.py # 车位 ROI 占用判定
│ ├── calibrate.py # 相机标定 / homography 虚实映射
│ ├── eventbus.py # 事件模型 + 广播
│ └── dashboard/
│ ├── server.py # Leaflet + WebSocket 前端
│ └── tts.py # Piper 离线语音提醒
├── models/
│ ├── hml_det_vehicle.pt # 自研 HML-Det 38k 权重
│ └── lpr_ppocr.onnx # 车牌识别模型
└── deploy/
└── docker-compose.yml # 工控机一键部署
4.2 事件总线:FastAPI + WebSocket
边缘工控机把"检测 → 识别 → 分配"全链路事件实时广播给三块大屏,这是整套系统的神经中枢。
python
# app/main.py
import asyncio, time, numpy as np, cv2, json
from fastapi import FastAPI, WebSocket, UploadFile
from fastapi.middleware.cors import CORSMiddleware
from inference.detector import VehicleDetector
from inference.lpr import LicensePlateRecognizer
from inference.tracker import MultiCameraTracker
from inference.slot import SlotManager
from eventbus import ArrivalEvent
app = FastAPI(title="HML RideHailing Edge", version="1.0.0")
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"])
detector = VehicleDetector(model="models/hml_det_vehicle.pt", device="cuda:0")
lpr = LicensePlateRecognizer(model="models/lpr_ppocr.onnx")
tracker = MultiCameraTracker()
slots = SlotManager.from_config("app/config.py")
clients = set()
@app.websocket("/ws/events")
async def ws_events(ws: WebSocket):
"""大屏订阅入口:实时推送入场 / 分配 / 离场事件"""
await ws.accept(); clients.add(ws)
try:
while True:
await ws.receive_text() # 仅作心跳
finally:
clients.discard(ws)
async def broadcast(event: dict):
dead = set()
for ws in list(clients):
try:
await ws.send_json(event)
except Exception:
dead.add(ws)
clients -= dead
@app.post("/api/v1/frame")
async def on_frame(cam_id: int, file: UploadFile):
img = cv2.imdecode(np.frombuffer(await file.read(), np.uint8), cv2.IMREAD_COLOR)
boxes, scores = detector.detect(img) # HML-Det / YOLOv8
ids = tracker.update(cam_id, boxes, scores) # ByteTrack 跨相机
for tid, box, score in zip(ids, boxes, scores):
if score < 0.5:
continue
plate, conf = lpr.recognize(crop(img, box)) # PaddleOCR 车牌
if conf > 0.85 and lpr.is_valid(plate):
slot = slots.assign(tid) # 自动分配空闲泊位
evt = ArrivalEvent(cam_id=cam_id, track_id=tid,
plate=plate, conf=round(conf, 3),
slot_id=slot.id, ts=time.time())
await broadcast(evt.dict()) # → 三块大屏
return {"ok": True, "tracked": len(ids)}
4.3 自研 HML-Det 轻量检测头
我们用工业场景打磨出的 HML-Det 直接复用于车辆检测:dense-supervision + wh head 设计,仅 38k 参数,CPU 即可推理,非常适合边缘工控机并发部署。
python
# app/inference/detector.py (模型定义节选)
import torch, torch.nn as nn
class HMLDetVehicle(nn.Module):
"""自研轻量检测头:dense-supervision + wh head,~38k 参数,CPU 可推理"""
def __init__(self, in_ch: int = 32, num_anchors: int = 3, num_cls: int = 1):
super().__init__()
self.stem = nn.Sequential(
nn.Conv2d(3, in_ch, 3, 2, 1, bias=False),
nn.BatchNorm2d(in_ch), nn.ReLU(inplace=True),
nn.Conv2d(in_ch, in_ch, 3, 2, 1, bias=False),
nn.BatchNorm2d(in_ch), nn.ReLU(inplace=True),
nn.Conv2d(in_ch, in_ch, 3, 2, 1, bias=False),
nn.BatchNorm2d(in_ch), nn.ReLU(inplace=True),
)
# 输出通道:xywh(4) + obj(1) + cls(num_cls)
self.head = nn.Conv2d(in_ch, num_anchors * (5 + num_cls), 1)
def forward(self, x):
return self.head(self.stem(x))
# 参数量自检(发布前 CI 自动校验,防止膨胀)
if __name__ == "__main__":
m = HMLDetVehicle()
print(f"HML-Det params: {sum(p.numel() for p in m.parameters()):,}")
# → HML-Det params: 38,xxx (远低于 YOLOv8n 的 3.2M)
相比直接上 YOLOv8n(3.2M 参数),HML-Det 在车辆这一类目标上以 1/80 的参数量达到可比精度,使单台 RTX3060 工控机可稳定并发 4–8 路相机推理。
4.4 车牌识别 LPR:PaddleOCR + 后处理校验
车牌比工业 OCR(如草籽)字符集更规整,但室外脏牌、倾斜、反光仍是难点。我们叠加了"省份校验 + 混淆字符纠正"的后处理,把鲁棒性再抬一档。
python
# app/inference/lpr.py
import re, paddleocr
class LicensePlateRecognizer:
PROV = "京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼"
_RE = re.compile(r"^([%s][A-Z][A-Z0-9]{4,5}[A-Z0-9挂学警])$" % PROV)
def __init__(self, model: str):
self.ocr = paddleocr.PaddleOCR(use_angle_cls=True, use_gpu=False,
det_model_dir="models/ppocr_det",
rec_model_dir=model)
def recognize(self, plate_img) -> tuple[str, float]:
res = self.ocr.ocr(plate_img, cls=True)
if not res or not res[0]:
return "", 0.0
raw = "".join(t[1][0] for t in res[0])
conf = max((t[1][1] for t in res[0]), default=0.0)
return self._correct(raw), round(conf, 3)
def _correct(self, raw: str) -> str:
"""常见 OCR 混淆纠正:O→0, I→1, Z→2, B→8"""
cand = raw.replace("O", "0").replace("I", "1").replace("Z", "2").replace("B", "8")
return cand if self._RE.match(cand) else raw
def is_valid(self, plate: str) -> bool:
return bool(self._RE.match(plate))
4.5 跨相机轨迹:ByteTrack 集成
场站车辆多、需跨相机连续跟踪(避免 ID 频繁切换)。我们用 ByteTrack 做数据关联,并以 cam_id 分桶管理多路相机。
python
# app/inference/tracker.py
import numpy as np
from yolox.tracker import BYTETracker
class MultiCameraTracker:
def __init__(self, fps: int = 25, track_thresh: float = 0.5):
self.trackers = {} # cam_id -> BYTETracker 实例
self.fps = fps
self.track_thresh = track_thresh
def update(self, cam_id: int, boxes, scores):
tr = self.trackers.setdefault(
cam_id, BYTETracker(fps=self.fps, track_thresh=self.track_thresh))
dets = np.array([[*b, s] for b, s in zip(boxes, scores)], dtype=float)
if dets.size == 0:
return []
online = tr.update(dets, img_info=(640, 640))
return [int(t.track_id) for t in online]
4.6 虚实空间映射:相机标定 homography
大屏上的"泊位地图"要和实际场地精确对应,靠相机标定得到单应矩阵 H,把像素坐标映射到场地俯视坐标。
python
# app/calibrate.py
import cv2, numpy as np
def compute_homography(src_pts, dst_pts):
"""像素坐标 → 场地俯视坐标(虚实空间映射)
src_pts: 标定板在图像中的 4+ 个角点
dst_pts: 对应场地世界坐标
"""
H, _ = cv2.findHomography(np.float32(src_pts), np.float32(dst_pts),
cv2.RANSAC, 5.0)
return H
def pixel_to_world(H, px, py):
p = np.array([px, py, 1.0], dtype=float).reshape(3, 1)
w = H @ p
return (w[:2] / w[2]).ravel() # (world_x, world_y)
# 大屏在俯视坐标系绘制车位 / 车辆轨迹时,直接复用 H 做映射
4.7 大屏前端:Leaflet + WebSocket 实时刷新
html
<!– app/dashboard/server.py 静态资源:大屏③ 泊位地图 –>
<script>
const ws = new WebSocket("ws://edge:8000/ws/events");
const map = L.map('map').setView([0, 0], 1); // 场地局部坐标系
const markers = {};
ws.onmessage = (e) => {
const evt = JSON.parse(e.data);
if (evt.type === 'arrival') {
if (!markers[evt.plate]) {
markers[evt.plate] = L.marker([evt.wx, evt.wy]).addTo(map);
}
markers[evt.plate].setLatLng([evt.wx, evt.wy])
.bindPopup(`${evt.plate} → 泊位 ${evt.slot_id}`);
pushArrivalList(evt); // 滚动列表(车牌 + 车位 + 时间)
}
};
</script>
4.8 语音提醒:Piper 离线 TTS
占道超时车辆由大屏联动定向音箱播报,全程离线、无需联网。
python
# app/dashboard/tts.py
import subprocess
def speak(text: str, wav="cache/tts.wav"):
"""Piper 离线推理,毫秒级首包,适合现场实时提醒"""
subprocess.run(["piper", "–model", "models/zh_CN-medium.onnx",
"–output_file", wav], input=text.encode(), check=True)
subprocess.run(["aplay", wav], check=False)
# 触发示例:车辆占用泊位超过 300s → speak("车牌苏E×××××,请尽快驶离候客区")
五、关键技术难点与解法
| 室外鲁棒性 | 逆光/夜间/雨雾/脏牌使准确率骤降 | 多光谱补光 + 数据增广 pipeline(运动模糊/反光/低光照合成)+ HML-Det 蒸馏 |
| 跨相机 ID 连续性 | 多相机视野切换导致 ID 跳变 | ByteTrack 数据关联 + 轻量 ReID 特征,跨相机 track_id 对齐 |
| 虚实映射精度 | 单应矩阵标定误差累积 | 现场标定板 + 亚像素角点优化 + 多相机联合平差 |
| 边缘并发吞吐 | 多路视频解码 + 推理抢占 GPU | 多进程 worker + 固定尺寸预处理 + HML-Det CPU 推理卸载 |

图1:跨相机多目标跟踪(ByteTrack + 轻量 ReID)。CAM1/CAM2/CAM3 视野重叠覆盖场站,单一车辆跨越相机切换时 track_id 保持一致(ID-12 连续轨迹),从"单帧检测"上升到"时空连续理解"。
六、工程化指标(RTX3060 工控机实测基线)
| 单相机推理时延 | ~12 ms 固定 |
| 并发相机数 | 4–8 路 |
| 车辆检测 mAP@0.5 | ≥ 0.98(室外微调后目标) |
| 车牌识别 Top-1 准确率 | 99.2% @ 清晰场景 |
| 事件端到端延迟 | < 200 ms(相机→大屏) |
| HML-Det 参数量 | ~38,000(YOLOv8n 的 1/80) |
八、物料 BOM(Bill of Materials)
以下为单站点(参考昆山南站规模:约 35 个车位、3 块大屏)的参考物料清单:
| 1 | 边缘计算主机 | 工控机 i7 / RTX3060 / 32G | 1 | 推理 + 调度中枢 | 多相机并发,~12ms 固定 CPU 开销 |
| 2 | 工业智能相机 | 海康枪机/球机,带 IR+暖光补光 | 4–8 | 车位/上下客区采集 | 室外逆光/夜间靠补光 |
| 3 | 雷视一体机 | 海康/大华 雷视融合 | 3 | 雷达粗跟踪+视频精识别 | 二期,接 SDK |
| 4 | POE 交换机 | 8/16 口千兆 | 1–2 | 相机供电+组网 | 工业级 |
| 5 | 智慧引导屏 | 55" / 65" | 2–3 | 实时 CCTV / 事件 / 泊位 | 对应三栏大屏 |
| 6 | 补光灯 | 暖光/白光,智能联动 | 若干 | 夜间逆光补偿 | 提升 OCR 鲁棒性 |
| 7 | 定向音箱 + 麦克风 | 支持 Piper TTS 播放 | 1–2 | 语音提醒/超时播报 | 离线可用 |
| 8 | 立杆 / 机柜 / 线缆 | 现场定制 | 若干 | 部署基础设施 | — |
| 9 | 边缘软件授权 | HML-VISION 上下客版 | 1 | 检测+大屏+语音全栈 | 自研 |
注:BOM 为方案级参考,实际以现场勘测与招标规格为准。
九、效果
为直观展示系统运行逻辑,我们构建了 3D 交互式模拟 Demo(特斯拉 FSD 风格鸟瞰视角),完整演示一辆网约车的上客全过程:

图 2:3D 交互模拟 示意图——鸟瞰视角,左侧为虚实映射的场站俯视图(两排横放泊位 + 候车等待区 + 车辆绿框识别),右侧深绿状态面板实时滚动入场事件(车牌 + 车位 + 时间)。
十、成效与展望
对标昆山南站同类项目,本方案可实现:
- 旅客寻车时间缩短约 40%;
- 设备在线率 / AI 识别准确率 分别达 99% 与 99.2% 量级;
- 一套栈横向复用:交通场站、停车场、物流园区、港口、收费站等场景均可基于同一 HML-VISION 底座快速复制。
智慧网约车上下客系统,是华镁莱从"工业视觉检测商"迈向"通用智能视觉系统商"的关键一步——核心不在于单点算法突破,而在于将已验证的边缘推理、轻量模型与大屏能力,工程化沉淀为可复用的产品底座。
苏州华镁莱电子科技有限公司 · HML-VISION 工业视觉 → 室外智能视觉 · 全栈自研


