Path: blob/master/modules/imgproc/test/test_imgwarp_strict.cpp
16354 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// Intel License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000, Intel Corporation, all rights reserved.13// Third party copyrights are property of their respective owners.14//15// Redistribution and use in source and binary forms, with or without modification,16// are permitted provided that the following conditions are met:17//18// * Redistribution's of source code must retain the above copyright notice,19// this list of conditions and the following disclaimer.20//21// * Redistribution's in binary form must reproduce the above copyright notice,22// this list of conditions and the following disclaimer in the documentation23// and/or other materials provided with the distribution.24//25// * The name of Intel Corporation may not be used to endorse or promote products26// derived from this software without specific prior written permission.27//28// This software is provided by the copyright holders and contributors "as is" and29// any express or implied warranties, including, but not limited to, the implied30// warranties of merchantability and fitness for a particular purpose are disclaimed.31// In no event shall the Intel Corporation or contributors be liable for any direct,32// indirect, incidental, special, exemplary, or consequential damages33// (including, but not limited to, procurement of substitute goods or services;34// loss of use, data, or profits; or business interruption) however caused35// and on any theory of liability, whether in contract, strict liability,36// or tort (including negligence or otherwise) arising in any way out of37// the use of this software, even if advised of the possibility of such damage.38//39//M*/4041#include "test_precomp.hpp"4243namespace opencv_test { namespace {4445void __wrap_printf_func(const char* fmt, ...)46{47va_list args;48va_start(args, fmt);49char buffer[256];50vsprintf (buffer, fmt, args);51cvtest::TS::ptr()->printf(cvtest::TS::SUMMARY, buffer);52va_end(args);53}5455#define PRINT_TO_LOG __wrap_printf_func5657#define SHOW_IMAGE58#undef SHOW_IMAGE5960////////////////////////////////////////////////////////////////////////////////////////////////////////61// ImageWarpBaseTest62////////////////////////////////////////////////////////////////////////////////////////////////////////6364class CV_ImageWarpBaseTest :65public cvtest::BaseTest66{67public:68enum { cell_size = 10 };6970CV_ImageWarpBaseTest();71virtual ~CV_ImageWarpBaseTest();7273virtual void run(int);74protected:75virtual void generate_test_data();7677virtual void run_func() = 0;78virtual void run_reference_func() = 0;79virtual float get_success_error_level(int _interpolation, int _depth) const;80virtual void validate_results() const;81virtual void prepare_test_data_for_reference_func();8283Size randSize(RNG& rng) const;8485String interpolation_to_string(int inter_type) const;8687int interpolation;88Mat src;89Mat dst;90Mat reference_dst;91};9293CV_ImageWarpBaseTest::CV_ImageWarpBaseTest() :94BaseTest(), interpolation(-1),95src(), dst(), reference_dst()96{97test_case_count = 40;98ts->set_failed_test_info(cvtest::TS::OK);99}100101CV_ImageWarpBaseTest::~CV_ImageWarpBaseTest()102{103}104105String CV_ImageWarpBaseTest::interpolation_to_string(int inter) const106{107bool inverse = (inter & WARP_INVERSE_MAP) != 0;108inter &= ~WARP_INVERSE_MAP;109String str;110111if (inter == INTER_NEAREST)112str = "INTER_NEAREST";113else if (inter == INTER_LINEAR)114str = "INTER_LINEAR";115else if (inter == INTER_LINEAR_EXACT)116str = "INTER_LINEAR_EXACT";117else if (inter == INTER_AREA)118str = "INTER_AREA";119else if (inter == INTER_CUBIC)120str = "INTER_CUBIC";121else if (inter == INTER_LANCZOS4)122str = "INTER_LANCZOS4";123else if (inter == INTER_LANCZOS4 + 1)124str = "INTER_AREA_FAST";125126if (inverse)127str += " | WARP_INVERSE_MAP";128129return str.empty() ? "Unsupported/Unknown interpolation type" : str;130}131132Size CV_ImageWarpBaseTest::randSize(RNG& rng) const133{134Size size;135size.width = static_cast<int>(std::exp(rng.uniform(1.0f, 7.0f)));136size.height = static_cast<int>(std::exp(rng.uniform(1.0f, 7.0f)));137138return size;139}140141void CV_ImageWarpBaseTest::generate_test_data()142{143RNG& rng = ts->get_rng();144145// generating the src matrix structure146Size ssize = randSize(rng), dsize;147148int depth = rng.uniform(0, CV_64F);149while (depth == CV_8S || depth == CV_32S)150depth = rng.uniform(0, CV_64F);151152int cn = rng.uniform(1, 4);153while (cn == 2)154cn = rng.uniform(1, 4);155156src.create(ssize, CV_MAKE_TYPE(depth, cn));157158// generating the src matrix159int x, y;160if (cvtest::randInt(rng) % 2)161{162for (y = 0; y < ssize.height; y += cell_size)163for (x = 0; x < ssize.width; x += cell_size)164rectangle(src, Point(x, y), Point(x + std::min<int>(cell_size, ssize.width - x), y +165std::min<int>(cell_size, ssize.height - y)), Scalar::all((x + y) % 2 ? 255: 0), CV_FILLED);166}167else168{169src = Scalar::all(255);170for (y = cell_size; y < src.rows; y += cell_size)171line(src, Point2i(0, y), Point2i(src.cols, y), Scalar::all(0), 1);172for (x = cell_size; x < src.cols; x += cell_size)173line(src, Point2i(x, 0), Point2i(x, src.rows), Scalar::all(0), 1);174}175176// generating an interpolation type177interpolation = rng.uniform(0, CV_INTER_LANCZOS4 + 1);178179// generating the dst matrix structure180double scale_x, scale_y;181if (interpolation == INTER_AREA)182{183bool area_fast = rng.uniform(0., 1.) > 0.5;184if (area_fast)185{186scale_x = rng.uniform(2, 5);187scale_y = rng.uniform(2, 5);188}189else190{191scale_x = rng.uniform(1.0, 3.0);192scale_y = rng.uniform(1.0, 3.0);193}194}195else196{197scale_x = rng.uniform(0.4, 4.0);198scale_y = rng.uniform(0.4, 4.0);199}200CV_Assert(scale_x > 0.0f && scale_y > 0.0f);201202dsize.width = saturate_cast<int>((ssize.width + scale_x - 1) / scale_x);203dsize.height = saturate_cast<int>((ssize.height + scale_y - 1) / scale_y);204205dst = Mat::zeros(dsize, src.type());206reference_dst = Mat::zeros(dst.size(), CV_MAKE_TYPE(CV_32F, dst.channels()));207208scale_x = src.cols / static_cast<double>(dst.cols);209scale_y = src.rows / static_cast<double>(dst.rows);210211if (interpolation == INTER_AREA && (scale_x < 1.0 || scale_y < 1.0))212interpolation = INTER_LINEAR;213}214215void CV_ImageWarpBaseTest::run(int)216{217for (int i = 0; i < test_case_count; ++i)218{219generate_test_data();220run_func();221run_reference_func();222if (ts->get_err_code() < 0)223break;224validate_results();225if (ts->get_err_code() < 0)226break;227ts->update_context(this, i, true);228}229ts->set_gtest_status();230}231232float CV_ImageWarpBaseTest::get_success_error_level(int _interpolation, int) const233{234if (_interpolation == INTER_CUBIC)235return 1.0f;236else if (_interpolation == INTER_LANCZOS4)237return 1.0f;238else if (_interpolation == INTER_NEAREST)239return 1.0f;240else if (_interpolation == INTER_AREA)241return 2.0f;242else243return 1.0f;244}245246void CV_ImageWarpBaseTest::validate_results() const247{248Mat _dst;249dst.convertTo(_dst, reference_dst.depth());250251Size dsize = dst.size(), ssize = src.size();252int cn = _dst.channels();253dsize.width *= cn;254float t = get_success_error_level(interpolation & INTER_MAX, dst.depth());255256for (int dy = 0; dy < dsize.height; ++dy)257{258const float* rD = reference_dst.ptr<float>(dy);259const float* D = _dst.ptr<float>(dy);260261for (int dx = 0; dx < dsize.width; ++dx)262if (fabs(rD[dx] - D[dx]) > t &&263// fabs(rD[dx] - D[dx]) < 250.0f &&264rD[dx] <= 255.0f && D[dx] <= 255.0f && rD[dx] >= 0.0f && D[dx] >= 0.0f)265{266PRINT_TO_LOG("\nNorm of the difference: %lf\n", cvtest::norm(reference_dst, _dst, NORM_INF));267PRINT_TO_LOG("Error in (dx, dy): (%d, %d)\n", dx / cn + 1, dy + 1);268PRINT_TO_LOG("Tuple (rD, D): (%f, %f)\n", rD[dx], D[dx]);269PRINT_TO_LOG("Dsize: (%d, %d)\n", dsize.width / cn, dsize.height);270PRINT_TO_LOG("Ssize: (%d, %d)\n", src.cols, src.rows);271272double scale_x = static_cast<double>(ssize.width) / dsize.width;273double scale_y = static_cast<double>(ssize.height) / dsize.height;274bool area_fast = interpolation == INTER_AREA &&275fabs(scale_x - cvRound(scale_x)) < FLT_EPSILON &&276fabs(scale_y - cvRound(scale_y)) < FLT_EPSILON;277if (area_fast)278{279scale_y = cvRound(scale_y);280scale_x = cvRound(scale_x);281}282283PRINT_TO_LOG("Interpolation: %s\n", interpolation_to_string(area_fast ? INTER_LANCZOS4 + 1 : interpolation).c_str());284PRINT_TO_LOG("Scale (x, y): (%lf, %lf)\n", scale_x, scale_y);285PRINT_TO_LOG("Elemsize: %d\n", src.elemSize1());286PRINT_TO_LOG("Channels: %d\n", cn);287288#ifdef SHOW_IMAGE289const std::string w1("OpenCV impl (run func)"), w2("Reference func"), w3("Src image"), w4("Diff");290namedWindow(w1, CV_WINDOW_KEEPRATIO);291namedWindow(w2, CV_WINDOW_KEEPRATIO);292namedWindow(w3, CV_WINDOW_KEEPRATIO);293namedWindow(w4, CV_WINDOW_KEEPRATIO);294295Mat diff;296absdiff(reference_dst, _dst, diff);297298imshow(w1, dst);299imshow(w2, reference_dst);300imshow(w3, src);301imshow(w4, diff);302303waitKey();304#endif305306const int radius = 3;307int rmin = MAX(dy - radius, 0), rmax = MIN(dy + radius, dsize.height);308int cmin = MAX(dx / cn - radius, 0), cmax = MIN(dx / cn + radius, dsize.width);309310std::cout << "opencv result:\n" << dst(Range(rmin, rmax), Range(cmin, cmax)) << std::endl;311std::cout << "reference result:\n" << reference_dst(Range(rmin, rmax), Range(cmin, cmax)) << std::endl;312313ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);314return;315}316}317}318319void CV_ImageWarpBaseTest::prepare_test_data_for_reference_func()320{321if (src.depth() != CV_32F)322{323Mat tmp;324src.convertTo(tmp, CV_32F);325src = tmp;326}327}328329////////////////////////////////////////////////////////////////////////////////////////////////////////330// Resize331////////////////////////////////////////////////////////////////////////////////////////////////////////332333class CV_Resize_Test :334public CV_ImageWarpBaseTest335{336public:337CV_Resize_Test();338virtual ~CV_Resize_Test();339340protected:341virtual void generate_test_data();342343virtual void run_func();344virtual void run_reference_func();345346private:347double scale_x;348double scale_y;349bool area_fast;350351void resize_generic();352void resize_area();353double getWeight(double a, double b, int x);354355typedef std::vector<std::pair<int, double> > dim;356void generate_buffer(double scale, dim& _dim);357void resize_1d(const Mat& _src, Mat& _dst, int dy, const dim& _dim);358};359360CV_Resize_Test::CV_Resize_Test() :361CV_ImageWarpBaseTest(), scale_x(),362scale_y(), area_fast(false)363{364}365366CV_Resize_Test::~CV_Resize_Test()367{368}369370namespace371{372void interpolateLinear(float x, float* coeffs)373{374coeffs[0] = 1.f - x;375coeffs[1] = x;376}377378void interpolateCubic(float x, float* coeffs)379{380const float A = -0.75f;381382coeffs[0] = ((A*(x + 1) - 5*A)*(x + 1) + 8*A)*(x + 1) - 4*A;383coeffs[1] = ((A + 2)*x - (A + 3))*x*x + 1;384coeffs[2] = ((A + 2)*(1 - x) - (A + 3))*(1 - x)*(1 - x) + 1;385coeffs[3] = 1.f - coeffs[0] - coeffs[1] - coeffs[2];386}387388void interpolateLanczos4(float x, float* coeffs)389{390static const double s45 = 0.70710678118654752440084436210485;391static const double cs[][2]=392{{1, 0}, {-s45, -s45}, {0, 1}, {s45, -s45}, {-1, 0}, {s45, s45}, {0, -1}, {-s45, s45}};393394if( x < FLT_EPSILON )395{396for( int i = 0; i < 8; i++ )397coeffs[i] = 0;398coeffs[3] = 1;399return;400}401402float sum = 0;403double y0=-(x+3)*CV_PI*0.25, s0 = sin(y0), c0=cos(y0);404for(int i = 0; i < 8; i++ )405{406double y = -(x+3-i)*CV_PI*0.25;407coeffs[i] = (float)((cs[i][0]*s0 + cs[i][1]*c0)/(y*y));408sum += coeffs[i];409}410411sum = 1.f/sum;412for(int i = 0; i < 8; i++ )413coeffs[i] *= sum;414}415416typedef void (*interpolate_method)(float x, float* coeffs);417interpolate_method inter_array[] = { &interpolateLinear, &interpolateCubic, &interpolateLanczos4 };418}419420void CV_Resize_Test::generate_test_data()421{422RNG& rng = ts->get_rng();423424// generating the src matrix structure425Size ssize = randSize(rng), dsize;426427int depth = rng.uniform(0, CV_64F);428while (depth == CV_8S || depth == CV_32S)429depth = rng.uniform(0, CV_64F);430431int cn = rng.uniform(1, 4);432while (cn == 2)433cn = rng.uniform(1, 4);434435src.create(ssize, CV_MAKE_TYPE(depth, cn));436437// generating the src matrix438int x, y;439if (cvtest::randInt(rng) % 2)440{441for (y = 0; y < ssize.height; y += cell_size)442for (x = 0; x < ssize.width; x += cell_size)443rectangle(src, Point(x, y), Point(x + std::min<int>(cell_size, ssize.width - x), y +444std::min<int>(cell_size, ssize.height - y)), Scalar::all((x + y) % 2 ? 255: 0), CV_FILLED);445}446else447{448src = Scalar::all(255);449for (y = cell_size; y < src.rows; y += cell_size)450line(src, Point2i(0, y), Point2i(src.cols, y), Scalar::all(0), 1);451for (x = cell_size; x < src.cols; x += cell_size)452line(src, Point2i(x, 0), Point2i(x, src.rows), Scalar::all(0), 1);453}454455// generating an interpolation type456interpolation = rng.uniform(0, cv::INTER_MAX - 1);457458// generating the dst matrix structure459if (interpolation == INTER_AREA)460{461area_fast = rng.uniform(0., 1.) > 0.5;462if (area_fast)463{464scale_x = rng.uniform(2, 5);465scale_y = rng.uniform(2, 5);466}467else468{469scale_x = rng.uniform(1.0, 3.0);470scale_y = rng.uniform(1.0, 3.0);471}472}473else474{475scale_x = rng.uniform(0.4, 4.0);476scale_y = rng.uniform(0.4, 4.0);477}478CV_Assert(scale_x > 0.0f && scale_y > 0.0f);479480dsize.width = saturate_cast<int>((ssize.width + scale_x - 1) / scale_x);481dsize.height = saturate_cast<int>((ssize.height + scale_y - 1) / scale_y);482483dst = Mat::zeros(dsize, src.type());484reference_dst = Mat::zeros(dst.size(), CV_MAKE_TYPE(CV_32F, dst.channels()));485486scale_x = src.cols / static_cast<double>(dst.cols);487scale_y = src.rows / static_cast<double>(dst.rows);488489if (interpolation == INTER_AREA && (scale_x < 1.0 || scale_y < 1.0))490interpolation = INTER_LINEAR_EXACT;491if (interpolation == INTER_LINEAR_EXACT && (depth == CV_32F || depth == CV_64F))492interpolation = INTER_LINEAR;493494area_fast = interpolation == INTER_AREA &&495fabs(scale_x - cvRound(scale_x)) < FLT_EPSILON &&496fabs(scale_y - cvRound(scale_y)) < FLT_EPSILON;497if (area_fast)498{499scale_x = cvRound(scale_x);500scale_y = cvRound(scale_y);501}502}503504void CV_Resize_Test::run_func()505{506cv::resize(src, dst, dst.size(), 0, 0, interpolation);507}508509void CV_Resize_Test::run_reference_func()510{511CV_ImageWarpBaseTest::prepare_test_data_for_reference_func();512513if (interpolation == INTER_AREA)514resize_area();515else516resize_generic();517}518519double CV_Resize_Test::getWeight(double a, double b, int x)520{521double w = std::min(static_cast<double>(x + 1), b) - std::max(static_cast<double>(x), a);522CV_Assert(w >= 0);523return w;524}525526void CV_Resize_Test::resize_area()527{528Size ssize = src.size(), dsize = reference_dst.size();529CV_Assert(!ssize.empty() && !dsize.empty());530int cn = src.channels();531532CV_Assert(scale_x >= 1.0 && scale_y >= 1.0);533534double fsy0 = 0, fsy1 = scale_y;535for (int dy = 0; dy < dsize.height; ++dy)536{537float* yD = reference_dst.ptr<float>(dy);538int isy0 = cvFloor(fsy0), isy1 = std::min(cvFloor(fsy1), ssize.height - 1);539CV_Assert(isy1 <= ssize.height && isy0 < ssize.height);540541double fsx0 = 0, fsx1 = scale_x;542543for (int dx = 0; dx < dsize.width; ++dx)544{545float* xyD = yD + cn * dx;546int isx0 = cvFloor(fsx0), isx1 = std::min(ssize.width - 1, cvFloor(fsx1));547548CV_Assert(isx1 <= ssize.width);549CV_Assert(isx0 < ssize.width);550551// for each pixel of dst552for (int r = 0; r < cn; ++r)553{554xyD[r] = 0.0f;555double area = 0.0;556for (int sy = isy0; sy <= isy1; ++sy)557{558const float* yS = src.ptr<float>(sy);559for (int sx = isx0; sx <= isx1; ++sx)560{561double wy = getWeight(fsy0, fsy1, sy);562double wx = getWeight(fsx0, fsx1, sx);563double w = wx * wy;564xyD[r] += static_cast<float>(yS[sx * cn + r] * w);565area += w;566}567}568569CV_Assert(area != 0);570// norming pixel571xyD[r] = static_cast<float>(xyD[r] / area);572}573fsx1 = std::min((fsx0 = fsx1) + scale_x, static_cast<double>(ssize.width));574}575fsy1 = std::min((fsy0 = fsy1) + scale_y, static_cast<double>(ssize.height));576}577}578579// for interpolation type : INTER_LINEAR, INTER_LINEAR_EXACT, INTER_CUBIC, INTER_LANCZOS4580void CV_Resize_Test::resize_1d(const Mat& _src, Mat& _dst, int dy, const dim& _dim)581{582Size dsize = _dst.size();583int cn = _dst.channels();584float* yD = _dst.ptr<float>(dy);585586if (interpolation == INTER_NEAREST)587{588const float* yS = _src.ptr<float>(dy);589for (int dx = 0; dx < dsize.width; ++dx)590{591int isx = _dim[dx].first;592const float* xyS = yS + isx * cn;593float* xyD = yD + dx * cn;594595for (int r = 0; r < cn; ++r)596xyD[r] = xyS[r];597}598}599else if (interpolation == INTER_LINEAR || interpolation == INTER_LINEAR_EXACT || interpolation == INTER_CUBIC || interpolation == INTER_LANCZOS4)600{601interpolate_method inter_func = inter_array[interpolation - (interpolation == INTER_LANCZOS4 ? 2 : interpolation == INTER_LINEAR_EXACT ? 5 : 1)];602size_t elemsize = _src.elemSize();603604int ofs = 0, ksize = 2;605if (interpolation == INTER_CUBIC)606ofs = 1, ksize = 4;607else if (interpolation == INTER_LANCZOS4)608ofs = 3, ksize = 8;609610Mat _extended_src_row(1, _src.cols + ksize * 2, _src.type());611const uchar* srow = _src.ptr(dy);612memcpy(_extended_src_row.ptr() + elemsize * ksize, srow, _src.step);613for (int k = 0; k < ksize; ++k)614{615memcpy(_extended_src_row.ptr() + k * elemsize, srow, elemsize);616memcpy(_extended_src_row.ptr() + (ksize + k) * elemsize + _src.step, srow + _src.step - elemsize, elemsize);617}618619for (int dx = 0; dx < dsize.width; ++dx)620{621int isx = _dim[dx].first;622double fsx = _dim[dx].second;623624float *xyD = yD + dx * cn;625const float* xyS = _extended_src_row.ptr<float>(0) + (isx + ksize - ofs) * cn;626627float w[8];628inter_func(static_cast<float>(fsx), w);629630for (int r = 0; r < cn; ++r)631{632xyD[r] = 0;633for (int k = 0; k < ksize; ++k)634xyD[r] += w[k] * xyS[k * cn + r];635}636}637}638else639CV_Assert(0);640}641642void CV_Resize_Test::generate_buffer(double scale, dim& _dim)643{644size_t length = _dim.size();645for (size_t dx = 0; dx < length; ++dx)646{647double fsx = scale * (dx + 0.5) - 0.5;648int isx = cvFloor(fsx);649_dim[dx] = std::make_pair(isx, fsx - isx);650}651}652653void CV_Resize_Test::resize_generic()654{655Size dsize = reference_dst.size(), ssize = src.size();656CV_Assert(!dsize.empty() && !ssize.empty());657658dim dims[] = { dim(dsize.width), dim(dsize.height) };659if (interpolation == INTER_NEAREST)660{661for (int dx = 0; dx < dsize.width; ++dx)662dims[0][dx].first = std::min(cvFloor(dx * scale_x), ssize.width - 1);663for (int dy = 0; dy < dsize.height; ++dy)664dims[1][dy].first = std::min(cvFloor(dy * scale_y), ssize.height - 1);665}666else667{668generate_buffer(scale_x, dims[0]);669generate_buffer(scale_y, dims[1]);670}671672Mat tmp(ssize.height, dsize.width, reference_dst.type());673for (int dy = 0; dy < tmp.rows; ++dy)674resize_1d(src, tmp, dy, dims[0]);675676cv::Mat tmp_t(tmp.cols, tmp.rows, tmp.type());677cvtest::transpose(tmp, tmp_t);678cv::Mat reference_dst_t(reference_dst.cols, reference_dst.rows, reference_dst.type());679cvtest::transpose(reference_dst, reference_dst_t);680681for (int dy = 0; dy < tmp_t.rows; ++dy)682resize_1d(tmp_t, reference_dst_t, dy, dims[1]);683684cvtest::transpose(reference_dst_t, reference_dst);685}686687////////////////////////////////////////////////////////////////////////////////////////////////////////688// remap689////////////////////////////////////////////////////////////////////////////////////////////////////////690691class CV_Remap_Test :692public CV_ImageWarpBaseTest693{694public:695CV_Remap_Test();696697virtual ~CV_Remap_Test();698699private:700typedef void (CV_Remap_Test::*remap_func)(const Mat&, Mat&);701702protected:703virtual void generate_test_data();704virtual void prepare_test_data_for_reference_func();705706virtual void run_func();707virtual void run_reference_func();708709Mat mapx, mapy;710int borderType;711Scalar borderValue;712713remap_func funcs[2];714715private:716void remap_nearest(const Mat&, Mat&);717void remap_generic(const Mat&, Mat&);718719void convert_maps();720const char* borderType_to_string() const;721virtual void validate_results() const;722};723724CV_Remap_Test::CV_Remap_Test() :725CV_ImageWarpBaseTest(), borderType(-1)726{727funcs[0] = &CV_Remap_Test::remap_nearest;728funcs[1] = &CV_Remap_Test::remap_generic;729}730731CV_Remap_Test::~CV_Remap_Test()732{733}734735void CV_Remap_Test::generate_test_data()736{737CV_ImageWarpBaseTest::generate_test_data();738739RNG& rng = ts->get_rng();740borderType = rng.uniform(1, BORDER_WRAP);741borderValue = Scalar::all(rng.uniform(0, 255));742743// generating the mapx, mapy matrices744static const int mapx_types[] = { CV_16SC2, CV_32FC1, CV_32FC2 };745mapx.create(dst.size(), mapx_types[rng.uniform(0, sizeof(mapx_types) / sizeof(int))]);746mapy.release();747748const int n = std::min(std::min(src.cols, src.rows) / 10 + 1, 2);749float _n = 0; //static_cast<float>(-n);750751switch (mapx.type())752{753case CV_16SC2:754{755MatIterator_<Vec2s> begin_x = mapx.begin<Vec2s>(), end_x = mapx.end<Vec2s>();756for ( ; begin_x != end_x; ++begin_x)757{758(*begin_x)[0] = static_cast<short>(rng.uniform(static_cast<int>(_n), std::max(src.cols + n - 1, 0)));759(*begin_x)[1] = static_cast<short>(rng.uniform(static_cast<int>(_n), std::max(src.rows + n - 1, 0)));760}761762if (interpolation != INTER_NEAREST)763{764static const int mapy_types[] = { CV_16UC1, CV_16SC1 };765mapy.create(dst.size(), mapy_types[rng.uniform(0, sizeof(mapy_types) / sizeof(int))]);766767switch (mapy.type())768{769case CV_16UC1:770{771MatIterator_<ushort> begin_y = mapy.begin<ushort>(), end_y = mapy.end<ushort>();772for ( ; begin_y != end_y; ++begin_y)773*begin_y = static_cast<ushort>(rng.uniform(0, 1024));774}775break;776777case CV_16SC1:778{779MatIterator_<short> begin_y = mapy.begin<short>(), end_y = mapy.end<short>();780for ( ; begin_y != end_y; ++begin_y)781*begin_y = static_cast<short>(rng.uniform(0, 1024));782}783break;784}785}786}787break;788789case CV_32FC1:790{791mapy.create(dst.size(), CV_32FC1);792float fscols = static_cast<float>(std::max(src.cols - 1 + n, 0)),793fsrows = static_cast<float>(std::max(src.rows - 1 + n, 0));794MatIterator_<float> begin_x = mapx.begin<float>(), end_x = mapx.end<float>();795MatIterator_<float> begin_y = mapy.begin<float>();796for ( ; begin_x != end_x; ++begin_x, ++begin_y)797{798*begin_x = rng.uniform(_n, fscols);799*begin_y = rng.uniform(_n, fsrows);800}801}802break;803804case CV_32FC2:805{806float fscols = static_cast<float>(std::max(src.cols - 1 + n, 0)),807fsrows = static_cast<float>(std::max(src.rows - 1 + n, 0));808int width = mapx.cols << 1;809810for (int y = 0; y < mapx.rows; ++y)811{812float * ptr = mapx.ptr<float>(y);813814for (int x = 0; x < width; x += 2)815{816ptr[x] = rng.uniform(_n, fscols);817ptr[x + 1] = rng.uniform(_n, fsrows);818}819}820}821break;822823default:824CV_Assert(0);825break;826}827}828829void CV_Remap_Test::run_func()830{831remap(src, dst, mapx, mapy, interpolation, borderType, borderValue);832}833834void CV_Remap_Test::convert_maps()835{836if (mapx.type() != CV_16SC2)837convertMaps(mapx.clone(), mapy.clone(), mapx, mapy, CV_16SC2, interpolation == INTER_NEAREST);838else if (interpolation != INTER_NEAREST)839if (mapy.type() != CV_16UC1)840mapy.clone().convertTo(mapy, CV_16UC1);841842if (interpolation == INTER_NEAREST)843mapy = Mat();844CV_Assert(((interpolation == INTER_NEAREST && mapy.empty()) || mapy.type() == CV_16UC1 ||845mapy.type() == CV_16SC1) && mapx.type() == CV_16SC2);846}847848const char* CV_Remap_Test::borderType_to_string() const849{850if (borderType == BORDER_CONSTANT)851return "BORDER_CONSTANT";852if (borderType == BORDER_REPLICATE)853return "BORDER_REPLICATE";854if (borderType == BORDER_REFLECT)855return "BORDER_REFLECT";856if (borderType == BORDER_WRAP)857return "BORDER_WRAP";858if (borderType == BORDER_REFLECT_101)859return "BORDER_REFLECT_101";860return "Unsupported/Unknown border type";861}862863void CV_Remap_Test::prepare_test_data_for_reference_func()864{865CV_ImageWarpBaseTest::prepare_test_data_for_reference_func();866convert_maps();867}868869void CV_Remap_Test::run_reference_func()870{871prepare_test_data_for_reference_func();872873if (interpolation == INTER_AREA)874interpolation = INTER_LINEAR;875876int index = interpolation == INTER_NEAREST ? 0 : 1;877(this->*funcs[index])(src, reference_dst);878}879880void CV_Remap_Test::remap_nearest(const Mat& _src, Mat& _dst)881{882CV_Assert(_src.depth() == CV_32F && _dst.type() == _src.type());883CV_Assert(mapx.type() == CV_16SC2 && mapy.empty());884885Size ssize = _src.size(), dsize = _dst.size();886CV_Assert(!ssize.empty() && !dsize.empty());887int cn = _src.channels();888889for (int dy = 0; dy < dsize.height; ++dy)890{891const short* yM = mapx.ptr<short>(dy);892float* yD = _dst.ptr<float>(dy);893894for (int dx = 0; dx < dsize.width; ++dx)895{896float* xyD = yD + cn * dx;897int sx = yM[dx * 2], sy = yM[dx * 2 + 1];898899if (sx >= 0 && sx < ssize.width && sy >= 0 && sy < ssize.height)900{901const float *xyS = _src.ptr<float>(sy) + sx * cn;902903for (int r = 0; r < cn; ++r)904xyD[r] = xyS[r];905}906else if (borderType != BORDER_TRANSPARENT)907{908if (borderType == BORDER_CONSTANT)909for (int r = 0; r < cn; ++r)910xyD[r] = saturate_cast<float>(borderValue[r]);911else912{913sx = borderInterpolate(sx, ssize.width, borderType);914sy = borderInterpolate(sy, ssize.height, borderType);915CV_Assert(sx >= 0 && sy >= 0 && sx < ssize.width && sy < ssize.height);916917const float *xyS = _src.ptr<float>(sy) + sx * cn;918919for (int r = 0; r < cn; ++r)920xyD[r] = xyS[r];921}922}923}924}925}926927void CV_Remap_Test::remap_generic(const Mat& _src, Mat& _dst)928{929CV_Assert(mapx.type() == CV_16SC2 && mapy.type() == CV_16UC1);930931int ksize = 2;932if (interpolation == INTER_CUBIC)933ksize = 4;934else if (interpolation == INTER_LANCZOS4)935ksize = 8;936else if (interpolation != INTER_LINEAR)937assert(0);938int ofs = (ksize / 2) - 1;939940CV_Assert(_src.depth() == CV_32F && _dst.type() == _src.type());941Size ssize = _src.size(), dsize = _dst.size();942int cn = _src.channels(), width1 = std::max(ssize.width - ksize + 1, 0),943height1 = std::max(ssize.height - ksize + 1, 0);944945float ix[8], w[16];946interpolate_method inter_func = inter_array[interpolation - (interpolation == INTER_LANCZOS4 ? 2 : 1)];947948for (int dy = 0; dy < dsize.height; ++dy)949{950const short* yMx = mapx.ptr<short>(dy);951const ushort* yMy = mapy.ptr<ushort>(dy);952953float* yD = _dst.ptr<float>(dy);954955for (int dx = 0; dx < dsize.width; ++dx)956{957float* xyD = yD + dx * cn;958float sx = yMx[dx * 2], sy = yMx[dx * 2 + 1];959int isx = cvFloor(sx), isy = cvFloor(sy);960961inter_func((yMy[dx] & (INTER_TAB_SIZE - 1)) / static_cast<float>(INTER_TAB_SIZE), w);962inter_func(((yMy[dx] >> INTER_BITS) & (INTER_TAB_SIZE - 1)) / static_cast<float>(INTER_TAB_SIZE), w + ksize);963964isx -= ofs;965isy -= ofs;966967if (isx >= 0 && isx < width1 && isy >= 0 && isy < height1)968{969for (int r = 0; r < cn; ++r)970{971for (int y = 0; y < ksize; ++y)972{973const float* xyS = _src.ptr<float>(isy + y) + isx * cn;974975ix[y] = 0;976for (int i = 0; i < ksize; ++i)977ix[y] += w[i] * xyS[i * cn + r];978}979xyD[r] = 0;980for (int i = 0; i < ksize; ++i)981xyD[r] += w[ksize + i] * ix[i];982}983}984else if (borderType != BORDER_TRANSPARENT)985{986int ar_x[8], ar_y[8];987988for (int k = 0; k < ksize; k++)989{990ar_x[k] = borderInterpolate(isx + k, ssize.width, borderType) * cn;991ar_y[k] = borderInterpolate(isy + k, ssize.height, borderType);992}993994for (int r = 0; r < cn; r++)995{996xyD[r] = 0;997for (int i = 0; i < ksize; ++i)998{999ix[i] = 0;1000if (ar_y[i] >= 0)1001{1002const float* yS = _src.ptr<float>(ar_y[i]);1003for (int j = 0; j < ksize; ++j)1004ix[i] += saturate_cast<float>((ar_x[j] >= 0 ? yS[ar_x[j] + r] : borderValue[r]) * w[j]);1005}1006else1007for (int j = 0; j < ksize; ++j)1008ix[i] += saturate_cast<float>(borderValue[r] * w[j]);1009}1010for (int i = 0; i < ksize; ++i)1011xyD[r] += saturate_cast<float>(w[ksize + i] * ix[i]);1012}1013}1014}1015}1016}10171018void CV_Remap_Test::validate_results() const1019{1020CV_ImageWarpBaseTest::validate_results();1021if (cvtest::TS::ptr()->get_err_code() == cvtest::TS::FAIL_BAD_ACCURACY)1022{1023PRINT_TO_LOG("BorderType: %s\n", borderType_to_string());1024PRINT_TO_LOG("BorderValue: (%f, %f, %f, %f)\n",1025borderValue[0], borderValue[1], borderValue[2], borderValue[3]);1026}1027}10281029////////////////////////////////////////////////////////////////////////////////////////////////////////1030// warpAffine1031////////////////////////////////////////////////////////////////////////////////////////////////////////10321033class CV_WarpAffine_Test :1034public CV_Remap_Test1035{1036public:1037CV_WarpAffine_Test();10381039virtual ~CV_WarpAffine_Test();10401041protected:1042virtual void generate_test_data();1043virtual float get_success_error_level(int _interpolation, int _depth) const;10441045virtual void run_func();1046virtual void run_reference_func();10471048Mat M;1049private:1050void warpAffine(const Mat&, Mat&);1051};10521053CV_WarpAffine_Test::CV_WarpAffine_Test() :1054CV_Remap_Test()1055{1056}10571058CV_WarpAffine_Test::~CV_WarpAffine_Test()1059{1060}10611062void CV_WarpAffine_Test::generate_test_data()1063{1064CV_Remap_Test::generate_test_data();10651066RNG& rng = ts->get_rng();10671068// generating the M 2x3 matrix1069static const int depths[] = { CV_32FC1, CV_64FC1 };10701071// generating 2d matrix1072M = getRotationMatrix2D(Point2f(src.cols / 2.f, src.rows / 2.f),1073rng.uniform(-180.f, 180.f), rng.uniform(0.4f, 2.0f));1074int depth = depths[rng.uniform(0, sizeof(depths) / sizeof(depths[0]))];1075if (M.depth() != depth)1076{1077Mat tmp;1078M.convertTo(tmp, depth);1079M = tmp;1080}10811082// warp_matrix is inverse1083if (rng.uniform(0., 1.) > 0)1084interpolation |= CV_WARP_INVERSE_MAP;1085}10861087void CV_WarpAffine_Test::run_func()1088{1089cv::warpAffine(src, dst, M, dst.size(), interpolation, borderType, borderValue);1090}10911092float CV_WarpAffine_Test::get_success_error_level(int _interpolation, int _depth) const1093{1094return _depth == CV_8U ? 0 : CV_ImageWarpBaseTest::get_success_error_level(_interpolation, _depth);1095}10961097void CV_WarpAffine_Test::run_reference_func()1098{1099Mat tmp = Mat::zeros(dst.size(), dst.type());1100warpAffine(src, tmp);1101tmp.convertTo(reference_dst, reference_dst.depth());1102}11031104void CV_WarpAffine_Test::warpAffine(const Mat& _src, Mat& _dst)1105{1106Size dsize = _dst.size();11071108CV_Assert(!_src.empty());1109CV_Assert(!dsize.empty());1110CV_Assert(_src.type() == _dst.type());11111112Mat tM;1113M.convertTo(tM, CV_64F);11141115int inter = interpolation & INTER_MAX;1116if (inter == INTER_AREA)1117inter = INTER_LINEAR;11181119mapx.create(dsize, CV_16SC2);1120if (inter != INTER_NEAREST)1121mapy.create(dsize, CV_16SC1);1122else1123mapy = Mat();11241125if (!(interpolation & CV_WARP_INVERSE_MAP))1126invertAffineTransform(tM.clone(), tM);11271128const int AB_BITS = MAX(10, (int)INTER_BITS);1129const int AB_SCALE = 1 << AB_BITS;1130int round_delta = (inter == INTER_NEAREST) ? AB_SCALE / 2 : (AB_SCALE / INTER_TAB_SIZE / 2);11311132const softdouble* data_tM = tM.ptr<softdouble>(0);1133for (int dy = 0; dy < dsize.height; ++dy)1134{1135short* yM = mapx.ptr<short>(dy);1136for (int dx = 0; dx < dsize.width; ++dx, yM += 2)1137{1138int v1 = saturate_cast<int>(saturate_cast<int>(data_tM[0] * dx * AB_SCALE) +1139saturate_cast<int>((data_tM[1] * dy + data_tM[2]) * AB_SCALE) + round_delta),1140v2 = saturate_cast<int>(saturate_cast<int>(data_tM[3] * dx * AB_SCALE) +1141saturate_cast<int>((data_tM[4] * dy + data_tM[5]) * AB_SCALE) + round_delta);1142v1 >>= AB_BITS - INTER_BITS;1143v2 >>= AB_BITS - INTER_BITS;11441145yM[0] = saturate_cast<short>(v1 >> INTER_BITS);1146yM[1] = saturate_cast<short>(v2 >> INTER_BITS);11471148if (inter != INTER_NEAREST)1149mapy.ptr<short>(dy)[dx] = ((v2 & (INTER_TAB_SIZE - 1)) * INTER_TAB_SIZE + (v1 & (INTER_TAB_SIZE - 1)));1150}1151}11521153CV_Assert(mapx.type() == CV_16SC2 && ((inter == INTER_NEAREST && mapy.empty()) || mapy.type() == CV_16SC1));1154cv::remap(_src, _dst, mapx, mapy, inter, borderType, borderValue);1155}11561157////////////////////////////////////////////////////////////////////////////////////////////////////////1158// warpPerspective1159////////////////////////////////////////////////////////////////////////////////////////////////////////11601161class CV_WarpPerspective_Test :1162public CV_WarpAffine_Test1163{1164public:1165CV_WarpPerspective_Test();11661167virtual ~CV_WarpPerspective_Test();11681169protected:1170virtual void generate_test_data();1171virtual float get_success_error_level(int _interpolation, int _depth) const;11721173virtual void run_func();1174virtual void run_reference_func();11751176private:1177void warpPerspective(const Mat&, Mat&);1178};11791180CV_WarpPerspective_Test::CV_WarpPerspective_Test() :1181CV_WarpAffine_Test()1182{1183}11841185CV_WarpPerspective_Test::~CV_WarpPerspective_Test()1186{1187}11881189void CV_WarpPerspective_Test::generate_test_data()1190{1191CV_Remap_Test::generate_test_data();11921193// generating the M 3x3 matrix1194RNG& rng = ts->get_rng();11951196float cols = static_cast<float>(src.cols), rows = static_cast<float>(src.rows);1197Point2f sp[] = { Point2f(0.0f, 0.0f), Point2f(cols, 0.0f), Point2f(0.0f, rows), Point2f(cols, rows) };1198Point2f dp[] = { Point2f(rng.uniform(0.0f, cols), rng.uniform(0.0f, rows)),1199Point2f(rng.uniform(0.0f, cols), rng.uniform(0.0f, rows)),1200Point2f(rng.uniform(0.0f, cols), rng.uniform(0.0f, rows)),1201Point2f(rng.uniform(0.0f, cols), rng.uniform(0.0f, rows)) };1202M = getPerspectiveTransform(sp, dp);12031204static const int depths[] = { CV_32F, CV_64F };1205int depth = depths[rng.uniform(0, 2)];1206M.clone().convertTo(M, depth);1207}12081209void CV_WarpPerspective_Test::run_func()1210{1211cv::warpPerspective(src, dst, M, dst.size(), interpolation, borderType, borderValue);1212}12131214float CV_WarpPerspective_Test::get_success_error_level(int _interpolation, int _depth) const1215{1216return CV_ImageWarpBaseTest::get_success_error_level(_interpolation, _depth);1217}12181219void CV_WarpPerspective_Test::run_reference_func()1220{1221Mat tmp = Mat::zeros(dst.size(), dst.type());1222warpPerspective(src, tmp);1223tmp.convertTo(reference_dst, reference_dst.depth());1224}12251226void CV_WarpPerspective_Test::warpPerspective(const Mat& _src, Mat& _dst)1227{1228Size ssize = _src.size(), dsize = _dst.size();12291230CV_Assert(!ssize.empty());1231CV_Assert(!dsize.empty());1232CV_Assert(_src.type() == _dst.type());12331234if (M.depth() != CV_64F)1235{1236Mat tmp;1237M.convertTo(tmp, CV_64F);1238M = tmp;1239}12401241if (!(interpolation & CV_WARP_INVERSE_MAP))1242{1243Mat tmp;1244invert(M, tmp);1245M = tmp;1246}12471248int inter = interpolation & INTER_MAX;1249if (inter == INTER_AREA)1250inter = INTER_LINEAR;12511252mapx.create(dsize, CV_16SC2);1253if (inter != INTER_NEAREST)1254mapy.create(dsize, CV_16SC1);1255else1256mapy = Mat();12571258double* tM = M.ptr<double>(0);1259for (int dy = 0; dy < dsize.height; ++dy)1260{1261short* yMx = mapx.ptr<short>(dy);12621263for (int dx = 0; dx < dsize.width; ++dx, yMx += 2)1264{1265double den = tM[6] * dx + tM[7] * dy + tM[8];1266den = den ? 1.0 / den : 0.0;12671268if (inter == INTER_NEAREST)1269{1270yMx[0] = saturate_cast<short>((tM[0] * dx + tM[1] * dy + tM[2]) * den);1271yMx[1] = saturate_cast<short>((tM[3] * dx + tM[4] * dy + tM[5]) * den);1272continue;1273}12741275den *= INTER_TAB_SIZE;1276int v0 = saturate_cast<int>((tM[0] * dx + tM[1] * dy + tM[2]) * den);1277int v1 = saturate_cast<int>((tM[3] * dx + tM[4] * dy + tM[5]) * den);12781279yMx[0] = saturate_cast<short>(v0 >> INTER_BITS);1280yMx[1] = saturate_cast<short>(v1 >> INTER_BITS);1281mapy.ptr<short>(dy)[dx] = saturate_cast<short>((v1 & (INTER_TAB_SIZE - 1)) *1282INTER_TAB_SIZE + (v0 & (INTER_TAB_SIZE - 1)));1283}1284}12851286CV_Assert(mapx.type() == CV_16SC2 && ((inter == INTER_NEAREST && mapy.empty()) || mapy.type() == CV_16SC1));1287cv::remap(_src, _dst, mapx, mapy, inter, borderType, borderValue);1288}12891290////////////////////////////////////////////////////////////////////////////////////////////////////////1291// Tests1292////////////////////////////////////////////////////////////////////////////////////////////////////////12931294TEST(Imgproc_Resize_Test, accuracy) { CV_Resize_Test test; test.safe_run(); }1295TEST(Imgproc_Remap_Test, accuracy) { CV_Remap_Test test; test.safe_run(); }1296TEST(Imgproc_WarpAffine_Test, accuracy) { CV_WarpAffine_Test test; test.safe_run(); }1297TEST(Imgproc_WarpPerspective_Test, accuracy) { CV_WarpPerspective_Test test; test.safe_run(); }12981299////////////////////////////////////////////////////////////////////////////////////////////////////////13001301#ifdef OPENCV_TEST_BIGDATA13021303CV_ENUM(Interpolation, INTER_NEAREST, INTER_LINEAR, INTER_LINEAR_EXACT, INTER_CUBIC, INTER_AREA)13041305class Imgproc_Resize :1306public ::testing::TestWithParam<Interpolation>1307{1308public:1309virtual void SetUp()1310{1311inter = GetParam();1312}13131314protected:1315int inter;1316};13171318TEST_P(Imgproc_Resize, BigSize)1319{1320cv::Mat src(46342, 46342, CV_8UC3, cv::Scalar::all(10)), dst;1321ASSERT_FALSE(src.empty());13221323ASSERT_NO_THROW(cv::resize(src, dst, cv::Size(), 0.5, 0.5, inter));1324}13251326INSTANTIATE_TEST_CASE_P(Imgproc, Imgproc_Resize, Interpolation::all());13271328#endif13291330}} // namespace133113321333