普通摄像头接入AI识别:绿联NAS部署Frigate监控实战

先说清楚这套方案解决什么问题

家里的摄像头大多是普通 IP 摄像头,能出 RTSP 流,但自带的人形检测基本靠 PIR 或者简单的画面变化判断,风一吹树叶、车灯扫过、猫走过去都会触发录像,手机一天能收到几十条推送。

我想要的其实不复杂:只在画面里出现人、车、猫狗这类目标时才记录事件,其余时间安静地存录像就行。Frigate 正好是干这个的------它把视频流拉进来,用目标检测模型逐帧推理,命中目标才生成事件,并且它自带一套基于 MQTT 和 Web UI 的事件管理,不需要自己再写一套后端。

之所以放在绿联 NAS 上,是因为它常年开机、有硬盘位、Docker 支持也齐全,比单独买一台 NVR 或者挂个树莓派省事。这篇就按我自己实际部署的顺序写一遍,中间哪些配置是必须的、哪些是坑,我会尽量说清楚。

硬件前提和版本说明

先说明一下我用的环境,因为 Frigate 对硬件比较敏感,不同平台配置差异不小:

  • 设备:绿联 DXP 系列 NAS(x86 架构,Intel 核显)
  • 系统:UGOS Pro,Docker 与 Docker Compose 可用
  • Frigate 镜像:ghcr.io/blakeblackshear/frigate:stable
  • 摄像头:两台支持 RTSP 的普通 IPC,主码流 1080p,副码流 640×360

【注意】Frigate 的镜像标签和配置项在版本之间改动比较频繁,我写这篇时用的是 stable 标签。你如果隔几个月再看,建议先去官方文档确认当前版本的配置字段,尤其是 detectobjectsrecord 这几块,字段名改过不止一次。我下面给的配置是以我本地能跑通的版本为准,不保证跨大版本完全兼容。

绿联 NAS 的 Docker 界面本质上是对标准 Docker 的封装,所以直接用 compose 文件最省事。我没有用它的图形化"容器"面板去逐个填参数,那样太容易漏环境变量。

为什么不用 CPU 直接跑检测

这是很多人第一步就会卡住的地方。Frigate 默认的检测器是 CPU(用 OpenVINO 或者直接跑 TFLite),1080p 一路流在纯 CPU 上推理,帧率会被压得很低,多路就基本跑不动。

Frigate 的检测流程大致是这样的:它从摄像头拉流,按 detect 里配置的宽高做缩放,然后把这个小图送进检测器推理,得到目标框之后再映射回原始分辨率。也就是说,真正影响推理开销的是缩放后的尺寸,不是你摄像头的原始分辨率。这一点理解清楚,后面调优会轻松很多。

检测器可选的路子:

方案 优点 缺点 适用场景
CPU(默认) 零配置,任何机器能跑 帧率低,多路吃力 单路、临时验证
Intel 核显(OpenVINO) 绿联 x86 机型可直接用,开销低 需要正确映射设备 有 Intel 核显的 NAS
Coral TPU(USB/PCIe) 推理快、功耗低 需要额外买硬件 路数多、追求稳定
NVIDIA GPU 性能强 NAS 基本没有 自建服务器

绿联的 x86 机型带 Intel 核显,所以走 OpenVINO 是最划算的。这里有个前提:容器里要能访问 /dev/dri,否则 OpenVINO 会退回 CPU,你会看到 CPU 占用飙高但检测帧率还是很低。

compose 配置

我最终的 docker-compose.yml 长这样,关键部分我加了注释:

yaml 复制代码
services:
  frigate:
    container_name: frigate
    image: ghcr.io/blakeblackshear/frigate:stable
    restart: unless-stopped
    shm_size: "256mb"          # 多路摄像头时共享内存要够,否则会崩
    devices:
      - /dev/dri:/dev/dri      # Intel 核显直通,OpenVINO 靠它
    volumes:
      - /volume1/docker/frigate/config:/config
      - /volume1/docker/frigate/media:/media/frigate
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "5000:5000"            # Web UI
      - "8554:8554"            # RTSP 回放(可选)
      - "8555:8555/tcp"        # WebRTC(可选)
    environment:
      - FRIGATE_RTSP_PASSWORD=你的摄像头密码

