用類封裝了下視頻的讀取(可以是視頻文件也可以是圖片序列),處理,以及寫入文件(可以是視頻文件也可以是圖片序列)。
代碼如下:
#include "opencv2/opencv.hpp"
#include <sstream>
#include <iomanip>
using namespace std;
using namespace cv;
class FrameProcessor;
class FrameProcessor{
public:
virtual void process(Mat &input,Mat &ouput);
};
class VideoProcessor{
private:
VideoCapture caputure;
//寫視頻流對象
VideoWriter writer;
//輸出文件名
string Outputfile;
int currentIndex;
int digits;
string extension;
FrameProcessor *frameprocessor;
//圖像處理函數指針
void (*process)(Mat &,Mat &);
bool callIt;
string WindowNameInput;
string WindowNameOutput;
//延時
int delay;
long fnumber;
//第frameToStop停止
long frameToStop;
//暫停標誌
bool stop;
//圖像序列作爲輸入視頻流
vector<string> images;
//迭代器
public:
VideoProcessor() : callIt(true),delay(0),fnumber(0),stop(false),digits(0),frameToStop(-1){}
//設置圖像處理函數
void setFrameProcessor(void (*process)(Mat &,Mat &)){
frameprocessor = 0;
this->process = process;
CallProcess ();
}
//打開視頻
bool setInput(string filename){
fnumber = 0;
//若已打開,釋放重新打開
caputure.release ();
return caputure.open (filename);
}
//設置輸入視頻播放窗口
void displayInput(string wn){
WindowNameInput = wn;
namedWindow (WindowNameInput);
}
//設置輸出視頻播放窗口
void displayOutput(string wn){
WindowNameOutput = wn;
namedWindow (WindowNameOutput);
}
//銷燬窗口
void dontDisplay(){
destroyWindow (WindowNameInput);
destroyWindow (WindowNameOutput);
WindowNameInput.clear ();
WindowNameOutput.clear ();
}
//啓動
void run(){
Mat frame;
Mat output;
if(!isOpened())
return;
stop = false;
while(!isStopped()){
//讀取下一幀
if(!readNextFrame(frame))
break;
if(WindowNameInput.length ()!=0)
imshow (WindowNameInput,frame);
//處理該幀
if(callIt){
if(process)
process(frame,output);
else if(frameprocessor)
frameprocessor->process (frame,output);
}
else{
output = frame;
}
if(Outputfile.length ()){
cvtColor (output,output,CV_GRAY2RGB);
writeNextFrame (output);
}
if(WindowNameOutput.length ()!=0)
imshow (WindowNameOutput,output);
//按鍵暫停,繼續按鍵繼續
if(delay>=0&&waitKey (delay)>=0)
waitKey(0);
//到達指定暫停鍵,退出
if(frameToStop>=0&&getFrameNumber()==frameToStop)
stopIt();
}
}
//暫停鍵置位
void stopIt(){
stop = true;
}
//查詢暫停標誌位
bool isStopped(){
return stop;
}
//返回視頻打開標誌
bool isOpened(){
return caputure.isOpened ()||!images.empty ();
}
//設置延時
void setDelay(int d){
delay = d;
}
//讀取下一幀
bool readNextFrame(Mat &frame){
if(images.size ()==0)
return caputure.read (frame);
else{
if(itImg!=images.end()){
frame = imread (*itImg);
itImg++;
return frame.data?1:0;
}
else
return false;
}
}
void CallProcess(){
callIt = true;
}
void dontCallProcess(){
callIt = false;
}
//設置停止幀
void stopAtFrameNo(long frame){
frameToStop = frame;
}
// 獲得當前幀的位置
long getFrameNumber(){
long fnumber = static_cast<long>(caputure.get ((CV_CAP_PROP_POS_FRAMES)));
return fnumber;
}
//獲得幀大小
Size getFrameSize() {
if (images.size()==0) {
// 從視頻流獲得幀大小
int w= static_cast<int>(caputure.get(CV_CAP_PROP_FRAME_WIDTH));
int h= static_cast<int>(caputure.get(CV_CAP_PROP_FRAME_HEIGHT));
return Size(w,h);
}
else {
//從圖像獲得幀大小
cv::Mat tmp= cv::imread(images[0]);
return (tmp.data)?(tmp.size()):(Size(0,0));
}
}
//獲取幀率
double getFrameRate(){
return caputure.get(CV_CAP_PROP_FPS);
}
vector<string>::const_iterator itImg;
bool setInput (const vector<string> &imgs){
fnumber = 0;
caputure.release ();
images = imgs;
itImg = images.begin ();
return true;
}
void setFrameProcessor(FrameProcessor *frameprocessor){
process = 0;
this->frameprocessor = frameprocessor;
CallProcess ();
}
//獲得編碼類型
int getCodec(char codec[4]) {
if (images.size()!=0)
return -1;
union { // 數據結構4-char
int value;
char code[4];
} returned;
//獲得編碼值
returned.value= static_cast<int>(
caputure.get(CV_CAP_PROP_FOURCC));
// get the 4 characters
codec[0]= returned.code[0];
codec[1]= returned.code[1];
codec[2]= returned.code[2];
codec[3]= returned.code[3];
return returned.value;
}
bool setOutput(const string &filename,int codec = 0,double framerate = 0.0,bool isColor = true){
//設置文件名
Outputfile = filename;
//清空擴展名
extension.clear ();
//設置幀率
if(framerate ==0.0){
framerate = getFrameRate ();
}
//獲取輸入原視頻的編碼方式
char c[4];
if(codec==0){
codec = getCodec(c);
}
return writer.open(Outputfile,
codec,
framerate,
getFrameSize(),
isColor);
}
//輸出視頻幀到圖片fileme+currentIndex.ext,如filename001.jpg
bool setOutput (const string &filename,//路徑
const string &ext,//擴展名
int numberOfDigits=3,//數字位數
int startIndex=0 ){//起始索引
if(numberOfDigits<0)
return false;
Outputfile = filename;
extension = ext;
digits = numberOfDigits;
currentIndex = startIndex;
return true;
}
//寫下一幀
void writeNextFrame(Mat &frame){
//如果擴展名不爲空,寫到圖片文件中
if(extension.length ()){
stringstream ss;
ss<<Outputfile<<setfill('0')<<setw(digits)<<currentIndex++<<extension;
imwrite (ss.str (),frame);
}
//反之,寫到視頻文件中
else{
writer.write (frame);
}
}
};
//幀處理函數:canny邊緣檢測
void canny(cv::Mat& img, cv::Mat& out) {
//灰度變換
if (img.channels()==3)
cvtColor(img,out,CV_BGR2GRAY);
// canny算子求邊緣
Canny(out,out,100,200);
//顏色反轉,看起來更舒服些
threshold(out,out,128,255,cv::THRESH_BINARY_INV);
}
int main(int argc, char *argv[])
{
VideoProcessor processor;
//打開輸入視頻
processor.setInput ("bike.avi");
processor.displayInput ("Current Frame");
processor.displayOutput ("Output Frame");
//設置每一幀的延時
processor.setDelay (1000./processor.getFrameRate ());
//設置幀處理函數,可以任意
processor.setFrameProcessor (canny );
processor.setOutput ("./bikeout.avi");
// processor.setOutput ("bikeout",".jpg");
processor.run ();
return 0;
}