# deepstream-multi-analysis **Repository Path**: Glacier_J/deepstream-multi-analysis ## Basic Information - **Project Name**: deepstream-multi-analysis - **Description**: 基于DeepStream SDK 开发的多路视频流分析服务 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-20 - **Last Updated**: 2026-09-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: deepstream, Yolo, Python ## README # DeepStream Multi-Analysis 基于 [NVIDIA DeepStream](https://developer.nvidia.com/deepstream-sdk) 的多路视频智能分析系统,实现机场停机坪/道路场景下的**多摄像头车辆检测、跟踪与速度估计**,并将结果以 **RTSP 视频流** 和 **Kafka 结构化消息** 两种方式对外输出。 ## 功能特性 - **多路视频接入**:通过 `nvurisrcbin` 固定加载多路本地文件或 RTSP 流,`nvstreammux` 统一批处理。 - **车辆检测与跟踪**:YOLO11 / YOLO26 检测 + NvDCF 多目标跟踪(`display-tracking-id` 叠加跟踪 ID)。 - **车辆速度估计**:基于单应性变换(像素 → 真实世界米制坐标)与媒体时间戳(PTS)的轨迹测速,带 EMA 平滑与速度限幅。 - **RTSP 输出**:`nvmultistreamtiler` 拼图 + `nvdsosd` 叠加 + H.264 编码,通过 `rtspclientsink` 发布到 MediaMTX / ZLMediaKit 等媒体服务器。 - **Kafka 消息推送**:支持两种方式 —— 官方 `nvmsgconv` + `nvmsgbroker` 插件,或自定义 `KafkaManager` 工作线程推送结构化 JSON。 - **相机标定**:JSON 配置每路相机的道路四点区域与真实世界尺寸,按 `camera_id` 隔离轨迹与测速状态。 - **优雅退出**:父子进程协作处理 `SIGINT` / `SIGTERM`,先优雅停止、超时后 `SIGTERM`、再 `SIGKILL`,避免遗留孤儿进程。 ![alt text](image.png) ![alt text](056cc8c4bf3d67be76bd81989434a58f.jpg) ![alt text](ac804faf3faf3659c20a426c4daf5f96.jpg) ## 处理链路 ``` nvurisrcbin(多路固定源) → nvstreammux(batch = 路数) → nvinfer(YOLO11 / YOLO26,TensorRT) → nvtracker(NvDCF) → tee ├─ 视频分支:nvmultistreamtiler → nvdsosd(检测框/ID/速度) │ → nvv4l2h264enc → h264parse → rtspclientsink(发布 RTSP) └─ 消息分支:nvmsgconv → nvmsgbroker(发布 Kafka) (可选) ``` 测速逻辑通过 `Probe` 挂载在 `tracker` 之后,由 `MultiStreamSpeedEstimator` 逐帧处理 DeepStream 元数据,按 `camera_id` 隔离轨迹并计算速度、叠加 OSD 文本。 ## 目录结构 ``` deepstream-multi-analysis/ ├── configs/ # deepstream-app 风格配置(早期方案,含 YOLO26 engine) ├── speed/ # Service Maker Pipeline API 主应用 │ ├── deepstream_speed_pipeline.py # 应用入口与进程生命周期 │ ├── speed_pipeline.py # Service Maker Pipeline 声明 │ ├── speed_estimator.py # 标定加载 + 元数据处理 + 测速 + OSD + Kafka payload │ ├── speed_config.py # 配置模型(Pydantic)、加载与校验 │ ├── camera_calibrations.json # 相机标定配置 │ ├── ai_kafka/kafka_manager.py # KafkaProducer 工作线程(Python 侧推送) │ ├── common/ │ │ ├── speed_estimation.py # 单应性变换、EMA 平滑速度计算(参考实现) │ │ └── timestamp_speed.py # 基于 PTS 的轨迹测速(当前实际使用) │ ├── utils/ │ │ ├── export_yolo11.py # YOLO11 → ONNX 导出 │ │ ├── export_yolo26.py # YOLO26 → ONNX 导出(支持动态 batch) │ │ └── logger_util.py # 统一日志格式 │ ├── config/ # msgconv / pgie 配置(dstest4) │ ├── models/ # YOLO 权重(.pt / .onnx) │ ├── deepstream_test5_app/ # NVIDIA 官方 test5 示例(参考) │ └── requirements.txt └── LICENSE ``` ## 环境要求 - NVIDIA GPU + [NVIDIA DeepStream 9.0](https://developer.nvidia.com/deepstream-sdk) 容器/环境(依赖 `pyservicemaker`,仅在 DeepStream 环境内可用) - TensorRT、GStreamer(`nvurisrcbin`、`nvstreammux`、`nvinfer`、`nvtracker` 等插件) - Python 3.10+,依赖见 [speed/requirements.txt](speed/requirements.txt): ```text opencv-python==4.8.0.76 numpy==1.26.4 pyyaml==6.0.2 onnx==1.22.0 kafka-python==3.0.11 ``` > `pydantic` 由 `speed_config.py` 使用,`pyservicemaker` 由 DeepStream 提供,二者不在此 requirements 中。 ## 快速开始 1. **准备视频/流与标定**:将视频放入 `speed/videos/`(默认已加入 `.gitignore`),并在 [speed/speed_config.py](speed/speed_config.py) 的 `STARTUP_SOURCES` 中登记数据源,在 [speed/camera_calibrations.json](speed/camera_calibrations.json) 中补充对应 `camera_id` 的标定。 2. **准备模型**:默认使用 YOLO26,需将 `config_infer_primary_yolo26.txt` 与 `model_b{N}_gpu0_fp32.engine` 放置在容器内 `/workspace/speed/` 下(engine 不存在时 `nvinfer` 会基于 ONNX 首次构建)。 3. **启动媒体服务器**(发布 RTSP 时需要):先启动 MediaMTX / ZLMediaKit 并监听对应端口。 4. **运行**: ```bash cd /workspace/speed python3 deepstream_speed_pipeline.py ``` 首次运行时输出会以 RTSP 发布到 `RTSP_PUBLISH_URL` 指定的地址,默认 `rtsp://192.168.1.122:6554/live/speed-result`。播放: ```bash ffplay -rtsp_transport tcp rtsp://192.168.1.122:6554/live/speed-result ``` ## 配置说明 应用通过**环境变量**覆盖默认配置(在 [speed/speed_config.py](speed/speed_config.py) 中加载): | 环境变量 | 默认值 | 说明 | | --- | --- | --- | | `PGIE_CONFIG_FILE` | `/workspace/speed/config_infer_primary_yolo26.txt` | nvinfer 主检测器配置 | | `PGIE_ENGINE_FILE` | `/workspace/speed/model_b{路数}_gpu0_fp32.engine` | TensorRT 推理引擎 | | `TRACKER_LL_CONFIG_FILE` | `config_tracker_NvDCF_perf.yml` | NvDCF 跟踪器配置 | | `TRACKER_LL_LIB_FILE` | `libnvds_nvmultiobjecttracker.so` | 跟踪器动态库 | | `MUX_WIDTH` / `MUX_HEIGHT` | `1920` / `1080` | streammux 统一输出尺寸 | | `OUTPUT_FPS` | `30` | 编码输出帧率 | | `BATCHED_PUSH_TIMEOUT_US` | `40000` | streammux 成批等待时间(微秒) | | `RTSP_PUBLISH_URL` | `rtsp://192.168.1.122:6554/live/speed-result` | RTSP 发布目标 | | `RTSP_PUBLISH_USER` / `RTSP_PUBLISH_PASSWORD` | 无 | RTSP 发布认证 | | `RTSP_PUBLISH_LATENCY_MS` | `200` | rtspclientsink 缓冲延迟 | | `CAMERA_CALIBRATION_FILE` | `speed/camera_calibrations.json` | 相机标定文件 | | `SOURCE_FILE_LOOP` | `false` | 本地视频循环开关 | | `LOG_LEVEL` | `INFO` | 应用日志级别(DEBUG/INFO/WARNING/ERROR/CRITICAL) | | `INFERENCE_LOG_INTERVAL_SEC` | `5` | 推理摘要输出周期(秒) | ### 数据源与开关 - 启动源在 [speed/speed_config.py:23](speed/speed_config.py#L23) 的 `STARTUP_SOURCES` 中声明,默认 4 路本地视频;`camera_id` 必须唯一,需测速时还要与标定文件中的 ID 一致。 - 速度估计与 Kafka 推送分别由 [speed/deepstream_speed_pipeline.py:38-40](speed/deepstream_speed_pipeline.py#L38-L40) 顶部的 `ENABLE_SPEED_ESTIMATION`、`ENABLE_KAFKA` 常量控制,当前默认均为 `False`。 ## 测速原理与相机标定 速度估计流程([speed/common/timestamp_speed.py](speed/common/timestamp_speed.py) + [speed/speed_estimator.py](speed/speed_estimator.py)): 1. **单应性变换**:将车辆检测框**底边中心点**(接地近似点)从画面像素坐标,通过 `cv2.getPerspectiveTransform` 映射到标定区域的真实世界米制坐标。 2. **轨迹测速**:按 `camera_id` + `tracker_id` 维护坐标/时间戳队列,用 PTS 计算时间间隔,欧氏距离除以时间得到速度(m/s → km/h)。 3. **平滑与限幅**:EMA 平滑(`ema_alpha=0.15`),限幅 `5 ~ 35 km/h`,低于下限视为静止。 每台相机的标定配置存储在 [speed/camera_calibrations.json](speed/camera_calibrations.json),字段: - `source_polygon`:画面中路面区域的 4 个角点(像素坐标,4×2)。 - `target_width_m` / `target_height_m`:该区域对应的真实世界宽/高(米)。 - `calibration_width` / `calibration_height`:标定时的画面尺寸。 > 更换摄像机或视频后,必须重新标定这四点与真实尺寸,否则测速不准确。 未标定或条件不满足时,`status` 会标记为 `UNCALIBRATED` / `NO_TIMESTAMP` / `CALIBRATION_MISMATCH`,此时仅检测和跟踪、不计算速度。 ## 输出 ### RTSP 视频流 画面为所有在线源的单幅拼图(`nvmultistreamtiler`),叠加 YOLO 检测框、NvDCF 跟踪 ID、速度标签(如 `ID 12 23 km/h`)以及相机名与状态。发布地址由 `RTSP_PUBLISH_URL` 决定。 ### Kafka 消息 存在两条独立路径: 1. **插件路径**:`nvmsgconv` + `nvmsgbroker`(DeepStream 官方插件),当 `OutputConfig.kafka_enabled` 为 `True` 时启用,在 [speed/speed_pipeline.py:145-168](speed/speed_pipeline.py#L145-L168) 构建。 2. **Python 路径**:`KafkaManager` 工作线程([speed/ai_kafka/kafka_manager.py](speed/ai_kafka/kafka_manager.py)),当 `ENABLE_KAFKA` 为 `True` 时启用,逐帧(每 5 帧)推送自定义结构化 JSON(含 `camera_id`、`frame_num`、`pts`、`status`、`objects` 及其速度)。Broker 与 topic 目前硬编码在 `KafkaManager` 中(`192.168.1.3:29092` / `airport-AI-video-analyze`),需按实际环境修改。 ## 模型转换 仓库自带 YOLO11 / YOLO26 的 ONNX 导出脚本,导出动态 batch 版本以支持多路推理: ```bash # YOLO26,动态 batch python3 utils/export_yolo26.py -w yolo26n.pt --dynamic --size 640 # YOLO11,动态 batch python3 utils/export_yolo11.py -w yolo11s.pt --dynamic --size 640 ``` 导出后由 `nvinfer` 根据 `batch-size = 路数` 自动构建对应 `.engine`。 ## 参考 - 更详细的运行说明与排障记录见 [speed/README.md](speed/README.md)。注意:该文档描述的是早期「动态数据源 + 内置 RTSP Server」版本,当前代码已切换为固定数据源 + `rtspclientsink` 发布(见 commit `b90df14`),请以本 README 与源码为准。 - NVIDIA 官方 `nvmsgconv` / `nvmsgbroker` 示例见 [speed/deepstream_test5_app/README](speed/deepstream_test5_app/README)。 ## License 见 [LICENSE](LICENSE)。