几个点解释一下。

shm_size 是共享内存。Frigate 用共享内存做帧缓冲,路数多、分辨率高的时候默认的 64MB 很容易不够,表现是容器莫名重启或者日志里报共享内存相关的错误。我给到 256MB,两路 1080p 是够的。你如果上四路以上,建议再往上加。

devices 那行是让容器能碰 /dev/dri。绿联的系统里这个设备节点是存在的,但默认容器拿不到,必须显式映射。这一步没做,OpenVINO 就用不了。

【踩坑提醒】绿联的存储路径和群晖不一样,它的主存储卷一般在 /volume1 这种路径下,但不同型号、不同存储池编号会变。配之前先在文件管理器里确认你的实际路径,别照抄我的。

config.yml:摄像头和检测器

Frigate 的主配置是 config/config.yml,compose 只是把它挂进去。核心内容:

yaml 复制代码
mqtt:
  enabled: false        # 我没接 MQTT,先关掉

detect:
  enabled: true

detectors:
  ov:
    type: openvino
    device: AUTO

model:
  path: /openvino-model/ssdlite_mobilenet_v2.xml
  width: 300
  height: 300
  input_pixel_format: bgr
  input_tensor: nhwc
  labelmap_path: /openvino-model/coco_91cl_bkgr.txt

cameras:
  front_door:
    ffmpeg:
      inputs:
        - path: rtsp://admin:密码@192.168.1.10:554/Streaming/Channels/101
          roles:
            - detect
            - record
        - path: rtsp://admin:密码@192.168.1.10:554/Streaming/Channels/102
          roles:
            - detect
    detect:
      width: 640
      height: 360
      fps: 5
    objects:
      track:
        - person
        - car
        - dog
        - cat
    record:
      enabled: true
      retain:
        days: 3
        mode: active_objects
    snapshots:
      enabled: true

这里有几处值得展开。

主副码流分开用。 海康、大华这类摄像头一般有主码流和子码流。我把子码流(102 通道)拿来给检测用,主码流(101 通道)用来录像。原因很直接:检测只需要低分辨率,用子码流能大幅降低解码和缩放的开销;而录像要清晰,用主码流。这是很实用的一招,尤其是多路的时候。

detect 里的 width/height。 这两个值是送给检测器的输入尺寸。设成 640×360 而不是 1920×1080,推理开销能差好几倍,而人形识别在 640 宽度上其实已经够用了。这是整个配置里对性能影响最大的一个参数。

fps: 5 检测帧率。人走动不是高速运动,5 帧足够捕捉到,没必要按摄像头原生 25 帧去跑。这个值直接决定推理频率,调低立竿见影。

model 部分用的是 OpenVINO 自带的 SSD MobileNet v2。 这是 Frigate 镜像里预置的模型,输入 300×300,识别 COCO 的常见类别。它不是最强的模型,但胜在轻、开箱即用。你如果追求精度,可以换 YOLO 系列的模型,但需要自己准备模型文件并改 model 配置,这一步我没在绿联上做,所以具体的路径和参数我这里就不写了,避免给错。

启动和验证

配好之后启动,然后看日志:

bash 复制代码
docker logs -f frigate

正常情况下你会看到它连接摄像头、初始化 ffmpeg、加载 OpenVINO 模型。如果 OpenVINO 加载成功,日志里会有类似 OpenVINO 和推理相关的输出。如果它退回 CPU,你会在日志里看到 CPU 检测器的提示,同时 Web UI 里检测帧率会明显偏低。

Web UI 默认在 5000 端口,浏览器打开 http://你的NAS_IP:5000。进去之后能看到实时画面、检测框、以及 Events 和 Recordings 两个页面。

判断是否真的走核显,我一般看两个地方:

  1. 日志里检测器类型;
  2. 检测帧率的实际值(在 UI 的 System 或者 debug 页面能看到 inference speed)。

