Watsor
Watsor使用基于深度学习的方法检测视频流中的对象。主要用于监控,它能实时分析最新的帧以对检测到的威胁做出最快反应。
目录
功能
- 基于人工神经网络执行智能检测,显著减少视频监控中的误报。
- 能够使用带有alpha通道的蒙版图像来限制检测区域。
- 支持多种硬件加速器,如Coral USB加速器和Nvidia CUDA GPU,以加速检测算法。
- 通过MQTT协议报告检测到的对象,主要用于与HomeAssistant集成。
- 允许通过MQTT发布的命令控制视频解码器。
- 通过HTTP以MPEG-TS和Motion JPEG格式广播带有渲染对象检测结果的视频流。
- 从任何源捕获视频,并以FFmpeg支持的任何格式编码带有渲染对象检测结果的视频。
Watsor适用于闭路电视,也适用于其他需要在视频流中进行对象检测的领域。
入门
Watsor使用Python 3编写,主要作为Python模块发布。然而,最简单的尝试方法是使用Docker,因为硬件驱动和模型都已捆绑在镜像中。
无论您如何运行Watsor,都需要准备一个配置文件,描述您的摄像头以及其他选项,如检测类型和区域。请参考以下指南。
配置
Watsor使用YAML语法进行配置。YAML语法的基础是包含键值对的块集合和映射。集合中的每个项目以-
开头,而映射的格式为key: value
。Watsor会执行配置验证,如果您指定了重复的键、缺少某些值或YAML语法错误,它会在启动时打印错误消息。
请查看配置示例文件,其中包含解释性注释,您可以将其用作模板。
摄像头
文档根目录中的cameras
块是您将用于监控的摄像头列表。每个摄像头必须有一个独特的名称,以区别于其他摄像头。摄像头的名称会出现在日志中,也包含在HTTP视频流的路径中。
展开代码片段
cameras:
- camera1:
width: 640
height: 480
input: rtsp://192.168.0.10:554
#output: !ENV "${HOME}/Videos/camera1.m3u8"
#mask: camera1.png
#detect: []
#ffmpeg: []
- ...
摄像头必须指定视频源的width
、height
和input
。请参考摄像头设置以确定正确的值。width
和height
应反映实际视频源的分辨率。它们不会改变视频的大小,但用于配置Watsor工作所需的帧缓冲区和其他内容。如果width
或height
值与视频源不匹配,图像将无法正确显示。输入源URL通常以rtsp://
或http://
开头,但也可以是FFmpeg可以使用的任何内容,例如.mp4
文件。
可选的mask
是用于限制检测区域的蒙版图像文件名。请参考以下章节。
可选的detect
块覆盖默认值,以指定感兴趣的对象类型和一组用于筛选不太重要检测结果的过滤器。
可选的ffmpeg
块覆盖默认值,以指定用于解码输入视频流的FFmpeg应用程序的参数,以及在必要时用于编码输出的参数。ffmpeg.encoder
是完全可选的,只有在您想要记录或广播带有渲染对象检测结果的视频流时才需要定义它。
当使用ffmpeg.encoder
录制视频文件时,使用output
键指定位置。请参考FFmpeg格式了解所有可用选项。当缺少output
键时,Watsor会运行轻量级HTTP服务器以通过网络流式传输视频。流传输采用MPEG-TS格式,因此请确保在ffmpeg.encoder
输出参数中设置了mpegts格式。当设置了output
时,编码后的流会被写入文件,此时无法通过HTTP广播MPEG-TS。
无论是否启用ffmpeg.encoder
或定义了output
,Motion JPEG格式的视频流都可以随时通过HTTP广播。
FFmpeg解码器和编码器
文档根目录中的ffmpeg
块用作解码和编码视频流的默认设置,如果摄像机没有设置自己的配置则使用此默认设置。
FFmpeg是一个非常快速的视频转换器,可以从源抓取实时视频。Watsor为每个摄像机运行一个或两个FFmpeg子进程:必需的解码器和可选的编码器。解码器从摄像机的input
键指定的源读取(可以是摄像机馈送的URL、常规文件或抓取设备),紧跟在-i
选项之后。如果设置了摄像机的output
,编码器将写入输出文件,否则写入_stdout_。命令行中-i
前后的选项决定了每个FFmpeg子进程的输入和输出参数。例如,输入参数可以启用硬件加速解码。解码器的输出和编码器的输入必须包含-f rawvideo -pix_fmt rgb24
,因为Watsor从第一个FFmpeg的_stdout_读取原始视频帧(24位),并在检测完成后可以将原始视频帧写入另一个FFmpeg子进程的stdin
。
您必须在命令行列表中包含-i
选项,但不要在其后跟随输入,因为Watsor会自动在-i
后添加摄像机的input
键。对于编码器,它还包括其他必需的选项,如-s
,用于明确定义原始视频帧的大小。
ffmpeg.encoder
是可选的,用于录制或广播带有渲染对象检测的视频流。录制适用于点播流,因为视频存储在.m3u8
(HLS)或.mp4
等文件中,可以重复观看。广播意味着视频实时录制,观众只能观看正在流式传输的内容。要通过HTTP广播带有渲染对象检测的视频,请在编码器中设置-f mpegts
选项,并删除摄像机的output
键。可以从Watsor的主页获取视频流链接,并在VLC等媒体播放器中打开。
在MPEG-TS格式广播实时视频流时,请注意明显的延迟,这是由于视频编码算法的性质而无法避免的。请记住,媒体播放器由于缓冲馈送也会引入自身的延迟。要以零延迟的纯实时方式观看带有渲染对象检测的视频,请打开摄像机馈送的Motion JPEG URL。
MPEG-TS格式的广播非常适合通过网络流式传输,因为视频序列压缩只传输序列中的变化,从而减少网络带宽(和存储)使用。Motion JPEG将每个视频帧压缩成JPEG图像,使其作为连续的图像流在网络上可用。由于所有帧都是独立且完全压缩的,因此通过网络传输的数据量远大于MPEG-TS。
检测类别和过滤器
文档根目录中的detect
块用作默认设置,如果摄像机没有设置自己的配置则使用此默认设置。该块是COCO类别的列表(最多90个),用于检测,每个类别指定三个过滤器:area
、confidence
和zones
。
area
是对象边界框应具有的最小面积,以便被检测到。如果未设置,默认为整个视频分辨率的10%。confidence
是判断检测结果是否符合猜测的最小阈值,否则将被排除。如果未设置,默认为50%。zones
是一个索引列表,指定掩码图像上允许检测的区域。默认未设置,表示允许所有区域。
区域和掩码
要限制检测区域,请从您的摄像机拍摄快照。图像的宽度和高度必须与您的视频馈送大小相同。 在图形编辑器(如GNU图像处理程序GIMP)中打开图像,选择所需区域。将选区浮动化,然后从该浮动选区创建新图层。该图层代表一个区域,在此区域之外的物体不会被检测。
选择包含图像其余部分的主图层,将该图层的不透明度更改为~85%
。来自浮动选区的图层不透明度必须保持100%
,以便Watsor能够将它们与背景区分开来。以32位PNG格式保存图像,包含alpha通道。在摄像机配置中指定文件名和路径(可以是相对路径)。
以下图片描述了上述过程:
你可以选择多个区域,形状不限,但确保它们不重叠,否则几个区域会合并成一个。
当物体的边界框与区域形状相交时,会发生检测,该区域会以黄色高亮显示。然后通过MQTT传输区域索引。区域在掩码图像中的索引取决于其中心到原点的距离。上面的示例中有两个区域,一辆车被检测到在2
区(以红色显示)。如果不清楚哪个区域是哪个索引,以下工具将为你显示:
python3 -m watsor.zones -m config/porch.png
提示
-
不使用硬件加速器会导致CPU负载高。为了降低CPU负载,可以在摄像机设置中或使用FFmpeg 过滤器更改输入视频流的帧率,如下所示:
FPS过滤器
- -filter:v - fps=fps=10
理想情况下,摄像机的输入帧率不应超过检测器的处理能力,否则所有可用的CPU单元都将用于检测。
-
除非你录制带有渲染对象检测的视频,否则请在摄像机设置中选择较小的分辨率。300x300是用于训练对象检测模型的图像尺寸。在检测过程中,框架会自动将输入图像转换为模型尺寸,以匹配其张量大小。由于在检测过程中无论如何都会进行调整大小,提供高分辨率流并没有太大意义,除非Watsor产生的输出流(其大小与输入分辨率匹配)正在被录制以供日后查看(在这种情况下,高分辨率视频显然是需要的)。
有时摄像机没有太多选项来更改分辨率。那么可以使用FFmpeg 缩放过滤器:
缩放过滤器
- -filter:v - scale=640:480
如果你需要将缩放过滤器与FPS过滤器结合使用,请用逗号分隔它们:
两个过滤器一起使用
- -filter:v - fps=fps=10,scale=640:480
-
考虑为FFmpeg配置H.264视频(或你的摄像机产生的任何格式)的硬件加速解码。带有
hwaccel
前缀的命令行选项正是为此而设。参考以下wiki了解你的设备上可用的方法。 -
在VLC(或其他播放器)中播放视频需要恒定的25帧/秒速率。如果有多个摄像机或很少的检测器处理所有视频源,有时可能无法提供这样的输出速度。假设你有2个摄像机,每个产生30 FPS,而只有一个基于CPU的检测器能够处理25 FPS。那么MPEG-TS视频流的输出速度对每个摄像机来说只有12.5 FPS,导致观看视频时出现卡顿和暂停。为了使视频流畅,需要改变帧率,使输出帧率高于输入帧率。
可以使用以下技巧(展开代码片段)
encoder: - -hide_banner - -f - rawvideo - -pix_fmt - rgb24 - -r - 10 - -vsync - drop - -i - -an - -f - mpegts - -r - 30000/1001 - -vsync - cfr - -vcodec - libx264 - -pix_fmt - yuv420p
首先将速率进一步降低到10 FPS,以保证FFmpeg编码器的恒定输入(
-r 10
)。超过10 FPS的帧会被丢弃(-vsync drop
)以匹配目标速率。然后将输出速度设置为标准的30000/1001
(约30 FPS)并保持恒定(-vsync cfr
)以产生流畅的视频流,必要时复制帧以达到目标输出帧率。
环境变量
你可以像 Home Assistant Core 那样包含系统环境变量的值:
password: !env_var PASSWORD default_password
或
input: !ENV "rtsp://${RTSP_USERNAME}:${RTSP_PASSWORD}@192.168.0.10:554"
密钥
你可以从配置文件中移除任何私密信息。密码条目可以用 !secret
关键字后跟一个标识符来替换。然后密码将在包含相应密码分配给标识符的 secrets.yaml
文件中查找:
config.yaml
mqtt:
username: !secret mqtt_username
password: !secret mqtt_password
secrets.yaml
mqtt_username: "john"
mqtt_password: "qwerty"
secrets.yaml
的解析首先会在引用密钥的 YAML 文件所在文件夹中查找,接着会在父文件夹中搜索 secrets.yaml
文件。这个逻辑继承自 Home Assistant,你可以将配置与 HA 文件放在一起,为两个应用程序重用单个 secrets.yaml
文件。
HomeAssistant 集成
最简单的入门方法是使用 Watsor 的 Home Assistant 插件。
Watsor 可以通过 MQTT("物联网"连接协议)与 HomeAssistant 通信。请参考 演示项目 以检查配置文件。
要配置可选的 MQTT 客户端,请添加以下行(展开代码片段):
mqtt:
host: localhost
#port: 1883
#username: !secret mqtt_username
#password: !secret mqtt_password
MQTT 主题列表:
watsor/cameras/{camera}/available
watsor/cameras/{camera}/command
watsor/cameras/{camera}/sensor
watsor/cameras/{camera}/state
watsor/cameras/{camera}/detection/{class}/state
watsor/cameras/{camera}/detection/{class}/details
检测到的对象类别的二进制状态(ON
/ OFF
)每10秒发布一次在 /detection/{class}/state
主题上,确认状态。这表示检测到威胁,应该触发警报。
订阅 available
主题以接收特定摄像头的可用性(在线/离线)更新。当 Watsor 启动时摄像头为 online
,应用程序停止时变为 offline
。
可以通过 command
主题控制摄像头,允许启动/停止解码器、限制帧率以及启用/禁用检测详情报告。
- 当警报控制面板被激活时,发送
ON
启动解码器和检测进程。当解除时 - 发送OFF
停止分析摄像头馈送。摄像头通过state
主题通知其运行状态。 - 如果超过30秒没有检测到任何东西,你可以通过发送
FPS = 5
(或你喜欢的任何速率)来降低摄像头速度,以限制帧率从而减少 CPU 或硬件加速检测器的负载。一旦检测到东西,摄像头将自行重置 FPS 限制并达到全速。 - 检测详情的报告包括置信度、边界框坐标和区域索引以及帧的时间戳,可以通过发送
details = on
/details = off
来打开/关闭。详情以 JSON 格式发布在另一个主题上,如下所示:
其中{ "t": "2020-06-27T17:41:21.681899", "d": [{ "c": 73.7, "b": [54, 244, 617, 479] }] }
t
是帧的时间戳,d
是主题路径中指定的给定对象类别的所有检测数组。每个检测都有置信度c
和边界框b
,由x_min
、y_min
、x_max
、y_max
组成。
sensor
主题用于发送关于摄像头当前输入和输出速度的更新。监控速度对于在摄像头突然损坏或断开时触发警报很有用。
传感器值和检测详情可能通过 MQTT 非常频繁地传输,最多每秒数十次。HomeAssistant 中的 recorder 集成会不断保存数据,默认存储从传感器到状态变化的所有内容。幸运的是,HomeAssistant 允许自定义需要写入和不需要写入的内容。一个好主意是只在记录器中包含真正需要的测量值,以避免 HomeAssistant 性能下降。
运行 Watsor
Docker
要在 Docker 中运行 Watsor,请将配置文件挂载到容器的 /etc/watsor
文件夹。为视频和检测硬件加速(如果可用)添加主机设备。由于 Watsor 运行多个共享内存的进程,请根据摄像头数量将默认的 64m 共享内存大小增加一些。以下是 docker-compose.yaml 的示例:
展开代码片段
version: '3'
services:
watsor:
container_name: watsor
image: smirnou/watsor:latest
environment:
- LOG_LEVEL=info
volumes:
- /etc/localtime:/etc/localtime:ro
- ../config:/etc/watsor:ro
devices:
- /dev/bus/usb:/dev/bus/usb
- /dev/dri:/dev/dri
ports:
- 8080:8080
shm_size: 512m
要运行GPU加速的`watsor.gpu` Docker镜像,请使用[NVIDIA Container Toolkit](https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(Native-GPU-Support))。
传递`--gpus all`标志以将GPU设备添加到容器中:
docker run -t -i \
--rm \
--env LOG_LEVEL=info \
--volume /etc/localtime:/etc/localtime:ro \
--volume $PWD/config:/etc/watsor:ro \
--device /dev/bus/usb:/dev/bus/usb \
--device /dev/dri:/dev/dri \
--publish 8080:8080 \
--shm-size=512m \
--gpus all \
smirnou/watsor.gpu:latest
如果您的GPU支持半精度(也称为FP16),您可以通过以下方式启用此模式来提高性能:
`docker run --gpus all --env TRT_FLOAT_PRECISION=16 ...`
Docker镜像中捆绑了适用于CPU/GPU和EdgeTPU(Coral)的模型。您可以使用自己的模型,这些模型是基于[对象检测模型](#object-detection-models)部分中列出的模型训练的,方法是将卷挂载到`/usr/share/watsor/model`。
下表列出了可用的docker镜像:
| 镜像 | 适用于 |
|---|---|
| [watsor](https://hub.docker.com/r/smirnou/watsor) | x86-64 |
| [watsor.gpu](https://hub.docker.com/r/smirnou/watsor.gpu) | 带有Nvidia CUDA GPU的x86-64 |
| [watsor.jetson](https://hub.docker.com/r/smirnou/watsor.jetson) | Jetson设备(Xavier、TX2和Nano) |
| [watsor.pi3](https://hub.docker.com/r/smirnou/watsor.pi3) | 使用32位操作系统的Raspberry PI 3或4 |
| [watsor.pi4](https://hub.docker.com/r/smirnou/watsor.pi4) | 使用64位操作系统的Raspberry PI 4 |
### Kubernetes
要在Kubernetes集群上部署Watsor,请使用[Helm chart](https://asmirnou.github.io/watsor-helm-chart/):
```bash
helm repo add asmirnou https://asmirnou.github.io/watsor-helm-chart
helm repo update
helm install watsor asmirnou/watsor
Python模块
Watsor在Python 3.6、3.7、3.8上运行良好。安装Python包时使用虚拟环境。
-
安装模块:
python3 -m pip install watsor
如果您有硬件加速器或在树莓派等小型板上安装应用程序,请查看setup.py中的_extra_配置文件
coral
、cuda
或lite
。这些配置文件中列出的依赖项需要提前安装。请参阅设备文档或查看Docker文件之一,以了解如何安装依赖项。 -
创建
model/
文件夹,下载、解压并准备对象检测模型(请参阅下面的章节)。 -
确保您的操作系统上安装了
ffmpeg
。 -
按如下方式运行watsor:
python3 -m watsor.main --config config/config.yaml --model-path model/
或者如果存在NVIDIA CUDA GPU并且正确设置:
python3 -m watsor.main_for_gpu --config config/config.yaml --model-path model/
打开http://localhost:8080导航到一个简单的主页,在那里您可以找到摄像机视频流的链接、检测到的对象类别的快照和指标。
对象检测模型
Watsor使用卷积神经网络,该网络经过训练可以识别90个对象类别。检测模型有几种类型,在准确性和速度之间提供权衡。例如,MobileNet v1_速度最快,但准确性低于_Inception v2。下面推荐的模型对于实时视频监控来说是合理的,但是您不限于仅使用这些模型,因为Watsor支持TensorFlow Model Garden中的任何模型。值得尝试他们最新的具有更高平均精度的模型。 根据所使用的设备不同,模型可以有几种不同的格式。
-
如果您有 Coral USB 加速器,请下载为 Edge TPU (MobileNet v1/v2) 构建的模型之一,重命名文件并将其放入
model/
文件夹中,命名为edgetpu.tflite
。 -
如果板载有 Nvidia CUDA GPU,请下载其中一个模型,重命名文件并将其放入
model/
文件夹中,命名为gpu.uff
。Watsor 还可以使用 ONNX 格式的 TF2 模型,您需要按照指南自行转换,然后保存为model/gpu.onnx
。 -
只有在没有加速器或未提供加速器模型时才使用 CPU。在 TensorFlow 压缩包中,您只需要将
frozen_inference_graph.pb
重命名为cpu.pb
并放入model/
文件夹中。TF2 模型没有冻结图,但有一个saved_model
文件夹需要完整复制到 Watsor 的model/
文件夹中。请注意,保存的模型启动时间较长。如果 TensorFlow 配置正确,将会使用 GPU。
-
对于树莓派或 Jetson Nano 等单板计算机,轻量级模型更高效。下载并解压(如需要),重命名文件并将其放入
model/
文件夹中,命名为cpu.tflite
。
设备 | 文件名 | MobileNet v1 | MobileNet v2 | Inception v2 |
---|---|---|---|---|
Coral | model/edgetpu.tflite | MobileNet v1 | MobileNet v2 | 不适用 |
Nvidia CUDA GPU | model/gpu.uff | MobileNet v1 | MobileNet v2 | Inception v2 |
CPU | model/cpu.pb | MobileNet v1 | MobileNet v2 | Inception v2 |
树莓派及其他 | model/cpu.tflite | MobileNet v1 | MobileNet v2 | 不适用 |
硬件加速驱动
使用硬件加速器是可选的,但强烈推荐,因为物体检测本身需要大量计算。就每秒处理帧数而言,台式计算机的 CPU 仅能处理最轻量模型的 24 帧/秒,而加速器可以将性能提升至 5 倍。两个连接或安装的加速器可以处理 200 帧/秒,足以处理多个视频摄像头。
Watsor 支持多个加速器,在它们之间平均分配负载。只要连接了至少一个加速器,Watsor 就会使用硬件进行计算,减轻 CPU 负担。如果没有可用的加速器,它会回退到运行 Tensorflow 的 CPU。
要限制 Watsor 可见的设备,请将 CORAL_VISIBLE_DEVICES
或 CUDA_VISIBLE_DEVICES
环境变量设置为以逗号分隔的设备 ID 列表,使应用程序只能看到这些设备。可以通过启用调试模式并使用以下命令行选项来查看应用程序日志中的设备 ID:--log-level debug
如果您有 Coral,请安装 Edge TPU 运行时和 PyCoral API。 具备 Nvidia CUDA GPU - 安装以下组件(现在是困难的部分,你最好考虑使用 Docker:
从源代码构建
克隆 Git 仓库:
git clone https://github.com/asmirnou/watsor.git
创建虚拟环境并安装 Watsor 依赖项:
make venv
source venv/bin/activate
make install
故障排除
如果在安装 Watsor 先决条件时遇到问题,请先尝试在网上寻找解决方案。我很乐意提供帮助,但大多数情况下,答案都是从 https://stackoverflow.com/ 等网站上的发现组合而成的。如果没有找到解决方案,请大胆地提交一个 issue。
致谢
- 灵感来自 Frigate
- 领域知识源自 pyimagesearch