计算机视觉课的作业,挺有意思的,记录一下。
一 问题描述
对输入的一个彩色视频与3张以上照片,用OpenCV实现以下功能要求:
1. 将输入视频vi与多张图片pics处理成相同长宽后,合在一起生成一个视频vo;
2. 图片pics合成到视频中时需要编程实现图片切换效果,如幻灯片中的渐入、飞入等;
3. 在新视频中vo中需要完全编程实现一段片头,如编程绘制一个动图;
4. 最后以输入视频vi的两倍播放输出视频vo,并在视频底部打上含自己姓名的字幕。
二 实现过程
第1步:构造输出视频
首先我们需要确定最终输出视频的参数信息,包括视频的长宽、帧率、编码等信息,这里我们使用输入视频的参数来确定输出视频vo的参数信息。代码如下:
VideoCapture cap = VideoCapture("in.avi");
double fps = cap.get(CV_CAP_PROP_FPS);
Size size = Size(cap.get(CV_CAP_PROP_FRAME_WIDTH), cap.get(CV_CAP_PROP_FRAME_HEIGHT));
VideoWriter writer;
writer.open("out.avi", CV_FOURCC('M', 'J', 'P', 'G'), fps*2, size);
初始化VideoCapture实例读入输入视频”in.avi”,这里的输入视频是截取的蓝色星球2的前600帧制作的,然后使用VideoCapture的get方法分别获取视频流的帧率fps和图像大小size,有了这些参数信息我们就可以使用VideoWriter的open方法来构造输出视频了,“out.avi”指定了视频的文件名,CV_FOURCC(‘M’, ‘J’, ‘P’, ‘G’)指定了视频的编码格式,fps*2指定了视频的帧率(乘以2是因为输出视频需要以两倍原视频的速度播放,因此我们设置输出视频的帧率为输入视频帧率的两倍即可),size指定了视频的长宽。构造出一个空的视频之后,接下来的工作就只需要按要求将一个个的帧插入到视频中就可以了。输入视频:
第2步:制作片头
因为刚开始接触OpenCV,啥高大上的技术也不会,片头这部分我就是参考OpenCV的例子程序画个旋转的原子图了。在图中有一个不动的原子核和四个围绕原子核旋转的电子,简单起见四个电子旋转时投影在二维平面上的大小没有做变化,虽然这样做看上去也就没有什么立体的效果了(后期可以再优化一下)。有了想法之后实现起来就比较容易了,主要就是在电子的旋转路径上依次把电子画出来就好了,而电子的旋转路径在二维平面看上去也就是围绕在原子核周边的一个个椭圆了。具体代码如下所示:
void rotateAtom2(Size size) {
cout << "rotateAtom2..." << endl;
Point center; // 原子的中心位置
center.x = size.width / 2;
center.y = size.height / 2;
Size axes; // 椭圆的半长轴和半短轴大小
axes.width = min(size.width, size.height) / 4;
axes.height = min(size.width, size.height) / 16;
int radius = min(size.width, size.height) / 32; // 原子核的半径大小
int lineType = 8;
for (int i = 0; i < 720; i++) {
Mat img = Mat(size.height, size.width, CV_8UC3, Scalar(0, 0, 0)); // 初始化一个背景为黑色的帧
circle(img, center, radius, Scalar(0, 0, 255), -1, lineType); // 画原子核:在center位置画一个半径为radius的圆
ellipse(img, center, axes, 0, 0<