/*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // // By downloading, copying, installing or using the software you agree to this license. // If you do not agree to this license, do not download, install, // copy or use the software. // // // License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. // Copyright (C) 2009, Willow Garage Inc., all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of the copyright holders may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, // indirect, incidental, special, exemplary, or consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. // //M*/ // S. Farsiu , D. Robinson, M. Elad, P. Milanfar. Fast and robust multiframe super resolution. // Dennis Mitzel, Thomas Pock, Thomas Schoenemann, Daniel Cremers. Video Super Resolution using Duality Based TV-L1 Optical Flow. #include "precomp.hpp" #include "opencl_kernels_superres.hpp" using namespace cv; using namespace cv::superres; using namespace cv::superres::detail; namespace { #ifdef HAVE_OPENCL bool ocl_calcRelativeMotions(InputArrayOfArrays _forwardMotions, InputArrayOfArrays _backwardMotions, OutputArrayOfArrays _relForwardMotions, OutputArrayOfArrays _relBackwardMotions, int baseIdx, const Size & size) { std::vector & forwardMotions = *(std::vector *)_forwardMotions.getObj(), & backwardMotions = *(std::vector *)_backwardMotions.getObj(), & relForwardMotions = *(std::vector *)_relForwardMotions.getObj(), & relBackwardMotions = *(std::vector *)_relBackwardMotions.getObj(); const int count = static_cast(forwardMotions.size()); relForwardMotions.resize(count); relForwardMotions[baseIdx].create(size, CV_32FC2); relForwardMotions[baseIdx].setTo(Scalar::all(0)); relBackwardMotions.resize(count); relBackwardMotions[baseIdx].create(size, CV_32FC2); relBackwardMotions[baseIdx].setTo(Scalar::all(0)); for (int i = baseIdx - 1; i >= 0; --i) { add(relForwardMotions[i + 1], forwardMotions[i], relForwardMotions[i]); add(relBackwardMotions[i + 1], backwardMotions[i + 1], relBackwardMotions[i]); } for (int i = baseIdx + 1; i < count; ++i) { add(relForwardMotions[i - 1], backwardMotions[i], relForwardMotions[i]); add(relBackwardMotions[i - 1], forwardMotions[i - 1], relBackwardMotions[i]); } return true; } #endif void calcRelativeMotions(InputArrayOfArrays _forwardMotions, InputArrayOfArrays _backwardMotions, OutputArrayOfArrays _relForwardMotions, OutputArrayOfArrays _relBackwardMotions, int baseIdx, const Size & size) { CV_OCL_RUN(_forwardMotions.isUMatVector() && _backwardMotions.isUMatVector() && _relForwardMotions.isUMatVector() && _relBackwardMotions.isUMatVector(), ocl_calcRelativeMotions(_forwardMotions, _backwardMotions, _relForwardMotions, _relBackwardMotions, baseIdx, size)) std::vector & forwardMotions = *(std::vector *)_forwardMotions.getObj(), & backwardMotions = *(std::vector *)_backwardMotions.getObj(), & relForwardMotions = *(std::vector *)_relForwardMotions.getObj(), & relBackwardMotions = *(std::vector *)_relBackwardMotions.getObj(); const int count = static_cast(forwardMotions.size()); relForwardMotions.resize(count); relForwardMotions[baseIdx].create(size, CV_32FC2); relForwardMotions[baseIdx].setTo(Scalar::all(0)); relBackwardMotions.resize(count); relBackwardMotions[baseIdx].create(size, CV_32FC2); relBackwardMotions[baseIdx].setTo(Scalar::all(0)); for (int i = baseIdx - 1; i >= 0; --i) { add(relForwardMotions[i + 1], forwardMotions[i], relForwardMotions[i]); add(relBackwardMotions[i + 1], backwardMotions[i + 1], relBackwardMotions[i]); } for (int i = baseIdx + 1; i < count; ++i) { add(relForwardMotions[i - 1], backwardMotions[i], relForwardMotions[i]); add(relBackwardMotions[i - 1], forwardMotions[i - 1], relBackwardMotions[i]); } } #ifdef HAVE_OPENCL bool ocl_upscaleMotions(InputArrayOfArrays _lowResMotions, OutputArrayOfArrays _highResMotions, int scale) { std::vector & lowResMotions = *(std::vector *)_lowResMotions.getObj(), & highResMotions = *(std::vector *)_highResMotions.getObj(); highResMotions.resize(lowResMotions.size()); for (size_t i = 0; i < lowResMotions.size(); ++i) { resize(lowResMotions[i], highResMotions[i], Size(), scale, scale, INTER_LINEAR); // TODO multiply(highResMotions[i], Scalar::all(scale), highResMotions[i]); } return true; } #endif void upscaleMotions(InputArrayOfArrays _lowResMotions, OutputArrayOfArrays _highResMotions, int scale) { CV_OCL_RUN(_lowResMotions.isUMatVector() && _highResMotions.isUMatVector(), ocl_upscaleMotions(_lowResMotions, _highResMotions, scale)) std::vector & lowResMotions = *(std::vector *)_lowResMotions.getObj(), & highResMotions = *(std::vector *)_highResMotions.getObj(); highResMotions.resize(lowResMotions.size()); for (size_t i = 0; i < lowResMotions.size(); ++i) { resize(lowResMotions[i], highResMotions[i], Size(), scale, scale, INTER_CUBIC); multiply(highResMotions[i], Scalar::all(scale), highResMotions[i]); } } #ifdef HAVE_OPENCL bool ocl_buildMotionMaps(InputArray _forwardMotion, InputArray _backwardMotion, OutputArray _forwardMap, OutputArray _backwardMap) { ocl::Kernel k("buildMotionMaps", ocl::superres::superres_btvl1_oclsrc); if (k.empty()) return false; UMat forwardMotion = _forwardMotion.getUMat(), backwardMotion = _backwardMotion.getUMat(); Size size = forwardMotion.size(); _forwardMap.create(size, CV_32FC2); _backwardMap.create(size, CV_32FC2); UMat forwardMap = _forwardMap.getUMat(), backwardMap = _backwardMap.getUMat(); k.args(ocl::KernelArg::ReadOnlyNoSize(forwardMotion), ocl::KernelArg::ReadOnlyNoSize(backwardMotion), ocl::KernelArg::WriteOnlyNoSize(forwardMap), ocl::KernelArg::WriteOnly(backwardMap)); size_t globalsize[2] = { size.width, size.height }; return k.run(2, globalsize, NULL, false); } #endif void buildMotionMaps(InputArray _forwardMotion, InputArray _backwardMotion, OutputArray _forwardMap, OutputArray _backwardMap) { CV_OCL_RUN(_forwardMap.isUMat() && _backwardMap.isUMat(), ocl_buildMotionMaps(_forwardMotion, _backwardMotion, _forwardMap, _backwardMap)); Mat forwardMotion = _forwardMotion.getMat(), backwardMotion = _backwardMotion.getMat(); _forwardMap.create(forwardMotion.size(), CV_32FC2); _backwardMap.create(forwardMotion.size(), CV_32FC2); Mat forwardMap = _forwardMap.getMat(), backwardMap = _backwardMap.getMat(); for (int y = 0; y < forwardMotion.rows; ++y) { const Point2f* forwardMotionRow = forwardMotion.ptr(y); const Point2f* backwardMotionRow = backwardMotion.ptr(y); Point2f* forwardMapRow = forwardMap.ptr(y); Point2f* backwardMapRow = backwardMap.ptr(y); for (int x = 0; x < forwardMotion.cols; ++x) { Point2f base(static_cast(x), static_cast(y)); forwardMapRow[x] = base + backwardMotionRow[x]; backwardMapRow[x] = base + forwardMotionRow[x]; } } } template void upscaleImpl(InputArray _src, OutputArray _dst, int scale) { Mat src = _src.getMat(); _dst.create(src.rows * scale, src.cols * scale, src.type()); _dst.setTo(Scalar::all(0)); Mat dst = _dst.getMat(); for (int y = 0, Y = 0; y < src.rows; ++y, Y += scale) { const T * const srcRow = src.ptr(y); T * const dstRow = dst.ptr(Y); for (int x = 0, X = 0; x < src.cols; ++x, X += scale) dstRow[X] = srcRow[x]; } } #ifdef HAVE_OPENCL static bool ocl_upscale(InputArray _src, OutputArray _dst, int scale) { int type = _src.type(), cn = CV_MAT_CN(type); ocl::Kernel k("upscale", ocl::superres::superres_btvl1_oclsrc, format("-D cn=%d", cn)); if (k.empty()) return false; UMat src = _src.getUMat(); _dst.create(src.rows * scale, src.cols * scale, type); _dst.setTo(Scalar::all(0)); UMat dst = _dst.getUMat(); k.args(ocl::KernelArg::ReadOnly(src), ocl::KernelArg::ReadWriteNoSize(dst), scale); size_t globalsize[2] = { src.cols, src.rows }; return k.run(2, globalsize, NULL, false); } #endif typedef struct _Point4f { float ar[4]; } Point4f; void upscale(InputArray _src, OutputArray _dst, int scale) { int cn = _src.channels(); CV_Assert( cn == 1 || cn == 3 || cn == 4 ); CV_OCL_RUN(_dst.isUMat(), ocl_upscale(_src, _dst, scale)) typedef void (*func_t)(InputArray src, OutputArray dst, int scale); static const func_t funcs[] = { 0, upscaleImpl, 0, upscaleImpl, upscaleImpl }; const func_t func = funcs[cn]; CV_Assert(func != 0); func(_src, _dst, scale); } inline float diffSign(float a, float b) { return a > b ? 1.0f : a < b ? -1.0f : 0.0f; } Point3f diffSign(Point3f a, Point3f b) { return Point3f( a.x > b.x ? 1.0f : a.x < b.x ? -1.0f : 0.0f, a.y > b.y ? 1.0f : a.y < b.y ? -1.0f : 0.0f, a.z > b.z ? 1.0f : a.z < b.z ? -1.0f : 0.0f ); } #ifdef HAVE_OPENCL static bool ocl_diffSign(InputArray _src1, OutputArray _src2, OutputArray _dst) { ocl::Kernel k("diffSign", ocl::superres::superres_btvl1_oclsrc); if (k.empty()) return false; UMat src1 = _src1.getUMat(), src2 = _src2.getUMat(); _dst.create(src1.size(), src1.type()); UMat dst = _dst.getUMat(); int cn = src1.channels(); k.args(ocl::KernelArg::ReadOnlyNoSize(src1), ocl::KernelArg::ReadOnlyNoSize(src2), ocl::KernelArg::WriteOnly(dst, cn)); size_t globalsize[2] = { src1.cols * cn, src1.rows }; return k.run(2, globalsize, NULL, false); } #endif void diffSign(InputArray _src1, OutputArray _src2, OutputArray _dst) { CV_OCL_RUN(_dst.isUMat(), ocl_diffSign(_src1, _src2, _dst)) Mat src1 = _src1.getMat(), src2 = _src2.getMat(); _dst.create(src1.size(), src1.type()); Mat dst = _dst.getMat(); const int count = src1.cols * src1.channels(); for (int y = 0; y < src1.rows; ++y) { const float * const src1Ptr = src1.ptr(y); const float * const src2Ptr = src2.ptr(y); float* dstPtr = dst.ptr(y); for (int x = 0; x < count; ++x) dstPtr[x] = diffSign(src1Ptr[x], src2Ptr[x]); } } void calcBtvWeights(int btvKernelSize, double alpha, std::vector& btvWeights) { const size_t size = btvKernelSize * btvKernelSize; btvWeights.resize(size); const int ksize = (btvKernelSize - 1) / 2; const float alpha_f = static_cast(alpha); for (int m = 0, ind = 0; m <= ksize; ++m) { for (int l = ksize; l + m >= 0; --l, ++ind) btvWeights[ind] = pow(alpha_f, std::abs(m) + std::abs(l)); } } template struct BtvRegularizationBody : ParallelLoopBody { void operator ()(const Range& range) const; Mat src; mutable Mat dst; int ksize; const float* btvWeights; }; template void BtvRegularizationBody::operator ()(const Range& range) const { for (int i = range.start; i < range.end; ++i) { const T * const srcRow = src.ptr(i); T * const dstRow = dst.ptr(i); for(int j = ksize; j < src.cols - ksize; ++j) { const T srcVal = srcRow[j]; for (int m = 0, ind = 0; m <= ksize; ++m) { const T* srcRow2 = src.ptr(i - m); const T* srcRow3 = src.ptr(i + m); for (int l = ksize; l + m >= 0; --l, ++ind) dstRow[j] += btvWeights[ind] * (diffSign(srcVal, srcRow3[j + l]) - diffSign(srcRow2[j - l], srcVal)); } } } } template void calcBtvRegularizationImpl(InputArray _src, OutputArray _dst, int btvKernelSize, const std::vector& btvWeights) { Mat src = _src.getMat(); _dst.create(src.size(), src.type()); _dst.setTo(Scalar::all(0)); Mat dst = _dst.getMat(); const int ksize = (btvKernelSize - 1) / 2; BtvRegularizationBody body; body.src = src; body.dst = dst; body.ksize = ksize; body.btvWeights = &btvWeights[0]; parallel_for_(Range(ksize, src.rows - ksize), body); } #ifdef HAVE_OPENCL static bool ocl_calcBtvRegularization(InputArray _src, OutputArray _dst, int btvKernelSize, const UMat & ubtvWeights) { int cn = _src.channels(); ocl::Kernel k("calcBtvRegularization", ocl::superres::superres_btvl1_oclsrc, format("-D cn=%d", cn)); if (k.empty()) return false; UMat src = _src.getUMat(); _dst.create(src.size(), src.type()); _dst.setTo(Scalar::all(0)); UMat dst = _dst.getUMat(); const int ksize = (btvKernelSize - 1) / 2; k.args(ocl::KernelArg::ReadOnlyNoSize(src), ocl::KernelArg::WriteOnly(dst), ksize, ocl::KernelArg::PtrReadOnly(ubtvWeights)); size_t globalsize[2] = { src.cols, src.rows }; return k.run(2, globalsize, NULL, false); } #endif void calcBtvRegularization(InputArray _src, OutputArray _dst, int btvKernelSize, const std::vector& btvWeights, const UMat & ubtvWeights) { CV_OCL_RUN(_dst.isUMat(), ocl_calcBtvRegularization(_src, _dst, btvKernelSize, ubtvWeights)) (void)ubtvWeights; typedef void (*func_t)(InputArray _src, OutputArray _dst, int btvKernelSize, const std::vector& btvWeights); static const func_t funcs[] = { 0, calcBtvRegularizationImpl, 0, calcBtvRegularizationImpl, 0 }; const func_t func = funcs[_src.channels()]; CV_Assert(func != 0); func(_src, _dst, btvKernelSize, btvWeights); } class BTVL1_Base : public cv::superres::SuperResolution { public: BTVL1_Base(); void process(InputArrayOfArrays src, OutputArray dst, InputArrayOfArrays forwardMotions, InputArrayOfArrays backwardMotions, int baseIdx); void collectGarbage(); CV_IMPL_PROPERTY(int, Scale, scale_) CV_IMPL_PROPERTY(int, Iterations, iterations_) CV_IMPL_PROPERTY(double, Tau, tau_) CV_IMPL_PROPERTY(double, Labmda, lambda_) CV_IMPL_PROPERTY(double, Alpha, alpha_) CV_IMPL_PROPERTY(int, KernelSize, btvKernelSize_) CV_IMPL_PROPERTY(int, BlurKernelSize, blurKernelSize_) CV_IMPL_PROPERTY(double, BlurSigma, blurSigma_) CV_IMPL_PROPERTY(int, TemporalAreaRadius, temporalAreaRadius_) CV_IMPL_PROPERTY_S(Ptr, OpticalFlow, opticalFlow_) protected: int scale_; int iterations_; double tau_; double lambda_; double alpha_; int btvKernelSize_; int blurKernelSize_; double blurSigma_; int temporalAreaRadius_; // not used in some implementations Ptr opticalFlow_; private: bool ocl_process(InputArrayOfArrays src, OutputArray dst, InputArrayOfArrays forwardMotions, InputArrayOfArrays backwardMotions, int baseIdx); //Ptr filter_; int curBlurKernelSize_; double curBlurSigma_; int curSrcType_; std::vector btvWeights_; UMat ubtvWeights_; int curBtvKernelSize_; double curAlpha_; // Mat std::vector lowResForwardMotions_; std::vector lowResBackwardMotions_; std::vector highResForwardMotions_; std::vector highResBackwardMotions_; std::vector forwardMaps_; std::vector backwardMaps_; Mat highRes_; Mat diffTerm_, regTerm_; Mat a_, b_, c_; #ifdef HAVE_OPENCL // UMat std::vector ulowResForwardMotions_; std::vector ulowResBackwardMotions_; std::vector uhighResForwardMotions_; std::vector uhighResBackwardMotions_; std::vector uforwardMaps_; std::vector ubackwardMaps_; UMat uhighRes_; UMat udiffTerm_, uregTerm_; UMat ua_, ub_, uc_; #endif }; BTVL1_Base::BTVL1_Base() { scale_ = 4; iterations_ = 180; lambda_ = 0.03; tau_ = 1.3; alpha_ = 0.7; btvKernelSize_ = 7; blurKernelSize_ = 5; blurSigma_ = 0.0; temporalAreaRadius_ = 0; opticalFlow_ = createOptFlow_Farneback(); curBlurKernelSize_ = -1; curBlurSigma_ = -1.0; curSrcType_ = -1; curBtvKernelSize_ = -1; curAlpha_ = -1.0; } #ifdef HAVE_OPENCL bool BTVL1_Base::ocl_process(InputArrayOfArrays _src, OutputArray _dst, InputArrayOfArrays _forwardMotions, InputArrayOfArrays _backwardMotions, int baseIdx) { std::vector & src = *(std::vector *)_src.getObj(), & forwardMotions = *(std::vector *)_forwardMotions.getObj(), & backwardMotions = *(std::vector *)_backwardMotions.getObj(); // update blur filter and btv weights if (blurKernelSize_ != curBlurKernelSize_ || blurSigma_ != curBlurSigma_ || src[0].type() != curSrcType_) { //filter_ = createGaussianFilter(src[0].type(), Size(blurKernelSize_, blurKernelSize_), blurSigma_); curBlurKernelSize_ = blurKernelSize_; curBlurSigma_ = blurSigma_; curSrcType_ = src[0].type(); } if (btvWeights_.empty() || btvKernelSize_ != curBtvKernelSize_ || alpha_ != curAlpha_) { calcBtvWeights(btvKernelSize_, alpha_, btvWeights_); Mat(btvWeights_, true).copyTo(ubtvWeights_); curBtvKernelSize_ = btvKernelSize_; curAlpha_ = alpha_; } // calc high res motions calcRelativeMotions(forwardMotions, backwardMotions, ulowResForwardMotions_, ulowResBackwardMotions_, baseIdx, src[0].size()); upscaleMotions(ulowResForwardMotions_, uhighResForwardMotions_, scale_); upscaleMotions(ulowResBackwardMotions_, uhighResBackwardMotions_, scale_); uforwardMaps_.resize(uhighResForwardMotions_.size()); ubackwardMaps_.resize(uhighResForwardMotions_.size()); for (size_t i = 0; i < uhighResForwardMotions_.size(); ++i) buildMotionMaps(uhighResForwardMotions_[i], uhighResBackwardMotions_[i], uforwardMaps_[i], ubackwardMaps_[i]); // initial estimation const Size lowResSize = src[0].size(); const Size highResSize(lowResSize.width * scale_, lowResSize.height * scale_); resize(src[baseIdx], uhighRes_, highResSize, 0, 0, INTER_LINEAR); // TODO // iterations udiffTerm_.create(highResSize, uhighRes_.type()); ua_.create(highResSize, uhighRes_.type()); ub_.create(highResSize, uhighRes_.type()); uc_.create(lowResSize, uhighRes_.type()); for (int i = 0; i < iterations_; ++i) { udiffTerm_.setTo(Scalar::all(0)); for (size_t k = 0; k < src.size(); ++k) { // a = M * Ih remap(uhighRes_, ua_, ubackwardMaps_[k], noArray(), INTER_NEAREST); // b = HM * Ih GaussianBlur(ua_, ub_, Size(blurKernelSize_, blurKernelSize_), blurSigma_); // c = DHM * Ih resize(ub_, uc_, lowResSize, 0, 0, INTER_NEAREST); diffSign(src[k], uc_, uc_); // a = Dt * diff upscale(uc_, ua_, scale_); // b = HtDt * diff GaussianBlur(ua_, ub_, Size(blurKernelSize_, blurKernelSize_), blurSigma_); // a = MtHtDt * diff remap(ub_, ua_, uforwardMaps_[k], noArray(), INTER_NEAREST); add(udiffTerm_, ua_, udiffTerm_); } if (lambda_ > 0) { calcBtvRegularization(uhighRes_, uregTerm_, btvKernelSize_, btvWeights_, ubtvWeights_); addWeighted(udiffTerm_, 1.0, uregTerm_, -lambda_, 0.0, udiffTerm_); } addWeighted(uhighRes_, 1.0, udiffTerm_, tau_, 0.0, uhighRes_); } Rect inner(btvKernelSize_, btvKernelSize_, uhighRes_.cols - 2 * btvKernelSize_, uhighRes_.rows - 2 * btvKernelSize_); uhighRes_(inner).copyTo(_dst); return true; } #endif void BTVL1_Base::process(InputArrayOfArrays _src, OutputArray _dst, InputArrayOfArrays _forwardMotions, InputArrayOfArrays _backwardMotions, int baseIdx) { CV_Assert( scale_ > 1 ); CV_Assert( iterations_ > 0 ); CV_Assert( tau_ > 0.0 ); CV_Assert( alpha_ > 0.0 ); CV_Assert( btvKernelSize_ > 0 ); CV_Assert( blurKernelSize_ > 0 ); CV_Assert( blurSigma_ >= 0.0 ); CV_OCL_RUN(_src.isUMatVector() && _dst.isUMat() && _forwardMotions.isUMatVector() && _backwardMotions.isUMatVector(), ocl_process(_src, _dst, _forwardMotions, _backwardMotions, baseIdx)) std::vector & src = *(std::vector *)_src.getObj(), & forwardMotions = *(std::vector *)_forwardMotions.getObj(), & backwardMotions = *(std::vector *)_backwardMotions.getObj(); // update blur filter and btv weights if (blurKernelSize_ != curBlurKernelSize_ || blurSigma_ != curBlurSigma_ || src[0].type() != curSrcType_) { //filter_ = createGaussianFilter(src[0].type(), Size(blurKernelSize_, blurKernelSize_), blurSigma_); curBlurKernelSize_ = blurKernelSize_; curBlurSigma_ = blurSigma_; curSrcType_ = src[0].type(); } if (btvWeights_.empty() || btvKernelSize_ != curBtvKernelSize_ || alpha_ != curAlpha_) { calcBtvWeights(btvKernelSize_, alpha_, btvWeights_); curBtvKernelSize_ = btvKernelSize_; curAlpha_ = alpha_; } // calc high res motions calcRelativeMotions(forwardMotions, backwardMotions, lowResForwardMotions_, lowResBackwardMotions_, baseIdx, src[0].size()); upscaleMotions(lowResForwardMotions_, highResForwardMotions_, scale_); upscaleMotions(lowResBackwardMotions_, highResBackwardMotions_, scale_); forwardMaps_.resize(highResForwardMotions_.size()); backwardMaps_.resize(highResForwardMotions_.size()); for (size_t i = 0; i < highResForwardMotions_.size(); ++i) buildMotionMaps(highResForwardMotions_[i], highResBackwardMotions_[i], forwardMaps_[i], backwardMaps_[i]); // initial estimation const Size lowResSize = src[0].size(); const Size highResSize(lowResSize.width * scale_, lowResSize.height * scale_); resize(src[baseIdx], highRes_, highResSize, 0, 0, INTER_CUBIC); // iterations diffTerm_.create(highResSize, highRes_.type()); a_.create(highResSize, highRes_.type()); b_.create(highResSize, highRes_.type()); c_.create(lowResSize, highRes_.type()); for (int i = 0; i < iterations_; ++i) { diffTerm_.setTo(Scalar::all(0)); for (size_t k = 0; k < src.size(); ++k) { // a = M * Ih remap(highRes_, a_, backwardMaps_[k], noArray(), INTER_NEAREST); // b = HM * Ih GaussianBlur(a_, b_, Size(blurKernelSize_, blurKernelSize_), blurSigma_); // c = DHM * Ih resize(b_, c_, lowResSize, 0, 0, INTER_NEAREST); diffSign(src[k], c_, c_); // a = Dt * diff upscale(c_, a_, scale_); // b = HtDt * diff GaussianBlur(a_, b_, Size(blurKernelSize_, blurKernelSize_), blurSigma_); // a = MtHtDt * diff remap(b_, a_, forwardMaps_[k], noArray(), INTER_NEAREST); add(diffTerm_, a_, diffTerm_); } if (lambda_ > 0) { calcBtvRegularization(highRes_, regTerm_, btvKernelSize_, btvWeights_, ubtvWeights_); addWeighted(diffTerm_, 1.0, regTerm_, -lambda_, 0.0, diffTerm_); } addWeighted(highRes_, 1.0, diffTerm_, tau_, 0.0, highRes_); } Rect inner(btvKernelSize_, btvKernelSize_, highRes_.cols - 2 * btvKernelSize_, highRes_.rows - 2 * btvKernelSize_); highRes_(inner).copyTo(_dst); } void BTVL1_Base::collectGarbage() { // Mat lowResForwardMotions_.clear(); lowResBackwardMotions_.clear(); highResForwardMotions_.clear(); highResBackwardMotions_.clear(); forwardMaps_.clear(); backwardMaps_.clear(); highRes_.release(); diffTerm_.release(); regTerm_.release(); a_.release(); b_.release(); c_.release(); #ifdef HAVE_OPENCL // UMat ulowResForwardMotions_.clear(); ulowResBackwardMotions_.clear(); uhighResForwardMotions_.clear(); uhighResBackwardMotions_.clear(); uforwardMaps_.clear(); ubackwardMaps_.clear(); uhighRes_.release(); udiffTerm_.release(); uregTerm_.release(); ua_.release(); ub_.release(); uc_.release(); #endif } //////////////////////////////////////////////////////////////////// class BTVL1 : public BTVL1_Base { public: BTVL1(); void collectGarbage(); protected: void initImpl(Ptr& frameSource); bool ocl_initImpl(Ptr& frameSource); void processImpl(Ptr& frameSource, OutputArray output); bool ocl_processImpl(Ptr& frameSource, OutputArray output); private: void readNextFrame(Ptr& frameSource); bool ocl_readNextFrame(Ptr& frameSource); void processFrame(int idx); bool ocl_processFrame(int idx); int storePos_; int procPos_; int outPos_; // Mat Mat curFrame_; Mat prevFrame_; std::vector frames_; std::vector forwardMotions_; std::vector backwardMotions_; std::vector outputs_; std::vector srcFrames_; std::vector srcForwardMotions_; std::vector srcBackwardMotions_; Mat finalOutput_; #ifdef HAVE_OPENCL // UMat UMat ucurFrame_; UMat uprevFrame_; std::vector uframes_; std::vector uforwardMotions_; std::vector ubackwardMotions_; std::vector uoutputs_; std::vector usrcFrames_; std::vector usrcForwardMotions_; std::vector usrcBackwardMotions_; #endif }; BTVL1::BTVL1() { temporalAreaRadius_ = 4; } void BTVL1::collectGarbage() { // Mat curFrame_.release(); prevFrame_.release(); frames_.clear(); forwardMotions_.clear(); backwardMotions_.clear(); outputs_.clear(); srcFrames_.clear(); srcForwardMotions_.clear(); srcBackwardMotions_.clear(); finalOutput_.release(); #ifdef HAVE_OPENCL // UMat ucurFrame_.release(); uprevFrame_.release(); uframes_.clear(); uforwardMotions_.clear(); ubackwardMotions_.clear(); uoutputs_.clear(); usrcFrames_.clear(); usrcForwardMotions_.clear(); usrcBackwardMotions_.clear(); #endif SuperResolution::collectGarbage(); BTVL1_Base::collectGarbage(); } #ifdef HAVE_OPENCL bool BTVL1::ocl_initImpl(Ptr& frameSource) { const int cacheSize = 2 * temporalAreaRadius_ + 1; uframes_.resize(cacheSize); uforwardMotions_.resize(cacheSize); ubackwardMotions_.resize(cacheSize); uoutputs_.resize(cacheSize); storePos_ = -1; for (int t = -temporalAreaRadius_; t <= temporalAreaRadius_; ++t) readNextFrame(frameSource); for (int i = 0; i <= temporalAreaRadius_; ++i) processFrame(i); procPos_ = temporalAreaRadius_; outPos_ = -1; return true; } #endif void BTVL1::initImpl(Ptr& frameSource) { const int cacheSize = 2 * temporalAreaRadius_ + 1; frames_.resize(cacheSize); forwardMotions_.resize(cacheSize); backwardMotions_.resize(cacheSize); outputs_.resize(cacheSize); CV_OCL_RUN(isUmat_, ocl_initImpl(frameSource)) storePos_ = -1; for (int t = -temporalAreaRadius_; t <= temporalAreaRadius_; ++t) readNextFrame(frameSource); for (int i = 0; i <= temporalAreaRadius_; ++i) processFrame(i); procPos_ = temporalAreaRadius_; outPos_ = -1; } #ifdef HAVE_OPENCL bool BTVL1::ocl_processImpl(Ptr& /*frameSource*/, OutputArray _output) { const UMat& curOutput = at(outPos_, uoutputs_); curOutput.convertTo(_output, CV_8U); return true; } #endif void BTVL1::processImpl(Ptr& frameSource, OutputArray _output) { if (outPos_ >= storePos_) { _output.release(); return; } readNextFrame(frameSource); if (procPos_ < storePos_) { ++procPos_; processFrame(procPos_); } ++outPos_; CV_OCL_RUN(isUmat_, ocl_processImpl(frameSource, _output)) const Mat& curOutput = at(outPos_, outputs_); if (_output.kind() < _InputArray::OPENGL_BUFFER || _output.isUMat()) curOutput.convertTo(_output, CV_8U); else { curOutput.convertTo(finalOutput_, CV_8U); arrCopy(finalOutput_, _output); } } #ifdef HAVE_OPENCL bool BTVL1::ocl_readNextFrame(Ptr& /*frameSource*/) { ucurFrame_.convertTo(at(storePos_, uframes_), CV_32F); if (storePos_ > 0) { opticalFlow_->calc(uprevFrame_, ucurFrame_, at(storePos_ - 1, uforwardMotions_)); opticalFlow_->calc(ucurFrame_, uprevFrame_, at(storePos_, ubackwardMotions_)); } ucurFrame_.copyTo(uprevFrame_); return true; } #endif void BTVL1::readNextFrame(Ptr& frameSource) { frameSource->nextFrame(curFrame_); if (curFrame_.empty()) return; #ifdef HAVE_OPENCL if (isUmat_) curFrame_.copyTo(ucurFrame_); #endif ++storePos_; CV_OCL_RUN(isUmat_, ocl_readNextFrame(frameSource)) curFrame_.convertTo(at(storePos_, frames_), CV_32F); if (storePos_ > 0) { opticalFlow_->calc(prevFrame_, curFrame_, at(storePos_ - 1, forwardMotions_)); opticalFlow_->calc(curFrame_, prevFrame_, at(storePos_, backwardMotions_)); } curFrame_.copyTo(prevFrame_); } #ifdef HAVE_OPENCL bool BTVL1::ocl_processFrame(int idx) { const int startIdx = std::max(idx - temporalAreaRadius_, 0); const int procIdx = idx; const int endIdx = std::min(startIdx + 2 * temporalAreaRadius_, storePos_); const int count = endIdx - startIdx + 1; usrcFrames_.resize(count); usrcForwardMotions_.resize(count); usrcBackwardMotions_.resize(count); int baseIdx = -1; for (int i = startIdx, k = 0; i <= endIdx; ++i, ++k) { if (i == procIdx) baseIdx = k; usrcFrames_[k] = at(i, uframes_); if (i < endIdx) usrcForwardMotions_[k] = at(i, uforwardMotions_); if (i > startIdx) usrcBackwardMotions_[k] = at(i, ubackwardMotions_); } process(usrcFrames_, at(idx, uoutputs_), usrcForwardMotions_, usrcBackwardMotions_, baseIdx); return true; } #endif void BTVL1::processFrame(int idx) { CV_OCL_RUN(isUmat_, ocl_processFrame(idx)) const int startIdx = std::max(idx - temporalAreaRadius_, 0); const int procIdx = idx; const int endIdx = std::min(startIdx + 2 * temporalAreaRadius_, storePos_); const int count = endIdx - startIdx + 1; srcFrames_.resize(count); srcForwardMotions_.resize(count); srcBackwardMotions_.resize(count); int baseIdx = -1; for (int i = startIdx, k = 0; i <= endIdx; ++i, ++k) { if (i == procIdx) baseIdx = k; srcFrames_[k] = at(i, frames_); if (i < endIdx) srcForwardMotions_[k] = at(i, forwardMotions_); if (i > startIdx) srcBackwardMotions_[k] = at(i, backwardMotions_); } process(srcFrames_, at(idx, outputs_), srcForwardMotions_, srcBackwardMotions_, baseIdx); } } Ptr cv::superres::createSuperResolution_BTVL1() { return makePtr(); }