OpenCV3学习(3)——视频文件的读取与写入

这方面的例程和博客已经很多了,这里贴出我自己的实例供大家学习。

      视频画面本质上是由一帧一帧的连续图像组成的,播放视频其实就是在播放窗口把一系列连续图像按一定的时间间隔一幅幅贴上去实现的。人眼在连续图像的刷新最少达到每秒24帧的时候,就分辨不出来图像间的闪动了,使人感觉呈现出来的是连续的画面,视频的播放就是利用了这一点。我们知道,电影被称为“24帧的艺术”,意思就是电影画面每秒刷新24帧,即每秒显示24副图像,它的帧率(Frames per Second,简称:FPS)为24。
    

      播放与进度控制里主要用到 VideoCapture类里的get()函数,和创建控制条的createTrackbar()函数,get()函数用于获取视频的帧数、帧率等信息,了解get函数的参数含义即可,像get(CV_CAP_PROP_FRAME_COUNT)用于获取总帧数,get(CV_CAP_PROP_FPS)用于获取帧率等。

控制条作为Opencv中一个重要的用户和图像传参、交互的工具,伴随了整个opencv图像处理的过程,这里有必要再说一说createTrackbar()这个函数。

函数原型

int createTrackbar(const string& trackbarname, const string& winname,
                              int* value, int count,
                              TrackbarCallback onChange = 0,
                              void* userdata = 0);

该函数作用是在指定图像窗口上创建一个控制条,这个控制条具有指定的参数控制范围,可以通过回调函数,执行对应的操作。

第一个参数:const修饰的string类型的引用trackbarname,表示控制条的名称

第二个参数:const修饰的string类型的引用winname,表示控制条所在的图像窗口的名称

第三个参数:int型的指针value,表示滑块的控制位置,拖动控制条滑块的位置,相应的会改变*value的值

第四个参数:int型的count,表示控制条上滑块的最大位置处对应的值

第五个参数:TrackbarCallback类型的onChange,表示一个指向回调函数的指针,每当滑块的位置发生变化,都会触发该回调函数

第六个参数:void型的userdata,一般使用其默认值0
 

每次拖动滑块位置发生,就会触发定义的“change”回调函数,这个函数做了件事,

capture.set(CV_CAP_PROP_POS_FRAMES,pos);     //通过set函数,设置当前播放帧。
在while循环里不断累加当前播放帧变量,当当前播放帧大于总的帧数时,表示视频已经播放到结尾,退出播放。
 

设置滑动条位置(setTrackbarPos)
void setTrackbarPos(const String& trackbarname, const String& winname, int pos)

trackbarname:滑动条名称。
winname:窗口名称。
pos:新位置。
 

视频读取,主要利用VideoCapture类下的方法打开视频并获取视频中的帧,具体示例如下:

#pragma warning(disable:4996)//应对sprintf报错
#include<opencv2\highgui\highgui.hpp>//用于视频读取与写入
#include<opencv2\imgproc\imgproc.hpp>//用于图像的基本操作,如边缘检测
#include<opencv2\opencv.hpp>
#include<iostream>//输入输出流
using namespace std;//定义命名空间
using namespace cv;

int trackbarValue=0;//播放视频
VideoCapture capture;//创建一个视频结构

void change(int pos, void *) {一个自定义的函数,用于进度条回调
	capture.set(CV_CAP_PROP_POS_FRAMES, pos);//设置视频帧位置
}
void main() {
	
	Mat frame,edge;//创建Mat存储读取的每一帧和对应的边缘检测图
	char strfps[20];
	char strfps2[20];
	frame = capture.open("jianpan.avi");//路径要正确,这里我将文件放在与源文件相同的路径下
	if (!capture.isOpened()) {
		printf("读取失败");
	}
	
	int frameCount = capture.get(CV_CAP_PROP_FRAME_COUNT);//从capture中读出该视频的帧数
	cout << "帧数" << frameCount << endl;
	namedWindow("Video",CV_WINDOW_AUTOSIZE);//创建进度条时,前面必须先创建一个窗口声明
	createTrackbar("Frame","Video", &trackbarValue,frameCount,change);//这是一个回调函数,创建进度条,将视频总帧数,frameCount最为进度条的终点。每次进度条移动,就会回调change函数
	while (capture.read(frame)) {
		double rate = capture.get(CV_CAP_PROP_FPS);
		sprintf(strfps, "rate%0.1f/s", rate);//格式化帧率字符串
		int current_framePos = capture.get(CV_CAP_PROP_POS_FRAMES);//当你移动滑动条,触发回调函数,会重新设置帧数,然后这里会读取你设置的帧数位置,读取这个位置的一帧图像
		sprintf(strfps2, "rate%d", current_framePos);//格式化帧数字符串
		setTrackbarPos("Frame", "Video", current_framePos);//设置滑动条位置(显示出来让我们看到进度条拖动到哪了)
		putText(frame, strfps, Point(5, 20), CV_FONT_HERSHEY_COMPLEX_SMALL, 1, Scalar(0, 255, 0), 2, 8);
		putText(frame, strfps2, Point(5, 50), CV_FONT_HERSHEY_COMPLEX_SMALL, 1, Scalar(255,0, 0), 2, 8);
		cvtColor(frame, edge, COLOR_RGB2GRAY);//彩色转灰度图
		Canny(edge,edge,40,80);//canny边缘检测
		imshow("Video", frame);
		imshow("After canny", edge);
		int key=waitKey(20);
		if  (key ==32)//按空格,暂停视频视频读取
		  waitKey(0);
		if (key == 'q' || key == 27)
			break;
	}
	capture.release();
}

视频写入
读取视频,然后通过capture.get(CV_CAP_PROP_FRAME_WIDTH), capture.get(CV_CAP_PROP_FRAME_HEIGHT)获取当前帧的宽度和高度,创建一个VideoWriter类对象writer进行视频的写入。 
写入前可进行视频的灰度处理。

#pragma warning(disable:4996)//应对sprintf报错
#include<opencv2\highgui\highgui.hpp>//用于视频读取与写入
#include<opencv2\imgproc\imgproc.hpp>//用于图像的基本操作,如边缘检测
#include<opencv2\opencv.hpp>
#include<iostream>//输入输出流
using namespace std;//定义命名空间
using namespace cv;

int main() {//写入视频文件
	Mat frame, gray;
	VideoCapture cap; 
	frame=cap.open("jianpan.avi");
	if (!cap.isOpened())
		printf("open failed");
	Size size =Size(cap.get(CV_CAP_PROP_FRAME_WIDTH), cap.get(CV_CAP_PROP_FRAME_HEIGHT));
	VideoWriter writer;
	writer.open("jianpancopy.avi",CV_FOURCC('M', 'J', 'P', 'G'),20,size,false );
//
	if (!writer.isOpened()) {
		printf("failed");
	}
	while (cap.read(frame)) {
		cvtColor(frame, gray, COLOR_BGR2GRAY);
		Canny(gray, gray, 40, 100);
		imshow("gray", gray);
		writer.write(gray);//把灰度图写进去,即最后写好的视频是原视频的灰度视频
		waitKey(10);
	}
	waitKey(0);
	cap.release();
}

  读取视频结果:

from:https://blog.csdn.net/dcrmg/article/details/52049304?utm_source=blogxgwz2

猜你喜欢

转载自blog.csdn.net/qq_30815237/article/details/86659784
今日推荐