Opencv 视频帧的读写指导
思路指导
1.先打开视频文件
2.遍历视频帧
3.处理视频帧
4.保存所有的视频帧
1.打开视频
1.当读取的是保存的视频时,打开视频的方法为:
cv::VideoCapture capture("视频名"); //将视频放到工程文件夹下
//或者
cv::VideoCapture capture;
capture.open("视频名"); //将视频放到工程文件夹下
2.当读取的是摄像头采集的是视频帧时,打开视频的方法为:
cv::VideoCapture capture(0); //每个摄像头都有一个从0开始的索引号,0是默认的摄像头的索引号;当还需要打开一个摄像头时,第二个摄像头索引号为1,即cv::VideoCapture capture(1);
3.当读取的是一系列图片时,打开视频的方式为:
//读取goose124.bmp-----goose275.bmp的图片
char filename[500];
cv::Mat frame;
for (int i = 124; i < 275; i++)
{
sprintf_s(filename,500, "D:\\KDubaSoftDownloads\\keepvadio\\12.1Project1\\pc\\goose%d.bmp", i);
frame = cv::imread(filename);
cv::imshow("Board Image",frame); //播放图片
cv::waitKey(300); //两张图片间隔300ms
}
2.遍历视频帧
1.当遍历的是视频时:
cv::VideoCapture capture;
cv::Mat frame;
capture.read(frame); //按顺序访问每一帧
cv::waitKey(delay) //设置每一帧间隔
2.当遍历的是一批独立的储存图像时:
cv::Mat frame;
//设置输入对象的图像文件名向量
std::vector<std::string> images;
// 图像向量的迭代器
std::vector<std::string>::const_iterator itImg;
//将这个图像向量作为输入对象,取地址
itImg = images.begin();
if(itImg != images.end())
{
frame = cv::imread(*itImg);
cv::imshow("image",frame);
itImg++;
}
3.处理视频帧
这时候我们需要一个函数(回调函数),让视频序列的每一帧都调用它。
在面向对象的编程中,最好是使用帧处理类而不是帧处理函数,实用类能提供很大的灵活性。
//定义一个接口函数类,(抽象类)
class FrameProcessor {
public:
// 处理方法
virtual void process(cv::Mat &input, cv::Mat &output) = 0; //纯虚函数,在不确定其功能时使用纯虚函数。
};
//由于FrameProcessor是抽象类,process是纯虚函数,所以需要在另一个类中对process进行实例化
class VideoProcessor
{
private:
void(*process)(cv::Mat&, cv::Mat&);
// 方便在调用在下面的函数中对其实例化
void setFrameProcessor(void(*frameProcessingCallback)(cv::Mat&, cv::Mat&)
{
// 对process实例化
process = frameProcessingCallback; //frameProcessingCallback处理函数
}
}
在读取每一帧后运行 process(frame, output) 就实现了对每一帧的处理。
4.保存所有的视频帧
Opencv用cv::VideoCapture 类写视频文件
cv::VideoWriter writer;
//读取视频帧速率
double getFrameRate()
{
double r = capture.get(cv::CAP_PROP_FPS);
return r;
}
//读取视频帧的宽和高
cv::Size size = cv::Size((int)capture.get(cv::CAP_PROP_FRAME_WIDTH), (int)capture.get(cv::CAP_PROP_FRAME_HEIGHT));
//制作视频AVI空间
writer.open(
"output.avi", //命名输出的视频名
cv::VideoWriter::fourcc('M', 'J', 'P', 'G'), //编码器格式
getFrameRate(), //视频帧速率,本次采用输入视频的视频帧速率
size, //保存视频帧的大小,建议采用输入视频帧的大小,不然运行可能出问题
false //彩色视频,true彩色视频,false不是彩色视频
);
//将读取的视频帧写入制作的视频空间 "output.avi"
writer << frame;
5.此次编程遇到的问题
1.setw()默认填充的内容为空格,可以setfill()配合使用设置其他字符填充。
如:
cout<<setfill(’&’)<<setw(5)<<‘a’<<endl;
则输出:
&&&&a //4个&和字符a共占5个位置。
所谓域宽,就是输出的内容(数值或字符等等)需要占据多少个字符的位置,如果位置有空余则会自动补足。比如我们要设置域宽为2,那么当输出一位数1的时候输出的就是“ 1”,即在1前面加了一个空格;那么当输出两位数12的时候输出的就是“12”,即在两个空格完全占用。
我 们在设置域宽和填充字符的时候要注意几点:
①设置域宽的时候应该填入整数,设置填充字符的时候应该填入字符。
②我们可以对一个要输出的内容同时设置域宽和 填充字符,但是设置好的属性仅对下一个输出的内容有效,之后的输出要再次设置。即 cout <<setw(2) <<a <<b;语句中域宽设置仅对a有效,对b无效。
③setw和setfill 被称为输出控制符,使用时需要在程序开头写上#include “iomanip.h”,否则无法使用。
2.
在函数前加 virtual 为虚函数,同时在函数尾部加 = 0 为纯虚函数
虚函数(impure virtual)
C++的虚函数主要作用是“运行时多态”,父类中提供虚函数的实现,为子类提供默认的函数实现。
子类可以重写父类的虚函数实现子类的特殊化。
纯虚函数(pure virtual)
C++中包含纯虚函数的类,被称为是“抽象类”。抽象类不能使用new出对象,只有实现了这个纯虚函数的子类才能new出对象。
C++中的纯虚函数更像是“只提供申明,没有实现”,是对子类的约束,是“接口继承”。
C++中的纯虚函数也是一种“运行时多态”。