基于 C++ OpenCV 生成小视频
制作个人小视频
一、实验内容和要求
基于 OpenCV 生成小视频,制作有浙大元素的图片和个人信息的片头,自己设计情节,其中要缓慢地画一张画面,最后自己设计一个片尾。
做了一个火柴人初见了 OpenCV,尝试了一下,发现非常神奇,大受震撼,最后开心地跑走了的视频。
二、实验器材
C++ OpenCV 4.5.0
开发平台:Visual Studio 2019 Debug x64
三、具体实现
3.1 基本图片与视频的读入
将一些图片和视频作为素材准备好,通过 C++的 fstream 库中定义的 finddata_t 结构来获取文件结构,findfirst 函数来检索指定目录下的文件,并通过文件的扩展名来获取文档,存入 vector 中。
对应的函数如下:

图片可以通过 OpenCV 的接口读入并按帧写入视频中。写视频采用的是 cv::VideoWriter 类,可以通过流的形式将 Mat(帧)写入视频文件中。

读取视频采用了 cv::VideoCapture 类,通过流的形式逐帧读入,进行 resize 以后再用 writer 逐帧写入。

3.2 绘图:绘制 OpenCV logo 和火柴人
逐帧绘制的部分调用了 OpenCV 自带的一些几何体绘制函数,下面以OpenCV 的 logo 绘制为例进行说明。
下面代码是一个红色部分的绘制。调用 ellipse 函数来画椭圆,参数说明如下:
void ellipse(InputOutputArray img, Point center, Size axes, double angle, double startAngle, double endAngle, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);
ellipse 函数将椭圆画到图像 img 上,椭圆中心为点 center,并且大小位于矩形 axes 内,椭圆旋转角度为 angle, 扩展的弧度从 0 度到 360 度,图形颜色为 Scalar(x, y,z),线宽 (thickness)为 1,线型(lineType)为 8 (8 联通线型)。当线性设为-1 的时候为全填充。
为了达到逐渐绘制的效果,在扩展弧度的部分采用 fps 控制,在帧内逐帧绘制。

效果如下:

另一个简笔画是火柴人,效果如下:

3.3 转场效果
编程实现了两种转场效果,一个是从模糊到清晰的过渡,一个是从右到左的进入。
模糊过渡调用 OpenCV 的 GaussianBlur 函数,根据 fps 控制逐帧从边缘到内部进行高斯模糊。

效果如下:



平移转场效果先设置一张空的图片,然后一列一列地将目标图片的像素复制到空图片的右侧,通过时间控制帧的写入。

效果如下:




3.4 播放与键盘控制
视频的播放采用 VideoCapture 类进行读入,逐帧用 imshow 函数进行输出。
调用 OpenCV 的 waitKey 函数来判断键盘交互。

四、实验结果与分析
实验结果请参见生成视频 output.mp4。其中一些重点的实现在上一部分也有讲述。
此处为语雀视频卡片,点击链接查看:output.mp4
但是在实验的过程中出现了一个现象:程序读取图片、视频和绘制的速度非常慢,整个一分多钟的小视频画完需要 45 秒左右。这一点后面还会再考虑是什么问题。(我认为可能是读取视频并解析的速度比较慢,因为不仅要逐帧读入、调整大小,还要逐帧写出)
五、实验体会与心得
通过这次实验,又捡回了对于 C++的编程,感觉自己的代码变得规范点了(之前老写 python,写的有点乱)。之前我经常使用 Python 语言的 cv2 库,但是都是在做一些检测之类的 demo。这次实验熟悉了 OpenCV 的基本函数,掌握了对图像和视频的读写,还没有探索更多炫酷的 OpenCV 制作动画效果,因为 OpenCV 主要的用途还是在于辅助功能,而不是视频编辑功能。
在实验的过程中遇到了一个小问题就是“逐渐”绘制的过程,最后为了达到效果,查阅了一些资料,想到了用 for 循环结合 fps 来控制。最后达到了预期的效果。
