1. 程式人生 > >OpenCV內建的超分辨演算法測試

OpenCV內建的超分辨演算法測試

最近在做超分辨相關的東西,從網上了解到OpenCV有自帶的超分辨演算法,於是就有了下面這些嘗試。

1、利用OpenCV驅動USB攝像頭拍攝視訊以及讀取視訊

        讀取視訊檔案或者攝像頭視訊需要使用OpenCV中的VideoCapture類,儲存視訊或者攝像頭視訊到本地磁碟,需要使用OpenCV中的VideoWriter類,使用非常簡單。

首先來看一下如何VideoWriter類:

VideoWriter(const string& filename, int fourcc, double fps, Size frameSize, bool isColor=true);

需要強調的引數是fourcc,它代表了所使用的編碼方式,支援的編碼器如下:

CV_FOURCC('P','I','M','1') = MPEG-1 codec
CV_FOURCC('M','J','P','G') = motion-jpeg codec
CV_FOURCC('M', 'P', '4', '2') = MPEG-4.2 codec
CV_FOURCC('D', 'I', 'V', '3') = MPEG-4.3 codec
CV_FOURCC('D', 'I', 'V', 'X') = MPEG-4 codec
CV_FOURCC('U', '2', '6', '3') = H263 codec
CV_FOURCC('I', '2', '6', '3') = H263I codec
CV_FOURCC('F', 'L', 'V', '1') = FLV1 codec

下面是一個驅動攝像頭採集視訊的程式(另外,貌似OpenCV只支援儲存為.avi格式的視訊):

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main( int argc, char **argv )
{
    //讀取視訊檔案或者攝像頭視訊需要使用VideoCapture
    VideoCapture video_cap;
    video_cap.open( 0 );

    if( !video_cap.isOpened() )
    {
        cout << "can not open camera!" << endl;
        return -1;
    }

    Size size = Size( video_cap.get(CV_CAP_PROP_FRAME_WIDTH), video_cap.get(CV_CAP_PROP_FRAME_HEIGHT) );

    //儲存視訊或者攝像頭視訊到本地需要使用VideoWriter
    VideoWriter video_writer;
    video_writer.open( "video_path.avi", CV_FOURCC('M', 'P', '4', '2'), 10, size, true );

    Mat frame;

    namedWindow( "output", CV_WINDOW_AUTOSIZE );

    while( video_cap.read(frame) )
    {
        imshow( "output", frame );
        //將當前這一幀寫入本地檔案
        video_writer.write( frame );    
        waitKey( 10 );
    }

    video_cap.release();
    return 0;
}

2、超分辨演算法的輸入

OpenCV內部的超分辨模組有cpu版本和gpu版本兩種,如果要使用gpu版本的要從原始碼編譯支援cuda的OpenCV,現在還沒有重新編譯,使用cpu處理的速度非常的感人,第一幀要6秒左右,接下來一幀大概2秒左右。

還有一個要注意的就是設定超分辨cv::superres::SuperResolution的input的時候,它的input是FrameSource,也就是一個幀序列,這個幀序列是讀取視訊的時候生成的。我查了一下OpenCV的官方手冊,好像沒有處理單張的介面。所以我就採用上面儲存視訊到本地的方式,使用VideoWriter將要進行超分辨的影象寫入到一個.avi的視訊檔案中(只寫入一張影象),這樣就相當對單張影象進行超分辨。(貌似這種方法有點傻乎乎的,不過暫時也還沒有想到好點的方法,先實現在說吧)。

3、然後就是使用OpneCV的超分辨演算法了

#include <iostream>
#include <iomanip>
#include <string>
#include <ctype.h>

#include "opencv2/core.hpp"
#include "opencv2/core/utility.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/superres.hpp"
#include "opencv2/superres/optical_flow.hpp"
#include "opencv2/opencv_modules.hpp"

using namespace std;
using namespace cv;
using namespace cv::superres;

//巨集定義偽函式
#define MEASURE_TIME(op) \
    { \
        TickMeter tm; \
        tm.start(); \
        op; \
        tm.stop(); \
        cout << tm.getTimeSec() << " sec" << endl; \
    }

static Ptr<cv::superres::DenseOpticalFlowExt> createOptFlow(const string& name, bool useGpu)
{
    if (name == "farneback")
    {
        if (useGpu)
            return cv::superres::createOptFlow_Farneback_CUDA();
        else
            return cv::superres::createOptFlow_Farneback();
    }
    /*else if (name == "simple")
        return createOptFlow_Simple();*/
    else if (name == "tvl1")
    {
        if (useGpu)
            return cv::superres::createOptFlow_DualTVL1_CUDA();
        else
            return cv::superres::createOptFlow_DualTVL1();
    }
    else if (name == "brox")
    {
        return cv::superres::createOptFlow_Brox_CUDA();
    }
    else if (name == "pyrlk")
        return cv::superres::createOptFlow_PyrLK_CUDA();
    else
        cerr << "Incorrect Optical Flow algorithm - " << name << endl;

    return Ptr<cv::superres::DenseOpticalFlowExt>();
}

int main( int argc, const char* argv[] )
{
    /*定義引數*/
    const string inputVideoName = "sr_input_by_read.avi";
    const int scale = 2;
    const int iterations = 5;
    const int temporalAreaRadius = 4;
    const string optFlow = "farneback";  //使用的演算法:farneback, tvl1, brox, pyrlk
    const bool gpu = false;

    Ptr<SuperResolution> superRes;

    if ( gpu )
        superRes = createSuperResolution_BTVL1_CUDA();
    else
        superRes = createSuperResolution_BTVL1();

    //optFlow指定使用的超分辨演算法
    Ptr<cv::superres::DenseOpticalFlowExt> of = createOptFlow(optFlow, gpu);

    if (of.empty())
        return EXIT_FAILURE;

    //設定使用的超分辨演算法
    superRes->setOpticalFlow( of );
    superRes->setScale(scale);
    superRes->setIterations(iterations);
    superRes->setTemporalAreaRadius(temporalAreaRadius);
    
    Ptr<FrameSource> frameSource;
    //設定要使用的超分辨演算法
    if( gpu )
    {
        //如果要使用gpu的話,要將視訊進行gpu編碼
        try
        {
            frameSource = createFrameSource_Video_CUDA(inputVideoName);
            Mat frame;
            frameSource->nextFrame(frame);
        }
        catch (const cv::Exception&)
        {
            frameSource.release();
        }
    }
    
    if (!frameSource)
    {
        frameSource = createFrameSource_Video(inputVideoName);
    }

    // skip first frame, it is usually corrupted
    Mat frame;
    frameSource->nextFrame(frame);

    superRes->setInput(frameSource);

    VideoWriter writer;

    for (int i = 0;; ++i)
    {
        //cout << flush; 無條件的將緩衝區中的輸出資訊送至顯示器
        cout << '[' << setw(3) << i << "] : " << flush;
        Mat result, src_frame;

        frameSource->nextFrame( src_frame );
        resize( src_frame, src_frame, Size(src_frame.cols*2, src_frame.rows*2) );

        //nextFrame(result)的作用是處理下一幀,同時利用result返回當前真的額處理結果
        MEASURE_TIME(superRes->nextFrame(result));

        if (result.empty())
            break;

        imshow("src_frame", src_frame);
        imshow("Super Resolution", result);
        waitKey( 0 );
    }

    return 0;
}