测试背景简介
大家好,我是徐珂靖,是个骨灰级工科男。最近,我机缘巧合地申请得到了一块云芯一号ARM微服务器开发板。填报申请表时,我的试用计划是设计一个用于家庭IoT设备的局域网计算系统,将会用到多种技术,包括视频编码、网络视频流采集、AI物体检测、UDP协议通信、MySQL数据库读写、网页动态数据显示等。
我将会主要用C、C++、PHP等语言来编程,以实现以上功能,并尽量使用现成的开源项目的API接口以减小工作量。另外,为了表达对极术社区的感谢,我会把所有代码都开源。
当然,在做复杂的服务器应用前,我们最好是先把各个子模块的接口给调通了。第一步是实现个最简单的视频监控存储服务器的功能。在这个应用里,我们将把捕获网络RTSP视频流与图像保存的代码调通。
笔者业余时间也是个极客,自制了不少有趣的设备,比如通过Arduino自动控制的鱼缸,那个鱼缸还带个IP摄像头可以远程监控。那么,今天就来给这个IP摄像头做个网络监控存储服务器吧。
实现思路
我们将用云芯一号采集来自IP摄像头的RTSP视频流,然后一边显示,一边按编号保存成一系列jpg图片文件。
我计划把这个功能将通过C++语言编程实现。其中视频流捕获、图像显示、图像保存的函数,不需要自己再重复实现一次了。这里可以偷个懒,我们将使用OpenCV的API接口。
源代码编写
已知IP摄像头的视频流地址是:rtsp://192.168.3.33:8554/live
用户名admin,密码123456
在OpenCV中,可以通过VideoCapture类来打开RTSP视频流,代码写法如下
VideoCapture cap("rtsp://admin:12345@192.168.3.33:8554/live");
从cap捕获视频流中的一帧图像放入Mat类型的frame变量中的写法如下
cap>>frame
然后,为了把照片按顺序保存,我们要给个顺序的编号设置一下文件名,并且希望文件存到一个合适的路径里。
这里我推荐一个方法,先定义一个char类型的filename数组,然后用sprintf函数把文件编号格式化输出到filename数组中。
举个例子,比如j变量每循环加1代表文件编号,格式化输出文件名,最后用imwrite函数保存图片,代码可以这样写:
j++;
sprintf(filename, "/home/dat/test/img/%06d.jpg", j);
imwrite(filename, frame);
最后,通过imshow函数实现图像显示,循环时候要加上waitKey(1),不然黑屏,这个BUG从很久以前的版本就存在,大家也习以为常了。
代码开源
代码中的i%30==0是个求余数并与0比较的判断,目的是每隔30帧进入括号内的语句然后保存图片。你可以按需求设置。举例,如果想要节省存储空间,可以设置i%1000,这样就每隔1000帧保存一张了。
源代码如下:
#include <iostream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include "opencv2/opencv.hpp"
using namespace cv;
using namespace std;
int main(int argc, char**argv)
{
`Mat frame;`
`int i=0,j=0;`
`VideoCapture cap("rtsp://admin:12345@192.168.3.33:8554/live");`
`char filename[256];`
`while (1)`
`{`
`i++;`
`cap >> frame;`
`if(i%30==0)`
`{`
`j++;`
`sprintf(filename, "/home/dat/test/img/%06d.jpg", j);`
`imwrite(filename, frame);`
`}`
`imshow("test",frame);`
`waitKey(1);`
`}`
`return 0;`
}
编译与运行
把上一小节代码保存为mycvtest.cpp,编译然候运行的命令如下
g++ -ggdb mycvtest.cpp -o aaaaa pkg-config --cflags --libs opencv
./aaaaa
以下是运行时候的屏幕截图。
多运行一会儿,可以发现/home/dat/test/img目录里保存的照片更多了。
下一步工作
我们已成功把RTSP视频流的图像帧存入Mat frame变量,下一步可以把该变量接入到OpenCV的DNN模块以实现目标检测。
在实现目标检测功能时,我们也可以评估一下Open AI Lab的Tengine推理框架,相信能获得更好的运行效能。
检测结果的存储将会使用MySQL客户端的C语言API接口,这样就不用单独开发数据存储及用户安全管理的服务了。
最后,多个进程一起调试时,程序是否还能保持实时和高效也需要测试。如果一台云芯一号无法胜任,我们还要考虑往局域网里再添加一台GPU服务器以同时跑多个神经网络。
更多云芯一号的技术教程及评测报告请关注Arm微服务器专栏。