现在的位置: 首页 > 综合 > 正文

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

2013年10月12日 ⁄ 综合 ⁄ 共 6447字 ⁄ 字号 评论关闭

 一、加载播放视频

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

代码注释:输出视频和输出图片一次只能设置一个。具体应用时,对处理函数的形式进行修改,使其适合相应程序的要求。
 

 

抱歉!评论已关闭.