距上次研究 树莓派编译构建 OpenCV C++ 项目 之后,我最终完成了一个强大的树莓派 NodeJs 应用—— pilib-capture,可以单程序实现:
- 远程视频监控
- 人脸识别抓拍
- 抓拍后上传
启动方式也很简单,单条指令即可运行:
sudo LOCAL_PORT=8080 pilib-capturer
pilib-capture 程序已经部署到了实际生产环境,用于监控进出人流量
当然实际部署的时候,基于用户隐私考虑,人脸抓拍只做计数,不做存储。
安装说明戳 这里。
pilib-capture 架构图如下:
- 采用 USB 摄像头作为视频输入源,比网上流传的主板 CAM 接口摄像头性价比更高。
- 采用 NodeJS 编写服务器,异步架构,事件驱动,并发量和 HTTP 支持比网上流传的 Python 版本服务器更好。
- NodeJS 通过 cpp 绑定直接调用 OpenCV 库,不会损失视频处理的性能。
- 开放 HTTP 控制端口和 AVI 视频串流端口,浏览器打开网页即可操作。
USB 摄像头调用
在 NodeJS 里,可以用 opencv4nodejs 库调用 OpenCV 提供的摄像头方法 cv.VideoCapture()
。
VideoCapture
类核心定义如下:
export class VideoCapture {
constructor(filePath: string);
constructor(devicePort: number);
read(): Mat;
constructor()
构造函数接受设备路径参数,可以是视频文件路径,也可以是 webcam 设备 id。
调用 .read()
方法,会返回当前捕获的帧 Mat
对象。Mat 即矩阵(matrix),是 opencv4nodejs 里的图形对象,包含所有的图形操作方法。
摄像头调用核心代码:
import * as cv from 'opencv4nodejs';
// 打开摄像头
const cam = new cv.VideoCapture(0);
// 从摄像头读取一帧
const mat = this.cam.read();
摄像头控制参数戳 这里。
OpenCV 人脸识别
可以用于树莓派的人脸识别方案有很多,比如 tensorFlow、dlib、OpenCV 等。
我在写 pilib-capturer 的时候,从实际应用场景、系统复杂度和树莓派性能出发考虑,并没有采用神经网络识别模型,而是采用了 OpenCV 自带的训练好的 基于 Haar 特征的人脸识别分类器。
Haar 分类器人脸识别核心代码:
import * as cv from 'opencv4nodejs';
const cam = new cv.VideoCapture(0);
const mat = this.cam.read();
// 载入分类器模型
const classifier = new cv.CascadeClassifier(cv.HAAR_FRONTALFACE_ALT2);
// 多尺度检测,定位人脸区域
const detection = classifier.detectMultiScale(mat);
// detection.objects 包含了所有人脸区域的位置信息
console.log(detection.objects);
// 还可以调 drawRectangle 方法,给人脸区域标记红框
detection.objects.forEach(r => {
mat.drawRectangle(r, new cv.Vec3(0, 0, 255));
});
实际测试中,发现 Haar 分类器存在抖动,偶尔会出现一两帧的误识别,把一些相似的图形识别成了人脸。
要解决这个问题,最直观的办法就是 提高分类器准确度,但这并不容易...
所以,在 pilib-capturer 里改用 一阶低通滤波 的方式去抖动。一两帧的误识别属于高频信号,可以被一阶低通滤波很自然地排除掉。
目前支持 CAPTURER_LPF_FA
(滤波系数) 和 CAPTURER_LPF_THRESHOLD
(滤波判断阈值) 两个参数调节滤波效果。
具体配置戳 这里
HTTP 控制接口
在 HTTP 的处理上,pilib-capturer 引用了我的另一个 NodeJs 模块:ah-server
ah-server 是一个非常轻量的可扩展的 web 服务器框架,使用体验类似 egg.js。使用框架能力,可以让 HTTP 端口处理轻松一点。
目前 pilib-capturer 只提供了“拍照”接口:GET http://{hostname}/shot
。通过这个接口,可以控制程序拍照和立即上传。
接口核心代码如下:
import { Controller, IContext, IControllerMapperItem } from 'ah-server';
export class ShotController extends Controller {
// 定义路由
mapper: IControllerMapperItem[] = [
{
path: '/shot',
method: 'GET',
handler: this.shot,
},
];
async shot(ctx: IContext) {
ctx.set({ 'Content-Type': 'image' });
// 返回图片二进制,以便浏览器可以直接打开查看
ctx.body = this.snapshot.toBuf().buf;
}
}
ah-server.Controller
是 ah-sever 的路由控制器基类,扩展这个类就可以访问请求的所有上下文信息。
Avi 视频串流接口
既然树莓派接入了网络,而且连接了 USB 摄像头,那就可以做“远程视频监控”了。最初我做这个功能是为了方便实时调试人脸识别抓拍,但发现完全可以包装成视频串流接口,实现类似“直播”、“远程视频监控”的功能。
当有客户端(比如 VLC 播放器)请求视频串流接口(GET /liveStream
)的时候,pilib-capturer 会启动一个 ffmpeg 进程,用来把摄像头的图片帧封装成 avi 格式,然后以串流的形式返回客户端。客户端收到 AVI 串流,就可以收看“直播”了。
ffmpeg 核心参数如下:
# -c:v copy 表示 直接复制到 avi 容器,不要编码(性能考虑)
# "-i -" 和 命令末尾的 "-" 表示管道输入、管道输出(与 NodeJS 进程间通信)
ffmpeg -y -f image2pipe -s 320x240 -r 20 -i - -an -c:v copy -f avi -
图像上传接口
pilib-capturer 从摄像头识别到人脸后,可以配置成:
- 上传到指定地址
- 保存到本地
由 UPLOAD_ENDPOINT
启动参数控制。默认保存目录是本地 ./output,但如果配置成 http 或 https 开头的地址,则会以 POST 请求的方式将抓拍照发送过去。
具体配置戳 这里
扩展资料
- 车牌识别:Haar 特征+Adaboost 原理_阿范同学的博客-优快云 博客
- concefly/ah-server: 轻量可扩展的 web server
- 视频和视频帧:如何搭建基于 VisionSeed+Raspberry Pi 的实时图传系统? - 知乎