Opencv學習筆記(八)視頻流2

    用類封裝了下視頻的讀取(可以是視頻文件也可以是圖片序列),處理,以及寫入文件(可以是視頻文件也可以是圖片序列)。

    代碼如下:

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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章