最近在做超分辨相关的东西,从网上了解到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;
}