1/*M///////////////////////////////////////////////////////////////////////////////////////
2//
3//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4//
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.
8//
9//
10//                           License Agreement
11//                For Open Source Computer Vision Library
12//
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.
16//
17// Redistribution and use in source and binary forms, with or without modification,
18// are permitted provided that the following conditions are met:
19//
20//   * Redistribution's of source code must retain the above copyright notice,
21//     this list of conditions and the following disclaimer.
22//
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.
26//
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.
29//
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.
40//
41//M*/
42
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.
45
46#include "precomp.hpp"
47#include "opencl_kernels_superres.hpp"
48
49using namespace cv;
50using namespace cv::superres;
51using namespace cv::superres::detail;
52
53namespace
54{
55#ifdef HAVE_OPENCL
56
57    bool ocl_calcRelativeMotions(InputArrayOfArrays _forwardMotions, InputArrayOfArrays _backwardMotions,
58                                 OutputArrayOfArrays _relForwardMotions, OutputArrayOfArrays _relBackwardMotions,
59                                 int baseIdx, const Size & size)
60    {
61        std::vector<UMat> & forwardMotions = *(std::vector<UMat> *)_forwardMotions.getObj(),
62                & backwardMotions = *(std::vector<UMat> *)_backwardMotions.getObj(),
63                & relForwardMotions = *(std::vector<UMat> *)_relForwardMotions.getObj(),
64                & relBackwardMotions = *(std::vector<UMat> *)_relBackwardMotions.getObj();
65
66        const int count = static_cast<int>(forwardMotions.size());
67
68        relForwardMotions.resize(count);
69        relForwardMotions[baseIdx].create(size, CV_32FC2);
70        relForwardMotions[baseIdx].setTo(Scalar::all(0));
71
72        relBackwardMotions.resize(count);
73        relBackwardMotions[baseIdx].create(size, CV_32FC2);
74        relBackwardMotions[baseIdx].setTo(Scalar::all(0));
75
76        for (int i = baseIdx - 1; i >= 0; --i)
77        {
78            add(relForwardMotions[i + 1], forwardMotions[i], relForwardMotions[i]);
79            add(relBackwardMotions[i + 1], backwardMotions[i + 1], relBackwardMotions[i]);
80        }
81
82        for (int i = baseIdx + 1; i < count; ++i)
83        {
84            add(relForwardMotions[i - 1], backwardMotions[i], relForwardMotions[i]);
85            add(relBackwardMotions[i - 1], forwardMotions[i - 1], relBackwardMotions[i]);
86        }
87
88        return true;
89    }
90
91#endif
92
93    void calcRelativeMotions(InputArrayOfArrays _forwardMotions, InputArrayOfArrays _backwardMotions,
94                             OutputArrayOfArrays _relForwardMotions, OutputArrayOfArrays _relBackwardMotions,
95                             int baseIdx, const Size & size)
96    {
97        CV_OCL_RUN(_forwardMotions.isUMatVector() && _backwardMotions.isUMatVector() &&
98                   _relForwardMotions.isUMatVector() && _relBackwardMotions.isUMatVector(),
99                   ocl_calcRelativeMotions(_forwardMotions, _backwardMotions, _relForwardMotions,
100                                           _relBackwardMotions, baseIdx, size))
101
102        std::vector<Mat> & forwardMotions = *(std::vector<Mat> *)_forwardMotions.getObj(),
103                & backwardMotions = *(std::vector<Mat> *)_backwardMotions.getObj(),
104                & relForwardMotions = *(std::vector<Mat> *)_relForwardMotions.getObj(),
105                & relBackwardMotions = *(std::vector<Mat> *)_relBackwardMotions.getObj();
106
107        const int count = static_cast<int>(forwardMotions.size());
108
109        relForwardMotions.resize(count);
110        relForwardMotions[baseIdx].create(size, CV_32FC2);
111        relForwardMotions[baseIdx].setTo(Scalar::all(0));
112
113        relBackwardMotions.resize(count);
114        relBackwardMotions[baseIdx].create(size, CV_32FC2);
115        relBackwardMotions[baseIdx].setTo(Scalar::all(0));
116
117        for (int i = baseIdx - 1; i >= 0; --i)
118        {
119            add(relForwardMotions[i + 1], forwardMotions[i], relForwardMotions[i]);
120            add(relBackwardMotions[i + 1], backwardMotions[i + 1], relBackwardMotions[i]);
121        }
122
123        for (int i = baseIdx + 1; i < count; ++i)
124        {
125            add(relForwardMotions[i - 1], backwardMotions[i], relForwardMotions[i]);
126            add(relBackwardMotions[i - 1], forwardMotions[i - 1], relBackwardMotions[i]);
127        }
128    }
129#ifdef HAVE_OPENCL
130
131    bool ocl_upscaleMotions(InputArrayOfArrays _lowResMotions, OutputArrayOfArrays _highResMotions, int scale)
132    {
133        std::vector<UMat> & lowResMotions = *(std::vector<UMat> *)_lowResMotions.getObj(),
134                & highResMotions = *(std::vector<UMat> *)_highResMotions.getObj();
135
136        highResMotions.resize(lowResMotions.size());
137
138        for (size_t i = 0; i < lowResMotions.size(); ++i)
139        {
140            resize(lowResMotions[i], highResMotions[i], Size(), scale, scale, INTER_LINEAR); // TODO
141            multiply(highResMotions[i], Scalar::all(scale), highResMotions[i]);
142        }
143
144        return true;
145    }
146
147#endif
148
149    void upscaleMotions(InputArrayOfArrays _lowResMotions, OutputArrayOfArrays _highResMotions, int scale)
150    {
151        CV_OCL_RUN(_lowResMotions.isUMatVector() && _highResMotions.isUMatVector(),
152                   ocl_upscaleMotions(_lowResMotions, _highResMotions, scale))
153
154        std::vector<Mat> & lowResMotions = *(std::vector<Mat> *)_lowResMotions.getObj(),
155                & highResMotions = *(std::vector<Mat> *)_highResMotions.getObj();
156
157        highResMotions.resize(lowResMotions.size());
158
159        for (size_t i = 0; i < lowResMotions.size(); ++i)
160        {
161            resize(lowResMotions[i], highResMotions[i], Size(), scale, scale, INTER_CUBIC);
162            multiply(highResMotions[i], Scalar::all(scale), highResMotions[i]);
163        }
164    }
165
166#ifdef HAVE_OPENCL
167
168    bool ocl_buildMotionMaps(InputArray _forwardMotion, InputArray _backwardMotion,
169                             OutputArray _forwardMap, OutputArray _backwardMap)
170    {
171        ocl::Kernel k("buildMotionMaps", ocl::superres::superres_btvl1_oclsrc);
172        if (k.empty())
173            return false;
174
175        UMat forwardMotion = _forwardMotion.getUMat(), backwardMotion = _backwardMotion.getUMat();
176        Size size = forwardMotion.size();
177
178        _forwardMap.create(size, CV_32FC2);
179        _backwardMap.create(size, CV_32FC2);
180
181        UMat forwardMap = _forwardMap.getUMat(), backwardMap = _backwardMap.getUMat();
182
183        k.args(ocl::KernelArg::ReadOnlyNoSize(forwardMotion),
184               ocl::KernelArg::ReadOnlyNoSize(backwardMotion),
185               ocl::KernelArg::WriteOnlyNoSize(forwardMap),
186               ocl::KernelArg::WriteOnly(backwardMap));
187
188        size_t globalsize[2] = { size.width, size.height };
189        return k.run(2, globalsize, NULL, false);
190    }
191
192#endif
193
194    void buildMotionMaps(InputArray _forwardMotion, InputArray _backwardMotion,
195                         OutputArray _forwardMap, OutputArray _backwardMap)
196    {
197        CV_OCL_RUN(_forwardMap.isUMat() && _backwardMap.isUMat(),
198                   ocl_buildMotionMaps(_forwardMotion, _backwardMotion, _forwardMap,
199                                       _backwardMap));
200
201        Mat forwardMotion = _forwardMotion.getMat(), backwardMotion = _backwardMotion.getMat();
202
203        _forwardMap.create(forwardMotion.size(), CV_32FC2);
204        _backwardMap.create(forwardMotion.size(), CV_32FC2);
205
206        Mat forwardMap = _forwardMap.getMat(), backwardMap = _backwardMap.getMat();
207
208        for (int y = 0; y < forwardMotion.rows; ++y)
209        {
210            const Point2f* forwardMotionRow = forwardMotion.ptr<Point2f>(y);
211            const Point2f* backwardMotionRow = backwardMotion.ptr<Point2f>(y);
212            Point2f* forwardMapRow = forwardMap.ptr<Point2f>(y);
213            Point2f* backwardMapRow = backwardMap.ptr<Point2f>(y);
214
215            for (int x = 0; x < forwardMotion.cols; ++x)
216            {
217                Point2f base(static_cast<float>(x), static_cast<float>(y));
218
219                forwardMapRow[x] = base + backwardMotionRow[x];
220                backwardMapRow[x] = base + forwardMotionRow[x];
221            }
222        }
223    }
224
225    template <typename T>
226    void upscaleImpl(InputArray _src, OutputArray _dst, int scale)
227    {
228        Mat src = _src.getMat();
229        _dst.create(src.rows * scale, src.cols * scale, src.type());
230        _dst.setTo(Scalar::all(0));
231        Mat dst = _dst.getMat();
232
233        for (int y = 0, Y = 0; y < src.rows; ++y, Y += scale)
234        {
235            const T * const srcRow = src.ptr<T>(y);
236            T * const dstRow = dst.ptr<T>(Y);
237
238            for (int x = 0, X = 0; x < src.cols; ++x, X += scale)
239                dstRow[X] = srcRow[x];
240        }
241    }
242
243#ifdef HAVE_OPENCL
244
245    static bool ocl_upscale(InputArray _src, OutputArray _dst, int scale)
246    {
247        int type = _src.type(), cn = CV_MAT_CN(type);
248        ocl::Kernel k("upscale", ocl::superres::superres_btvl1_oclsrc,
249                      format("-D cn=%d", cn));
250        if (k.empty())
251            return false;
252
253        UMat src = _src.getUMat();
254        _dst.create(src.rows * scale, src.cols * scale, type);
255        _dst.setTo(Scalar::all(0));
256        UMat dst = _dst.getUMat();
257
258        k.args(ocl::KernelArg::ReadOnly(src),
259               ocl::KernelArg::ReadWriteNoSize(dst), scale);
260
261        size_t globalsize[2] = { src.cols, src.rows };
262        return k.run(2, globalsize, NULL, false);
263    }
264
265#endif
266
267    typedef struct _Point4f { float ar[4]; } Point4f;
268
269    void upscale(InputArray _src, OutputArray _dst, int scale)
270    {
271        int cn = _src.channels();
272        CV_Assert( cn == 1 || cn == 3 || cn == 4 );
273
274        CV_OCL_RUN(_dst.isUMat(),
275                   ocl_upscale(_src, _dst, scale))
276
277        typedef void (*func_t)(InputArray src, OutputArray dst, int scale);
278        static const func_t funcs[] =
279        {
280            0, upscaleImpl<float>, 0, upscaleImpl<Point3f>, upscaleImpl<Point4f>
281        };
282
283        const func_t func = funcs[cn];
284        CV_Assert(func != 0);
285        func(_src, _dst, scale);
286    }
287
288    inline float diffSign(float a, float b)
289    {
290        return a > b ? 1.0f : a < b ? -1.0f : 0.0f;
291    }
292
293    Point3f diffSign(Point3f a, Point3f b)
294    {
295        return Point3f(
296            a.x > b.x ? 1.0f : a.x < b.x ? -1.0f : 0.0f,
297            a.y > b.y ? 1.0f : a.y < b.y ? -1.0f : 0.0f,
298            a.z > b.z ? 1.0f : a.z < b.z ? -1.0f : 0.0f
299        );
300    }
301
302#ifdef HAVE_OPENCL
303
304    static bool ocl_diffSign(InputArray _src1, OutputArray _src2, OutputArray _dst)
305    {
306        ocl::Kernel k("diffSign", ocl::superres::superres_btvl1_oclsrc);
307        if (k.empty())
308            return false;
309
310        UMat src1 = _src1.getUMat(), src2 = _src2.getUMat();
311        _dst.create(src1.size(), src1.type());
312        UMat dst = _dst.getUMat();
313
314        int cn = src1.channels();
315        k.args(ocl::KernelArg::ReadOnlyNoSize(src1),
316               ocl::KernelArg::ReadOnlyNoSize(src2),
317               ocl::KernelArg::WriteOnly(dst, cn));
318
319        size_t globalsize[2] = { src1.cols * cn, src1.rows };
320        return k.run(2, globalsize, NULL, false);
321    }
322
323#endif
324
325    void diffSign(InputArray _src1, OutputArray _src2, OutputArray _dst)
326    {
327        CV_OCL_RUN(_dst.isUMat(),
328                   ocl_diffSign(_src1, _src2, _dst))
329
330        Mat src1 = _src1.getMat(), src2 = _src2.getMat();
331        _dst.create(src1.size(), src1.type());
332        Mat dst = _dst.getMat();
333
334        const int count = src1.cols * src1.channels();
335
336        for (int y = 0; y < src1.rows; ++y)
337        {
338            const float * const src1Ptr = src1.ptr<float>(y);
339            const float * const src2Ptr = src2.ptr<float>(y);
340            float* dstPtr = dst.ptr<float>(y);
341
342            for (int x = 0; x < count; ++x)
343                dstPtr[x] = diffSign(src1Ptr[x], src2Ptr[x]);
344        }
345    }
346
347    void calcBtvWeights(int btvKernelSize, double alpha, std::vector<float>& btvWeights)
348    {
349        const size_t size = btvKernelSize * btvKernelSize;
350
351        btvWeights.resize(size);
352
353        const int ksize = (btvKernelSize - 1) / 2;
354        const float alpha_f = static_cast<float>(alpha);
355
356        for (int m = 0, ind = 0; m <= ksize; ++m)
357        {
358            for (int l = ksize; l + m >= 0; --l, ++ind)
359                btvWeights[ind] = pow(alpha_f, std::abs(m) + std::abs(l));
360        }
361    }
362
363    template <typename T>
364    struct BtvRegularizationBody : ParallelLoopBody
365    {
366        void operator ()(const Range& range) const;
367
368        Mat src;
369        mutable Mat dst;
370        int ksize;
371        const float* btvWeights;
372    };
373
374    template <typename T>
375    void BtvRegularizationBody<T>::operator ()(const Range& range) const
376    {
377        for (int i = range.start; i < range.end; ++i)
378        {
379            const T * const srcRow = src.ptr<T>(i);
380            T * const dstRow = dst.ptr<T>(i);
381
382            for(int j = ksize; j < src.cols - ksize; ++j)
383            {
384                const T srcVal = srcRow[j];
385
386                for (int m = 0, ind = 0; m <= ksize; ++m)
387                {
388                    const T* srcRow2 = src.ptr<T>(i - m);
389                    const T* srcRow3 = src.ptr<T>(i + m);
390
391                    for (int l = ksize; l + m >= 0; --l, ++ind)
392                        dstRow[j] += btvWeights[ind] * (diffSign(srcVal, srcRow3[j + l])
393                                                        - diffSign(srcRow2[j - l], srcVal));
394                }
395            }
396        }
397    }
398
399    template <typename T>
400    void calcBtvRegularizationImpl(InputArray _src, OutputArray _dst, int btvKernelSize, const std::vector<float>& btvWeights)
401    {
402        Mat src = _src.getMat();
403        _dst.create(src.size(), src.type());
404        _dst.setTo(Scalar::all(0));
405        Mat dst = _dst.getMat();
406
407        const int ksize = (btvKernelSize - 1) / 2;
408
409        BtvRegularizationBody<T> body;
410
411        body.src = src;
412        body.dst = dst;
413        body.ksize = ksize;
414        body.btvWeights = &btvWeights[0];
415
416        parallel_for_(Range(ksize, src.rows - ksize), body);
417    }
418
419#ifdef HAVE_OPENCL
420
421    static bool ocl_calcBtvRegularization(InputArray _src, OutputArray _dst, int btvKernelSize, const UMat & ubtvWeights)
422    {
423        int cn = _src.channels();
424        ocl::Kernel k("calcBtvRegularization", ocl::superres::superres_btvl1_oclsrc,
425                      format("-D cn=%d", cn));
426        if (k.empty())
427            return false;
428
429        UMat src = _src.getUMat();
430        _dst.create(src.size(), src.type());
431        _dst.setTo(Scalar::all(0));
432        UMat dst = _dst.getUMat();
433
434        const int ksize = (btvKernelSize - 1) / 2;
435
436        k.args(ocl::KernelArg::ReadOnlyNoSize(src), ocl::KernelArg::WriteOnly(dst),
437              ksize, ocl::KernelArg::PtrReadOnly(ubtvWeights));
438
439        size_t globalsize[2] = { src.cols, src.rows };
440        return k.run(2, globalsize, NULL, false);
441    }
442
443#endif
444
445    void calcBtvRegularization(InputArray _src, OutputArray _dst, int btvKernelSize,
446                               const std::vector<float>& btvWeights, const UMat & ubtvWeights)
447    {
448        CV_OCL_RUN(_dst.isUMat(),
449                   ocl_calcBtvRegularization(_src, _dst, btvKernelSize, ubtvWeights))
450        (void)ubtvWeights;
451
452        typedef void (*func_t)(InputArray _src, OutputArray _dst, int btvKernelSize, const std::vector<float>& btvWeights);
453        static const func_t funcs[] =
454        {
455            0, calcBtvRegularizationImpl<float>, 0, calcBtvRegularizationImpl<Point3f>, 0
456        };
457
458        const func_t func = funcs[_src.channels()];
459        CV_Assert(func != 0);
460        func(_src, _dst, btvKernelSize, btvWeights);
461    }
462
463    class BTVL1_Base : public cv::superres::SuperResolution
464    {
465    public:
466        BTVL1_Base();
467
468        void process(InputArrayOfArrays src, OutputArray dst, InputArrayOfArrays forwardMotions,
469                     InputArrayOfArrays backwardMotions, int baseIdx);
470
471        void collectGarbage();
472
473        CV_IMPL_PROPERTY(int, Scale, scale_)
474        CV_IMPL_PROPERTY(int, Iterations, iterations_)
475        CV_IMPL_PROPERTY(double, Tau, tau_)
476        CV_IMPL_PROPERTY(double, Labmda, lambda_)
477        CV_IMPL_PROPERTY(double, Alpha, alpha_)
478        CV_IMPL_PROPERTY(int, KernelSize, btvKernelSize_)
479        CV_IMPL_PROPERTY(int, BlurKernelSize, blurKernelSize_)
480        CV_IMPL_PROPERTY(double, BlurSigma, blurSigma_)
481        CV_IMPL_PROPERTY(int, TemporalAreaRadius, temporalAreaRadius_)
482        CV_IMPL_PROPERTY_S(Ptr<cv::superres::DenseOpticalFlowExt>, OpticalFlow, opticalFlow_)
483
484    protected:
485        int scale_;
486        int iterations_;
487        double tau_;
488        double lambda_;
489        double alpha_;
490        int btvKernelSize_;
491        int blurKernelSize_;
492        double blurSigma_;
493        int temporalAreaRadius_; // not used in some implementations
494        Ptr<cv::superres::DenseOpticalFlowExt> opticalFlow_;
495
496    private:
497        bool ocl_process(InputArrayOfArrays src, OutputArray dst, InputArrayOfArrays forwardMotions,
498                         InputArrayOfArrays backwardMotions, int baseIdx);
499
500        //Ptr<FilterEngine> filter_;
501        int curBlurKernelSize_;
502        double curBlurSigma_;
503        int curSrcType_;
504
505        std::vector<float> btvWeights_;
506        UMat ubtvWeights_;
507
508        int curBtvKernelSize_;
509        double curAlpha_;
510
511        // Mat
512        std::vector<Mat> lowResForwardMotions_;
513        std::vector<Mat> lowResBackwardMotions_;
514
515        std::vector<Mat> highResForwardMotions_;
516        std::vector<Mat> highResBackwardMotions_;
517
518        std::vector<Mat> forwardMaps_;
519        std::vector<Mat> backwardMaps_;
520
521        Mat highRes_;
522
523        Mat diffTerm_, regTerm_;
524        Mat a_, b_, c_;
525
526#ifdef HAVE_OPENCL
527        // UMat
528        std::vector<UMat> ulowResForwardMotions_;
529        std::vector<UMat> ulowResBackwardMotions_;
530
531        std::vector<UMat> uhighResForwardMotions_;
532        std::vector<UMat> uhighResBackwardMotions_;
533
534        std::vector<UMat> uforwardMaps_;
535        std::vector<UMat> ubackwardMaps_;
536
537        UMat uhighRes_;
538
539        UMat udiffTerm_, uregTerm_;
540        UMat ua_, ub_, uc_;
541#endif
542    };
543
544    BTVL1_Base::BTVL1_Base()
545    {
546        scale_ = 4;
547        iterations_ = 180;
548        lambda_ = 0.03;
549        tau_ = 1.3;
550        alpha_ = 0.7;
551        btvKernelSize_ = 7;
552        blurKernelSize_ = 5;
553        blurSigma_ = 0.0;
554        temporalAreaRadius_ = 0;
555        opticalFlow_ = createOptFlow_Farneback();
556
557        curBlurKernelSize_ = -1;
558        curBlurSigma_ = -1.0;
559        curSrcType_ = -1;
560
561        curBtvKernelSize_ = -1;
562        curAlpha_ = -1.0;
563    }
564
565#ifdef HAVE_OPENCL
566
567    bool BTVL1_Base::ocl_process(InputArrayOfArrays _src, OutputArray _dst, InputArrayOfArrays _forwardMotions,
568                                 InputArrayOfArrays _backwardMotions, int baseIdx)
569    {
570        std::vector<UMat> & src = *(std::vector<UMat> *)_src.getObj(),
571                & forwardMotions = *(std::vector<UMat> *)_forwardMotions.getObj(),
572                & backwardMotions = *(std::vector<UMat> *)_backwardMotions.getObj();
573
574        // update blur filter and btv weights
575        if (blurKernelSize_ != curBlurKernelSize_ || blurSigma_ != curBlurSigma_ || src[0].type() != curSrcType_)
576        {
577            //filter_ = createGaussianFilter(src[0].type(), Size(blurKernelSize_, blurKernelSize_), blurSigma_);
578            curBlurKernelSize_ = blurKernelSize_;
579            curBlurSigma_ = blurSigma_;
580            curSrcType_ = src[0].type();
581        }
582
583        if (btvWeights_.empty() || btvKernelSize_ != curBtvKernelSize_ || alpha_ != curAlpha_)
584        {
585            calcBtvWeights(btvKernelSize_, alpha_, btvWeights_);
586            Mat(btvWeights_, true).copyTo(ubtvWeights_);
587
588            curBtvKernelSize_ = btvKernelSize_;
589            curAlpha_ = alpha_;
590        }
591
592        // calc high res motions
593        calcRelativeMotions(forwardMotions, backwardMotions, ulowResForwardMotions_, ulowResBackwardMotions_, baseIdx, src[0].size());
594
595        upscaleMotions(ulowResForwardMotions_, uhighResForwardMotions_, scale_);
596        upscaleMotions(ulowResBackwardMotions_, uhighResBackwardMotions_, scale_);
597
598        uforwardMaps_.resize(uhighResForwardMotions_.size());
599        ubackwardMaps_.resize(uhighResForwardMotions_.size());
600        for (size_t i = 0; i < uhighResForwardMotions_.size(); ++i)
601            buildMotionMaps(uhighResForwardMotions_[i], uhighResBackwardMotions_[i], uforwardMaps_[i], ubackwardMaps_[i]);
602
603        // initial estimation
604        const Size lowResSize = src[0].size();
605        const Size highResSize(lowResSize.width * scale_, lowResSize.height * scale_);
606
607        resize(src[baseIdx], uhighRes_, highResSize, 0, 0, INTER_LINEAR); // TODO
608
609        // iterations
610        udiffTerm_.create(highResSize, uhighRes_.type());
611        ua_.create(highResSize, uhighRes_.type());
612        ub_.create(highResSize, uhighRes_.type());
613        uc_.create(lowResSize, uhighRes_.type());
614
615        for (int i = 0; i < iterations_; ++i)
616        {
617            udiffTerm_.setTo(Scalar::all(0));
618
619            for (size_t k = 0; k < src.size(); ++k)
620            {
621                // a = M * Ih
622                remap(uhighRes_, ua_, ubackwardMaps_[k], noArray(), INTER_NEAREST);
623                // b = HM * Ih
624                GaussianBlur(ua_, ub_, Size(blurKernelSize_, blurKernelSize_), blurSigma_);
625                // c = DHM * Ih
626                resize(ub_, uc_, lowResSize, 0, 0, INTER_NEAREST);
627
628                diffSign(src[k], uc_, uc_);
629
630                // a = Dt * diff
631                upscale(uc_, ua_, scale_);
632
633                // b = HtDt * diff
634                GaussianBlur(ua_, ub_, Size(blurKernelSize_, blurKernelSize_), blurSigma_);
635                // a = MtHtDt * diff
636                remap(ub_, ua_, uforwardMaps_[k], noArray(), INTER_NEAREST);
637
638                add(udiffTerm_, ua_, udiffTerm_);
639            }
640
641            if (lambda_ > 0)
642            {
643                calcBtvRegularization(uhighRes_, uregTerm_, btvKernelSize_, btvWeights_, ubtvWeights_);
644                addWeighted(udiffTerm_, 1.0, uregTerm_, -lambda_, 0.0, udiffTerm_);
645            }
646
647            addWeighted(uhighRes_, 1.0, udiffTerm_, tau_, 0.0, uhighRes_);
648        }
649
650        Rect inner(btvKernelSize_, btvKernelSize_, uhighRes_.cols - 2 * btvKernelSize_, uhighRes_.rows - 2 * btvKernelSize_);
651        uhighRes_(inner).copyTo(_dst);
652
653        return true;
654    }
655
656#endif
657
658    void BTVL1_Base::process(InputArrayOfArrays _src, OutputArray _dst, InputArrayOfArrays _forwardMotions,
659                             InputArrayOfArrays _backwardMotions, int baseIdx)
660    {
661        CV_Assert( scale_ > 1 );
662        CV_Assert( iterations_ > 0 );
663        CV_Assert( tau_ > 0.0 );
664        CV_Assert( alpha_ > 0.0 );
665        CV_Assert( btvKernelSize_ > 0 );
666        CV_Assert( blurKernelSize_ > 0 );
667        CV_Assert( blurSigma_ >= 0.0 );
668
669        CV_OCL_RUN(_src.isUMatVector() && _dst.isUMat() && _forwardMotions.isUMatVector() &&
670                   _backwardMotions.isUMatVector(),
671                   ocl_process(_src, _dst, _forwardMotions, _backwardMotions, baseIdx))
672
673        std::vector<Mat> & src = *(std::vector<Mat> *)_src.getObj(),
674                & forwardMotions = *(std::vector<Mat> *)_forwardMotions.getObj(),
675                & backwardMotions = *(std::vector<Mat> *)_backwardMotions.getObj();
676
677        // update blur filter and btv weights
678        if (blurKernelSize_ != curBlurKernelSize_ || blurSigma_ != curBlurSigma_ || src[0].type() != curSrcType_)
679        {
680            //filter_ = createGaussianFilter(src[0].type(), Size(blurKernelSize_, blurKernelSize_), blurSigma_);
681            curBlurKernelSize_ = blurKernelSize_;
682            curBlurSigma_ = blurSigma_;
683            curSrcType_ = src[0].type();
684        }
685
686        if (btvWeights_.empty() || btvKernelSize_ != curBtvKernelSize_ || alpha_ != curAlpha_)
687        {
688            calcBtvWeights(btvKernelSize_, alpha_, btvWeights_);
689            curBtvKernelSize_ = btvKernelSize_;
690            curAlpha_ = alpha_;
691        }
692
693        // calc high res motions
694        calcRelativeMotions(forwardMotions, backwardMotions, lowResForwardMotions_, lowResBackwardMotions_, baseIdx, src[0].size());
695
696        upscaleMotions(lowResForwardMotions_, highResForwardMotions_, scale_);
697        upscaleMotions(lowResBackwardMotions_, highResBackwardMotions_, scale_);
698
699        forwardMaps_.resize(highResForwardMotions_.size());
700        backwardMaps_.resize(highResForwardMotions_.size());
701        for (size_t i = 0; i < highResForwardMotions_.size(); ++i)
702            buildMotionMaps(highResForwardMotions_[i], highResBackwardMotions_[i], forwardMaps_[i], backwardMaps_[i]);
703
704        // initial estimation
705        const Size lowResSize = src[0].size();
706        const Size highResSize(lowResSize.width * scale_, lowResSize.height * scale_);
707
708        resize(src[baseIdx], highRes_, highResSize, 0, 0, INTER_CUBIC);
709
710        // iterations
711        diffTerm_.create(highResSize, highRes_.type());
712        a_.create(highResSize, highRes_.type());
713        b_.create(highResSize, highRes_.type());
714        c_.create(lowResSize, highRes_.type());
715
716        for (int i = 0; i < iterations_; ++i)
717        {
718            diffTerm_.setTo(Scalar::all(0));
719
720            for (size_t k = 0; k < src.size(); ++k)
721            {
722                // a = M * Ih
723                remap(highRes_, a_, backwardMaps_[k], noArray(), INTER_NEAREST);
724                // b = HM * Ih
725                GaussianBlur(a_, b_, Size(blurKernelSize_, blurKernelSize_), blurSigma_);
726                // c = DHM * Ih
727                resize(b_, c_, lowResSize, 0, 0, INTER_NEAREST);
728
729                diffSign(src[k], c_, c_);
730
731                // a = Dt * diff
732                upscale(c_, a_, scale_);
733                // b = HtDt * diff
734                GaussianBlur(a_, b_, Size(blurKernelSize_, blurKernelSize_), blurSigma_);
735                // a = MtHtDt * diff
736                remap(b_, a_, forwardMaps_[k], noArray(), INTER_NEAREST);
737
738                add(diffTerm_, a_, diffTerm_);
739            }
740
741            if (lambda_ > 0)
742            {
743                calcBtvRegularization(highRes_, regTerm_, btvKernelSize_, btvWeights_, ubtvWeights_);
744                addWeighted(diffTerm_, 1.0, regTerm_, -lambda_, 0.0, diffTerm_);
745            }
746
747            addWeighted(highRes_, 1.0, diffTerm_, tau_, 0.0, highRes_);
748        }
749
750        Rect inner(btvKernelSize_, btvKernelSize_, highRes_.cols - 2 * btvKernelSize_, highRes_.rows - 2 * btvKernelSize_);
751        highRes_(inner).copyTo(_dst);
752    }
753
754    void BTVL1_Base::collectGarbage()
755    {
756        // Mat
757        lowResForwardMotions_.clear();
758        lowResBackwardMotions_.clear();
759
760        highResForwardMotions_.clear();
761        highResBackwardMotions_.clear();
762
763        forwardMaps_.clear();
764        backwardMaps_.clear();
765
766        highRes_.release();
767
768        diffTerm_.release();
769        regTerm_.release();
770        a_.release();
771        b_.release();
772        c_.release();
773
774#ifdef HAVE_OPENCL
775        // UMat
776        ulowResForwardMotions_.clear();
777        ulowResBackwardMotions_.clear();
778
779        uhighResForwardMotions_.clear();
780        uhighResBackwardMotions_.clear();
781
782        uforwardMaps_.clear();
783        ubackwardMaps_.clear();
784
785        uhighRes_.release();
786
787        udiffTerm_.release();
788        uregTerm_.release();
789        ua_.release();
790        ub_.release();
791        uc_.release();
792#endif
793    }
794
795////////////////////////////////////////////////////////////////////
796
797    class BTVL1 : public BTVL1_Base
798    {
799    public:
800        BTVL1();
801
802        void collectGarbage();
803
804    protected:
805        void initImpl(Ptr<FrameSource>& frameSource);
806        bool ocl_initImpl(Ptr<FrameSource>& frameSource);
807
808        void processImpl(Ptr<FrameSource>& frameSource, OutputArray output);
809        bool ocl_processImpl(Ptr<FrameSource>& frameSource, OutputArray output);
810
811    private:
812        void readNextFrame(Ptr<FrameSource>& frameSource);
813        bool ocl_readNextFrame(Ptr<FrameSource>& frameSource);
814
815        void processFrame(int idx);
816        bool ocl_processFrame(int idx);
817
818        int storePos_;
819        int procPos_;
820        int outPos_;
821
822        // Mat
823        Mat curFrame_;
824        Mat prevFrame_;
825
826        std::vector<Mat> frames_;
827        std::vector<Mat> forwardMotions_;
828        std::vector<Mat> backwardMotions_;
829        std::vector<Mat> outputs_;
830
831        std::vector<Mat> srcFrames_;
832        std::vector<Mat> srcForwardMotions_;
833        std::vector<Mat> srcBackwardMotions_;
834        Mat finalOutput_;
835
836#ifdef HAVE_OPENCL
837        // UMat
838        UMat ucurFrame_;
839        UMat uprevFrame_;
840
841        std::vector<UMat> uframes_;
842        std::vector<UMat> uforwardMotions_;
843        std::vector<UMat> ubackwardMotions_;
844        std::vector<UMat> uoutputs_;
845
846        std::vector<UMat> usrcFrames_;
847        std::vector<UMat> usrcForwardMotions_;
848        std::vector<UMat> usrcBackwardMotions_;
849#endif
850    };
851
852    BTVL1::BTVL1()
853    {
854        temporalAreaRadius_ = 4;
855    }
856
857    void BTVL1::collectGarbage()
858    {
859        // Mat
860        curFrame_.release();
861        prevFrame_.release();
862
863        frames_.clear();
864        forwardMotions_.clear();
865        backwardMotions_.clear();
866        outputs_.clear();
867
868        srcFrames_.clear();
869        srcForwardMotions_.clear();
870        srcBackwardMotions_.clear();
871        finalOutput_.release();
872
873#ifdef HAVE_OPENCL
874        // UMat
875        ucurFrame_.release();
876        uprevFrame_.release();
877
878        uframes_.clear();
879        uforwardMotions_.clear();
880        ubackwardMotions_.clear();
881        uoutputs_.clear();
882
883        usrcFrames_.clear();
884        usrcForwardMotions_.clear();
885        usrcBackwardMotions_.clear();
886#endif
887
888        SuperResolution::collectGarbage();
889        BTVL1_Base::collectGarbage();
890    }
891
892#ifdef HAVE_OPENCL
893
894    bool BTVL1::ocl_initImpl(Ptr<FrameSource>& frameSource)
895    {
896        const int cacheSize = 2 * temporalAreaRadius_ + 1;
897
898        uframes_.resize(cacheSize);
899        uforwardMotions_.resize(cacheSize);
900        ubackwardMotions_.resize(cacheSize);
901        uoutputs_.resize(cacheSize);
902
903        storePos_ = -1;
904
905        for (int t = -temporalAreaRadius_; t <= temporalAreaRadius_; ++t)
906            readNextFrame(frameSource);
907
908        for (int i = 0; i <= temporalAreaRadius_; ++i)
909            processFrame(i);
910
911        procPos_ = temporalAreaRadius_;
912        outPos_ = -1;
913
914        return true;
915    }
916
917#endif
918
919    void BTVL1::initImpl(Ptr<FrameSource>& frameSource)
920    {
921        const int cacheSize = 2 * temporalAreaRadius_ + 1;
922
923        frames_.resize(cacheSize);
924        forwardMotions_.resize(cacheSize);
925        backwardMotions_.resize(cacheSize);
926        outputs_.resize(cacheSize);
927
928        CV_OCL_RUN(isUmat_,
929                   ocl_initImpl(frameSource))
930
931        storePos_ = -1;
932
933        for (int t = -temporalAreaRadius_; t <= temporalAreaRadius_; ++t)
934            readNextFrame(frameSource);
935
936        for (int i = 0; i <= temporalAreaRadius_; ++i)
937            processFrame(i);
938
939        procPos_ = temporalAreaRadius_;
940        outPos_ = -1;
941    }
942
943#ifdef HAVE_OPENCL
944
945    bool BTVL1::ocl_processImpl(Ptr<FrameSource>& /*frameSource*/, OutputArray _output)
946    {
947        const UMat& curOutput = at(outPos_, uoutputs_);
948        curOutput.convertTo(_output, CV_8U);
949
950        return true;
951    }
952
953#endif
954
955    void BTVL1::processImpl(Ptr<FrameSource>& frameSource, OutputArray _output)
956    {
957        if (outPos_ >= storePos_)
958        {
959            _output.release();
960            return;
961        }
962
963        readNextFrame(frameSource);
964
965        if (procPos_ < storePos_)
966        {
967            ++procPos_;
968            processFrame(procPos_);
969        }
970        ++outPos_;
971
972        CV_OCL_RUN(isUmat_,
973                   ocl_processImpl(frameSource, _output))
974
975        const Mat& curOutput = at(outPos_, outputs_);
976
977        if (_output.kind() < _InputArray::OPENGL_BUFFER || _output.isUMat())
978            curOutput.convertTo(_output, CV_8U);
979        else
980        {
981            curOutput.convertTo(finalOutput_, CV_8U);
982            arrCopy(finalOutput_, _output);
983        }
984    }
985
986#ifdef HAVE_OPENCL
987
988    bool BTVL1::ocl_readNextFrame(Ptr<FrameSource>& /*frameSource*/)
989    {
990        ucurFrame_.convertTo(at(storePos_, uframes_), CV_32F);
991
992        if (storePos_ > 0)
993        {
994            opticalFlow_->calc(uprevFrame_, ucurFrame_, at(storePos_ - 1, uforwardMotions_));
995            opticalFlow_->calc(ucurFrame_, uprevFrame_, at(storePos_, ubackwardMotions_));
996        }
997
998        ucurFrame_.copyTo(uprevFrame_);
999        return true;
1000    }
1001
1002#endif
1003
1004    void BTVL1::readNextFrame(Ptr<FrameSource>& frameSource)
1005    {
1006        frameSource->nextFrame(curFrame_);
1007        if (curFrame_.empty())
1008            return;
1009
1010#ifdef HAVE_OPENCL
1011        if (isUmat_)
1012            curFrame_.copyTo(ucurFrame_);
1013#endif
1014        ++storePos_;
1015
1016        CV_OCL_RUN(isUmat_,
1017                   ocl_readNextFrame(frameSource))
1018
1019        curFrame_.convertTo(at(storePos_, frames_), CV_32F);
1020
1021        if (storePos_ > 0)
1022        {
1023            opticalFlow_->calc(prevFrame_, curFrame_, at(storePos_ - 1, forwardMotions_));
1024            opticalFlow_->calc(curFrame_, prevFrame_, at(storePos_, backwardMotions_));
1025        }
1026
1027        curFrame_.copyTo(prevFrame_);
1028    }
1029
1030#ifdef HAVE_OPENCL
1031
1032    bool BTVL1::ocl_processFrame(int idx)
1033    {
1034        const int startIdx = std::max(idx - temporalAreaRadius_, 0);
1035        const int procIdx = idx;
1036        const int endIdx = std::min(startIdx + 2 * temporalAreaRadius_, storePos_);
1037
1038        const int count = endIdx - startIdx + 1;
1039
1040        usrcFrames_.resize(count);
1041        usrcForwardMotions_.resize(count);
1042        usrcBackwardMotions_.resize(count);
1043
1044        int baseIdx = -1;
1045
1046        for (int i = startIdx, k = 0; i <= endIdx; ++i, ++k)
1047        {
1048            if (i == procIdx)
1049                baseIdx = k;
1050
1051            usrcFrames_[k] = at(i, uframes_);
1052
1053            if (i < endIdx)
1054                usrcForwardMotions_[k] = at(i, uforwardMotions_);
1055            if (i > startIdx)
1056                usrcBackwardMotions_[k] = at(i, ubackwardMotions_);
1057        }
1058
1059        process(usrcFrames_, at(idx, uoutputs_), usrcForwardMotions_, usrcBackwardMotions_, baseIdx);
1060
1061        return true;
1062    }
1063
1064#endif
1065
1066    void BTVL1::processFrame(int idx)
1067    {
1068        CV_OCL_RUN(isUmat_,
1069                   ocl_processFrame(idx))
1070
1071        const int startIdx = std::max(idx - temporalAreaRadius_, 0);
1072        const int procIdx = idx;
1073        const int endIdx = std::min(startIdx + 2 * temporalAreaRadius_, storePos_);
1074
1075        const int count = endIdx - startIdx + 1;
1076
1077        srcFrames_.resize(count);
1078        srcForwardMotions_.resize(count);
1079        srcBackwardMotions_.resize(count);
1080
1081        int baseIdx = -1;
1082
1083        for (int i = startIdx, k = 0; i <= endIdx; ++i, ++k)
1084        {
1085            if (i == procIdx)
1086                baseIdx = k;
1087
1088            srcFrames_[k] = at(i, frames_);
1089
1090            if (i < endIdx)
1091                srcForwardMotions_[k] = at(i, forwardMotions_);
1092            if (i > startIdx)
1093                srcBackwardMotions_[k] = at(i, backwardMotions_);
1094        }
1095
1096        process(srcFrames_, at(idx, outputs_), srcForwardMotions_, srcBackwardMotions_, baseIdx);
1097    }
1098}
1099
1100Ptr<cv::superres::SuperResolution> cv::superres::createSuperResolution_BTVL1()
1101{
1102    return makePtr<BTVL1>();
1103}
1104