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#include "test_precomp.hpp" 44#include "opencv2/ts/ocl_test.hpp" 45 46#if BUILD_WITH_VIDEO_INPUT_SUPPORT 47 48class AllignedFrameSource : public cv::superres::FrameSource 49{ 50public: 51 AllignedFrameSource(const cv::Ptr<cv::superres::FrameSource>& base, int scale); 52 53 void nextFrame(cv::OutputArray frame); 54 void reset(); 55 56private: 57 cv::Ptr<cv::superres::FrameSource> base_; 58 59 cv::Mat origFrame_; 60 int scale_; 61}; 62 63AllignedFrameSource::AllignedFrameSource(const cv::Ptr<cv::superres::FrameSource>& base, int scale) : 64 base_(base), scale_(scale) 65{ 66 CV_Assert( base_ ); 67} 68 69void AllignedFrameSource::nextFrame(cv::OutputArray frame) 70{ 71 base_->nextFrame(origFrame_); 72 73 if (origFrame_.rows % scale_ == 0 && origFrame_.cols % scale_ == 0) 74 cv::superres::arrCopy(origFrame_, frame); 75 else 76 { 77 cv::Rect ROI(0, 0, (origFrame_.cols / scale_) * scale_, (origFrame_.rows / scale_) * scale_); 78 cv::superres::arrCopy(origFrame_(ROI), frame); 79 } 80} 81 82void AllignedFrameSource::reset() 83{ 84 base_->reset(); 85} 86 87class DegradeFrameSource : public cv::superres::FrameSource 88{ 89public: 90 DegradeFrameSource(const cv::Ptr<cv::superres::FrameSource>& base, int scale); 91 92 void nextFrame(cv::OutputArray frame); 93 void reset(); 94 95private: 96 cv::Ptr<cv::superres::FrameSource> base_; 97 98 cv::Mat origFrame_; 99 cv::Mat blurred_; 100 cv::Mat deg_; 101 double iscale_; 102}; 103 104DegradeFrameSource::DegradeFrameSource(const cv::Ptr<cv::superres::FrameSource>& base, int scale) : 105 base_(base), iscale_(1.0 / scale) 106{ 107 CV_Assert( base_ ); 108} 109 110static void addGaussNoise(cv::OutputArray _image, double sigma) 111{ 112 int type = _image.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); 113 cv::Mat noise(_image.size(), CV_32FC(cn)); 114 cvtest::TS::ptr()->get_rng().fill(noise, cv::RNG::NORMAL, 0.0, sigma); 115 116 cv::addWeighted(_image, 1.0, noise, 1.0, 0.0, _image, depth); 117} 118 119static void addSpikeNoise(cv::OutputArray _image, int frequency) 120{ 121 cv::Mat_<uchar> mask(_image.size(), 0); 122 123 for (int y = 0; y < mask.rows; ++y) 124 for (int x = 0; x < mask.cols; ++x) 125 if (cvtest::TS::ptr()->get_rng().uniform(0, frequency) < 1) 126 mask(y, x) = 255; 127 128 _image.setTo(cv::Scalar::all(255), mask); 129} 130 131void DegradeFrameSource::nextFrame(cv::OutputArray frame) 132{ 133 base_->nextFrame(origFrame_); 134 135 cv::GaussianBlur(origFrame_, blurred_, cv::Size(5, 5), 0); 136 cv::resize(blurred_, deg_, cv::Size(), iscale_, iscale_, cv::INTER_NEAREST); 137 138 addGaussNoise(deg_, 10.0); 139 addSpikeNoise(deg_, 500); 140 141 cv::superres::arrCopy(deg_, frame); 142} 143 144void DegradeFrameSource::reset() 145{ 146 base_->reset(); 147} 148 149double MSSIM(cv::InputArray _i1, cv::InputArray _i2) 150{ 151 const double C1 = 6.5025; 152 const double C2 = 58.5225; 153 154 const int depth = CV_32F; 155 156 cv::Mat I1, I2; 157 _i1.getMat().convertTo(I1, depth); 158 _i2.getMat().convertTo(I2, depth); 159 160 cv::Mat I2_2 = I2.mul(I2); // I2^2 161 cv::Mat I1_2 = I1.mul(I1); // I1^2 162 cv::Mat I1_I2 = I1.mul(I2); // I1 * I2 163 164 cv::Mat mu1, mu2; 165 cv::GaussianBlur(I1, mu1, cv::Size(11, 11), 1.5); 166 cv::GaussianBlur(I2, mu2, cv::Size(11, 11), 1.5); 167 168 cv::Mat mu1_2 = mu1.mul(mu1); 169 cv::Mat mu2_2 = mu2.mul(mu2); 170 cv::Mat mu1_mu2 = mu1.mul(mu2); 171 172 cv::Mat sigma1_2, sigma2_2, sigma12; 173 174 cv::GaussianBlur(I1_2, sigma1_2, cv::Size(11, 11), 1.5); 175 sigma1_2 -= mu1_2; 176 177 cv::GaussianBlur(I2_2, sigma2_2, cv::Size(11, 11), 1.5); 178 sigma2_2 -= mu2_2; 179 180 cv::GaussianBlur(I1_I2, sigma12, cv::Size(11, 11), 1.5); 181 sigma12 -= mu1_mu2; 182 183 cv::Mat t1, t2; 184 cv::Mat numerator; 185 cv::Mat denominator; 186 187 // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2)) 188 t1 = 2 * mu1_mu2 + C1; 189 t2 = 2 * sigma12 + C2; 190 numerator = t1.mul(t2); 191 192 // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2)) 193 t1 = mu1_2 + mu2_2 + C1; 194 t2 = sigma1_2 + sigma2_2 + C2; 195 denominator = t1.mul(t2); 196 197 // ssim_map = numerator./denominator; 198 cv::Mat ssim_map; 199 cv::divide(numerator, denominator, ssim_map); 200 201 // mssim = average of ssim map 202 cv::Scalar mssim = cv::mean(ssim_map); 203 204 if (_i1.channels() == 1) 205 return mssim[0]; 206 207 return (mssim[0] + mssim[1] + mssim[3]) / 3; 208} 209 210class SuperResolution : public testing::Test 211{ 212public: 213 template <typename T> 214 void RunTest(cv::Ptr<cv::superres::SuperResolution> superRes); 215}; 216 217template <typename T> 218void SuperResolution::RunTest(cv::Ptr<cv::superres::SuperResolution> superRes) 219{ 220 const std::string inputVideoName = cvtest::TS::ptr()->get_data_path() + "car.avi"; 221 const int scale = 2; 222 const int iterations = 100; 223 const int temporalAreaRadius = 2; 224 225 ASSERT_FALSE( superRes.empty() ); 226 227 const int btvKernelSize = superRes->getKernelSize(); 228 229 superRes->setScale(scale); 230 superRes->setIterations(iterations); 231 superRes->setTemporalAreaRadius(temporalAreaRadius); 232 233 cv::Ptr<cv::superres::FrameSource> goldSource(new AllignedFrameSource(cv::superres::createFrameSource_Video(inputVideoName), scale)); 234 cv::Ptr<cv::superres::FrameSource> lowResSource(new DegradeFrameSource( 235 cv::makePtr<AllignedFrameSource>(cv::superres::createFrameSource_Video(inputVideoName), scale), scale)); 236 237 // skip first frame 238 cv::Mat frame; 239 240 lowResSource->nextFrame(frame); 241 goldSource->nextFrame(frame); 242 243 cv::Rect inner(btvKernelSize, btvKernelSize, frame.cols - 2 * btvKernelSize, frame.rows - 2 * btvKernelSize); 244 245 superRes->setInput(lowResSource); 246 247 double srAvgMSSIM = 0.0; 248 const int count = 10; 249 250 cv::Mat goldFrame; 251 T superResFrame; 252 for (int i = 0; i < count; ++i) 253 { 254 goldSource->nextFrame(goldFrame); 255 ASSERT_FALSE( goldFrame.empty() ); 256 257 superRes->nextFrame(superResFrame); 258 ASSERT_FALSE( superResFrame.empty() ); 259 260 const double srMSSIM = MSSIM(goldFrame(inner), superResFrame); 261 262 srAvgMSSIM += srMSSIM; 263 } 264 265 srAvgMSSIM /= count; 266 267 EXPECT_GE( srAvgMSSIM, 0.5 ); 268} 269 270TEST_F(SuperResolution, BTVL1) 271{ 272 RunTest<cv::Mat>(cv::superres::createSuperResolution_BTVL1()); 273} 274 275#if defined(HAVE_CUDA) && defined(HAVE_OPENCV_CUDAARITHM) && defined(HAVE_OPENCV_CUDAWARPING) && defined(HAVE_OPENCV_CUDAFILTERS) 276 277TEST_F(SuperResolution, BTVL1_CUDA) 278{ 279 RunTest<cv::Mat>(cv::superres::createSuperResolution_BTVL1_CUDA()); 280} 281 282#endif 283 284#ifdef HAVE_OPENCL 285 286namespace cvtest { 287namespace ocl { 288 289OCL_TEST_F(SuperResolution, BTVL1) 290{ 291 RunTest<cv::UMat>(cv::superres::createSuperResolution_BTVL1()); 292} 293 294} } // namespace cvtest::ocl 295 296#endif 297 298#endif // BUILD_WITH_VIDEO_INPUT_SUPPORT 299