OpenCV內建的超分辨演算法測試
阿新 • • 發佈:2019-02-16
最近在做超分辨相關的東西,從網上了解到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;
}