Home | History | Annotate | Download | only in test
      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 //                        Intel License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
     14 // Third party copyrights are property of their respective owners.
     15 //
     16 // Redistribution and use in source and binary forms, with or without modification,
     17 // are permitted provided that the following conditions are met:
     18 //
     19 //   * Redistribution's of source code must retain the above copyright notice,
     20 //     this list of conditions and the following disclaimer.
     21 //
     22 //   * Redistribution's in binary form must reproduce the above copyright notice,
     23 //     this list of conditions and the following disclaimer in the documentation
     24 //     and/or other materials provided with the distribution.
     25 //
     26 //   * The name of Intel Corporation may not be used to endorse or promote products
     27 //     derived from this software without specific prior written permission.
     28 //
     29 // This software is provided by the copyright holders and contributors "as is" and
     30 // any express or implied warranties, including, but not limited to, the implied
     31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     32 // In no event shall the Intel Corporation or contributors be liable for any direct,
     33 // indirect, incidental, special, exemplary, or consequential damages
     34 // (including, but not limited to, procurement of substitute goods or services;
     35 // loss of use, data, or profits; or business interruption) however caused
     36 // and on any theory of liability, whether in contract, strict liability,
     37 // or tort (including negligence or otherwise) arising in any way out of
     38 // the use of this software, even if advised of the possibility of such damage.
     39 //
     40 //M*/
     41 
     42 #include "test_precomp.hpp"
     43 
     44 #include <cmath>
     45 #include <vector>
     46 #include <iostream>
     47 
     48 using namespace cv;
     49 
     50 namespace
     51 {
     52     void __wrap_printf_func(const char* fmt, ...)
     53     {
     54         va_list args;
     55         va_start(args, fmt);
     56         char buffer[256];
     57         vsprintf (buffer, fmt, args);
     58         cvtest::TS::ptr()->printf(cvtest::TS::SUMMARY, buffer);
     59         va_end(args);
     60     }
     61 
     62     #define PRINT_TO_LOG __wrap_printf_func
     63 }
     64 
     65 #define SHOW_IMAGE
     66 #undef SHOW_IMAGE
     67 
     68 ////////////////////////////////////////////////////////////////////////////////////////////////////////
     69 // ImageWarpBaseTest
     70 ////////////////////////////////////////////////////////////////////////////////////////////////////////
     71 
     72 class CV_ImageWarpBaseTest :
     73     public cvtest::BaseTest
     74 {
     75 public:
     76     enum { cell_size = 10 };
     77 
     78     CV_ImageWarpBaseTest();
     79     virtual ~CV_ImageWarpBaseTest();
     80 
     81     virtual void run(int);
     82 protected:
     83     virtual void generate_test_data();
     84 
     85     virtual void run_func() = 0;
     86     virtual void run_reference_func() = 0;
     87     virtual void validate_results() const;
     88     virtual void prepare_test_data_for_reference_func();
     89 
     90     Size randSize(RNG& rng) const;
     91 
     92     String interpolation_to_string(int inter_type) const;
     93 
     94     int interpolation;
     95     Mat src;
     96     Mat dst;
     97     Mat reference_dst;
     98 };
     99 
    100 CV_ImageWarpBaseTest::CV_ImageWarpBaseTest() :
    101     BaseTest(), interpolation(-1),
    102     src(), dst(), reference_dst()
    103 {
    104     test_case_count = 40;
    105     ts->set_failed_test_info(cvtest::TS::OK);
    106 }
    107 
    108 CV_ImageWarpBaseTest::~CV_ImageWarpBaseTest()
    109 {
    110 }
    111 
    112 String CV_ImageWarpBaseTest::interpolation_to_string(int inter) const
    113 {
    114     bool inverse = (inter & WARP_INVERSE_MAP) != 0;
    115     inter &= ~WARP_INVERSE_MAP;
    116     String str;
    117 
    118     if (inter == INTER_NEAREST)
    119         str = "INTER_NEAREST";
    120     else if (inter == INTER_LINEAR)
    121         str = "INTER_LINEAR";
    122     else if (inter == INTER_AREA)
    123         str = "INTER_AREA";
    124     else if (inter == INTER_CUBIC)
    125         str = "INTER_CUBIC";
    126     else if (inter == INTER_LANCZOS4)
    127         str = "INTER_LANCZOS4";
    128     else if (inter == INTER_LANCZOS4 + 1)
    129         str = "INTER_AREA_FAST";
    130 
    131     if (inverse)
    132         str += " | WARP_INVERSE_MAP";
    133 
    134     return str.empty() ? "Unsupported/Unkown interpolation type" : str;
    135 }
    136 
    137 Size CV_ImageWarpBaseTest::randSize(RNG& rng) const
    138 {
    139     Size size;
    140     size.width = static_cast<int>(std::exp(rng.uniform(1.0f, 7.0f)));
    141     size.height = static_cast<int>(std::exp(rng.uniform(1.0f, 7.0f)));
    142 
    143     return size;
    144 }
    145 
    146 void CV_ImageWarpBaseTest::generate_test_data()
    147 {
    148     RNG& rng = ts->get_rng();
    149 
    150     // generating the src matrix structure
    151     Size ssize = randSize(rng), dsize;
    152 
    153     int depth = rng.uniform(0, CV_64F);
    154     while (depth == CV_8S || depth == CV_32S)
    155         depth = rng.uniform(0, CV_64F);
    156 
    157     int cn = rng.uniform(1, 4);
    158     while (cn == 2)
    159         cn = rng.uniform(1, 4);
    160 
    161     src.create(ssize, CV_MAKE_TYPE(depth, cn));
    162 
    163     // generating the src matrix
    164     int x, y;
    165     if (cvtest::randInt(rng) % 2)
    166     {
    167         for (y = 0; y < ssize.height; y += cell_size)
    168             for (x = 0; x < ssize.width; x += cell_size)
    169                 rectangle(src, Point(x, y), Point(x + std::min<int>(cell_size, ssize.width - x), y +
    170                         std::min<int>(cell_size, ssize.height - y)), Scalar::all((x + y) % 2 ? 255: 0), CV_FILLED);
    171     }
    172     else
    173     {
    174         src = Scalar::all(255);
    175         for (y = cell_size; y < src.rows; y += cell_size)
    176             line(src, Point2i(0, y), Point2i(src.cols, y), Scalar::all(0), 1);
    177         for (x = cell_size; x < src.cols; x += cell_size)
    178             line(src, Point2i(x, 0), Point2i(x, src.rows), Scalar::all(0), 1);
    179     }
    180 
    181     // generating an interpolation type
    182     interpolation = rng.uniform(0, CV_INTER_LANCZOS4 + 1);
    183 
    184     // generating the dst matrix structure
    185     double scale_x, scale_y;
    186     if (interpolation == INTER_AREA)
    187     {
    188         bool area_fast = rng.uniform(0., 1.) > 0.5;
    189         if (area_fast)
    190         {
    191             scale_x = rng.uniform(2, 5);
    192             scale_y = rng.uniform(2, 5);
    193         }
    194         else
    195         {
    196             scale_x = rng.uniform(1.0, 3.0);
    197             scale_y = rng.uniform(1.0, 3.0);
    198         }
    199     }
    200     else
    201     {
    202         scale_x = rng.uniform(0.4, 4.0);
    203         scale_y = rng.uniform(0.4, 4.0);
    204     }
    205     CV_Assert(scale_x > 0.0f && scale_y > 0.0f);
    206 
    207     dsize.width = saturate_cast<int>((ssize.width + scale_x - 1) / scale_x);
    208     dsize.height = saturate_cast<int>((ssize.height + scale_y - 1) / scale_y);
    209 
    210     dst = Mat::zeros(dsize, src.type());
    211     reference_dst = Mat::zeros(dst.size(), CV_MAKE_TYPE(CV_32F, dst.channels()));
    212 
    213     scale_x = src.cols / static_cast<double>(dst.cols);
    214     scale_y = src.rows / static_cast<double>(dst.rows);
    215 
    216     if (interpolation == INTER_AREA && (scale_x < 1.0 || scale_y < 1.0))
    217         interpolation = INTER_LINEAR;
    218 }
    219 
    220 void CV_ImageWarpBaseTest::run(int)
    221 {
    222     for (int i = 0; i < test_case_count; ++i)
    223     {
    224         generate_test_data();
    225         run_func();
    226         run_reference_func();
    227         if (ts->get_err_code() < 0)
    228             break;
    229         validate_results();
    230         if (ts->get_err_code() < 0)
    231             break;
    232         ts->update_context(this, i, true);
    233     }
    234     ts->set_gtest_status();
    235 }
    236 
    237 void CV_ImageWarpBaseTest::validate_results() const
    238 {
    239     Mat _dst;
    240     dst.convertTo(_dst, reference_dst.depth());
    241 
    242     Size dsize = dst.size(), ssize = src.size();
    243     int cn = _dst.channels();
    244     dsize.width *= cn;
    245     float t = 1.0f;
    246     if (interpolation == INTER_CUBIC)
    247         t = 1.0f;
    248     else if (interpolation == INTER_LANCZOS4)
    249         t = 1.0f;
    250     else if (interpolation == INTER_NEAREST)
    251         t = 1.0f;
    252     else if (interpolation == INTER_AREA)
    253         t = 2.0f;
    254 
    255     for (int dy = 0; dy < dsize.height; ++dy)
    256     {
    257         const float* rD = reference_dst.ptr<float>(dy);
    258         const float* D = _dst.ptr<float>(dy);
    259 
    260         for (int dx = 0; dx < dsize.width; ++dx)
    261             if (fabs(rD[dx] - D[dx]) > t &&
    262 //                fabs(rD[dx] - D[dx]) < 250.0f &&
    263                 rD[dx] <= 255.0f && D[dx] <= 255.0f && rD[dx] >= 0.0f && D[dx] >= 0.0f)
    264             {
    265                 PRINT_TO_LOG("\nNorm of the difference: %lf\n", cvtest::norm(reference_dst, _dst, NORM_INF));
    266                 PRINT_TO_LOG("Error in (dx, dy): (%d, %d)\n", dx / cn + 1, dy + 1);
    267                 PRINT_TO_LOG("Tuple (rD, D): (%f, %f)\n", rD[dx], D[dx]);
    268                 PRINT_TO_LOG("Dsize: (%d, %d)\n", dsize.width / cn, dsize.height);
    269                 PRINT_TO_LOG("Ssize: (%d, %d)\n", src.cols, src.rows);
    270 
    271                 double scale_x = static_cast<double>(ssize.width) / dsize.width;
    272                 double scale_y = static_cast<double>(ssize.height) / dsize.height;
    273                 bool area_fast = interpolation == INTER_AREA &&
    274                     fabs(scale_x - cvRound(scale_x)) < FLT_EPSILON &&
    275                     fabs(scale_y - cvRound(scale_y)) < FLT_EPSILON;
    276                 if (area_fast)
    277                 {
    278                     scale_y = cvRound(scale_y);
    279                     scale_x = cvRound(scale_x);
    280                 }
    281 
    282                 PRINT_TO_LOG("Interpolation: %s\n", interpolation_to_string(area_fast ? INTER_LANCZOS4 + 1 : interpolation).c_str());
    283                 PRINT_TO_LOG("Scale (x, y): (%lf, %lf)\n", scale_x, scale_y);
    284                 PRINT_TO_LOG("Elemsize: %d\n", src.elemSize1());
    285                 PRINT_TO_LOG("Channels: %d\n", cn);
    286 
    287 #ifdef SHOW_IMAGE
    288                 const std::string w1("OpenCV impl (run func)"), w2("Reference func"), w3("Src image"), w4("Diff");
    289                 namedWindow(w1, CV_WINDOW_KEEPRATIO);
    290                 namedWindow(w2, CV_WINDOW_KEEPRATIO);
    291                 namedWindow(w3, CV_WINDOW_KEEPRATIO);
    292                 namedWindow(w4, CV_WINDOW_KEEPRATIO);
    293 
    294                 Mat diff;
    295                 absdiff(reference_dst, _dst, diff);
    296 
    297                 imshow(w1, dst);
    298                 imshow(w2, reference_dst);
    299                 imshow(w3, src);
    300                 imshow(w4, diff);
    301 
    302                 waitKey();
    303 #endif
    304 
    305                 const int radius = 3;
    306                 int rmin = MAX(dy - radius, 0), rmax = MIN(dy + radius, dsize.height);
    307                 int cmin = MAX(dx / cn - radius, 0), cmax = MIN(dx / cn + radius, dsize.width);
    308 
    309                 std::cout << "opencv result:\n" << dst(Range(rmin, rmax), Range(cmin, cmax)) << std::endl;
    310                 std::cout << "reference result:\n" << reference_dst(Range(rmin, rmax), Range(cmin, cmax)) << std::endl;
    311 
    312                 ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
    313                 return;
    314             }
    315     }
    316 }
    317 
    318 void CV_ImageWarpBaseTest::prepare_test_data_for_reference_func()
    319 {
    320     if (src.depth() != CV_32F)
    321     {
    322         Mat tmp;
    323         src.convertTo(tmp, CV_32F);
    324         src = tmp;
    325     }
    326 }
    327 
    328 ////////////////////////////////////////////////////////////////////////////////////////////////////////
    329 // Resize
    330 ////////////////////////////////////////////////////////////////////////////////////////////////////////
    331 
    332 class CV_Resize_Test :
    333     public CV_ImageWarpBaseTest
    334 {
    335 public:
    336     CV_Resize_Test();
    337     virtual ~CV_Resize_Test();
    338 
    339 protected:
    340     virtual void generate_test_data();
    341 
    342     virtual void run_func();
    343     virtual void run_reference_func();
    344 
    345 private:
    346     double scale_x;
    347     double scale_y;
    348     bool area_fast;
    349 
    350     void resize_generic();
    351     void resize_area();
    352     double getWeight(double a, double b, int x);
    353 
    354     typedef std::vector<std::pair<int, double> > dim;
    355     void generate_buffer(double scale, dim& _dim);
    356     void resize_1d(const Mat& _src, Mat& _dst, int dy, const dim& _dim);
    357 };
    358 
    359 CV_Resize_Test::CV_Resize_Test() :
    360     CV_ImageWarpBaseTest(), scale_x(),
    361     scale_y(), area_fast(false)
    362 {
    363 }
    364 
    365 CV_Resize_Test::~CV_Resize_Test()
    366 {
    367 }
    368 
    369 namespace
    370 {
    371     void interpolateLinear(float x, float* coeffs)
    372     {
    373         coeffs[0] = 1.f - x;
    374         coeffs[1] = x;
    375     }
    376 
    377     void interpolateCubic(float x, float* coeffs)
    378     {
    379         const float A = -0.75f;
    380 
    381         coeffs[0] = ((A*(x + 1) - 5*A)*(x + 1) + 8*A)*(x + 1) - 4*A;
    382         coeffs[1] = ((A + 2)*x - (A + 3))*x*x + 1;
    383         coeffs[2] = ((A + 2)*(1 - x) - (A + 3))*(1 - x)*(1 - x) + 1;
    384         coeffs[3] = 1.f - coeffs[0] - coeffs[1] - coeffs[2];
    385     }
    386 
    387     void interpolateLanczos4(float x, float* coeffs)
    388     {
    389         static const double s45 = 0.70710678118654752440084436210485;
    390         static const double cs[][2]=
    391         {{1, 0}, {-s45, -s45}, {0, 1}, {s45, -s45}, {-1, 0}, {s45, s45}, {0, -1}, {-s45, s45}};
    392 
    393         if( x < FLT_EPSILON )
    394         {
    395             for( int i = 0; i < 8; i++ )
    396                 coeffs[i] = 0;
    397             coeffs[3] = 1;
    398             return;
    399         }
    400 
    401         float sum = 0;
    402         double y0=-(x+3)*CV_PI*0.25, s0 = sin(y0), c0=cos(y0);
    403         for(int i = 0; i < 8; i++ )
    404         {
    405             double y = -(x+3-i)*CV_PI*0.25;
    406             coeffs[i] = (float)((cs[i][0]*s0 + cs[i][1]*c0)/(y*y));
    407             sum += coeffs[i];
    408         }
    409 
    410         sum = 1.f/sum;
    411         for(int i = 0; i < 8; i++ )
    412             coeffs[i] *= sum;
    413     }
    414 
    415     typedef void (*interpolate_method)(float x, float* coeffs);
    416     interpolate_method inter_array[] = { &interpolateLinear, &interpolateCubic, &interpolateLanczos4 };
    417 }
    418 
    419 void CV_Resize_Test::generate_test_data()
    420 {
    421     CV_ImageWarpBaseTest::generate_test_data();
    422 
    423     scale_x = src.cols / static_cast<double>(dst.cols);
    424     scale_y = src.rows / static_cast<double>(dst.rows);
    425 
    426     area_fast = interpolation == INTER_AREA &&
    427         fabs(scale_x - cvRound(scale_x)) < FLT_EPSILON &&
    428         fabs(scale_y - cvRound(scale_y)) < FLT_EPSILON;
    429     if (area_fast)
    430     {
    431         scale_x = cvRound(scale_x);
    432         scale_y = cvRound(scale_y);
    433     }
    434 }
    435 
    436 void CV_Resize_Test::run_func()
    437 {
    438     cv::resize(src, dst, dst.size(), 0, 0, interpolation);
    439 }
    440 
    441 void CV_Resize_Test::run_reference_func()
    442 {
    443     CV_ImageWarpBaseTest::prepare_test_data_for_reference_func();
    444 
    445     if (interpolation == INTER_AREA)
    446         resize_area();
    447     else
    448         resize_generic();
    449 }
    450 
    451 double CV_Resize_Test::getWeight(double a, double b, int x)
    452 {
    453     double w = std::min(static_cast<double>(x + 1), b) - std::max(static_cast<double>(x), a);
    454     CV_Assert(w >= 0);
    455     return w;
    456 }
    457 
    458 void CV_Resize_Test::resize_area()
    459 {
    460     Size ssize = src.size(), dsize = reference_dst.size();
    461     CV_Assert(ssize.area() > 0 && dsize.area() > 0);
    462     int cn = src.channels();
    463 
    464     CV_Assert(scale_x >= 1.0 && scale_y >= 1.0);
    465 
    466     double fsy0 = 0, fsy1 = scale_y;
    467     for (int dy = 0; dy < dsize.height; ++dy)
    468     {
    469         float* yD = reference_dst.ptr<float>(dy);
    470         int isy0 = cvFloor(fsy0), isy1 = std::min(cvFloor(fsy1), ssize.height - 1);
    471         CV_Assert(isy1 <= ssize.height && isy0 < ssize.height);
    472 
    473         double fsx0 = 0, fsx1 = scale_x;
    474 
    475         for (int dx = 0; dx < dsize.width; ++dx)
    476         {
    477             float* xyD = yD + cn * dx;
    478             int isx0 = cvFloor(fsx0), isx1 = std::min(ssize.width - 1, cvFloor(fsx1));
    479 
    480             CV_Assert(isx1 <= ssize.width);
    481             CV_Assert(isx0 < ssize.width);
    482 
    483             // for each pixel of dst
    484             for (int r = 0; r < cn; ++r)
    485             {
    486                 xyD[r] = 0.0f;
    487                 double area = 0.0;
    488                 for (int sy = isy0; sy <= isy1; ++sy)
    489                 {
    490                     const float* yS = src.ptr<float>(sy);
    491                     for (int sx = isx0; sx <= isx1; ++sx)
    492                     {
    493                         double wy = getWeight(fsy0, fsy1, sy);
    494                         double wx = getWeight(fsx0, fsx1, sx);
    495                         double w = wx * wy;
    496                         xyD[r] += static_cast<float>(yS[sx * cn + r] * w);
    497                         area += w;
    498                     }
    499                 }
    500 
    501                 CV_Assert(area != 0);
    502                 // norming pixel
    503                 xyD[r] = static_cast<float>(xyD[r] / area);
    504             }
    505             fsx1 = std::min((fsx0 = fsx1) + scale_x, static_cast<double>(ssize.width));
    506         }
    507         fsy1 = std::min((fsy0 = fsy1) + scale_y, static_cast<double>(ssize.height));
    508     }
    509 }
    510 
    511 // for interpolation type : INTER_LINEAR, INTER_LINEAR, INTER_CUBIC, INTER_LANCZOS4
    512 void CV_Resize_Test::resize_1d(const Mat& _src, Mat& _dst, int dy, const dim& _dim)
    513 {
    514     Size dsize = _dst.size();
    515     int cn = _dst.channels();
    516     float* yD = _dst.ptr<float>(dy);
    517 
    518     if (interpolation == INTER_NEAREST)
    519     {
    520         const float* yS = _src.ptr<float>(dy);
    521         for (int dx = 0; dx < dsize.width; ++dx)
    522         {
    523             int isx = _dim[dx].first;
    524             const float* xyS = yS + isx * cn;
    525             float* xyD = yD + dx * cn;
    526 
    527             for (int r = 0; r < cn; ++r)
    528                 xyD[r] = xyS[r];
    529         }
    530     }
    531     else if (interpolation == INTER_LINEAR || interpolation == INTER_CUBIC || interpolation == INTER_LANCZOS4)
    532     {
    533         interpolate_method inter_func = inter_array[interpolation - (interpolation == INTER_LANCZOS4 ? 2 : 1)];
    534         size_t elemsize = _src.elemSize();
    535 
    536         int ofs = 0, ksize = 2;
    537         if (interpolation == INTER_CUBIC)
    538             ofs = 1, ksize = 4;
    539         else if (interpolation == INTER_LANCZOS4)
    540             ofs = 3, ksize = 8;
    541 
    542         Mat _extended_src_row(1, _src.cols + ksize * 2, _src.type());
    543         const uchar* srow = _src.ptr(dy);
    544         memcpy(_extended_src_row.ptr() + elemsize * ksize, srow, _src.step);
    545         for (int k = 0; k < ksize; ++k)
    546         {
    547             memcpy(_extended_src_row.ptr() + k * elemsize, srow, elemsize);
    548             memcpy(_extended_src_row.ptr() + (ksize + k) * elemsize + _src.step, srow + _src.step - elemsize, elemsize);
    549         }
    550 
    551         for (int dx = 0; dx < dsize.width; ++dx)
    552         {
    553             int isx = _dim[dx].first;
    554             double fsx = _dim[dx].second;
    555 
    556             float *xyD = yD + dx * cn;
    557             const float* xyS = _extended_src_row.ptr<float>(0) + (isx + ksize - ofs) * cn;
    558 
    559             float w[8];
    560             inter_func(static_cast<float>(fsx), w);
    561 
    562             for (int r = 0; r < cn; ++r)
    563             {
    564                 xyD[r] = 0;
    565                 for (int k = 0; k < ksize; ++k)
    566                     xyD[r] += w[k] * xyS[k * cn + r];
    567             }
    568         }
    569     }
    570     else
    571         CV_Assert(0);
    572 }
    573 
    574 void CV_Resize_Test::generate_buffer(double scale, dim& _dim)
    575 {
    576     size_t length = _dim.size();
    577     for (size_t dx = 0; dx < length; ++dx)
    578     {
    579         double fsx = scale * (dx + 0.5) - 0.5;
    580         int isx = cvFloor(fsx);
    581         _dim[dx] = std::make_pair(isx, fsx - isx);
    582     }
    583 }
    584 
    585 void CV_Resize_Test::resize_generic()
    586 {
    587     Size dsize = reference_dst.size(), ssize = src.size();
    588     CV_Assert(dsize.area() > 0 && ssize.area() > 0);
    589 
    590     dim dims[] = { dim(dsize.width), dim(dsize.height) };
    591     if (interpolation == INTER_NEAREST)
    592     {
    593         for (int dx = 0; dx < dsize.width; ++dx)
    594             dims[0][dx].first = std::min(cvFloor(dx * scale_x), ssize.width - 1);
    595         for (int dy = 0; dy < dsize.height; ++dy)
    596             dims[1][dy].first = std::min(cvFloor(dy * scale_y), ssize.height - 1);
    597     }
    598     else
    599     {
    600         generate_buffer(scale_x, dims[0]);
    601         generate_buffer(scale_y, dims[1]);
    602     }
    603 
    604     Mat tmp(ssize.height, dsize.width, reference_dst.type());
    605     for (int dy = 0; dy < tmp.rows; ++dy)
    606         resize_1d(src, tmp, dy, dims[0]);
    607 
    608     transpose(tmp, tmp);
    609     transpose(reference_dst, reference_dst);
    610 
    611     for (int dy = 0; dy < tmp.rows; ++dy)
    612         resize_1d(tmp, reference_dst, dy, dims[1]);
    613     transpose(reference_dst, reference_dst);
    614 }
    615 
    616 ////////////////////////////////////////////////////////////////////////////////////////////////////////
    617 // remap
    618 ////////////////////////////////////////////////////////////////////////////////////////////////////////
    619 
    620 class CV_Remap_Test :
    621     public CV_ImageWarpBaseTest
    622 {
    623 public:
    624     CV_Remap_Test();
    625 
    626     virtual ~CV_Remap_Test();
    627 
    628 private:
    629     typedef void (CV_Remap_Test::*remap_func)(const Mat&, Mat&);
    630 
    631 protected:
    632     virtual void generate_test_data();
    633     virtual void prepare_test_data_for_reference_func();
    634 
    635     virtual void run_func();
    636     virtual void run_reference_func();
    637 
    638     Mat mapx, mapy;
    639     int borderType;
    640     Scalar borderValue;
    641 
    642     remap_func funcs[2];
    643 
    644 private:
    645     void remap_nearest(const Mat&, Mat&);
    646     void remap_generic(const Mat&, Mat&);
    647 
    648     void convert_maps();
    649     const char* borderType_to_string() const;
    650     virtual void validate_results() const;
    651 };
    652 
    653 CV_Remap_Test::CV_Remap_Test() :
    654     CV_ImageWarpBaseTest(), mapx(), mapy(),
    655     borderType(-1), borderValue()
    656 {
    657     funcs[0] = &CV_Remap_Test::remap_nearest;
    658     funcs[1] = &CV_Remap_Test::remap_generic;
    659 }
    660 
    661 CV_Remap_Test::~CV_Remap_Test()
    662 {
    663 }
    664 
    665 void CV_Remap_Test::generate_test_data()
    666 {
    667     CV_ImageWarpBaseTest::generate_test_data();
    668 
    669     RNG& rng = ts->get_rng();
    670     borderType = rng.uniform(1, BORDER_WRAP);
    671     borderValue = Scalar::all(rng.uniform(0, 255));
    672 
    673     // generating the mapx, mapy matrices
    674     static const int mapx_types[] = { CV_16SC2, CV_32FC1, CV_32FC2 };
    675     mapx.create(dst.size(), mapx_types[rng.uniform(0, sizeof(mapx_types) / sizeof(int))]);
    676     mapy = Mat();
    677 
    678     const int n = std::min(std::min(src.cols, src.rows) / 10 + 1, 2);
    679     float _n = 0; //static_cast<float>(-n);
    680 
    681     switch (mapx.type())
    682     {
    683         case CV_16SC2:
    684         {
    685             MatIterator_<Vec2s> begin_x = mapx.begin<Vec2s>(), end_x = mapx.end<Vec2s>();
    686             for ( ; begin_x != end_x; ++begin_x)
    687             {
    688                 (*begin_x)[0] = static_cast<short>(rng.uniform(static_cast<int>(_n), std::max(src.cols + n - 1, 0)));
    689                 (*begin_x)[1] = static_cast<short>(rng.uniform(static_cast<int>(_n), std::max(src.rows + n - 1, 0)));
    690             }
    691 
    692             if (interpolation != INTER_NEAREST)
    693             {
    694                 static const int mapy_types[] = { CV_16UC1, CV_16SC1 };
    695                 mapy.create(dst.size(), mapy_types[rng.uniform(0, sizeof(mapy_types) / sizeof(int))]);
    696 
    697                 switch (mapy.type())
    698                 {
    699                     case CV_16UC1:
    700                     {
    701                         MatIterator_<ushort> begin_y = mapy.begin<ushort>(), end_y = mapy.end<ushort>();
    702                         for ( ; begin_y != end_y; ++begin_y)
    703                             begin_y[0] = static_cast<short>(rng.uniform(0, 1024));
    704                     }
    705                     break;
    706 
    707                     case CV_16SC1:
    708                     {
    709                         MatIterator_<short> begin_y = mapy.begin<short>(), end_y = mapy.end<short>();
    710                         for ( ; begin_y != end_y; ++begin_y)
    711                             begin_y[0] = static_cast<short>(rng.uniform(0, 1024));
    712                     }
    713                     break;
    714                 }
    715             }
    716         }
    717         break;
    718 
    719         case CV_32FC1:
    720         {
    721             mapy.create(dst.size(), CV_32FC1);
    722             float fscols = static_cast<float>(std::max(src.cols - 1 + n, 0)),
    723                     fsrows = static_cast<float>(std::max(src.rows - 1 + n, 0));
    724             MatIterator_<float> begin_x = mapx.begin<float>(), end_x = mapx.end<float>();
    725             MatIterator_<float> begin_y = mapy.begin<float>();
    726             for ( ; begin_x != end_x; ++begin_x, ++begin_y)
    727             {
    728                 begin_x[0] = rng.uniform(_n, fscols);
    729                 begin_y[0] = rng.uniform(_n, fsrows);
    730             }
    731         }
    732         break;
    733 
    734         case CV_32FC2:
    735         {
    736             float fscols = static_cast<float>(std::max(src.cols - 1 + n, 0)),
    737                     fsrows = static_cast<float>(std::max(src.rows - 1 + n, 0));
    738             int width = mapx.cols << 1;
    739 
    740             for (int y = 0; y < mapx.rows; ++y)
    741             {
    742                 float * ptr = mapx.ptr<float>(y);
    743 
    744                 for (int x = 0; x < width; x += 2)
    745                 {
    746                     ptr[x] = rng.uniform(_n, fscols);
    747                     ptr[x + 1] = rng.uniform(_n, fsrows);
    748                 }
    749             }
    750         }
    751         break;
    752 
    753         default:
    754             CV_Assert(0);
    755         break;
    756     }
    757 }
    758 
    759 void CV_Remap_Test::run_func()
    760 {
    761     remap(src, dst, mapx, mapy, interpolation, borderType, borderValue);
    762 }
    763 
    764 void CV_Remap_Test::convert_maps()
    765 {
    766     if (mapx.type() != CV_16SC2)
    767         convertMaps(mapx.clone(), mapy.clone(), mapx, mapy, CV_16SC2, interpolation == INTER_NEAREST);
    768     else if (interpolation != INTER_NEAREST)
    769         if (mapy.type() != CV_16UC1)
    770             mapy.clone().convertTo(mapy, CV_16UC1);
    771 
    772     if (interpolation == INTER_NEAREST)
    773         mapy = Mat();
    774     CV_Assert(((interpolation == INTER_NEAREST && mapy.empty()) || mapy.type() == CV_16UC1 ||
    775                mapy.type() == CV_16SC1) && mapx.type() == CV_16SC2);
    776 }
    777 
    778 const char* CV_Remap_Test::borderType_to_string() const
    779 {
    780     if (borderType == BORDER_CONSTANT)
    781         return "BORDER_CONSTANT";
    782     if (borderType == BORDER_REPLICATE)
    783         return "BORDER_REPLICATE";
    784     if (borderType == BORDER_REFLECT)
    785         return "BORDER_REFLECT";
    786     if (borderType == BORDER_WRAP)
    787         return "BORDER_WRAP";
    788     if (borderType == BORDER_REFLECT_101)
    789         return "BORDER_REFLECT_101";
    790     return "Unsupported/Unkown border type";
    791 }
    792 
    793 void CV_Remap_Test::prepare_test_data_for_reference_func()
    794 {
    795     CV_ImageWarpBaseTest::prepare_test_data_for_reference_func();
    796     convert_maps();
    797 /*
    798     const int ksize = 3;
    799     Mat kernel = getStructuringElement(CV_MOP_ERODE, Size(ksize, ksize));
    800     Mat mask(src.size(), CV_8UC1, Scalar::all(255)), dst_mask;
    801     cv::erode(src, erode_src, kernel);
    802     cv::erode(mask, dst_mask, kernel, Point(-1, -1), 1, BORDER_CONSTANT, Scalar::all(0));
    803     bitwise_not(dst_mask, mask);
    804     src.copyTo(erode_src, mask);
    805     dst_mask.release();
    806 
    807     mask = Scalar::all(0);
    808     kernel = getStructuringElement(CV_MOP_DILATE, kernel.size());
    809     cv::dilate(src, dilate_src, kernel);
    810     cv::dilate(mask, dst_mask, kernel, Point(-1, -1), 1, BORDER_CONSTANT, Scalar::all(255));
    811     src.copyTo(dilate_src, dst_mask);
    812     dst_mask.release();
    813 */
    814 }
    815 
    816 void CV_Remap_Test::run_reference_func()
    817 {
    818     prepare_test_data_for_reference_func();
    819 
    820     if (interpolation == INTER_AREA)
    821         interpolation = INTER_LINEAR;
    822 
    823     int index = interpolation == INTER_NEAREST ? 0 : 1;
    824     (this->*funcs[index])(src, reference_dst);
    825 }
    826 
    827 void CV_Remap_Test::remap_nearest(const Mat& _src, Mat& _dst)
    828 {
    829     CV_Assert(_src.depth() == CV_32F && _dst.type() == _src.type());
    830     CV_Assert(mapx.type() == CV_16SC2 && mapy.empty());
    831 
    832     Size ssize = _src.size(), dsize = _dst.size();
    833     CV_Assert(ssize.area() > 0 && dsize.area() > 0);
    834     int cn = _src.channels();
    835 
    836     for (int dy = 0; dy < dsize.height; ++dy)
    837     {
    838         const short* yM = mapx.ptr<short>(dy);
    839         float* yD = _dst.ptr<float>(dy);
    840 
    841         for (int dx = 0; dx < dsize.width; ++dx)
    842         {
    843             float* xyD = yD + cn * dx;
    844             int sx = yM[dx * 2], sy = yM[dx * 2 + 1];
    845 
    846             if (sx >= 0 && sx < ssize.width && sy >= 0 && sy < ssize.height)
    847             {
    848                 const float *xyS = _src.ptr<float>(sy) + sx * cn;
    849 
    850                 for (int r = 0; r < cn; ++r)
    851                     xyD[r] = xyS[r];
    852             }
    853             else if (borderType != BORDER_TRANSPARENT)
    854             {
    855                 if (borderType == BORDER_CONSTANT)
    856                     for (int r = 0; r < cn; ++r)
    857                         xyD[r] = saturate_cast<float>(borderValue[r]);
    858                 else
    859                 {
    860                     sx = borderInterpolate(sx, ssize.width, borderType);
    861                     sy = borderInterpolate(sy, ssize.height, borderType);
    862                     CV_Assert(sx >= 0 && sy >= 0 && sx < ssize.width && sy < ssize.height);
    863 
    864                     const float *xyS = _src.ptr<float>(sy) + sx * cn;
    865 
    866                     for (int r = 0; r < cn; ++r)
    867                         xyD[r] = xyS[r];
    868                 }
    869             }
    870         }
    871     }
    872 }
    873 
    874 void CV_Remap_Test::remap_generic(const Mat& _src, Mat& _dst)
    875 {
    876     CV_Assert(mapx.type() == CV_16SC2 && mapy.type() == CV_16UC1);
    877 
    878     int ksize = 2;
    879     if (interpolation == INTER_CUBIC)
    880         ksize = 4;
    881     else if (interpolation == INTER_LANCZOS4)
    882         ksize = 8;
    883     else if (interpolation != INTER_LINEAR)
    884         assert(0);
    885     int ofs = (ksize / 2) - 1;
    886 
    887     CV_Assert(_src.depth() == CV_32F && _dst.type() == _src.type());
    888     Size ssize = _src.size(), dsize = _dst.size();
    889     int cn = _src.channels(), width1 = std::max(ssize.width - ksize + 1, 0),
    890         height1 = std::max(ssize.height - ksize + 1, 0);
    891 
    892     float ix[8], w[16];
    893     interpolate_method inter_func = inter_array[interpolation - (interpolation == INTER_LANCZOS4 ? 2 : 1)];
    894 
    895     for (int dy = 0; dy < dsize.height; ++dy)
    896     {
    897         const short* yMx = mapx.ptr<short>(dy);
    898         const ushort* yMy = mapy.ptr<ushort>(dy);
    899 
    900         float* yD = _dst.ptr<float>(dy);
    901 
    902         for (int dx = 0; dx < dsize.width; ++dx)
    903         {
    904             float* xyD = yD + dx * cn;
    905             float sx = yMx[dx * 2], sy = yMx[dx * 2 + 1];
    906             int isx = cvFloor(sx), isy = cvFloor(sy);
    907 
    908             inter_func((yMy[dx] & (INTER_TAB_SIZE - 1)) / static_cast<float>(INTER_TAB_SIZE), w);
    909             inter_func(((yMy[dx] >> INTER_BITS) & (INTER_TAB_SIZE - 1)) / static_cast<float>(INTER_TAB_SIZE), w + ksize);
    910 
    911             isx -= ofs;
    912             isy -= ofs;
    913 
    914             if (isx >= 0 && isx < width1 && isy >= 0 && isy < height1)
    915             {
    916                 for (int r = 0; r < cn; ++r)
    917                 {
    918                     for (int y = 0; y < ksize; ++y)
    919                     {
    920                         const float* xyS = _src.ptr<float>(isy + y) + isx * cn;
    921 
    922                         ix[y] = 0;
    923                         for (int i = 0; i < ksize; ++i)
    924                             ix[y] += w[i] * xyS[i * cn + r];
    925                     }
    926                     xyD[r] = 0;
    927                     for (int i = 0; i < ksize; ++i)
    928                         xyD[r] += w[ksize + i] * ix[i];
    929                 }
    930             }
    931             else if (borderType != BORDER_TRANSPARENT)
    932             {
    933                 int ar_x[8], ar_y[8];
    934 
    935                 for (int k = 0; k < ksize; k++)
    936                 {
    937                     ar_x[k] = borderInterpolate(isx + k, ssize.width, borderType) * cn;
    938                     ar_y[k] = borderInterpolate(isy + k, ssize.height, borderType);
    939                 }
    940 
    941                 for (int r = 0; r < cn; r++)
    942                 {
    943                     xyD[r] = 0;
    944                     for (int i = 0; i < ksize; ++i)
    945                     {
    946                         ix[i] = 0;
    947                         if (ar_y[i] >= 0)
    948                         {
    949                             const float* yS = _src.ptr<float>(ar_y[i]);
    950                             for (int j = 0; j < ksize; ++j)
    951                                 ix[i] += saturate_cast<float>((ar_x[j] >= 0 ? yS[ar_x[j] + r] : borderValue[r]) * w[j]);
    952                         }
    953                         else
    954                             for (int j = 0; j < ksize; ++j)
    955                                 ix[i] += saturate_cast<float>(borderValue[r] * w[j]);
    956                     }
    957                     for (int i = 0; i < ksize; ++i)
    958                         xyD[r] += saturate_cast<float>(w[ksize + i] * ix[i]);
    959                 }
    960             }
    961         }
    962     }
    963 }
    964 
    965 void CV_Remap_Test::validate_results() const
    966 {
    967     CV_ImageWarpBaseTest::validate_results();
    968     if (cvtest::TS::ptr()->get_err_code() == cvtest::TS::FAIL_BAD_ACCURACY)
    969     {
    970         PRINT_TO_LOG("BorderType: %s\n", borderType_to_string());
    971         PRINT_TO_LOG("BorderValue: (%f, %f, %f, %f)\n",
    972                      borderValue[0], borderValue[1], borderValue[2], borderValue[3]);
    973     }
    974 }
    975 
    976 ////////////////////////////////////////////////////////////////////////////////////////////////////////
    977 // warpAffine
    978 ////////////////////////////////////////////////////////////////////////////////////////////////////////
    979 
    980 class CV_WarpAffine_Test :
    981     public CV_Remap_Test
    982 {
    983 public:
    984     CV_WarpAffine_Test();
    985 
    986     virtual ~CV_WarpAffine_Test();
    987 
    988 protected:
    989     virtual void generate_test_data();
    990     virtual void prepare_test_data_for_reference_func();
    991 
    992     virtual void run_func();
    993     virtual void run_reference_func();
    994 
    995     Mat M;
    996 private:
    997     void warpAffine(const Mat&, Mat&);
    998 };
    999 
   1000 CV_WarpAffine_Test::CV_WarpAffine_Test() :
   1001     CV_Remap_Test()
   1002 {
   1003 }
   1004 
   1005 CV_WarpAffine_Test::~CV_WarpAffine_Test()
   1006 {
   1007 }
   1008 
   1009 void CV_WarpAffine_Test::generate_test_data()
   1010 {
   1011     CV_Remap_Test::generate_test_data();
   1012 
   1013     RNG& rng = ts->get_rng();
   1014 
   1015     // generating the M 2x3 matrix
   1016     static const int depths[] = { CV_32FC1, CV_64FC1 };
   1017 
   1018     // generating 2d matrix
   1019     M = getRotationMatrix2D(Point2f(src.cols / 2.f, src.rows / 2.f),
   1020         rng.uniform(-180.f, 180.f), rng.uniform(0.4f, 2.0f));
   1021     int depth = depths[rng.uniform(0, sizeof(depths) / sizeof(depths[0]))];
   1022     if (M.depth() != depth)
   1023     {
   1024         Mat tmp;
   1025         M.convertTo(tmp, depth);
   1026         M = tmp;
   1027     }
   1028 
   1029     // warp_matrix is inverse
   1030     if (rng.uniform(0., 1.) > 0)
   1031         interpolation |= CV_WARP_INVERSE_MAP;
   1032 }
   1033 
   1034 void CV_WarpAffine_Test::run_func()
   1035 {
   1036     cv::warpAffine(src, dst, M, dst.size(), interpolation, borderType, borderValue);
   1037 }
   1038 
   1039 void CV_WarpAffine_Test::prepare_test_data_for_reference_func()
   1040 {
   1041     CV_ImageWarpBaseTest::prepare_test_data_for_reference_func();
   1042 }
   1043 
   1044 void CV_WarpAffine_Test::run_reference_func()
   1045 {
   1046     prepare_test_data_for_reference_func();
   1047 
   1048     warpAffine(src, reference_dst);
   1049 }
   1050 
   1051 void CV_WarpAffine_Test::warpAffine(const Mat& _src, Mat& _dst)
   1052 {
   1053     Size dsize = _dst.size();
   1054 
   1055     CV_Assert(_src.size().area() > 0);
   1056     CV_Assert(dsize.area() > 0);
   1057     CV_Assert(_src.type() == _dst.type());
   1058 
   1059     Mat tM;
   1060     M.convertTo(tM, CV_64F);
   1061 
   1062     int inter = interpolation & INTER_MAX;
   1063     if (inter == INTER_AREA)
   1064         inter = INTER_LINEAR;
   1065 
   1066     mapx.create(dsize, CV_16SC2);
   1067     if (inter != INTER_NEAREST)
   1068         mapy.create(dsize, CV_16SC1);
   1069     else
   1070         mapy = Mat();
   1071 
   1072     if (!(interpolation & CV_WARP_INVERSE_MAP))
   1073         invertAffineTransform(tM.clone(), tM);
   1074 
   1075     const int AB_BITS = MAX(10, (int)INTER_BITS);
   1076     const int AB_SCALE = 1 << AB_BITS;
   1077     int round_delta = (inter == INTER_NEAREST) ? AB_SCALE / 2 : (AB_SCALE / INTER_TAB_SIZE / 2);
   1078 
   1079     const double* data_tM = tM.ptr<double>(0);
   1080     for (int dy = 0; dy < dsize.height; ++dy)
   1081     {
   1082         short* yM = mapx.ptr<short>(dy);
   1083         for (int dx = 0; dx < dsize.width; ++dx, yM += 2)
   1084         {
   1085             int v1 = saturate_cast<int>(saturate_cast<int>(data_tM[0] * dx * AB_SCALE) +
   1086                     saturate_cast<int>((data_tM[1] * dy + data_tM[2]) * AB_SCALE) + round_delta),
   1087                    v2 = saturate_cast<int>(saturate_cast<int>(data_tM[3] * dx * AB_SCALE) +
   1088                     saturate_cast<int>((data_tM[4] * dy + data_tM[5]) * AB_SCALE) + round_delta);
   1089             v1 >>= AB_BITS - INTER_BITS;
   1090             v2 >>= AB_BITS - INTER_BITS;
   1091 
   1092             yM[0] = saturate_cast<short>(v1 >> INTER_BITS);
   1093             yM[1] = saturate_cast<short>(v2 >> INTER_BITS);
   1094 
   1095             if (inter != INTER_NEAREST)
   1096                 mapy.ptr<short>(dy)[dx] = ((v2 & (INTER_TAB_SIZE - 1)) * INTER_TAB_SIZE + (v1 & (INTER_TAB_SIZE - 1)));
   1097         }
   1098     }
   1099 
   1100     CV_Assert(mapx.type() == CV_16SC2 && ((inter == INTER_NEAREST && mapy.empty()) || mapy.type() == CV_16SC1));
   1101     cv::remap(_src, _dst, mapx, mapy, inter, borderType, borderValue);
   1102 }
   1103 
   1104 ////////////////////////////////////////////////////////////////////////////////////////////////////////
   1105 // warpPerspective
   1106 ////////////////////////////////////////////////////////////////////////////////////////////////////////
   1107 
   1108 class CV_WarpPerspective_Test :
   1109     public CV_WarpAffine_Test
   1110 {
   1111 public:
   1112     CV_WarpPerspective_Test();
   1113 
   1114     virtual ~CV_WarpPerspective_Test();
   1115 
   1116 protected:
   1117     virtual void generate_test_data();
   1118 
   1119     virtual void run_func();
   1120     virtual void run_reference_func();
   1121 
   1122 private:
   1123     void warpPerspective(const Mat&, Mat&);
   1124 };
   1125 
   1126 CV_WarpPerspective_Test::CV_WarpPerspective_Test() :
   1127     CV_WarpAffine_Test()
   1128 {
   1129 }
   1130 
   1131 CV_WarpPerspective_Test::~CV_WarpPerspective_Test()
   1132 {
   1133 }
   1134 
   1135 void CV_WarpPerspective_Test::generate_test_data()
   1136 {
   1137     CV_Remap_Test::generate_test_data();
   1138 
   1139     // generating the M 3x3 matrix
   1140     RNG& rng = ts->get_rng();
   1141 
   1142     float cols = static_cast<float>(src.cols), rows = static_cast<float>(src.rows);
   1143     Point2f sp[] = { Point2f(0.0f, 0.0f), Point2f(cols, 0.0f), Point2f(0.0f, rows), Point2f(cols, rows) };
   1144     Point2f dp[] = { Point2f(rng.uniform(0.0f, cols), rng.uniform(0.0f, rows)),
   1145         Point2f(rng.uniform(0.0f, cols), rng.uniform(0.0f, rows)),
   1146         Point2f(rng.uniform(0.0f, cols), rng.uniform(0.0f, rows)),
   1147         Point2f(rng.uniform(0.0f, cols), rng.uniform(0.0f, rows)) };
   1148     M = getPerspectiveTransform(sp, dp);
   1149 
   1150     static const int depths[] = { CV_32F, CV_64F };
   1151     int depth = depths[rng.uniform(0, 2)];
   1152     M.clone().convertTo(M, depth);
   1153 }
   1154 
   1155 void CV_WarpPerspective_Test::run_func()
   1156 {
   1157     cv::warpPerspective(src, dst, M, dst.size(), interpolation, borderType, borderValue);
   1158 }
   1159 
   1160 void CV_WarpPerspective_Test::run_reference_func()
   1161 {
   1162     prepare_test_data_for_reference_func();
   1163 
   1164     warpPerspective(src, reference_dst);
   1165 }
   1166 
   1167 void CV_WarpPerspective_Test::warpPerspective(const Mat& _src, Mat& _dst)
   1168 {
   1169     Size ssize = _src.size(), dsize = _dst.size();
   1170 
   1171     CV_Assert(ssize.area() > 0);
   1172     CV_Assert(dsize.area() > 0);
   1173     CV_Assert(_src.type() == _dst.type());
   1174 
   1175     if (M.depth() != CV_64F)
   1176     {
   1177         Mat tmp;
   1178         M.convertTo(tmp, CV_64F);
   1179         M = tmp;
   1180     }
   1181 
   1182     if (!(interpolation & CV_WARP_INVERSE_MAP))
   1183     {
   1184         Mat tmp;
   1185         invert(M, tmp);
   1186         M = tmp;
   1187     }
   1188 
   1189     int inter = interpolation & INTER_MAX;
   1190     if (inter == INTER_AREA)
   1191         inter = INTER_LINEAR;
   1192 
   1193     mapx.create(dsize, CV_16SC2);
   1194     if (inter != INTER_NEAREST)
   1195         mapy.create(dsize, CV_16SC1);
   1196     else
   1197         mapy = Mat();
   1198 
   1199     double* tM = M.ptr<double>(0);
   1200     for (int dy = 0; dy < dsize.height; ++dy)
   1201     {
   1202         short* yMx = mapx.ptr<short>(dy);
   1203 
   1204         for (int dx = 0; dx < dsize.width; ++dx, yMx += 2)
   1205         {
   1206             double den = tM[6] * dx + tM[7] * dy + tM[8];
   1207             den = den ? 1.0 / den : 0.0;
   1208 
   1209             if (inter == INTER_NEAREST)
   1210             {
   1211                 yMx[0] = saturate_cast<short>((tM[0] * dx + tM[1] * dy + tM[2]) * den);
   1212                 yMx[1] = saturate_cast<short>((tM[3] * dx + tM[4] * dy + tM[5]) * den);
   1213                 continue;
   1214             }
   1215 
   1216             den *= INTER_TAB_SIZE;
   1217             int v0 = saturate_cast<int>((tM[0] * dx + tM[1] * dy + tM[2]) * den);
   1218             int v1 = saturate_cast<int>((tM[3] * dx + tM[4] * dy + tM[5]) * den);
   1219 
   1220             yMx[0] = saturate_cast<short>(v0 >> INTER_BITS);
   1221             yMx[1] = saturate_cast<short>(v1 >> INTER_BITS);
   1222             mapy.ptr<short>(dy)[dx] = saturate_cast<short>((v1 & (INTER_TAB_SIZE - 1)) *
   1223                     INTER_TAB_SIZE + (v0 & (INTER_TAB_SIZE - 1)));
   1224         }
   1225     }
   1226 
   1227     CV_Assert(mapx.type() == CV_16SC2 && ((inter == INTER_NEAREST && mapy.empty()) || mapy.type() == CV_16SC1));
   1228     cv::remap(_src, _dst, mapx, mapy, inter, borderType, borderValue);
   1229 }
   1230 
   1231 ////////////////////////////////////////////////////////////////////////////////////////////////////////
   1232 // Tests
   1233 ////////////////////////////////////////////////////////////////////////////////////////////////////////
   1234 
   1235 TEST(Imgproc_Resize_Test, accuracy) { CV_Resize_Test test; test.safe_run(); }
   1236 TEST(Imgproc_Remap_Test, accuracy) { CV_Remap_Test test; test.safe_run(); }
   1237 TEST(Imgproc_WarpAffine_Test, accuracy) { CV_WarpAffine_Test test; test.safe_run(); }
   1238 TEST(Imgproc_WarpPerspective_Test, accuracy) { CV_WarpPerspective_Test test; test.safe_run(); }
   1239