邻道车辆进入检测
画面中常有对向车道、路边停放的车辆。提高检测阈值后,分数足够的邻道目标仍会被检出。
每路相机标定多边形 ROI,区域外涂白后再送入模型。不改权重,只识别本车道。
通道需同时识别中国牌和俄罗斯牌。拉流与识别拆成两个进程:采集持续写图,识别只处理该路目录中最新一帧。 识别结果以 TCP JSON 上报业务系统;是否放行、是否抬杆由海关业务侧完成,不进入识别进程。
部署过程中遇到的问题,以及对应的处理方式。
画面中常有对向车道、路边停放的车辆。提高检测阈值后,分数足够的邻道目标仍会被检出。
每路相机标定多边形 ROI,区域外涂白后再送入模型。不改权重,只识别本车道。
部分车牌横向绑有铁丝,字符被遮挡。这不属于阈值或后处理能覆盖的情况,模型输出不可靠。
不在识别程序中做猜测补全。现场要求司机拆除铁丝后再通行,按通道管理处理。
拉流进程持续写图。过车只关心当前画面;若将目录中积压的历史帧全部送入模型,延迟和算力都会被拖高。
识别按修改时间只取当前目录最新一张。积压帧不进入推理。
M1 上两者分别链接 TBB 与 GNU OpenMP。无论加载顺序如何,进程会 abort(exit 134),或阻塞在 mutex。
OpenVINO 放到独立子进程,只承担检测和中国牌;主进程运行 PaddleOCR。图像经队列传递。
OCR 将主号与地区码读成连续字符串。后处理若只保留 6 个字符,三位地区码会被截断。
按 6 位主号加 2 或 3 位数字拼接,三位优先。T326XO-125 可以完整保留。
检测+中国牌:现场 Windows 上 OpenVINO 64.6 ms → 11.1 ms;M1 上同样的 IR 为 50.3 → 31.4 ms。
模型未更换。Intel 可走 AVX / VNNI;M1 的 OpenVINO 目前只有 ARM CPU 插件,没有核显和神经引擎路径。
模型在识别进程内只加载一份,多路相机共用。OpenVINO 单独子进程,避免与 PaddleOCR 的 OpenMP 运行时冲突。
视频会断流、重连,抽帧节奏也与推理不对齐。识别只读取已写完且最新的 jpg。采集进程退出时,模型无需重新加载。
配置中有几路相机,就启动几条识别线程。YOLO、CRNN、PaddleOCR 各一份,进程内共享,不是一路复制一套权重。
按推理顺序:先限车道,再读牌,最后上报。闸控不进入识别进程。
在抓拍图上标定四个顶点,写入该路 config.ini。推理前将车道外区域涂白。未配置则整图识别。标定工具 tools/lane_config.py 与线上读取同一套坐标。
[boxes] x1=120 y1=380 x2=1860 y2=400 x3=1920 y3=1080 x4=0 y4=1080
先由 YOLO 定位车牌,四点透视校正后由 CRNN 解码字符与颜色。满足 7 位、省份开头、蓝色或黄色,即判定为中国牌并结束该帧。
规则不匹配时,将同一检测框裁切后交给 PaddleOCR 3.x,按 6 位主号 + 地区码拼接俄牌。检测框常偏左,透视校正后再向右扩展,避免 125 被读成 25。
识别只发送 device_id / plate / color / country / img / time。是否放行、是否抬杆由业务系统决定。一线 / 二线入区出区共用同一套字段,区别只在相机位置。
{
"device_id": "43",
"plate": "M009XK-25",
"country": "rus"
}
Apple Silicon 上 PaddleOCR 2.x 首次推理会崩溃,已升级到 3.x。曾试用 RapidOCR,俄牌易被切成单字,未用于生产。
.pt 导出为 ONNX(opset 12),再转换为 OpenVINO FP16。运行时加载 IR 或 .pt,不加载 ONNX。默认后端为 PyTorch CPU。
python job_mac.py --backend mps,或环境变量 PLATE_BACKEND。MPS 只执行卷积,NMS 仍在 CPU。权重先在 CPU 加载再拷到 GPU;直接 map_location=mps 会触发 float64 相关错误。
.pt 约 1.12 MB,其中权重大约 0.89 MB。IR 的 bin 体量接近(0.91 MB),多出的 0.58 MB 来自 xml 中内联的 YOLO 解框计算图。.pt 中对应逻辑在 Python 侧,不计入文件大小。
MPS 与 CPU 的检测框 IoU=1.000,OpenVINO 相对 CPU 约 0.993。中国牌多数一致,远景个别字符可能不同。上报字段不变,业务侧无需同步修改。
M1 Pro:YOLO 检测,独立进程,warmup 10,重复 30 次,8 张 640 图。MPS 含 Host-to-Device 拷贝。
| 后端 | 平均 | P50 | P95 | 相对 CPU | 框 IoU |
|---|---|---|---|---|---|
| PyTorch CPU | 49.5 ms | 49.4 ms | 50.3 ms | 1.0× | — |
| PyTorch MPS | 21.7 ms | 21.6 ms | 22.7 ms | 2.3× | 1.000 |
| OpenVINO FP16 | 24.1 ms | 24.2 ms | 25.1 ms | 2.1× | 0.993 |
检测 + 中国牌 CRNN(不含俄牌 OCR)。Mac:8 张 640;Windows:现场单张 434×640。口径不完全一致,以加速倍数对照。
| 平台 | 后端 | 平均 | P50 | P95 | 只读字 | 加速 |
|---|---|---|---|---|---|---|
| Apple M1 Pro | PyTorch CPU | 50.3 ms | 51.0 ms | 53.6 ms | — | 1.0× |
| Apple M1 Pro | OpenVINO | 31.4 ms | 30.7 ms | 42.9 ms | — | 1.6× |
| Windows Intel | PyTorch CPU | 64.6 ms | 65.5 ms | 66.6 ms | 13.77 ms | 1.0× |
| Windows Intel | OpenVINO | 11.1 ms | 10.8 ms | 12.3 ms | 0.66 ms | 5.81× |
俄牌还需 PaddleOCR,大约 0.2–1 秒。端到端延迟的主要部分在 OCR,不在 YOLO。
公开卡车图,非绥芬河海关近景,用于检查检测框与后处理。现场距离、角度不同,个别字符可能不一致。红框为检测结果。
配置收拢到 config/,根目录只保留入口。现场启停通过控制台完成,避免直接操作命令行。
Socket 和后端在 settings.py。Mac / Windows 各一份相机列表。日志在 config/logger.py。
一键启动按顺序拉起拉流和识别,日志输出到同一窗口。车道 ROI 按钮打开标定工具。
tools/lane_config.py 在图上标定多边形,写回该路 config.ini。识别读取同一份文件,标定错误会直接进入推理。
python tools/control_panel.py python job_mac.py --once --backend mps python job_mac.py --once --backend openvino python tools/lane_config.py --dir img/imgs12
INT8 需要接近现场分布的校准数据,存在读错字的风险。Windows 上 FP16 已有 5.81 倍加速。路数继续增加时再评估,当前优先保证号牌正确。
条带 ×2.5 曾将 2848 宽的图拉到 4272,超过 PaddleOCR 4000 边长上限。当前仅对小图放大,最长边限制为 1600。