为什么现在才发
MiBeeNVR 是个开源的 NVR,Go 写的。摄像头接入、录像存储、回放、导出,这些基础功能都有。
在这条链路后面挂一个做目标检测的程序------把录下来的视频过一遍、认出人和车、圈出感兴趣的区域、出了事把截图和结论塞回 NVR------这个想法比代码出现得早。代码仓库里最早一次提交是今年 6 月 15 日,到今天放出第一个可用版本,四个多月,74 次提交。
功能上早就打通了。我拿真实摄像头录的一段 9MB 多的视频丢进去,它能解码、能检测、能算区域归属,最后把结果写回 NVR,录像列表上多出 AI 标记。
这四个月主要花在两件事上。
一、检测结果会抖
最早那版跑起来,事件数量远超预期。太阳挪个位置影子变了,报一次;树被风吹得晃,报一次;晚上车灯扫过,报一次。单帧看每一帧都没错,连起来事件列表就被淹没了。
这没法靠调参解决。能调的只有阈值:调高了,人走进画面走到一半才认出来,框还在闪;调低了,回到满屏误报。
实际起作用的是几层不复杂的办法叠起来:在画面上画区域,区域外的不算;要求连续若干帧都命中才触发,帧数可调;判定时区分「位置」和「目标本身」,避免把同一帧里的两个目标当成一个。这些做法技术含量不高,只是让阈值那根线有地方搁。
需要说明的是:这属于把系统调到「不烦人」,不等于把模型变强了。 夜里、逆光、远距离小目标仍然会漏。这部分到现在还在调。
二、最初按实时去设计是错的
最初的设计是实时的------视频流进来,边到边算。这套思路在 NVR 这里不成立。
NVR 的实际情况是视频先落盘、再处理。一段录像几十秒到几分钟,文件在那儿放好了,什么时候读都行。这个场景不需要实时,但实时设计的成本要全部付出来:缓冲、排队、背压、多线程之间传递对象。视频和音频数据量一大,搬运开销比检测本身还大。
改成离线后处理之后,不少问题不再出现。机器忙的时候排队等着即可,不用抢,也不用为了不掉帧牺牲稳定性------视频落盘了才去碰它,最坏的情况是慢一点,不会是错的。
视频音频数据的处理效率目前还在优化,是这块最花时间的部分。
还有一个成本是语言选择:这一层用 Rust 写的,不是 NVR 那边的 Go。
选 Rust 不是因为语言时髦。这个场景的数据量大、生命周期长,任何一次悄悄的内存复制或者缓冲堆积,跑到第三天都会变成一个难以定位的问题;而 NVR 的常态是连接数不多、带宽松,并发代码写起来快,内存多复制几次也不影响运行。Rust 的所有权约束要求把每块大数据的归属写清楚,不能随手 clone 出第二份,也不能让两个线程同时持有一个可变引用。写起来更慢,按我的体感应是写 NVR 的三到四倍,换来的是内存占用和排队行为可预测。对一个要长期挂在生产录像旁边的常驻程序,这个取舍成立。
代价之一是二进制大:54MB 里有很大一部分是把解码器静态链了进去。文件大不等于内存占用大。
它是怎么接进 NVR 的

对接方式是不侵入的。NVR 照常录像,录完一段照例发一条事件通知,Vision 靠这条通知知道有新料,去把那一段取回来,读完把结论写回去。
NVR 那边不用升级、不用改配置,也不需要知道有这个东西存在。
由此带来的性质是:Vision 挂掉、没启动或算不过来时,录像不受影响,最坏的情况是 AI 标记一直是空的。摄像头该转码转码、该直播直播,录像链路不受牵连。
跑完一段能得到什么

输出包含框、类别、置信度、区域归属,以及一张画好框的快照。
图中画面是示意图,不是真实录像------真实画面涉及隐私,不放进文章。
区域决定的是告警的含义。没有区域,输出的只是「画面里有人」;加上区域之后才是「有人进了院子」。安防场景关心的是后者。
跑起来是个什么量级

单帧检测 40 毫秒左右,纯 CPU,不需要 GPU。默认每秒抽两帧分析,一段 60 秒的录像大约看 120 帧。
这个耗时在常见场景下不构成瓶颈。
另外两点降低使用门槛:模型内置在程序里,解压出来即可运行,不需要另外下载模型库;配置走网页,填 NVR 地址、粘 API Key、拉摄像头列表、选一个、拉区域、保存,不需要改配置文件。
目前的限制
-
一次处理一路摄像头。 Lite 版的处理上限就是一路。
-
平台是 Linux。 提供 x86_64 和 ARM64 两个架构。
-
视频音频数据的处理效率还在优化。
-
模型是通用目标检测。 覆盖人、自行车、狗、椅子这些大类;「快递」「翻墙」这类具体语义目前做不到。
怎么拿
在 MiBeeNVR 的发布页里,是一条独立的发行:
https://github.com/Mi-Bee-Studio/MiBeeNvr/releases/tag/mibee-vision-v0.1.0
下载对应自己机器架构的二进制,和随包的 libonnxruntime-*.so 放在同一目录,然后:
ORT_DYLIB_PATH=/opt/mibee-vision/libonnxruntime-1.17.1-linux-x86_64.so \
/opt/mibee-vision/mibee-vision-lite-v0.1.0-linux-x86_64 serve
浏览器打开 http://<本机IP>:9092,按页面提示填写。
两个需要注意的地方:ORT_DYLIB_PATH 必须设置 ,不设置则推理库加载不上;必须用 NVR 的 API Key(mbv_ 开头) ,网页登录用的 mbs_ 会话 token 无效,用它回写会返回 401。
跑起来之后,无论是否达到预期都欢迎反馈,失效的场景信息更有帮助。
