1
/*M///////////////////////////////////////////////////////////////////////////////////////
3
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5
// By downloading, copying, installing or using the software you agree to this license.
6
// If you do not agree to this license, do not download, install,
7
// copy or use the software.
11
// For Open Source Computer Vision Library
13
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15
// Third party copyrights are property of their respective owners.
17
// Redistribution and use in source and binary forms, with or without modification,
18
// are permitted provided that the following conditions are met:
20
// * Redistribution's of source code must retain the above copyright notice,
21
// this list of conditions and the following disclaimer.
23
// * Redistribution's in binary form must reproduce the above copyright notice,
24
// this list of conditions and the following disclaimer in the documentation
25
// and/or other materials provided with the distribution.
27
// * The name of the copyright holders may not be used to endorse or promote products
28
// derived from this software without specific prior written permission.
30
// This software is provided by the copyright holders and contributors "as is" and
31
// any express or implied warranties, including, but not limited to, the implied
32
// warranties of merchantability and fitness for a particular purpose are disclaimed.
33
// In no event shall the Intel Corporation or contributors be liable for any direct,
34
// indirect, incidental, special, exemplary, or consequential damages
35
// (including, but not limited to, procurement of substitute goods or services;
36
// loss of use, data, or profits; or business interruption) however caused
37
// and on any theory of liability, whether in contract, strict liability,
38
// or tort (including negligence or otherwise) arising in any way out of
39
// the use of this software, even if advised of the possibility of such damage.
43
// S. Farsiu , D. Robinson, M. Elad, P. Milanfar. Fast and robust multiframe super resolution.
44
// Dennis Mitzel, Thomas Pock, Thomas Schoenemann, Daniel Cremers. Video Super Resolution using Duality Based TV-L1 Optical Flow.
46
#include "precomp.hpp"
49
using namespace cv::cuda;
50
using namespace cv::superres;
51
using namespace cv::superres::detail;
53
#if !defined(HAVE_CUDA) || !defined(HAVE_OPENCV_CUDAARITHM) || !defined(HAVE_OPENCV_CUDAWARPING) || !defined(HAVE_OPENCV_CUDAFILTERS)
55
Ptr<SuperResolution> cv::superres::createSuperResolution_BTVL1_CUDA()
57
CV_Error(Error::StsNotImplemented, "The called functionality is disabled for current build or platform");
58
return Ptr<SuperResolution>();
63
namespace btv_l1_cudev
65
void buildMotionMaps(PtrStepSzf forwardMotionX, PtrStepSzf forwardMotionY,
66
PtrStepSzf backwardMotionX, PtrStepSzf bacwardMotionY,
67
PtrStepSzf forwardMapX, PtrStepSzf forwardMapY,
68
PtrStepSzf backwardMapX, PtrStepSzf backwardMapY);
71
void upscale(const PtrStepSzb src, PtrStepSzb dst, int scale, cudaStream_t stream);
73
void diffSign(PtrStepSzf src1, PtrStepSzf src2, PtrStepSzf dst, cudaStream_t stream);
75
void loadBtvWeights(const float* weights, size_t count);
76
template <int cn> void calcBtvRegularization(PtrStepSzb src, PtrStepSzb dst, int ksize);
81
void calcRelativeMotions(const std::vector<std::pair<GpuMat, GpuMat> >& forwardMotions, const std::vector<std::pair<GpuMat, GpuMat> >& backwardMotions,
82
std::vector<std::pair<GpuMat, GpuMat> >& relForwardMotions, std::vector<std::pair<GpuMat, GpuMat> >& relBackwardMotions,
83
int baseIdx, Size size)
85
const int count = static_cast<int>(forwardMotions.size());
87
relForwardMotions.resize(count);
88
relForwardMotions[baseIdx].first.create(size, CV_32FC1);
89
relForwardMotions[baseIdx].first.setTo(Scalar::all(0));
90
relForwardMotions[baseIdx].second.create(size, CV_32FC1);
91
relForwardMotions[baseIdx].second.setTo(Scalar::all(0));
93
relBackwardMotions.resize(count);
94
relBackwardMotions[baseIdx].first.create(size, CV_32FC1);
95
relBackwardMotions[baseIdx].first.setTo(Scalar::all(0));
96
relBackwardMotions[baseIdx].second.create(size, CV_32FC1);
97
relBackwardMotions[baseIdx].second.setTo(Scalar::all(0));
99
for (int i = baseIdx - 1; i >= 0; --i)
101
cuda::add(relForwardMotions[i + 1].first, forwardMotions[i].first, relForwardMotions[i].first);
102
cuda::add(relForwardMotions[i + 1].second, forwardMotions[i].second, relForwardMotions[i].second);
104
cuda::add(relBackwardMotions[i + 1].first, backwardMotions[i + 1].first, relBackwardMotions[i].first);
105
cuda::add(relBackwardMotions[i + 1].second, backwardMotions[i + 1].second, relBackwardMotions[i].second);
108
for (int i = baseIdx + 1; i < count; ++i)
110
cuda::add(relForwardMotions[i - 1].first, backwardMotions[i].first, relForwardMotions[i].first);
111
cuda::add(relForwardMotions[i - 1].second, backwardMotions[i].second, relForwardMotions[i].second);
113
cuda::add(relBackwardMotions[i - 1].first, forwardMotions[i - 1].first, relBackwardMotions[i].first);
114
cuda::add(relBackwardMotions[i - 1].second, forwardMotions[i - 1].second, relBackwardMotions[i].second);
118
void upscaleMotions(const std::vector<std::pair<GpuMat, GpuMat> >& lowResMotions, std::vector<std::pair<GpuMat, GpuMat> >& highResMotions, int scale)
120
highResMotions.resize(lowResMotions.size());
122
for (size_t i = 0; i < lowResMotions.size(); ++i)
124
cuda::resize(lowResMotions[i].first, highResMotions[i].first, Size(), scale, scale, INTER_CUBIC);
125
cuda::resize(lowResMotions[i].second, highResMotions[i].second, Size(), scale, scale, INTER_CUBIC);
127
cuda::multiply(highResMotions[i].first, Scalar::all(scale), highResMotions[i].first);
128
cuda::multiply(highResMotions[i].second, Scalar::all(scale), highResMotions[i].second);
132
void buildMotionMaps(const std::pair<GpuMat, GpuMat>& forwardMotion, const std::pair<GpuMat, GpuMat>& backwardMotion,
133
std::pair<GpuMat, GpuMat>& forwardMap, std::pair<GpuMat, GpuMat>& backwardMap)
135
forwardMap.first.create(forwardMotion.first.size(), CV_32FC1);
136
forwardMap.second.create(forwardMotion.first.size(), CV_32FC1);
138
backwardMap.first.create(forwardMotion.first.size(), CV_32FC1);
139
backwardMap.second.create(forwardMotion.first.size(), CV_32FC1);
141
btv_l1_cudev::buildMotionMaps(forwardMotion.first, forwardMotion.second,
142
backwardMotion.first, backwardMotion.second,
143
forwardMap.first, forwardMap.second,
144
backwardMap.first, backwardMap.second);
147
void upscale(const GpuMat& src, GpuMat& dst, int scale, Stream& stream)
149
typedef void (*func_t)(const PtrStepSzb src, PtrStepSzb dst, int scale, cudaStream_t stream);
150
static const func_t funcs[] =
152
0, btv_l1_cudev::upscale<1>, 0, btv_l1_cudev::upscale<3>, btv_l1_cudev::upscale<4>
155
CV_Assert( src.channels() == 1 || src.channels() == 3 || src.channels() == 4 );
157
dst.create(src.rows * scale, src.cols * scale, src.type());
158
dst.setTo(Scalar::all(0));
160
const func_t func = funcs[src.channels()];
162
func(src, dst, scale, StreamAccessor::getStream(stream));
165
void diffSign(const GpuMat& src1, const GpuMat& src2, GpuMat& dst, Stream& stream)
167
dst.create(src1.size(), src1.type());
169
btv_l1_cudev::diffSign(src1.reshape(1), src2.reshape(1), dst.reshape(1), StreamAccessor::getStream(stream));
172
void calcBtvWeights(int btvKernelSize, double alpha, std::vector<float>& btvWeights)
174
const size_t size = btvKernelSize * btvKernelSize;
176
btvWeights.resize(size);
178
const int ksize = (btvKernelSize - 1) / 2;
179
const float alpha_f = static_cast<float>(alpha);
181
for (int m = 0, ind = 0; m <= ksize; ++m)
183
for (int l = ksize; l + m >= 0; --l, ++ind)
184
btvWeights[ind] = pow(alpha_f, std::abs(m) + std::abs(l));
187
btv_l1_cudev::loadBtvWeights(&btvWeights[0], size);
190
void calcBtvRegularization(const GpuMat& src, GpuMat& dst, int btvKernelSize)
192
typedef void (*func_t)(PtrStepSzb src, PtrStepSzb dst, int ksize);
193
static const func_t funcs[] =
196
btv_l1_cudev::calcBtvRegularization<1>,
198
btv_l1_cudev::calcBtvRegularization<3>,
199
btv_l1_cudev::calcBtvRegularization<4>
202
dst.create(src.size(), src.type());
203
dst.setTo(Scalar::all(0));
205
const int ksize = (btvKernelSize - 1) / 2;
207
funcs[src.channels()](src, dst, ksize);
210
class BTVL1_CUDA_Base : public cv::superres::SuperResolution
215
void process(const std::vector<GpuMat>& src, GpuMat& dst,
216
const std::vector<std::pair<GpuMat, GpuMat> >& forwardMotions, const std::vector<std::pair<GpuMat, GpuMat> >& backwardMotions,
219
void collectGarbage();
221
CV_IMPL_PROPERTY(int, Scale, scale_)
222
CV_IMPL_PROPERTY(int, Iterations, iterations_)
223
CV_IMPL_PROPERTY(double, Tau, tau_)
224
CV_IMPL_PROPERTY(double, Labmda, lambda_)
225
CV_IMPL_PROPERTY(double, Alpha, alpha_)
226
CV_IMPL_PROPERTY(int, KernelSize, btvKernelSize_)
227
CV_IMPL_PROPERTY(int, BlurKernelSize, blurKernelSize_)
228
CV_IMPL_PROPERTY(double, BlurSigma, blurSigma_)
229
CV_IMPL_PROPERTY(int, TemporalAreaRadius, temporalAreaRadius_)
230
CV_IMPL_PROPERTY_S(Ptr<cv::superres::DenseOpticalFlowExt>, OpticalFlow, opticalFlow_)
241
int temporalAreaRadius_;
242
Ptr<cv::superres::DenseOpticalFlowExt> opticalFlow_;
245
std::vector<Ptr<cuda::Filter> > filters_;
246
int curBlurKernelSize_;
247
double curBlurSigma_;
250
std::vector<float> btvWeights_;
251
int curBtvKernelSize_;
254
std::vector<std::pair<GpuMat, GpuMat> > lowResForwardMotions_;
255
std::vector<std::pair<GpuMat, GpuMat> > lowResBackwardMotions_;
257
std::vector<std::pair<GpuMat, GpuMat> > highResForwardMotions_;
258
std::vector<std::pair<GpuMat, GpuMat> > highResBackwardMotions_;
260
std::vector<std::pair<GpuMat, GpuMat> > forwardMaps_;
261
std::vector<std::pair<GpuMat, GpuMat> > backwardMaps_;
265
std::vector<Stream> streams_;
266
std::vector<GpuMat> diffTerms_;
267
std::vector<GpuMat> a_, b_, c_;
271
BTVL1_CUDA_Base::BTVL1_CUDA_Base()
282
#ifdef HAVE_OPENCV_CUDAOPTFLOW
283
opticalFlow_ = createOptFlow_Farneback_CUDA();
285
opticalFlow_ = createOptFlow_Farneback();
287
temporalAreaRadius_ = 0;
289
curBlurKernelSize_ = -1;
290
curBlurSigma_ = -1.0;
293
curBtvKernelSize_ = -1;
297
void BTVL1_CUDA_Base::process(const std::vector<GpuMat>& src, GpuMat& dst,
298
const std::vector<std::pair<GpuMat, GpuMat> >& forwardMotions, const std::vector<std::pair<GpuMat, GpuMat> >& backwardMotions,
301
CV_Assert( scale_ > 1 );
302
CV_Assert( iterations_ > 0 );
303
CV_Assert( tau_ > 0.0 );
304
CV_Assert( alpha_ > 0.0 );
305
CV_Assert( btvKernelSize_ > 0 && btvKernelSize_ <= 16 );
306
CV_Assert( blurKernelSize_ > 0 );
307
CV_Assert( blurSigma_ >= 0.0 );
309
// update blur filter and btv weights
311
if (filters_.size() != src.size() || blurKernelSize_ != curBlurKernelSize_ || blurSigma_ != curBlurSigma_ || src[0].type() != curSrcType_)
313
filters_.resize(src.size());
314
for (size_t i = 0; i < src.size(); ++i)
315
filters_[i] = cuda::createGaussianFilter(src[0].type(), -1, Size(blurKernelSize_, blurKernelSize_), blurSigma_);
316
curBlurKernelSize_ = blurKernelSize_;
317
curBlurSigma_ = blurSigma_;
318
curSrcType_ = src[0].type();
321
if (btvWeights_.empty() || btvKernelSize_ != curBtvKernelSize_ || alpha_ != curAlpha_)
323
calcBtvWeights(btvKernelSize_, alpha_, btvWeights_);
324
curBtvKernelSize_ = btvKernelSize_;
328
// calc motions between input frames
330
calcRelativeMotions(forwardMotions, backwardMotions, lowResForwardMotions_, lowResBackwardMotions_, baseIdx, src[0].size());
332
upscaleMotions(lowResForwardMotions_, highResForwardMotions_, scale_);
333
upscaleMotions(lowResBackwardMotions_, highResBackwardMotions_, scale_);
335
forwardMaps_.resize(highResForwardMotions_.size());
336
backwardMaps_.resize(highResForwardMotions_.size());
337
for (size_t i = 0; i < highResForwardMotions_.size(); ++i)
338
buildMotionMaps(highResForwardMotions_[i], highResBackwardMotions_[i], forwardMaps_[i], backwardMaps_[i]);
340
// initial estimation
342
const Size lowResSize = src[0].size();
343
const Size highResSize(lowResSize.width * scale_, lowResSize.height * scale_);
345
cuda::resize(src[baseIdx], highRes_, highResSize, 0, 0, INTER_CUBIC);
349
streams_.resize(src.size());
350
diffTerms_.resize(src.size());
351
a_.resize(src.size());
352
b_.resize(src.size());
353
c_.resize(src.size());
355
for (int i = 0; i < iterations_; ++i)
357
for (size_t k = 0; k < src.size(); ++k)
360
cuda::remap(highRes_, a_[k], backwardMaps_[k].first, backwardMaps_[k].second, INTER_NEAREST, BORDER_REPLICATE, Scalar(), streams_[k]);
362
filters_[k]->apply(a_[k], b_[k], streams_[k]);
364
cuda::resize(b_[k], c_[k], lowResSize, 0, 0, INTER_NEAREST, streams_[k]);
366
diffSign(src[k], c_[k], c_[k], streams_[k]);
369
upscale(c_[k], a_[k], scale_, streams_[k]);
371
filters_[k]->apply(a_[k], b_[k], streams_[k]);
372
// diffTerm = MtHtDt * diff
373
cuda::remap(b_[k], diffTerms_[k], forwardMaps_[k].first, forwardMaps_[k].second, INTER_NEAREST, BORDER_REPLICATE, Scalar(), streams_[k]);
378
calcBtvRegularization(highRes_, regTerm_, btvKernelSize_);
379
cuda::addWeighted(highRes_, 1.0, regTerm_, -tau_ * lambda_, 0.0, highRes_);
382
for (size_t k = 0; k < src.size(); ++k)
384
streams_[k].waitForCompletion();
385
cuda::addWeighted(highRes_, 1.0, diffTerms_[k], tau_, 0.0, highRes_);
389
Rect inner(btvKernelSize_, btvKernelSize_, highRes_.cols - 2 * btvKernelSize_, highRes_.rows - 2 * btvKernelSize_);
390
highRes_(inner).copyTo(dst);
393
void BTVL1_CUDA_Base::collectGarbage()
397
lowResForwardMotions_.clear();
398
lowResBackwardMotions_.clear();
400
highResForwardMotions_.clear();
401
highResBackwardMotions_.clear();
403
forwardMaps_.clear();
404
backwardMaps_.clear();
415
////////////////////////////////////////////////////////////
417
class BTVL1_CUDA : public BTVL1_CUDA_Base
422
void collectGarbage();
425
void initImpl(Ptr<FrameSource>& frameSource);
426
void processImpl(Ptr<FrameSource>& frameSource, OutputArray output);
429
void readNextFrame(Ptr<FrameSource>& frameSource);
430
void processFrame(int idx);
435
std::vector<GpuMat> frames_;
436
std::vector<std::pair<GpuMat, GpuMat> > forwardMotions_;
437
std::vector<std::pair<GpuMat, GpuMat> > backwardMotions_;
438
std::vector<GpuMat> outputs_;
444
std::vector<GpuMat> srcFrames_;
445
std::vector<std::pair<GpuMat, GpuMat> > srcForwardMotions_;
446
std::vector<std::pair<GpuMat, GpuMat> > srcBackwardMotions_;
450
BTVL1_CUDA::BTVL1_CUDA()
452
temporalAreaRadius_ = 4;
455
void BTVL1_CUDA::collectGarbage()
458
prevFrame_.release();
461
forwardMotions_.clear();
462
backwardMotions_.clear();
466
srcForwardMotions_.clear();
467
srcBackwardMotions_.clear();
468
finalOutput_.release();
470
SuperResolution::collectGarbage();
471
BTVL1_CUDA_Base::collectGarbage();
474
void BTVL1_CUDA::initImpl(Ptr<FrameSource>& frameSource)
476
const int cacheSize = 2 * temporalAreaRadius_ + 1;
478
frames_.resize(cacheSize);
479
forwardMotions_.resize(cacheSize);
480
backwardMotions_.resize(cacheSize);
481
outputs_.resize(cacheSize);
485
for (int t = -temporalAreaRadius_; t <= temporalAreaRadius_; ++t)
486
readNextFrame(frameSource);
488
for (int i = 0; i <= temporalAreaRadius_; ++i)
491
procPos_ = temporalAreaRadius_;
495
void BTVL1_CUDA::processImpl(Ptr<FrameSource>& frameSource, OutputArray _output)
497
if (outPos_ >= storePos_)
503
readNextFrame(frameSource);
505
if (procPos_ < storePos_)
508
processFrame(procPos_);
512
const GpuMat& curOutput = at(outPos_, outputs_);
514
if (_output.kind() == _InputArray::CUDA_GPU_MAT)
515
curOutput.convertTo(_output.getGpuMatRef(), CV_8U);
518
curOutput.convertTo(finalOutput_, CV_8U);
519
arrCopy(finalOutput_, _output);
523
void BTVL1_CUDA::readNextFrame(Ptr<FrameSource>& frameSource)
525
frameSource->nextFrame(curFrame_);
527
if (curFrame_.empty())
531
curFrame_.convertTo(at(storePos_, frames_), CV_32F);
535
std::pair<GpuMat, GpuMat>& forwardMotion = at(storePos_ - 1, forwardMotions_);
536
std::pair<GpuMat, GpuMat>& backwardMotion = at(storePos_, backwardMotions_);
538
opticalFlow_->calc(prevFrame_, curFrame_, forwardMotion.first, forwardMotion.second);
539
opticalFlow_->calc(curFrame_, prevFrame_, backwardMotion.first, backwardMotion.second);
542
curFrame_.copyTo(prevFrame_);
545
void BTVL1_CUDA::processFrame(int idx)
547
const int startIdx = std::max(idx - temporalAreaRadius_, 0);
548
const int procIdx = idx;
549
const int endIdx = std::min(startIdx + 2 * temporalAreaRadius_, storePos_);
551
const int count = endIdx - startIdx + 1;
553
srcFrames_.resize(count);
554
srcForwardMotions_.resize(count);
555
srcBackwardMotions_.resize(count);
559
for (int i = startIdx, k = 0; i <= endIdx; ++i, ++k)
564
srcFrames_[k] = at(i, frames_);
567
srcForwardMotions_[k] = at(i, forwardMotions_);
569
srcBackwardMotions_[k] = at(i, backwardMotions_);
572
process(srcFrames_, at(idx, outputs_), srcForwardMotions_, srcBackwardMotions_, baseIdx);
576
Ptr<SuperResolution> cv::superres::createSuperResolution_BTVL1_CUDA()
578
return makePtr<BTVL1_CUDA>();