如果 inference speed 是几十毫秒级别,基本就是 CPU 在跑;如果是几毫秒,说明核显生效了。具体数值因机器而异,我这里不给绝对值,你自己对比开不开 /dev/dri 的差别就能看出来。

事件和录像策略

Frigate 的录像有两套逻辑,容易搞混:

  • record.retain.days:整体保留多少天。
  • record.retain.mode:保留模式。all 是全录,active_objects 是只保留有目标活动的时间段,motion 是保留有运动的时间段。

我一开始想省空间,直接用了 active_objects,结果发现有些"人刚进入画面还没被判定为目标"的片段会被丢掉,回看时经常缺开头。后来我改成保留全录 3 天 + 事件片段单独保留更久,实际体验更稳。

对象过滤这块,objects.track 决定哪些类别会产生事件。默认可能只跟踪 person 之类,我显式加了 car、dog、cat。这里要注意:你加的类别必须是模型支持识别的类别,SSD MobileNet 用的是 COCO 数据集,包含常见的 80 类,像 person、car、dog、cat 都在里面。你如果想识别 COCO 里没有的类别,就得换模型。

另外 Frigate 有个 zone(区域)的概念,可以只在画面的某一块区域内检测,比如门口、车道,忽略马路这种干扰源。我刚开始没配 zone,结果马路上的车一直触发事件。加上 zone 之后噪音少了很多。zone 的坐标是在 UI 里画出来的,画完它会给你一组相对坐标,贴回 config 就行。

我实际遇到的几个问题

容器反复重启。 排查下来是 shm_size 太小,加了之后就稳定了。

检测不到目标。 有一次是 detect 的宽高比例和摄像头实际画面比例对不上,画面被拉伸得厉害,人形变形导致识别率下降。把宽高改成和子码流接近的比例后正常了。

CPU 一直很高。 检查发现 /dev/dri 没映射成功,OpenVINO 退回 CPU。补上 devices 映射解决。

录像找不到对应事件。 是录像和检测用了不同码流,时间轴对不齐。后来统一让录像走主码流、检测走子码流,事件片段用主码流回放,就对上了。

关于要不要上更强的东西

跑通之后我确实想过换 YOLO 模型、接 MQTT 做自动化、甚至加个本地 LLM 对事件做自然语言描述。但冷静下来看,对我这种家庭场景,SSD MobileNet + 区域过滤已经能过滤掉绝大部分误报,再往上堆的收益不明显。

如果你有更复杂的需求,比如要区分快递员和陌生人、要统计车流量,那确实值得研究更强的模型和 Frigate 的 zone + object 组合。但这属于另一条路了,本文就不铺开。我的建议是先把基础链路跑稳,确认误报率能接受,再决定要不要继续投入。

最后提醒一句:Frigate 的配置字段和镜像版本绑定很紧,升级镜像前先看 release notes,尤其注意 recorddetectmodel 这几块的变更。我吃过一次升级后配置报错、容器起不来的亏,后来养成习惯------升级前先把 config 目录备份一份。

相关推荐
kuuailetianzi2 小时前
第3篇:《变量、数据类型与基本运算》
python
2601_957638242 小时前
常佐网络做的裂变小程序会不会被封:实践与思考
人工智能·常佐网络做的裂变小程序会
爱丶不疚2 小时前
Skill的形态有哪些?什么样的Skill 叫做好Skill?
人工智能·agent
逻辑君2 小时前
MoreLogic RAG 个人免费版 · 产品宣传手册和产品白皮书
人工智能·机器学习
AskHarries2 小时前
我用 Grok Bot 搭了一个「数字军团」,还真的把网站做出来了
人工智能
byte轻骑兵2 小时前
【BlueZ 】input 模块:蓝牙鼠标/键盘等输入设备的基础适配逻辑
linux·人工智能·bluez·电脑蓝牙·嵌入式蓝牙
autotian2 小时前
神经网络及其应用
人工智能·深度学习·神经网络
雾屿_Mistisle2 小时前
AI安全设计总结
人工智能·机器学习·数据分析
aichitang20242 小时前
前端小skill
前端·人工智能·算法·ai·前端框架