您的位置:首页 > 运维架构

视频加载、处理、输出-----opencv2.0学习笔记4

2013-01-05 20:32 387 查看

一、加载播放视频

#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);
if(waitKey(delay) >= 0)
stop = true;//当delay==0时,将会暂停在该帧,不再执行下去,若不是0,则会等待键盘的消息输入,则结束
}
//关闭视频文件,但是不是必须的,VideoCapture构造函数会默认调用它
capture.release();
}

二、对视频读入、处理、输出进行的封装

头文件代码:

#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);
};

相应cpp文件:

#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;
}

主函数对这个类的引用:

#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();
}

代码注释:输出视频和输出图片一次只能设置一个。具体应用时,对处理函数的形式进行修改,使其适合相应程序的要求。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: