🎥 LuxVideoDet 整体架构
跨平台工业视频检测系统 — 单一视频源 + 多算法并行推理的通用框架 技术栈:C# / .NET 8 · OpenCvSharp · ONNX Runtime / OpenVINO · Avalonia UI · ASP.NET Core
1. 系统定位
LuxVideoDet 是一个面向工业制造现场的视频行为检测与流程合规判定平台。它从一路视频源(RTSP 摄像头 / 本地视频文件 / MQTT 推流 / 本地摄像头)读取画面,同时并行运行一个或多个「检测算法」,对画面中的目标进行识别、对作业流程进行状态机判定,并在命中违规/异常时触发多渠道告警(Webhook / 企业微信 / 语音播报 / PLC),同时落盘 NG 截图、录像与生产统计。
核心设计原则:
- 一源多用:视频流只拉取一次,分发给 N 个算法各自独立推理,避免带宽与解码浪费。
- 算法可插拔:每个算法是一个「描述符 + 算法类」的组合,通过反射自动注册,新增算法无需改动框架代码。
- 三宿主形态:同一套 Core 引擎由 Desktop(Avalonia 桌面端)、Web(ASP.NET Core 控制台)、Headless(无头服务)三种前端复用。
- 状态机驱动:每个流程类算法内部用显式状态机描述「上一步完成 → 检测下一步」的语义,而非散落的 if/else。
2. 解决方案结构
解决方案 LuxVideoDet.sln 由 6 个项目 + 1 个测试分组构成:
| 项目 | 类型 | 职责 |
|---|---|---|
| LuxVideoDet.Core | 类库 | 核心引擎:算法框架、推理引擎、视频源、通知、配置、存储、区域、渲染。所有业务逻辑所在,不依赖任何 UI。 |
| LuxVideoDet.Desktop | Avalonia 可执行 | 桌面客户端(MVVM + AXAML),配置编辑、实时预览、区域绘制、日志查看、NG 回放。 |
| LuxVideoDet.Web | ASP.NET Core 可执行 | Web 控制台:REST API + MJPEG 视频流 + 静态页面,远程配置与监控。 |
| LuxVideoDet.Headless | 控制台可执行 | 无头检测服务:命令行启动、Serilog 日志、Ctrl+C 优雅停机,用于服务器/盒子部署。 |
| LuxVideoDet.Localization | 类库 | UI 本地化:AppLocalizer + UiKeys,支持 zh-CN / en-US / vi-VN 三语。 |
| tests/LuxVideoDet.Tests | 测试 | 单元测试 + 集成测试(含各算法定向测试子项目)。 |
依赖方向:Desktop / Web / Headless → Core + Localization,三者互不依赖,共享同一套 Core 引擎。
3. Core 分层架构
LuxVideoDet.Core 内部按职责划分为以下命名空间(目录):
| 目录 | 职责 | 关键类型 |
|---|---|---|
Algorithm/ |
算法框架(接口、基类、工厂、结果模型、UI 动作) | IDetectionAlgorithm、IAlgorithmDescriptor、DetectionAlgorithmBase、DetectionAlgorithmFactory、DetectionResult |
Algorithm/Implementations/ |
21+ 个具体算法(每个一个目录) | 见 §5 算法清单 |
Algorithm/Pipeline/ |
多算法并行流水线 | MultiAlgorithmPipeline、AlgorithmWorker、PipelineFactory |
Inference/ |
推理引擎抽象与实现 | IInferenceEngine、OnnxInferenceEngine、OpenVinoInferenceEngine、RemoteHttpInferenceEngine、MqttInferenceEngine |
Inference/Postprocessors/ |
模型输出后处理(按任务类型) | DetectionPostprocessor、ObbPostprocessor、PosePostprocessor、SegmentationPostprocessor、ClassificationPostprocessor、PostprocessorFactory |
VideoSource/ |
视频源抽象与实现 | IVideoSource、RtspSource、CameraSource、LocalVideoSource、MqttVideoSource、VideoSourceFactory |
Notification/ |
告警通知渠道 | INotificationService、WebhookNotificationService、WeChatNotificationService、SpeakerNotificationService、PlcNotificationService、NotificationServiceFactory |
Configuration/ |
配置加载、存储、校验 | ConfigurationService、JsonConfigurationStore、SingleFileConfigurationStore、DetectionConfigurationValidator |
Configuration/Models/ |
配置数据模型 | DetectionConfiguration、AlgorithmConfig、VideoSourceConfig、InferenceConfig、RegionConfig、NotificationConfig |
Region/ |
检测区域(多边形 ROI)管理 | Region、RegionManager、RegionRenderer |
Aoi/ |
AOI 检测器(可插拔视觉算子) | IAoiDetector、AoiDetectorBase、AoiDetectorFactory、HandLandmark、UDet |
Storage/ |
截图/录像/统计落盘 | StorageManager、RecordingManager、VideoRecorder、ProductionStatisticsStore、CrossPlatformMediaWriter |
Rendering/ |
标注渲染 | TaskAwareDetectionRenderer、ClassificationOverlayRenderer |
Common/ |
基础类型 | Frame(Mat 封装) |
Utils/ |
工具 | ChineseTextRenderer(帧内中文)、FpsCounter、CooldownTimer、RollingMinute*Stats(滑动窗口统计)、PythonNetRuntimeHost |
Logging/ · Extensions/ |
日志与 DI 扩展 | AddLuxVideoDetCore() 服务注册入口 |
4. 运行时数据流
一次检测会话(Session)从启动到产出的完整链路如下:
关键机制:
- 单帧多投:
BroadcastLoopAsync是唯一的取帧线程,读取一帧后分发给所有AlgorithmWorker。单算法时直接传原始帧(零克隆),多算法时前 N-1 个收到克隆、最后一个收到原始帧,避免引用冲突。 - 异步解耦:每个 Worker 拥有独立的
Queue<Frame>与处理线程,以各自节奏推理,互不阻塞;队列满时丢弃最旧帧(RTSP 式跳帧),保证实时预览不堆积。 - 本地视频节流:
LocalVideoSource按标称帧率节流,防止文件被以最大速度解码导致播放加速。 - 录像解耦:录像帧由
IngestFrameForRecording(Mat)在取帧线程全速喂入环形缓冲,与算法推理速度无关,保证慢推理(如远程 HTTP)下 NG 视频帧仍充足。 - 多算法结果合成:以「处理帧数最多」的算法画面为底图,叠加其他算法的检测框与区域轮廓,避免快慢算法并行时画面「跳回过去」。
5. 算法开发框架
5.1 三层抽象
IAlgorithmDescriptor:算法的「元数据 + 工厂」。框架启动时通过反射扫描程序集中所有实现自动注册,无需手动改工厂代码。它声明了算法类型键、显示名、默认类别、所需区域、可配置的「其他参数」(DefaultOtherArgs)与 AOI 使用声明(AlgorithmAoiUsages)。DetectionAlgorithmBase:模板方法基类。子类只需实现ProcessDetections(核心判定逻辑);可选覆写GetDetectionClassBindings完成「业务键 ↔ 模型类名 ↔ ClassId」映射,基类会在配色前统一处理类别绑定。IDetectionAlgorithm:运行实例接口,Process(frame)是每帧入口。
5.2 每个算法的标准文件结构
一个算法目录通常包含以下协作文件(以 E9_2F_NXT_PDA_Feeding_Monitor 为例):
| 文件 | 职责 |
|---|---|
*Algorithm.cs |
算法主体:ProcessDetections 每帧算标志位、驱动状态机、构造结果/通知 |
*Descriptor.cs |
描述符:TypeKey/DisplayName/类别/区域/参数定义 |
*StateMachine.cs |
状态机:状态转移、超时判定、错误处理 |
*Context.cs |
上下文:跨帧状态、信号锁存、每帧输入的中间标志 |
*WorkState.cs |
状态枚举 |
*DetectionBindings.cs |
类别绑定:业务键 ↔ 模型类名 |
*Regions.cs |
区域定义(多边形 ROI 的默认形状/颜色) |
*UiActions.cs |
UI 动作(可选,如「确认错误」「手动置 NG」按钮) |
*PipelineChecklistRenderer.cs |
清单渲染(可选,帧内步骤清单) |
*CameraFlagReporter.cs |
摄像头 Flag 上报(可选,与 SimpleX 摄像头标志位联动) |
5.3 状态机模式
流程类算法采用「检测下一步」的状态机语义:
- 每个状态对应一个实际步骤;
TransitionTo进入新状态时重置CurrentStateEnterTime计时起点。 - 每帧
ProcessDetections先计算各信号的确认值(经ConfirmWithFrames连续 N 帧抗抖动),再交给状态机Update()判定推进或超时。 - 步骤超时:每个中间步骤可配独立的
*_timeout_seconds参数,超时即报「操作错误」并进入 ERROR 状态,等待恢复或手动确认。
5.4 算法清单
| 算法目录 | 说明 |
|---|---|
Example |
示例模板(新算法开发起点) |
E1_2F_Material_Distribution |
E1_2F 物料配送 |
E9_2F_NXT_PDA_Feeding_Monitor |
E9_2F NXT PDA 上料监测(备料→刷备料台→刷料架) |
ExpansionRoomPdDieBarcodeStation |
扩展间 PD 晶粒条码站(11 步状态机) |
GenericPipeline |
通用可配置流水线(声明式步骤/区域条件) |
MidFrameScanLoose / MidFrameScanStrict / MidFrameScanLooseHand |
中框扫描(宽松 / 严格 / 含手部) |
NtxSmt |
NXT SMT 上料(备料→扫卷码→扫料架) |
OvenDet |
烤箱检测(门/绿灯/手/料/料车/鼠标/扫描枪) |
OVEN |
烤箱(另一套实现) |
TwoOven |
双烤箱(OvenDet 变体,料车放空用 Empty_Cart 类) |
PackagingBehavior |
包装行为 |
ProneSleepingDetection |
趴桌睡觉检测(YOLO-pose 关键点三层判定) |
ReelFoilBagPackagingStation |
卷膜袋包装站 |
SafetyPpeWork |
安全 PPE 着装 |
SmtFeeder / SmtFeeders |
SMT 供料器(单/多,TypeKey 与目录分开) |
U7Lite |
U7 精简 |
UCS / UCSHand |
UCS / UCS 手部 |
6. 推理引擎体系
6.1 引擎抽象
所有推理引擎实现 IInferenceEngine 接口,通过 InferenceEngineFactory 按配置实例化:
| 引擎 | 实现 | 说明 |
|---|---|---|
| ONNX Runtime | OnnxInferenceEngine |
默认引擎,支持 CPU / CUDA(GPU) |
| OpenVINO | OpenVinoInferenceEngine |
Intel 硬件加速 |
| 远程 HTTP | RemoteHttpInferenceEngine |
将图像发往远程推理服务,支持按类置信度过滤 |
| MQTT | MqttInferenceEngine |
经 MQTT 主题接收远端推理结果 |
设备注册表 InferenceDeviceRegistry 提供 CPU / CUDA / QNN / CoreML 等设备描述。
6.2 模型输出布局
DetectionOutputLayout 自动区分两种导出格式:
- 标准格式:
[1, 4+nc, anchors](YOLO 原始输出,需本框架做 NMS)。 - end2end 格式:
[1, max_det, 6](导出时已内嵌 NMS),按dim2==6 && dim1>6自动识别,不重复 NMS。
预处理:letterbox + BGR→RGB + /255 + NCHW。后处理按任务类型由 PostprocessorFactory 分发(检测/旋转框/姿态/分割/分类),检测类无 DFL。
6.3 类别名解析
- 模型类别名从 ONNX 元数据
metadata_props["names"]读取。 ClassIdsResolution将「业务键 ↔ 模型类名」绑定解析为实际 ClassId;配置classes与 metadata 不一致时引擎告警并按模型顺序强制解析。ClassIdAutoMapper支持类别名自动映射。
7. 通知体系
告警由算法在 DetectionResult 中携带,经 NotificationServiceFactory 分发到配置的渠道:
| 渠道 | 实现 | 载体 |
|---|---|---|
| Webhook | WebhookNotificationService |
HTTP POST JSON,支持自定义正文模板 |
| 企业微信 | WeChatNotificationService |
固定格式消息(含图片/视频路径) |
| 语音播报 | SpeakerNotificationService |
TTS 或固定音频文件 |
| PLC | PlcNotificationService |
Modbus TCP 写寄存器数字量 |
正文归属原则:NotificationMessage.Text(自定义模板)由算法自行构造,渠道不硬编码算法文案。当算法未提供 Text 时,Webhook 回退到通用默认格式 【标题】\n时间\n级别\n内容(标题优先级:title_content 参数 → NotificationTitle → AlgorithmType → “检测告警”)。企业微信 / 喇叭 / PLC 各自使用固定格式,不读 Text。
8. 配置系统
- 存储:
JsonConfigurationStore(多文件)或SingleFileConfigurationStore(单文件configs.json)。 - 服务:
ConfigurationService提供ListAsync/LoadAsync/SaveAsync/ValidateAsync/ImportAsync等。 - 序列化:JSON 键统一 camelCase(
ConfigurationJsonOptions.ForConfigurationFile+JsonNamingPolicy.CamelCase),代码中禁止使用JsonPropertyName特性。 - 校验:
DetectionConfigurationValidator在启动/保存时校验区域完整性、算法与模型类别匹配等,缺失必要区域抛MissingAlgorithmRegionsException。 - 数据模型:
DetectionConfiguration(顶层,含Name/Id/Enabled/VideoSource/Algorithms[])→AlgorithmConfig(含AlgorithmType/Inference/Regions/Notification/Args)→InferenceConfig(模型路径/设备/阈值/类别)。
9. 存储与统计
| 组件 | 职责 |
|---|---|
StorageManager |
统一管理截图/录像保存目录与生命周期 |
RecordingManager + VideoRecorder |
NG 录像:环形缓冲 + 事件触发导出 |
FileStorageService |
跨平台文件写入(含回退目录) |
ProductionStatisticsStore |
生产统计:按「日期 + 配置名」分桶,跨程序重启不归零;算法通过实现 IProductionStatisticsProvider 覆写 SetStatisticsCounters 上报 OK/NG |
CrossPlatformMediaWriter |
跨平台媒体编码(JPEG/视频封装) |
10. 三种宿主形态
| 宿主 | 启动入口 | 适用场景 |
|---|---|---|
| Desktop | App.axaml → MainWindow |
现场调试、配置编辑、实时画面预览、区域绘制、NG 回放 |
| Web | Program.cs(Kestrel,默认端口 5050) |
远程监控:REST API(配置/会话/统计/NG 回放)+ MJPEG 视频流 |
| Headless | Program.cs(控制台) |
服务器/盒子部署:命令行筛选配置、Serilog 日志、优雅停机 |
三者均通过 AddLuxVideoDetCore() 复用同一套 DI 注册与 Core 引擎,仅前端呈现层不同。
11. 关键设计决策(约定)
- JSON 键 camelCase,禁止
JsonPropertyName特性。 - UI 文案本地化:一律
_appLocalizer.GetString(UiKeys.Xxx),禁止 AXAML 硬编码中文。 - 增量功能禁止引入新 NuGet 包。
- 「其他参数」UI 自动驱动:
IAlgorithmDescriptor.DefaultOtherArgs声明参数即出现在编辑器,无需改 ViewModel/AXAML。 - 清单渲染统一缩放:
s = frame.Width / 2560.0,新增清单渲染器须带同样缩放。 - 通知正文归算法所有:渠道不硬编码算法文案。
- NG 录像与推理解耦:录像帧全速喂入环形缓冲,不在
Process内喂。 - 类别名严格一致:模型 metadata 类别名须与代码类名精确匹配(大小写/空格/拼写)。
- 测试用
--filter定向运行:存在预存错误时跳过,避免全量测试被旧错误阻塞。 - 模型选型以实测为准:不同训练轮次/窄化重训模型能力差异大,不能仅凭类别名判断。
文档基于代码库 LuxVideoDet.sln 结构梳理,随架构演进持续更新。