本文转自:http://blog.csdn.net/xiaojiegege123456/article/details/8470427
一、加载播放视频
- <span style="font-size: 24px;">#include "stdafx.h"
- using namespace std;
- using namespace cv;
- int main()
- {
- //下面两种方法都可以打开视频
- VideoCapture capture("../1.avi");
- /*2、VideoCapture capture;
- capture.open("../1.avi");*/
- if(!capture.isOpened())
- return 1;
- double rate = capture.get(CV_CAP_PROP_FPS);
- bool stop(false);
- Mat frame;
- namedWindow("Extracted Frame");
- //这个delay的单位是ms,若是秒,则delay为1/rate。
- //rate为每秒播放的帧数
- int delay = 1000/rate;
- //用于设置直接播放哪一帧
- double position= 0.0;
- capture.set(CV_CAP_PROP_POS_FRAMES, position);
- while(!stop)
- {
- //以下三种方法都可以读取视频
- if(!capture.read(frame))
- break;
- /*2、capture>>frame;*/
- /*3、capture.grab();
- capture.retrieve(frame);*/
- imshow("Extracted Frame",frame);</span><span style="font-size: 24px;">
- </span><span style="font-size: 24px;">if(waitKey(delay) >= 0)
- stop = true;<span style="font-size: 24px;">//<span style="color: rgb(255, 0, 0);">当delay==0时,将会暂停在该帧,不再执行下去,</span><span style="color: rgb(255, 0, 0);">若不是0,则会等待键盘的消息输入,则结束</span></span>
- }
- //</span><span style="font-size: 24px;"><span style="color: rgb(255, 0, 0);">关闭视频文件,但是不是必须的,VideoCapture构造函数会默认调用它
- </span> capture.release();
- }
- </span>
<span style="font-size: 24px;">#include "stdafx.h"
using namespace std;
using namespace cv;
int main()
{
//下面两种方法都可以打开视频
VideoCapture capture("../1.avi");
/*2、VideoCapture capture;
capture.open("../1.avi");*/
if(!capture.isOpened())
return 1;
double rate = capture.get(CV_CAP_PROP_FPS);
bool stop(false);
Mat frame;
namedWindow("Extracted Frame");
//这个delay的单位是ms,若是秒,则delay为1/rate。
//rate为每秒播放的帧数
int delay = 1000/rate;
//用于设置直接播放哪一帧
double position= 0.0;
capture.set(CV_CAP_PROP_POS_FRAMES, position);
while(!stop)
{
//以下三种方法都可以读取视频
if(!capture.read(frame))
break;
/*2、capture>>frame;*/
/*3、capture.grab();
capture.retrieve(frame);*/
imshow("Extracted Frame",frame);</span><span style="font-size: 24px;">
</span><span style="font-size: 24px;">if(waitKey(delay) >= 0)
stop = true;<span style="font-size: 24px;">//<span style="color: rgb(255, 0, 0);">当delay==0时,将会暂停在该帧,不再执行下去,</span><span style="color: rgb(255, 0, 0);">若不是0,则会等待键盘的消息输入,则结束</span></span>
}
//</span><span style="font-size: 24px;"><span style="color: rgb(255, 0, 0);">关闭视频文件,但是不是必须的,VideoCapture构造函数会默认调用它
</span> capture.release();
}
</span>
二、对视频读入、处理、输出进行的封装
头文件代码:
- <span style="font-size: 24px;">#pragma once
- using namespace cv;
- class VideoProcessor
- {
- private://用于打开处理视频
- //opencv 视频捕捉对象
- VideoCapture capture;
- //回调函数将调用每帧处理函数
- void (*process)(Mat&,Mat&);
- //是否调用回调函数的开关
- bool callIt;
- //输入视频的播放窗口名字
- string windowNameInput;
- //输入视频的播放窗口名字
- string windowNameOutput;
- //播放每帧之间的暂停间隔
- int delay;
- //已处理的帧数
- long fnumber;
- //停止在某一帧
- long frameToStop;
- //停止处理的开关
- bool stop;
- //存储获得的视频每帧
- Mat image;
- public:
- //设置回调函数,用于处理帧
- void setFrameProcessor(
- void (*frameProcessingCallback)(Mat&,Mat&))
- {
- process = frameProcessingCallback;
- }
- //打开一个视频文件
- bool setInput(string filename);
- //创建一个窗口显示输入帧
- void displayInput(string wn);
- //创建一个窗口显示输出帧
- void displayOutput(string wn);
- //不显示帧
- void dontDisplay(void);
- //抓取或处理帧序列
- void run(void);
- //捕捉设备是否打开
- bool isOpened(){ return capture.isOpened() || !images.empty();}
- //是否停止处理
- bool isStopped(){ return stop; }
- //停止处理
- void stopIt(){ stop = true; }
- //从视频或摄像头或图片文件读取下一帧
- bool readNextFrame(Mat& frame);
- //设置播放延时
- void setDelay(int d){ delay = d;}
- //设置调用回调函数
- void callProcess(){ callIt = true; }
- //设置不调用回调函数
- void dontCallProcess(){ callIt = false;}
- //设置停留在某帧
- void stopAtFrameNo(long frame){ frameToStop = frame;}
- //返回视频总帧数
- long getFrameNumber(void);
- //返回输入视频的帧频
- long getFrameRate(){ return capture.get(CV_CAP_PROP_FPS); }
- private://用于输出视频或图片文件
- //opencv用于视频输出类对象
- VideoWriter writer;
- //输出文件名
- string outputFile;
- //输出图片的当前索引值
- int currentIndex;
- //输出图像的数字编号的位数
- int digits;
- //扩展名
- string extension;
- //保存图片文件名
- vector<string> images;
- //遍历图片vector的迭代器
- vector<string>::const_iterator itImg;
- public:
- //输出视频文件以原视频相同的参数
- //还不能正确得到输入视频的codec格式,只能在codec==-1时,输出视频
- bool setOutput(const string& filename, int codec=-1, double framerate=0.0, bool isColor=true);
- //用于输出每一帧
- void writeNextFrame(Mat& frame);
- //用于以图片格式输出
- bool setOutput(const string &filename,const string &ext,int numberOfDigits=3, int startIndex=0);
- //获得输入视频的编码格式
- int getCodec(char codec[4]);
- //获得图片大小
- cv::Size getFrameSize()
- {
- cv::Size S ;
- return S = Size((int) capture.get(CV_CAP_PROP_FRAME_WIDTH), //获取输入尺寸
- (int) capture.get(CV_CAP_PROP_FRAME_HEIGHT));
- }
- public:
- VideoProcessor(void);
- ~VideoProcessor(void);
- //设置输入图片向量
- bool setInput(const vector<string>& imgs);
- };
- </span>
<span style="font-size: 24px;">#pragma once
using namespace cv;
class VideoProcessor
{
private://用于打开处理视频
//opencv 视频捕捉对象
VideoCapture capture;
//回调函数将调用每帧处理函数
void (*process)(Mat&,Mat&);
//是否调用回调函数的开关
bool callIt;
//输入视频的播放窗口名字
string windowNameInput;
//输入视频的播放窗口名字
string windowNameOutput;
//播放每帧之间的暂停间隔
int delay;
//已处理的帧数
long fnumber;
//停止在某一帧
long frameToStop;
//停止处理的开关
bool stop;
//存储获得的视频每帧
Mat image;
public:
//设置回调函数,用于处理帧
void setFrameProcessor(
void (*frameProcessingCallback)(Mat&,Mat&))
{
process = frameProcessingCallback;
}
//打开一个视频文件
bool setInput(string filename);
//创建一个窗口显示输入帧
void displayInput(string wn);
//创建一个窗口显示输出帧
void displayOutput(string wn);
//不显示帧
void dontDisplay(void);
//抓取或处理帧序列
void run(void);
//捕捉设备是否打开
bool isOpened(){ return capture.isOpened() || !images.empty();}
//是否停止处理
bool isStopped(){ return stop; }
//停止处理
void stopIt(){ stop = true; }
//从视频或摄像头或图片文件读取下一帧
bool readNextFrame(Mat& frame);
//设置播放延时
void setDelay(int d){ delay = d;}
//设置调用回调函数
void callProcess(){ callIt = true; }
//设置不调用回调函数
void dontCallProcess(){ callIt = false;}
//设置停留在某帧
void stopAtFrameNo(long frame){ frameToStop = frame;}
//返回视频总帧数
long getFrameNumber(void);
//返回输入视频的帧频
long getFrameRate(){ return capture.get(CV_CAP_PROP_FPS); }
private://用于输出视频或图片文件
//opencv用于视频输出类对象
VideoWriter writer;
//输出文件名
string outputFile;
//输出图片的当前索引值
int currentIndex;
//输出图像的数字编号的位数
int digits;
//扩展名
string extension;
//保存图片文件名
vector<string> images;
//遍历图片vector的迭代器
vector<string>::const_iterator itImg;
public:
//输出视频文件以原视频相同的参数
//还不能正确得到输入视频的codec格式,只能在codec==-1时,输出视频
bool setOutput(const string& filename, int codec=-1, double framerate=0.0, bool isColor=true);
//用于输出每一帧
void writeNextFrame(Mat& frame);
//用于以图片格式输出
bool setOutput(const string &filename,const string &ext,int numberOfDigits=3, int startIndex=0);
//获得输入视频的编码格式
int getCodec(char codec[4]);
//获得图片大小
cv::Size getFrameSize()
{
cv::Size S ;
return S = Size((int) capture.get(CV_CAP_PROP_FRAME_WIDTH), //获取输入尺寸
(int) capture.get(CV_CAP_PROP_FRAME_HEIGHT));
}
public:
VideoProcessor(void);
~VideoProcessor(void);
//设置输入图片向量
bool setInput(const vector<string>& imgs);
};
</span>
相应cpp文件:
- <span style="font-size: 24px;">#include "StdAfx.h"
- #include "VideoProcessor.h"
- VideoProcessor::VideoProcessor(void):
- callIt(true),
- delay(0),
- fnumber(0),
- stop(false),
- frameToStop(-1),
- currentIndex(0),
- digits(0)
- {
- }
- VideoProcessor::~VideoProcessor(void)
- {
- }
- bool VideoProcessor::setInput(string filename)
- {
- fnumber = 0;
- //万一该VideoCapture对象已经关联了一个资源
- capture.release();
- //images.clear();
- //打开视频文件
- return capture.open(filename);
- }
- void VideoProcessor::displayInput(string wn)
- {
- windowNameInput = wn;
- namedWindow(windowNameInput);
- }
- void VideoProcessor::displayOutput(string wn)
- {
- windowNameOutput = wn;
- namedWindow(windowNameOutput);
- }
- void VideoProcessor::dontDisplay(void)
- {
- destroyWindow(windowNameInput);
- destroyWindow(windowNameOutput);
- windowNameInput.clear();
- windowNameOutput.clear();
- }
- void VideoProcessor::run(void)
- {
- //当前帧
- Mat frame;
- //输出帧
- Mat output;
- //判断是否打开成功
- if(!isOpened())
- return;
- stop = false;
- while(!isStopped())
- {
- //若存在视频下一帧,则读取
- if(!readNextFrame(frame))
- break;
- //将当前帧存于image中
- image = frame;
- //frame.copyTo(image);
- //显示输入帧
- if(windowNameInput.length() != 0)
- imshow(windowNameInput,frame);
- //调用处理函数
- if(callIt)
- {
- process(frame,output);
- fnumber++;
- }else{
- output = frame;
- }
- //**写输出序列
- if(outputFile.length() != 0)
- writeNextFrame(output);
- //显示输出帧
- if(windowNameOutput.length() != 0)
- imshow(windowNameOutput,output);
- //延时
- if(delay >= 0 && waitKey(delay) >= 0)
- stopIt();
- if(frameToStop >= 0 && getFrameNumber() == frameToStop)
- stopIt();
- }
- }
- bool VideoProcessor::readNextFrame(Mat& frame)
- {
- if(images.size() == 0)
- return capture.read(frame);
- else{
- if(itImg != images.end())
- {
- frame = imread(*itImg);
- itImg++;
- return frame.data != 0;
- }else{
- return false;
- }
- }
- }
- long VideoProcessor::getFrameNumber(void)
- {
- long fnumber = static_cast<long>(capture.get(CV_CAP_PROP_POS_FRAMES));
- return fnumber;
- }
- bool VideoProcessor::setOutput(const string& filename, int codec, double framerate, bool isColor)
- {
- outputFile = filename;
- extension.clear();
- if(framerate == 0.0)
- framerate = getFrameRate();
- char c[4];
- //使用与输出视频相同的编码方式
- if(codec == 0)
- {
- codec = getCodec(c);
- }
- writer.open(outputFile,
- codec=-1,
- framerate,
- getFrameSize(),
- isColor);
- if(writer.isOpened()) std::cout<<"dai kai cheng gong"<<std::endl;
- return true;
- }
- void VideoProcessor::writeNextFrame(Mat& frame)
- {
- if(extension.length())
- {
- std::stringstream ss;
- //构成输出文件名
- ss<<outputFile<<std::setfill('0')
- <<std::setw(digits)
- <<currentIndex++<<extension;
- imwrite(ss.str(),frame);
- }else//否则以视频格式写出
- {
- writer.write(frame);
- }
- }
- bool VideoProcessor::setOutput(const string &filename,//文件前缀
- const string& ext,//图片文件的扩展名
- int numberOfDigits,//数据位
- int startIndex) //开始索引值
- {
- //数字必须为正
- if(numberOfDigits<0)
- return false;
- //文件名及其扩展名
- outputFile = filename;
- extension = ext;
- //输出图片的编号
- digits = numberOfDigits;
- //图片数字编号的起始值
- currentIndex = startIndex;
- return true;
- }
- int VideoProcessor::getCodec(char codec[4])
- {
- //
- if(images.size() != 0)
- return -1;
- union{//4-char编码的数据结构
- int value;
- char code[4];
- }returned;
- //获得编码方式
- returned.value = static_cast<int>(
- capture.get(CV_CAP_PROP_FOURCC));
- //获得四个字符
- codec[0] = returned.code[0];
- codec[1] = returned.code[1];
- codec[2] = returned.code[2];
- codec[3] = returned.code[3];
- /*std::cout << "Codec: " << codec[0] << codec[1]
- << codec[2] << codec[3] << std::endl;*/
- return returned.value;
- }
- bool VideoProcessor::setInput(const vector<string>& imgs)
- {
- fnumber = 0;
- capture.release();
- //将输入图片放入iamges中
- images = imgs;
- itImg = images.begin();
- return true;
- }
- </span>
<span style="font-size: 24px;">#include "StdAfx.h"
#include "VideoProcessor.h"
VideoProcessor::VideoProcessor(void):
callIt(true),
delay(0),
fnumber(0),
stop(false),
frameToStop(-1),
currentIndex(0),
digits(0)
{
}
VideoProcessor::~VideoProcessor(void)
{
}
bool VideoProcessor::setInput(string filename)
{
fnumber = 0;
//万一该VideoCapture对象已经关联了一个资源
capture.release();
//images.clear();
//打开视频文件
return capture.open(filename);
}
void VideoProcessor::displayInput(string wn)
{
windowNameInput = wn;
namedWindow(windowNameInput);
}
void VideoProcessor::displayOutput(string wn)
{
windowNameOutput = wn;
namedWindow(windowNameOutput);
}
void VideoProcessor::dontDisplay(void)
{
destroyWindow(windowNameInput);
destroyWindow(windowNameOutput);
windowNameInput.clear();
windowNameOutput.clear();
}
void VideoProcessor::run(void)
{
//当前帧
Mat frame;
//输出帧
Mat output;
//判断是否打开成功
if(!isOpened())
return;
stop = false;
while(!isStopped())
{
//若存在视频下一帧,则读取
if(!readNextFrame(frame))
break;
//将当前帧存于image中
image = frame;
//frame.copyTo(image);
//显示输入帧
if(windowNameInput.length() != 0)
imshow(windowNameInput,frame);
//调用处理函数
if(callIt)
{
process(frame,output);
fnumber++;
}else{
output = frame;
}
//**写输出序列
if(outputFile.length() != 0)
writeNextFrame(output);
//显示输出帧
if(windowNameOutput.length() != 0)
imshow(windowNameOutput,output);
//延时
if(delay >= 0 && waitKey(delay) >= 0)
stopIt();
if(frameToStop >= 0 && getFrameNumber() == frameToStop)
stopIt();
}
}
bool VideoProcessor::readNextFrame(Mat& frame)
{
if(images.size() == 0)
return capture.read(frame);
else{
if(itImg != images.end())
{
frame = imread(*itImg);
itImg++;
return frame.data != 0;
}else{
return false;
}
}
}
long VideoProcessor::getFrameNumber(void)
{
long fnumber = static_cast<long>(capture.get(CV_CAP_PROP_POS_FRAMES));
return fnumber;
}
bool VideoProcessor::setOutput(const string& filename, int codec, double framerate, bool isColor)
{
outputFile = filename;
extension.clear();
if(framerate == 0.0)
framerate = getFrameRate();
char c[4];
//使用与输出视频相同的编码方式
if(codec == 0)
{
codec = getCodec(c);
}
writer.open(outputFile,
codec=-1,
framerate,
getFrameSize(),
isColor);
if(writer.isOpened()) std::cout<<"dai kai cheng gong"<<std::endl;
return true;
}
void VideoProcessor::writeNextFrame(Mat& frame)
{
if(extension.length())
{
std::stringstream ss;
//构成输出文件名
ss<<outputFile<<std::setfill('0')
<<std::setw(digits)
<<currentIndex++<<extension;
imwrite(ss.str(),frame);
}else//否则以视频格式写出
{
writer.write(frame);
}
}
bool VideoProcessor::setOutput(const string &filename,//文件前缀
const string& ext,//图片文件的扩展名
int numberOfDigits,//数据位
int startIndex) //开始索引值
{
//数字必须为正
if(numberOfDigits<0)
return false;
//文件名及其扩展名
outputFile = filename;
extension = ext;
//输出图片的编号
digits = numberOfDigits;
//图片数字编号的起始值
currentIndex = startIndex;
return true;
}
int VideoProcessor::getCodec(char codec[4])
{
//
if(images.size() != 0)
return -1;
union{//4-char编码的数据结构
int value;
char code[4];
}returned;
//获得编码方式
returned.value = static_cast<int>(
capture.get(CV_CAP_PROP_FOURCC));
//获得四个字符
codec[0] = returned.code[0];
codec[1] = returned.code[1];
codec[2] = returned.code[2];
codec[3] = returned.code[3];
/*std::cout << "Codec: " << codec[0] << codec[1]
<< codec[2] << codec[3] << std::endl;*/
return returned.value;
}
bool VideoProcessor::setInput(const vector<string>& imgs)
{
fnumber = 0;
capture.release();
//将输入图片放入iamges中
images = imgs;
itImg = images.begin();
return true;
}
</span>
主函数对这个类的引用:
- <span style="font-size: 24px;">#include "stdafx.h"
- #include "VideoProcessor.h"
- using namespace std;
- using namespace cv;
- void canny(cv::Mat& img, cv::Mat& out) {
- // Convert to gray
- if (img.channels()==3)
- cv::cvtColor(img,out,CV_BGR2GRAY);
- // Compute Canny edges
- cv::Canny(out,out,100,200);
- // Invert the image
- cv::threshold(out,out,128,255,cv::THRESH_BINARY_INV);
- }
- int main()
- {
- VideoProcessor processor;
- processor.setInput("../1.avi");
- processor.displayInput("Current Frame");
- processor.displayOutput("Output Frame");
- processor.setDelay(1000./processor.getFrameRate());
- processor.setFrameProcessor(canny);
- processor.setOutput("../laneout.avi");
- //processor.setOutput("../laneout",".bmp");
- processor.stopAtFrameNo(300);
- processor.run();
- }</span>
<span style="font-size: 24px;">#include "stdafx.h"
#include "VideoProcessor.h"
using namespace std;
using namespace cv;
void canny(cv::Mat& img, cv::Mat& out) {
// Convert to gray
if (img.channels()==3)
cv::cvtColor(img,out,CV_BGR2GRAY);
// Compute Canny edges
cv::Canny(out,out,100,200);
// Invert the image
cv::threshold(out,out,128,255,cv::THRESH_BINARY_INV);
}
int main()
{
VideoProcessor processor;
processor.setInput("../1.avi");
processor.displayInput("Current Frame");
processor.displayOutput("Output Frame");
processor.setDelay(1000./processor.getFrameRate());
processor.setFrameProcessor(canny);
processor.setOutput("../laneout.avi");
//processor.setOutput("../laneout",".bmp");
processor.stopAtFrameNo(300);
processor.run();
}</span>
代码注释:输出视频和输出图片一次只能设置一个。具体应用时,对处理函数的形式进行修改,使其适合相应程序的要求。