some formal changes (generally adding constness)
[profile/ivi/opencv.git] / modules / imgproc / test / test_imgwarp.cpp
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 using namespace cv;
45 using namespace std;
46
47 class CV_ImgWarpBaseTest : public cvtest::ArrayTest
48 {
49 public:
50     CV_ImgWarpBaseTest( bool warp_matrix );
51
52 protected:
53     int read_params( CvFileStorage* fs );
54     int prepare_test_case( int test_case_idx );
55     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
56     void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
57     void fill_array( int test_case_idx, int i, int j, Mat& arr );
58
59     int interpolation;
60     int max_interpolation;
61     double spatial_scale_zoom, spatial_scale_decimate;
62 };
63
64
65 CV_ImgWarpBaseTest::CV_ImgWarpBaseTest( bool warp_matrix )
66 {
67     test_array[INPUT].push_back(NULL);
68     if( warp_matrix )
69         test_array[INPUT].push_back(NULL);
70     test_array[INPUT_OUTPUT].push_back(NULL);
71     test_array[REF_INPUT_OUTPUT].push_back(NULL);
72     max_interpolation = 5;
73     interpolation = 0;
74     element_wise_relative_error = false;
75     spatial_scale_zoom = 0.01;
76     spatial_scale_decimate = 0.005;
77 }
78
79
80 int CV_ImgWarpBaseTest::read_params( CvFileStorage* fs )
81 {
82     int code = cvtest::ArrayTest::read_params( fs );
83     return code;
84 }
85
86
87 void CV_ImgWarpBaseTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
88 {
89     cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
90     if( CV_MAT_DEPTH(type) == CV_32F )
91     {
92         low = Scalar::all(-10.);
93         high = Scalar::all(10);
94     }
95 }
96
97
98 void CV_ImgWarpBaseTest::get_test_array_types_and_sizes( int test_case_idx,
99                                                 vector<vector<Size> >& sizes, vector<vector<int> >& types )
100 {
101     RNG& rng = ts->get_rng();
102     int depth = cvtest::randInt(rng) % 3;
103     int cn = cvtest::randInt(rng) % 3 + 1;
104     cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
105     depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : CV_32F;
106     cn += cn == 2;
107
108     types[INPUT][0] = types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(depth, cn);
109     if( test_array[INPUT].size() > 1 )
110         types[INPUT][1] = cvtest::randInt(rng) & 1 ? CV_32FC1 : CV_64FC1;
111
112     interpolation = cvtest::randInt(rng) % max_interpolation;
113 }
114
115
116 void CV_ImgWarpBaseTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
117 {
118     if( i != INPUT || j != 0 )
119         cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr );
120 }
121
122 int CV_ImgWarpBaseTest::prepare_test_case( int test_case_idx )
123 {
124     int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
125     Mat& img = test_mat[INPUT][0];
126     int i, j, cols = img.cols;
127     int type = img.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
128     double scale = depth == CV_16U ? 1000. : 255.*0.5;
129     double space_scale = spatial_scale_decimate;
130     vector<float> buffer(img.cols*cn);
131
132     if( code <= 0 )
133         return code;
134
135     if( test_mat[INPUT_OUTPUT][0].cols >= img.cols &&
136         test_mat[INPUT_OUTPUT][0].rows >= img.rows )
137         space_scale = spatial_scale_zoom;
138
139     for( i = 0; i < img.rows; i++ )
140     {
141         uchar* ptr = img.ptr(i);
142         switch( cn )
143         {
144         case 1:
145             for( j = 0; j < cols; j++ )
146                 buffer[j] = (float)((sin((i+1)*space_scale)*sin((j+1)*space_scale)+1.)*scale);
147             break;
148         case 2:
149             for( j = 0; j < cols; j++ )
150             {
151                 buffer[j*2] = (float)((sin((i+1)*space_scale)+1.)*scale);
152                 buffer[j*2+1] = (float)((sin((i+j)*space_scale)+1.)*scale);
153             }
154             break;
155         case 3:
156             for( j = 0; j < cols; j++ )
157             {
158                 buffer[j*3] = (float)((sin((i+1)*space_scale)+1.)*scale);
159                 buffer[j*3+1] = (float)((sin(j*space_scale)+1.)*scale);
160                 buffer[j*3+2] = (float)((sin((i+j)*space_scale)+1.)*scale);
161             }
162             break;
163         case 4:
164             for( j = 0; j < cols; j++ )
165             {
166                 buffer[j*4] = (float)((sin((i+1)*space_scale)+1.)*scale);
167                 buffer[j*4+1] = (float)((sin(j*space_scale)+1.)*scale);
168                 buffer[j*4+2] = (float)((sin((i+j)*space_scale)+1.)*scale);
169                 buffer[j*4+3] = (float)((sin((i-j)*space_scale)+1.)*scale);
170             }
171             break;
172         default:
173             assert(0);
174         }
175
176         /*switch( depth )
177         {
178         case CV_8U:
179             for( j = 0; j < cols*cn; j++ )
180                 ptr[j] = (uchar)cvRound(buffer[j]);
181             break;
182         case CV_16U:
183             for( j = 0; j < cols*cn; j++ )
184                 ((ushort*)ptr)[j] = (ushort)cvRound(buffer[j]);
185             break;
186         case CV_32F:
187             for( j = 0; j < cols*cn; j++ )
188                 ((float*)ptr)[j] = (float)buffer[j];
189             break;
190         default:
191             assert(0);
192         }*/
193         cv::Mat src(1, cols*cn, CV_32F, &buffer[0]);
194         cv::Mat dst(1, cols*cn, depth, ptr);
195         src.convertTo(dst, dst.type());
196     }
197
198     return code;
199 }
200
201
202 /////////////////////////
203
204 class CV_ResizeTest : public CV_ImgWarpBaseTest
205 {
206 public:
207     CV_ResizeTest();
208
209 protected:
210     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
211     void run_func();
212     void prepare_to_validation( int /*test_case_idx*/ );
213     double get_success_error_level( int test_case_idx, int i, int j );
214 };
215
216
217 CV_ResizeTest::CV_ResizeTest() : CV_ImgWarpBaseTest( false )
218 {
219 }
220
221
222 void CV_ResizeTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
223 {
224     RNG& rng = ts->get_rng();
225     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
226     CvSize sz;
227
228     sz.width = (cvtest::randInt(rng) % sizes[INPUT][0].width) + 1;
229     sz.height = (cvtest::randInt(rng) % sizes[INPUT][0].height) + 1;
230
231     if( cvtest::randInt(rng) & 1 )
232     {
233         int xfactor = cvtest::randInt(rng) % 10 + 1;
234         int yfactor = cvtest::randInt(rng) % 10 + 1;
235
236         if( cvtest::randInt(rng) & 1 )
237             yfactor = xfactor;
238
239         sz.width = sizes[INPUT][0].width / xfactor;
240         sz.width = MAX(sz.width,1);
241         sz.height = sizes[INPUT][0].height / yfactor;
242         sz.height = MAX(sz.height,1);
243         sizes[INPUT][0].width = sz.width * xfactor;
244         sizes[INPUT][0].height = sz.height * yfactor;
245     }
246
247     if( cvtest::randInt(rng) & 1 )
248         sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = sz;
249     else
250     {
251         sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = sizes[INPUT][0];
252         sizes[INPUT][0] = sz;
253     }
254     if( interpolation == 4 &&
255        (MIN(sizes[INPUT][0].width,sizes[INPUT_OUTPUT][0].width) < 4 ||
256         MIN(sizes[INPUT][0].height,sizes[INPUT_OUTPUT][0].height) < 4))
257         interpolation = 2;
258 }
259
260
261 void CV_ResizeTest::run_func()
262 {
263     cvResize( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], interpolation );
264 }
265
266
267 double CV_ResizeTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
268 {
269     int depth = test_mat[INPUT][0].depth();
270     return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 1e-1;
271 }
272
273
274 void CV_ResizeTest::prepare_to_validation( int /*test_case_idx*/ )
275 {
276     CvMat _src = test_mat[INPUT][0], _dst = test_mat[REF_INPUT_OUTPUT][0];
277     CvMat *src = &_src, *dst = &_dst;
278     int i, j, k;
279     CvMat* x_idx = cvCreateMat( 1, dst->cols, CV_32SC1 );
280     CvMat* y_idx = cvCreateMat( 1, dst->rows, CV_32SC1 );
281     int* x_tab = x_idx->data.i;
282     int elem_size = CV_ELEM_SIZE(src->type);
283     int drows = dst->rows, dcols = dst->cols;
284
285     if( interpolation == CV_INTER_NN )
286     {
287         for( j = 0; j < dcols; j++ )
288         {
289             int t = (j*src->cols*2 + MIN(src->cols,dcols) - 1)/(dcols*2);
290             t -= t >= src->cols;
291             x_idx->data.i[j] = t*elem_size;
292         }
293
294         for( j = 0; j < drows; j++ )
295         {
296             int t = (j*src->rows*2 + MIN(src->rows,drows) - 1)/(drows*2);
297             t -= t >= src->rows;
298             y_idx->data.i[j] = t;
299         }
300     }
301     else
302     {
303         double scale_x = (double)src->cols/dcols;
304         double scale_y = (double)src->rows/drows;
305
306         for( j = 0; j < dcols; j++ )
307         {
308             double f = ((j+0.5)*scale_x - 0.5);
309             i = cvRound(f);
310             x_idx->data.i[j] = (i < 0 ? 0 : i >= src->cols ? src->cols - 1 : i)*elem_size;
311         }
312
313         for( j = 0; j < drows; j++ )
314         {
315             double f = ((j+0.5)*scale_y - 0.5);
316             i = cvRound(f);
317             y_idx->data.i[j] = i < 0 ? 0 : i >= src->rows ? src->rows - 1 : i;
318         }
319     }
320
321     for( i = 0; i < drows; i++ )
322     {
323         uchar* dptr = dst->data.ptr + dst->step*i;
324         const uchar* sptr0 = src->data.ptr + src->step*y_idx->data.i[i];
325
326         for( j = 0; j < dcols; j++, dptr += elem_size )
327         {
328             const uchar* sptr = sptr0 + x_tab[j];
329             for( k = 0; k < elem_size; k++ )
330                 dptr[k] = sptr[k];
331         }
332     }
333
334     cvReleaseMat( &x_idx );
335     cvReleaseMat( &y_idx );
336 }
337
338
339 /////////////////////////
340
341 static void test_remap( const Mat& src, Mat& dst, const Mat& mapx, const Mat& mapy,
342                         Mat* mask=0, int interpolation=CV_INTER_LINEAR )
343 {
344     int x, y, k;
345     int drows = dst.rows, dcols = dst.cols;
346     int srows = src.rows, scols = src.cols;
347     const uchar* sptr0 = src.data;
348     int depth = src.depth(), cn = src.channels();
349     int elem_size = (int)src.elemSize();
350     int step = (int)(src.step / CV_ELEM_SIZE(depth));
351     int delta;
352
353     if( interpolation != CV_INTER_CUBIC )
354     {
355         delta = 0;
356         scols -= 1; srows -= 1;
357     }
358     else
359     {
360         delta = 1;
361         scols = MAX(scols - 3, 0);
362         srows = MAX(srows - 3, 0);
363     }
364
365     int scols1 = MAX(scols - 2, 0);
366     int srows1 = MAX(srows - 2, 0);
367
368     if( mask )
369         *mask = Scalar::all(0);
370
371     for( y = 0; y < drows; y++ )
372     {
373         uchar* dptr = dst.ptr(y);
374         const float* mx = mapx.ptr<float>(y);
375         const float* my = mapy.ptr<float>(y);
376         uchar* m = mask ? mask->ptr(y) : 0;
377
378         for( x = 0; x < dcols; x++, dptr += elem_size )
379         {
380             float xs = mx[x];
381             float ys = my[x];
382             int ixs = cvFloor(xs);
383             int iys = cvFloor(ys);
384
385             if( (unsigned)(ixs - delta - 1) >= (unsigned)scols1 ||
386                 (unsigned)(iys - delta - 1) >= (unsigned)srows1 )
387             {
388                 if( m )
389                     m[x] = 1;
390                 if( (unsigned)(ixs - delta) >= (unsigned)scols ||
391                     (unsigned)(iys - delta) >= (unsigned)srows )
392                     continue;
393             }
394
395             xs -= ixs;
396             ys -= iys;
397
398             switch( depth )
399             {
400             case CV_8U:
401                 {
402                 const uchar* sptr = sptr0 + iys*step + ixs*cn;
403                 for( k = 0; k < cn; k++ )
404                 {
405                     float v00 = sptr[k];
406                     float v01 = sptr[cn + k];
407                     float v10 = sptr[step + k];
408                     float v11 = sptr[step + cn + k];
409
410                     v00 = v00 + xs*(v01 - v00);
411                     v10 = v10 + xs*(v11 - v10);
412                     v00 = v00 + ys*(v10 - v00);
413                     dptr[k] = (uchar)cvRound(v00);
414                 }
415                 }
416                 break;
417             case CV_16U:
418                 {
419                 const ushort* sptr = (const ushort*)sptr0 + iys*step + ixs*cn;
420                 for( k = 0; k < cn; k++ )
421                 {
422                     float v00 = sptr[k];
423                     float v01 = sptr[cn + k];
424                     float v10 = sptr[step + k];
425                     float v11 = sptr[step + cn + k];
426
427                     v00 = v00 + xs*(v01 - v00);
428                     v10 = v10 + xs*(v11 - v10);
429                     v00 = v00 + ys*(v10 - v00);
430                     ((ushort*)dptr)[k] = (ushort)cvRound(v00);
431                 }
432                 }
433                 break;
434             case CV_32F:
435                 {
436                 const float* sptr = (const float*)sptr0 + iys*step + ixs*cn;
437                 for( k = 0; k < cn; k++ )
438                 {
439                     float v00 = sptr[k];
440                     float v01 = sptr[cn + k];
441                     float v10 = sptr[step + k];
442                     float v11 = sptr[step + cn + k];
443
444                     v00 = v00 + xs*(v01 - v00);
445                     v10 = v10 + xs*(v11 - v10);
446                     v00 = v00 + ys*(v10 - v00);
447                     ((float*)dptr)[k] = (float)v00;
448                 }
449                 }
450                 break;
451             default:
452                 assert(0);
453             }
454         }
455     }
456 }
457
458 /////////////////////////
459
460 class CV_WarpAffineTest : public CV_ImgWarpBaseTest
461 {
462 public:
463     CV_WarpAffineTest();
464
465 protected:
466     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
467     void run_func();
468     int prepare_test_case( int test_case_idx );
469     void prepare_to_validation( int /*test_case_idx*/ );
470     double get_success_error_level( int test_case_idx, int i, int j );
471 };
472
473
474 CV_WarpAffineTest::CV_WarpAffineTest() : CV_ImgWarpBaseTest( true )
475 {
476     //spatial_scale_zoom = spatial_scale_decimate;
477     spatial_scale_decimate = spatial_scale_zoom;
478 }
479
480
481 void CV_WarpAffineTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
482 {
483     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
484     CvSize sz = sizes[INPUT][0];
485     // run for the second time to get output of a different size
486     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
487     sizes[INPUT][0] = sz;
488     sizes[INPUT][1] = cvSize( 3, 2 );
489 }
490
491
492 void CV_WarpAffineTest::run_func()
493 {
494     CvMat mtx = test_mat[INPUT][1];
495     cvWarpAffine( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &mtx, interpolation );
496 }
497
498
499 double CV_WarpAffineTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
500 {
501     int depth = test_mat[INPUT][0].depth();
502     return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2;
503 }
504
505
506 int CV_WarpAffineTest::prepare_test_case( int test_case_idx )
507 {
508     RNG& rng = ts->get_rng();
509     int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
510     const Mat& src = test_mat[INPUT][0];
511     const Mat& dst = test_mat[INPUT_OUTPUT][0];
512     Mat& mat = test_mat[INPUT][1];
513     CvPoint2D32f center;
514     double scale, angle;
515
516     if( code <= 0 )
517         return code;
518
519     double buffer[6];
520     Mat tmp( 2, 3, mat.type(), buffer );
521
522     center.x = (float)((cvtest::randReal(rng)*1.2 - 0.1)*src.cols);
523     center.y = (float)((cvtest::randReal(rng)*1.2 - 0.1)*src.rows);
524     angle = cvtest::randReal(rng)*360;
525     scale = ((double)dst.rows/src.rows + (double)dst.cols/src.cols)*0.5;
526     getRotationMatrix2D(center, angle, scale).convertTo(mat, mat.depth());
527     rng.fill( tmp, CV_RAND_NORMAL, Scalar::all(1.), Scalar::all(0.01) );
528     cv::max(tmp, 0.9, tmp);
529     cv::min(tmp, 1.1, tmp);
530     cv::multiply(tmp, mat, mat, 1.);
531
532     return code;
533 }
534
535
536 void CV_WarpAffineTest::prepare_to_validation( int /*test_case_idx*/ )
537 {
538     const Mat& src = test_mat[INPUT][0];
539     Mat& dst = test_mat[REF_INPUT_OUTPUT][0];
540     Mat& dst0 = test_mat[INPUT_OUTPUT][0];
541     Mat mapx(dst.size(), CV_32F), mapy(dst.size(), CV_32F);
542     double m[6];
543     Mat srcAb, dstAb( 2, 3, CV_64FC1, m );
544
545     //cvInvert( &tM, &M, CV_LU );
546     // [R|t] -> [R^-1 | -(R^-1)*t]
547     test_mat[INPUT][1].convertTo( srcAb, CV_64F );
548     Mat A = srcAb.colRange(0, 2);
549     Mat b = srcAb.col(2);
550     Mat invA = dstAb.colRange(0, 2);
551     Mat invAb = dstAb.col(2);
552     cv::invert(A, invA, CV_SVD);
553     cv::gemm(invA, b, -1, Mat(), 0, invAb);
554
555     for( int y = 0; y < dst.rows; y++ )
556         for( int x = 0; x < dst.cols; x++ )
557         {
558             mapx.at<float>(y, x) = (float)(x*m[0] + y*m[1] + m[2]);
559             mapy.at<float>(y, x) = (float)(x*m[3] + y*m[4] + m[5]);
560         }
561
562     Mat mask( dst.size(), CV_8U );
563     test_remap( src, dst, mapx, mapy, &mask );
564     dst.setTo(Scalar::all(0), mask);
565     dst0.setTo(Scalar::all(0), mask);
566 }
567
568
569 /////////////////////////
570
571 class CV_WarpPerspectiveTest : public CV_ImgWarpBaseTest
572 {
573 public:
574     CV_WarpPerspectiveTest();
575
576 protected:
577     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
578     void run_func();
579     int prepare_test_case( int test_case_idx );
580     void prepare_to_validation( int /*test_case_idx*/ );
581     double get_success_error_level( int test_case_idx, int i, int j );
582 };
583
584
585 CV_WarpPerspectiveTest::CV_WarpPerspectiveTest() : CV_ImgWarpBaseTest( true )
586 {
587     //spatial_scale_zoom = spatial_scale_decimate;
588     spatial_scale_decimate = spatial_scale_zoom;
589 }
590
591
592 void CV_WarpPerspectiveTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
593 {
594     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
595     CvSize sz = sizes[INPUT][0];
596     // run for the second time to get output of a different size
597     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
598     sizes[INPUT][0] = sz;
599     sizes[INPUT][1] = cvSize( 3, 3 );
600 }
601
602
603 void CV_WarpPerspectiveTest::run_func()
604 {
605     CvMat mtx = test_mat[INPUT][1];
606     cvWarpPerspective( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &mtx, interpolation );
607 }
608
609
610 double CV_WarpPerspectiveTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
611 {
612     int depth = test_mat[INPUT][0].depth();
613     return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2;
614 }
615
616
617 int CV_WarpPerspectiveTest::prepare_test_case( int test_case_idx )
618 {
619     RNG& rng = ts->get_rng();
620     int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
621     const CvMat& src = test_mat[INPUT][0];
622     const CvMat& dst = test_mat[INPUT_OUTPUT][0];
623     Mat& mat = test_mat[INPUT][1];
624     Point2f s[4], d[4];
625     int i;
626
627     if( code <= 0 )
628         return code;
629
630     s[0] = Point2f(0,0);
631     d[0] = Point2f(0,0);
632     s[1] = Point2f(src.cols-1.f,0);
633     d[1] = Point2f(dst.cols-1.f,0);
634     s[2] = Point2f(src.cols-1.f,src.rows-1.f);
635     d[2] = Point2f(dst.cols-1.f,dst.rows-1.f);
636     s[3] = Point2f(0,src.rows-1.f);
637     d[3] = Point2f(0,dst.rows-1.f);
638
639     float bufer[16];
640     Mat tmp( 1, 16, CV_32FC1, bufer );
641
642     rng.fill( tmp, CV_RAND_NORMAL, Scalar::all(0.), Scalar::all(0.1) );
643
644     for( i = 0; i < 4; i++ )
645     {
646         s[i].x += bufer[i*4]*src.cols/2;
647         s[i].y += bufer[i*4+1]*src.rows/2;
648         d[i].x += bufer[i*4+2]*dst.cols/2;
649         d[i].y += bufer[i*4+3]*dst.rows/2;
650     }
651
652     cv::getPerspectiveTransform( s, d ).convertTo( mat, mat.depth() );
653     return code;
654 }
655
656
657 void CV_WarpPerspectiveTest::prepare_to_validation( int /*test_case_idx*/ )
658 {
659     Mat& src = test_mat[INPUT][0];
660     Mat& dst = test_mat[REF_INPUT_OUTPUT][0];
661     Mat& dst0 = test_mat[INPUT_OUTPUT][0];
662     Mat mapx(dst.size(), CV_32F), mapy(dst.size(), CV_32F);
663     double m[9];
664     Mat srcM, dstM(3, 3, CV_64F, m);
665
666     //cvInvert( &tM, &M, CV_LU );
667     // [R|t] -> [R^-1 | -(R^-1)*t]
668     test_mat[INPUT][1].convertTo( srcM, CV_64F );
669     cv::invert(srcM, dstM, CV_SVD);
670
671     for( int y = 0; y < dst.rows; y++ )
672     {
673         for( int x = 0; x < dst.cols; x++ )
674         {
675             double xs = x*m[0] + y*m[1] + m[2];
676             double ys = x*m[3] + y*m[4] + m[5];
677             double ds = x*m[6] + y*m[7] + m[8];
678
679             ds = ds ? 1./ds : 0;
680             xs *= ds;
681             ys *= ds;
682
683             mapx.at<float>(y, x) = (float)xs;
684             mapy.at<float>(y, x) = (float)ys;
685         }
686     }
687
688     Mat mask( dst.size(), CV_8U );
689     test_remap( src, dst, mapx, mapy, &mask );
690     dst.setTo(Scalar::all(0), mask);
691     dst0.setTo(Scalar::all(0), mask);
692 }
693
694
695 /////////////////////////
696
697 class CV_RemapTest : public CV_ImgWarpBaseTest
698 {
699 public:
700     CV_RemapTest();
701
702 protected:
703     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
704     void run_func();
705     int prepare_test_case( int test_case_idx );
706     void prepare_to_validation( int /*test_case_idx*/ );
707     double get_success_error_level( int test_case_idx, int i, int j );
708     void fill_array( int test_case_idx, int i, int j, Mat& arr );
709 };
710
711
712 CV_RemapTest::CV_RemapTest() : CV_ImgWarpBaseTest( false )
713 {
714     //spatial_scale_zoom = spatial_scale_decimate;
715     test_array[INPUT].push_back(NULL);
716     test_array[INPUT].push_back(NULL);
717
718     spatial_scale_decimate = spatial_scale_zoom;
719 }
720
721
722 void CV_RemapTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
723 {
724     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
725     types[INPUT][1] = types[INPUT][2] = CV_32FC1;
726     interpolation = CV_INTER_LINEAR;
727 }
728
729
730 void CV_RemapTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
731 {
732     if( i != INPUT )
733         CV_ImgWarpBaseTest::fill_array( test_case_idx, i, j, arr );
734 }
735
736
737 void CV_RemapTest::run_func()
738 {
739     cvRemap( test_array[INPUT][0], test_array[INPUT_OUTPUT][0],
740              test_array[INPUT][1], test_array[INPUT][2], interpolation );
741 }
742
743
744 double CV_RemapTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
745 {
746     int depth = test_mat[INPUT][0].depth();
747     return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2;
748 }
749
750
751 int CV_RemapTest::prepare_test_case( int test_case_idx )
752 {
753     RNG& rng = ts->get_rng();
754     int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
755     const Mat& src = test_mat[INPUT][0];
756     double a[9] = {0,0,0,0,0,0,0,0,1}, k[4];
757     Mat _a( 3, 3, CV_64F, a );
758     Mat _k( 4, 1, CV_64F, k );
759     double sz = MAX(src.rows, src.cols);
760
761     if( code <= 0 )
762         return code;
763
764     double aspect_ratio = cvtest::randReal(rng)*0.6 + 0.7;
765     a[2] = (src.cols - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
766     a[5] = (src.rows - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
767     a[0] = sz/(0.9 - cvtest::randReal(rng)*0.6);
768     a[4] = aspect_ratio*a[0];
769     k[0] = cvtest::randReal(rng)*0.06 - 0.03;
770     k[1] = cvtest::randReal(rng)*0.06 - 0.03;
771     if( k[0]*k[1] > 0 )
772         k[1] = -k[1];
773     k[2] = cvtest::randReal(rng)*0.004 - 0.002;
774     k[3] = cvtest::randReal(rng)*0.004 - 0.002;
775
776     cvtest::initUndistortMap( _a, _k, test_mat[INPUT][1].size(), test_mat[INPUT][1], test_mat[INPUT][2] );
777     return code;
778 }
779
780
781 void CV_RemapTest::prepare_to_validation( int /*test_case_idx*/ )
782 {
783     Mat& dst = test_mat[REF_INPUT_OUTPUT][0];
784     Mat& dst0 = test_mat[INPUT_OUTPUT][0];
785     Mat mask( dst.size(), CV_8U );
786     test_remap(test_mat[INPUT][0], dst, test_mat[INPUT][1],
787                test_mat[INPUT][2], &mask, interpolation );
788     dst.setTo(Scalar::all(0), mask);
789     dst0.setTo(Scalar::all(0), mask);
790 }
791
792
793 ////////////////////////////// undistort /////////////////////////////////
794
795 class CV_UndistortTest : public CV_ImgWarpBaseTest
796 {
797 public:
798     CV_UndistortTest();
799
800 protected:
801     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
802     void run_func();
803     int prepare_test_case( int test_case_idx );
804     void prepare_to_validation( int /*test_case_idx*/ );
805     double get_success_error_level( int test_case_idx, int i, int j );
806     void fill_array( int test_case_idx, int i, int j, Mat& arr );
807
808 private:
809     bool useCPlus;
810     cv::Mat input0;
811     cv::Mat input1;
812     cv::Mat input2;
813     cv::Mat input_new_cam;
814     cv::Mat input_output;
815
816     bool zero_new_cam;
817     bool zero_distortion;
818 };
819
820
821 CV_UndistortTest::CV_UndistortTest() : CV_ImgWarpBaseTest( false )
822 {
823     //spatial_scale_zoom = spatial_scale_decimate;
824     test_array[INPUT].push_back(NULL);
825     test_array[INPUT].push_back(NULL);
826     test_array[INPUT].push_back(NULL);
827
828     spatial_scale_decimate = spatial_scale_zoom;
829 }
830
831
832 void CV_UndistortTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
833 {
834     RNG& rng = ts->get_rng();
835     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
836     int type = types[INPUT][0];
837     type = CV_MAKETYPE( CV_8U, CV_MAT_CN(type) );
838     types[INPUT][0] = types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = type;
839     types[INPUT][1] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
840     types[INPUT][2] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
841     sizes[INPUT][1] = cvSize(3,3);
842     sizes[INPUT][2] = cvtest::randInt(rng)%2 ? cvSize(4,1) : cvSize(1,4);
843     types[INPUT][3] =  types[INPUT][1];
844     sizes[INPUT][3] = sizes[INPUT][1];
845     interpolation = CV_INTER_LINEAR;
846 }
847
848
849 void CV_UndistortTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
850 {
851     if( i != INPUT )
852         CV_ImgWarpBaseTest::fill_array( test_case_idx, i, j, arr );
853 }
854
855
856 void CV_UndistortTest::run_func()
857 {
858     if (!useCPlus)
859     {
860         CvMat a = test_mat[INPUT][1], k = test_mat[INPUT][2];
861         cvUndistort2( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &a, &k);
862     }
863     else
864     {
865         if (zero_distortion)
866         {
867             cv::undistort(input0,input_output,input1,cv::Mat());
868         }
869         else
870         {
871             cv::undistort(input0,input_output,input1,input2);
872         }
873     }
874 }
875
876
877 double CV_UndistortTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
878 {
879     int depth = test_mat[INPUT][0].depth();
880     return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2;
881 }
882
883
884 int CV_UndistortTest::prepare_test_case( int test_case_idx )
885 {
886     RNG& rng = ts->get_rng();
887     int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
888
889     const Mat& src = test_mat[INPUT][0];
890     double k[4], a[9] = {0,0,0,0,0,0,0,0,1};
891     double new_cam[9] = {0,0,0,0,0,0,0,0,1};
892     double sz = MAX(src.rows, src.cols);
893
894     Mat& _new_cam0 = test_mat[INPUT][3];
895     Mat _new_cam(test_mat[INPUT][3].rows,test_mat[INPUT][3].cols,CV_64F,new_cam);
896     Mat& _a0 = test_mat[INPUT][1];
897     Mat _a(3,3,CV_64F,a);
898     Mat& _k0 = test_mat[INPUT][2];
899     Mat _k(_k0.rows,_k0.cols, CV_MAKETYPE(CV_64F,_k0.channels()),k);
900
901     if( code <= 0 )
902         return code;
903
904     double aspect_ratio = cvtest::randReal(rng)*0.6 + 0.7;
905     a[2] = (src.cols - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
906     a[5] = (src.rows - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
907     a[0] = sz/(0.9 - cvtest::randReal(rng)*0.6);
908     a[4] = aspect_ratio*a[0];
909     k[0] = cvtest::randReal(rng)*0.06 - 0.03;
910     k[1] = cvtest::randReal(rng)*0.06 - 0.03;
911     if( k[0]*k[1] > 0 )
912         k[1] = -k[1];
913     if( cvtest::randInt(rng)%4 != 0 )
914     {
915         k[2] = cvtest::randReal(rng)*0.004 - 0.002;
916         k[3] = cvtest::randReal(rng)*0.004 - 0.002;
917     }
918     else
919         k[2] = k[3] = 0;
920
921     new_cam[0] = a[0] + (cvtest::randReal(rng) - (double)0.5)*0.2*a[0]; //10%
922     new_cam[4] = a[4] + (cvtest::randReal(rng) - (double)0.5)*0.2*a[4]; //10%
923     new_cam[2] = a[2] + (cvtest::randReal(rng) - (double)0.5)*0.3*test_mat[INPUT][0].rows; //15%
924     new_cam[5] = a[5] + (cvtest::randReal(rng) - (double)0.5)*0.3*test_mat[INPUT][0].cols; //15%
925
926     _a.convertTo(_a0, _a0.depth());
927
928     zero_distortion = (cvtest::randInt(rng)%2) == 0 ? false : true;
929     _k.convertTo(_k0, _k0.depth());
930
931     zero_new_cam = (cvtest::randInt(rng)%2) == 0 ? false : true;
932     _new_cam.convertTo(_new_cam0, _new_cam0.depth());
933
934     //Testing C++ code
935     useCPlus = ((cvtest::randInt(rng) % 2)!=0);
936     if (useCPlus)
937     {
938         input0 = test_mat[INPUT][0];
939         input1 = test_mat[INPUT][1];
940         input2 = test_mat[INPUT][2];
941         input_new_cam = test_mat[INPUT][3];
942     }
943
944     return code;
945 }
946
947
948 void CV_UndistortTest::prepare_to_validation( int /*test_case_idx*/ )
949 {
950     if (useCPlus)
951     {
952         Mat& output = test_mat[INPUT_OUTPUT][0];
953         input_output.convertTo(output, output.type());
954     }
955     Mat& src = test_mat[INPUT][0];
956     Mat& dst = test_mat[REF_INPUT_OUTPUT][0];
957     Mat& dst0 = test_mat[INPUT_OUTPUT][0];
958     Mat mapx, mapy;
959     cvtest::initUndistortMap( test_mat[INPUT][1], test_mat[INPUT][2], dst.size(), mapx, mapy );
960     Mat mask( dst.size(), CV_8U );
961     test_remap( src, dst, mapx, mapy, &mask, interpolation );
962     dst.setTo(Scalar::all(0), mask);
963     dst0.setTo(Scalar::all(0), mask);
964 }
965
966
967 class CV_UndistortMapTest : public cvtest::ArrayTest
968 {
969 public:
970     CV_UndistortMapTest();
971
972 protected:
973     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
974     void run_func();
975     int prepare_test_case( int test_case_idx );
976     void prepare_to_validation( int /*test_case_idx*/ );
977     double get_success_error_level( int test_case_idx, int i, int j );
978     void fill_array( int test_case_idx, int i, int j, Mat& arr );
979
980 private:
981     bool dualChannel;
982 };
983
984
985 CV_UndistortMapTest::CV_UndistortMapTest()
986 {
987     test_array[INPUT].push_back(NULL);
988     test_array[INPUT].push_back(NULL);
989     test_array[OUTPUT].push_back(NULL);
990     test_array[OUTPUT].push_back(NULL);
991     test_array[REF_OUTPUT].push_back(NULL);
992     test_array[REF_OUTPUT].push_back(NULL);
993
994     element_wise_relative_error = false;
995 }
996
997
998 void CV_UndistortMapTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
999 {
1000     RNG& rng = ts->get_rng();
1001     cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1002     int depth = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
1003
1004     CvSize sz = sizes[OUTPUT][0];
1005     types[INPUT][0] = types[INPUT][1] = depth;
1006     dualChannel = cvtest::randInt(rng)%2 == 0;
1007     types[OUTPUT][0] = types[OUTPUT][1] =
1008         types[REF_OUTPUT][0] = types[REF_OUTPUT][1] = dualChannel ? CV_32FC2 : CV_32F;
1009     sizes[INPUT][0] = cvSize(3,3);
1010     sizes[INPUT][1] = cvtest::randInt(rng)%2 ? cvSize(4,1) : cvSize(1,4);
1011
1012     sz.width = MAX(sz.width,16);
1013     sz.height = MAX(sz.height,16);
1014     sizes[OUTPUT][0] = sizes[OUTPUT][1] =
1015         sizes[REF_OUTPUT][0] = sizes[REF_OUTPUT][1] = sz;
1016 }
1017
1018
1019 void CV_UndistortMapTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
1020 {
1021     if( i != INPUT )
1022         cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr );
1023 }
1024
1025
1026 void CV_UndistortMapTest::run_func()
1027 {
1028     CvMat a = test_mat[INPUT][0], k = test_mat[INPUT][1];
1029
1030     if (!dualChannel )
1031         cvInitUndistortMap( &a, &k, test_array[OUTPUT][0], test_array[OUTPUT][1] );
1032     else
1033         cvInitUndistortMap( &a, &k, test_array[OUTPUT][0], 0 );
1034 }
1035
1036
1037 double CV_UndistortMapTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1038 {
1039     return 1e-3;
1040 }
1041
1042
1043 int CV_UndistortMapTest::prepare_test_case( int test_case_idx )
1044 {
1045     RNG& rng = ts->get_rng();
1046     int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
1047     const Mat& mapx = test_mat[OUTPUT][0];
1048     double k[4], a[9] = {0,0,0,0,0,0,0,0,1};
1049     double sz = MAX(mapx.rows, mapx.cols);
1050     Mat& _a0 = test_mat[INPUT][0], &_k0 = test_mat[INPUT][1];
1051     Mat _a(3,3,CV_64F,a);
1052     Mat _k(_k0.rows,_k0.cols, CV_MAKETYPE(CV_64F,_k0.channels()),k);
1053
1054     if( code <= 0 )
1055         return code;
1056
1057     double aspect_ratio = cvtest::randReal(rng)*0.6 + 0.7;
1058     a[2] = (mapx.cols - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
1059     a[5] = (mapx.rows - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
1060     a[0] = sz/(0.9 - cvtest::randReal(rng)*0.6);
1061     a[4] = aspect_ratio*a[0];
1062     k[0] = cvtest::randReal(rng)*0.06 - 0.03;
1063     k[1] = cvtest::randReal(rng)*0.06 - 0.03;
1064     if( k[0]*k[1] > 0 )
1065         k[1] = -k[1];
1066     k[2] = cvtest::randReal(rng)*0.004 - 0.002;
1067     k[3] = cvtest::randReal(rng)*0.004 - 0.002;
1068
1069     _a.convertTo(_a0, _a0.depth());
1070     _k.convertTo(_k0, _k0.depth());
1071
1072     if (dualChannel)
1073     {
1074         test_mat[REF_OUTPUT][1] = Scalar::all(0);
1075         test_mat[OUTPUT][1] = Scalar::all(0);
1076     }
1077
1078     return code;
1079 }
1080
1081
1082 void CV_UndistortMapTest::prepare_to_validation( int )
1083 {
1084     Mat mapx, mapy;
1085     cvtest::initUndistortMap( test_mat[INPUT][0], test_mat[INPUT][1], test_mat[REF_OUTPUT][0].size(), mapx, mapy );
1086     if( !dualChannel )
1087     {
1088         mapx.copyTo(test_mat[REF_OUTPUT][0]);
1089         mapy.copyTo(test_mat[REF_OUTPUT][1]);
1090     }
1091     else
1092     {
1093         Mat p[2] = {mapx, mapy};
1094         cv::merge(p, 2, test_mat[REF_OUTPUT][0]);
1095     }
1096 }
1097
1098 ////////////////////////////// GetRectSubPix /////////////////////////////////
1099
1100 static void
1101 test_getQuadrangeSubPix( const Mat& src, Mat& dst, double* a )
1102 {
1103     int sstep = (int)(src.step / sizeof(float));
1104     int scols = src.cols, srows = src.rows;
1105
1106     CV_Assert( src.depth() == CV_32F && src.type() == dst.type() );
1107
1108     int cn = dst.channels();
1109
1110     for( int y = 0; y < dst.rows; y++ )
1111         for( int x = 0; x < dst.cols; x++ )
1112         {
1113             float* d = dst.ptr<float>(y) + x*cn;
1114             float sx = (float)(a[0]*x + a[1]*y + a[2]);
1115             float sy = (float)(a[3]*x + a[4]*y + a[5]);
1116             int ix = cvFloor(sx), iy = cvFloor(sy);
1117             int dx = cn, dy = sstep;
1118             const float* s;
1119             sx -= ix; sy -= iy;
1120
1121             if( (unsigned)ix >= (unsigned)(scols-1) )
1122                 ix = ix < 0 ? 0 : scols - 1, sx = 0, dx = 0;
1123             if( (unsigned)iy >= (unsigned)(srows-1) )
1124                 iy = iy < 0 ? 0 : srows - 1, sy = 0, dy = 0;
1125
1126             s = src.ptr<float>(iy) + ix*cn;
1127             for( int k = 0; k < cn; k++, s++ )
1128             {
1129                 float t0 = s[0] + sx*(s[dx] - s[0]);
1130                 float t1 = s[dy] + sx*(s[dy + dx] - s[dy]);
1131                 d[k] = t0 + sy*(t1 - t0);
1132             }
1133         }
1134 }
1135
1136
1137 class CV_GetRectSubPixTest : public CV_ImgWarpBaseTest
1138 {
1139 public:
1140     CV_GetRectSubPixTest();
1141
1142 protected:
1143     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
1144     void run_func();
1145     int prepare_test_case( int test_case_idx );
1146     void prepare_to_validation( int /*test_case_idx*/ );
1147     double get_success_error_level( int test_case_idx, int i, int j );
1148     void fill_array( int test_case_idx, int i, int j, Mat& arr );
1149
1150     CvPoint2D32f center;
1151     bool test_cpp;
1152 };
1153
1154
1155 CV_GetRectSubPixTest::CV_GetRectSubPixTest() : CV_ImgWarpBaseTest( false )
1156 {
1157     //spatial_scale_zoom = spatial_scale_decimate;
1158     spatial_scale_decimate = spatial_scale_zoom;
1159     test_cpp = false;
1160 }
1161
1162
1163 void CV_GetRectSubPixTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
1164 {
1165     RNG& rng = ts->get_rng();
1166     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1167     int src_depth = cvtest::randInt(rng) % 2, dst_depth;
1168     int cn = cvtest::randInt(rng) % 2 ? 3 : 1;
1169     CvSize src_size, dst_size;
1170
1171     dst_depth = src_depth = src_depth == 0 ? CV_8U : CV_32F;
1172     if( src_depth < CV_32F && cvtest::randInt(rng) % 2 )
1173         dst_depth = CV_32F;
1174
1175     types[INPUT][0] = CV_MAKETYPE(src_depth,cn);
1176     types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(dst_depth,cn);
1177
1178     src_size = sizes[INPUT][0];
1179     dst_size.width = cvRound(sqrt(cvtest::randReal(rng)*src_size.width) + 1);
1180     dst_size.height = cvRound(sqrt(cvtest::randReal(rng)*src_size.height) + 1);
1181     dst_size.width = MIN(dst_size.width,src_size.width);
1182     dst_size.height = MIN(dst_size.width,src_size.height);
1183     sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = dst_size;
1184
1185     center.x = (float)(cvtest::randReal(rng)*src_size.width);
1186     center.y = (float)(cvtest::randReal(rng)*src_size.height);
1187     interpolation = CV_INTER_LINEAR;
1188
1189     test_cpp = (cvtest::randInt(rng) & 256) == 0;
1190 }
1191
1192
1193 void CV_GetRectSubPixTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
1194 {
1195     if( i != INPUT )
1196         CV_ImgWarpBaseTest::fill_array( test_case_idx, i, j, arr );
1197 }
1198
1199
1200 void CV_GetRectSubPixTest::run_func()
1201 {
1202     if(!test_cpp)
1203         cvGetRectSubPix( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], center );
1204     else
1205     {
1206         cv::Mat _out = cv::cvarrToMat(test_array[INPUT_OUTPUT][0]);
1207         cv::getRectSubPix( cv::cvarrToMat(test_array[INPUT][0]), _out.size(), center, _out, _out.type());
1208     }
1209 }
1210
1211
1212 double CV_GetRectSubPixTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1213 {
1214     int in_depth = test_mat[INPUT][0].depth();
1215     int out_depth = test_mat[INPUT_OUTPUT][0].depth();
1216
1217     return in_depth >= CV_32F ? 1e-3 : out_depth >= CV_32F ? 1e-2 : 1;
1218 }
1219
1220
1221 int CV_GetRectSubPixTest::prepare_test_case( int test_case_idx )
1222 {
1223     return CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
1224 }
1225
1226
1227 void CV_GetRectSubPixTest::prepare_to_validation( int /*test_case_idx*/ )
1228 {
1229     Mat& src0 = test_mat[INPUT][0];
1230     Mat& dst0 = test_mat[REF_INPUT_OUTPUT][0];
1231     Mat src = src0, dst = dst0;
1232     int ftype = CV_MAKETYPE(CV_32F,src0.channels());
1233     double a[] = { 1, 0, center.x - dst.cols*0.5 + 0.5,
1234                    0, 1, center.y - dst.rows*0.5 + 0.5 };
1235     if( src.depth() != CV_32F )
1236         src0.convertTo(src, CV_32F);
1237
1238     if( dst.depth() != CV_32F )
1239         dst.create(dst0.size(), ftype);
1240
1241     test_getQuadrangeSubPix( src, dst, a );
1242
1243     if( dst.data != dst0.data )
1244         dst.convertTo(dst0, dst0.depth());
1245 }
1246
1247
1248 class CV_GetQuadSubPixTest : public CV_ImgWarpBaseTest
1249 {
1250 public:
1251     CV_GetQuadSubPixTest();
1252
1253 protected:
1254     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
1255     void run_func();
1256     int prepare_test_case( int test_case_idx );
1257     void prepare_to_validation( int /*test_case_idx*/ );
1258     double get_success_error_level( int test_case_idx, int i, int j );
1259 };
1260
1261
1262 CV_GetQuadSubPixTest::CV_GetQuadSubPixTest() : CV_ImgWarpBaseTest( true )
1263 {
1264     //spatial_scale_zoom = spatial_scale_decimate;
1265     spatial_scale_decimate = spatial_scale_zoom;
1266 }
1267
1268
1269 void CV_GetQuadSubPixTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
1270 {
1271     int min_size = 4;
1272     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1273     CvSize sz = sizes[INPUT][0], dsz;
1274     RNG& rng = ts->get_rng();
1275     int msz, src_depth = cvtest::randInt(rng) % 2, dst_depth;
1276     int cn = cvtest::randInt(rng) % 2 ? 3 : 1;
1277
1278     dst_depth = src_depth = src_depth == 0 ? CV_8U : CV_32F;
1279     if( src_depth < CV_32F && cvtest::randInt(rng) % 2 )
1280         dst_depth = CV_32F;
1281
1282     types[INPUT][0] = CV_MAKETYPE(src_depth,cn);
1283     types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(dst_depth,cn);
1284
1285     sz.width = MAX(sz.width,min_size);
1286     sz.height = MAX(sz.height,min_size);
1287     sizes[INPUT][0] = sz;
1288     msz = MIN( sz.width, sz.height );
1289
1290     dsz.width = cvRound(sqrt(cvtest::randReal(rng)*msz) + 1);
1291     dsz.height = cvRound(sqrt(cvtest::randReal(rng)*msz) + 1);
1292     dsz.width = MIN(dsz.width,msz);
1293     dsz.height = MIN(dsz.width,msz);
1294     dsz.width = MAX(dsz.width,min_size);
1295     dsz.height = MAX(dsz.height,min_size);
1296     sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = dsz;
1297     sizes[INPUT][1] = cvSize( 3, 2 );
1298 }
1299
1300
1301 void CV_GetQuadSubPixTest::run_func()
1302 {
1303     CvMat mtx = test_mat[INPUT][1];
1304     cvGetQuadrangleSubPix( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &mtx );
1305 }
1306
1307
1308 double CV_GetQuadSubPixTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1309 {
1310     int in_depth = test_mat[INPUT][0].depth();
1311     //int out_depth = test_mat[INPUT_OUTPUT][0].depth();
1312
1313     return in_depth >= CV_32F ? 1e-2 : 4;
1314 }
1315
1316
1317 int CV_GetQuadSubPixTest::prepare_test_case( int test_case_idx )
1318 {
1319     RNG& rng = ts->get_rng();
1320     int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
1321     const Mat& src = test_mat[INPUT][0];
1322     Mat& mat = test_mat[INPUT][1];
1323     CvPoint2D32f center;
1324     double scale, angle;
1325
1326     if( code <= 0 )
1327         return code;
1328
1329     double a[6];
1330     Mat A( 2, 3, CV_64FC1, a );
1331
1332     center.x = (float)((cvtest::randReal(rng)*1.2 - 0.1)*src.cols);
1333     center.y = (float)((cvtest::randReal(rng)*1.2 - 0.1)*src.rows);
1334     angle = cvtest::randReal(rng)*360;
1335     scale = cvtest::randReal(rng)*0.2 + 0.9;
1336
1337     // y = Ax + b -> x = A^-1(y - b) = A^-1*y - A^-1*b
1338     scale = 1./scale;
1339     angle = angle*(CV_PI/180.);
1340     a[0] = a[4] = cos(angle)*scale;
1341     a[1] = sin(angle)*scale;
1342     a[3] = -a[1];
1343     a[2] = center.x - a[0]*center.x - a[1]*center.y;
1344     a[5] = center.y - a[3]*center.x - a[4]*center.y;
1345     A.convertTo( mat, mat.depth() );
1346
1347     return code;
1348 }
1349
1350
1351 void CV_GetQuadSubPixTest::prepare_to_validation( int /*test_case_idx*/ )
1352 {
1353     Mat& src0 = test_mat[INPUT][0];
1354     Mat& dst0 = test_mat[REF_INPUT_OUTPUT][0];
1355     Mat src = src0, dst = dst0;
1356     int ftype = CV_MAKETYPE(CV_32F,src0.channels());
1357     double a[6], dx = (dst0.cols - 1)*0.5, dy = (dst0.rows - 1)*0.5;
1358     Mat A( 2, 3, CV_64F, a );
1359
1360     if( src.depth() != CV_32F )
1361         src0.convertTo(src, CV_32F);
1362
1363     if( dst.depth() != CV_32F )
1364         dst.create(dst0.size(), ftype);
1365
1366     test_mat[INPUT][1].convertTo( A, CV_64F );
1367     a[2] -= a[0]*dx + a[1]*dy;
1368     a[5] -= a[3]*dx + a[4]*dy;
1369     test_getQuadrangeSubPix( src, dst, a );
1370
1371     if( dst.data != dst0.data )
1372         dst.convertTo(dst0, dst0.depth());
1373 }
1374
1375 TEST(Imgproc_cvWarpAffine, regression)
1376 {
1377     IplImage* src = cvCreateImage(cvSize(100, 100), IPL_DEPTH_8U, 1);
1378     IplImage* dst = cvCreateImage(cvSize(100, 100), IPL_DEPTH_8U, 1);
1379
1380     float m[6];
1381     CvMat M = cvMat( 2, 3, CV_32F, m );
1382     int w = src->width;
1383     int h = src->height;
1384     cv2DRotationMatrix(cvPoint2D32f(w*0.5f, h*0.5f), 45.0, 1.0, &M);
1385     cvWarpAffine(src, dst, &M);
1386 }
1387
1388 TEST(Imgproc_fitLine_vector_3d, regression)
1389 {
1390     std::vector<Point3f> points_vector;
1391
1392     Point3f p21(4,4,4);
1393     Point3f p22(8,8,8);
1394
1395     points_vector.push_back(p21);
1396     points_vector.push_back(p22);
1397
1398     std::vector<float> line;
1399
1400     cv::fitLine(points_vector, line, CV_DIST_L2, 0 ,0 ,0);
1401
1402     ASSERT_EQ(line.size(), (size_t)6);
1403
1404 }
1405
1406 TEST(Imgproc_fitLine_vector_2d, regression)
1407 {
1408     std::vector<Point2f> points_vector;
1409
1410     Point2f p21(4,4);
1411     Point2f p22(8,8);
1412     Point2f p23(16,16);
1413
1414     points_vector.push_back(p21);
1415     points_vector.push_back(p22);
1416     points_vector.push_back(p23);
1417
1418     std::vector<float> line;
1419
1420     cv::fitLine(points_vector, line, CV_DIST_L2, 0 ,0 ,0);
1421
1422     ASSERT_EQ(line.size(), (size_t)4);
1423 }
1424
1425 TEST(Imgproc_fitLine_Mat_2dC2, regression)
1426 {
1427     cv::Mat mat1 = Mat::zeros(3, 1, CV_32SC2);
1428     std::vector<float> line1;
1429
1430     cv::fitLine(mat1, line1, CV_DIST_L2, 0 ,0 ,0);
1431
1432     ASSERT_EQ(line1.size(), (size_t)4);
1433 }
1434
1435 TEST(Imgproc_fitLine_Mat_2dC1, regression)
1436 {
1437     cv::Matx<int, 3, 2> mat2;
1438     std::vector<float> line2;
1439
1440     cv::fitLine(mat2, line2, CV_DIST_L2, 0 ,0 ,0);
1441
1442     ASSERT_EQ(line2.size(), (size_t)4);
1443 }
1444
1445 TEST(Imgproc_fitLine_Mat_3dC3, regression)
1446 {
1447     cv::Mat mat1 = Mat::zeros(2, 1, CV_32SC3);
1448     std::vector<float> line1;
1449
1450     cv::fitLine(mat1, line1, CV_DIST_L2, 0 ,0 ,0);
1451
1452     ASSERT_EQ(line1.size(), (size_t)6);
1453 }
1454
1455 TEST(Imgproc_fitLine_Mat_3dC1, regression)
1456 {
1457     cv::Mat mat2 = Mat::zeros(2, 3, CV_32SC1);
1458     std::vector<float> line2;
1459
1460     cv::fitLine(mat2, line2, CV_DIST_L2, 0 ,0 ,0);
1461
1462     ASSERT_EQ(line2.size(), (size_t)6);
1463 }
1464
1465 TEST(Imgproc_resize_area, regression)
1466 {
1467     static ushort input_data[16 * 16] = {
1468          90,  94,  80,   3, 231,   2, 186, 245, 188, 165,  10,  19, 201, 169,   8, 228,
1469          86,   5, 203, 120, 136, 185,  24,  94,  81, 150, 163, 137,  88, 105, 132, 132,
1470         236,  48, 250, 218,  19,  52,  54, 221, 159, 112,  45,  11, 152, 153, 112, 134,
1471          78, 133, 136,  83,  65,  76,  82, 250,   9, 235, 148,  26, 236, 179, 200,  50,
1472          99,  51, 103, 142, 201,  65, 176,  33,  49, 226, 177, 109,  46,  21,  67, 130,
1473          54, 125, 107, 154, 145,  51, 199, 189, 161, 142, 231, 240, 139, 162, 240,  22,
1474         231,  86,  79, 106,  92,  47, 146, 156,  36, 207,  71,  33,   2, 244, 221,  71,
1475          44, 127,  71, 177,  75, 126,  68, 119, 200, 129, 191, 251,   6, 236, 247,  6,
1476         133, 175,  56, 239, 147, 221, 243, 154, 242,  82, 106,  99,  77, 158,  60, 229,
1477           2,  42,  24, 174,  27, 198,  14, 204, 246, 251, 141,  31, 114, 163,  29, 147,
1478         121,  53,  74,  31, 147, 189,  42,  98, 202,  17, 228, 123, 209,  40,  77,  49,
1479         112, 203,  30,  12, 205,  25,  19, 106, 145, 185, 163, 201, 237, 223, 247,  38,
1480          33, 105, 243, 117,  92, 179, 204, 248, 160,  90,  73, 126,   2,  41, 213, 204,
1481           6, 124, 195, 201, 230, 187, 210, 167,  48,  79, 123, 159, 145, 218, 105, 209,
1482         240, 152, 136, 235, 235, 164, 157,  9,  152,  38,  27, 209, 120,  77, 238, 196,
1483         240, 233,  10, 241,  90,  67,  12, 79,    0,  43,  58,  27,  83, 199, 190, 182};
1484
1485     static ushort expected_data[5 * 5] = {
1486         120, 100, 151, 101, 130,
1487         106, 115, 141, 130, 127,
1488          91, 136, 170, 114, 140,
1489         104, 122, 131, 147, 133,
1490         161, 163,  70, 107, 182
1491     };
1492
1493     cv::Mat src(16, 16, CV_16UC1, input_data);
1494     cv::Mat expected(5, 5, CV_16UC1, expected_data);
1495     cv::Mat actual(expected.size(), expected.type());
1496
1497     cv::resize(src, actual, cv::Size(), 0.3, 0.3, INTER_AREA);
1498
1499     ASSERT_EQ(actual.type(), expected.type());
1500     ASSERT_EQ(actual.size(), expected.size());
1501
1502     Mat diff;
1503     absdiff(actual, expected, diff);
1504
1505     Mat one_channel_diff = diff; //.reshape(1);
1506
1507     float elem_diff = 1.0f;
1508     Size dsize = actual.size();
1509     bool next = true;
1510     for (int dy = 0; dy < dsize.height && next; ++dy)
1511     {
1512         ushort* eD = expected.ptr<ushort>(dy);
1513         ushort* aD = actual.ptr<ushort>(dy);
1514
1515         for (int dx = 0; dx < dsize.width && next; ++dx)
1516             if (fabs(static_cast<float>(aD[dx] - eD[dx])) > elem_diff)
1517             {
1518                 cvtest::TS::ptr()->printf(cvtest::TS::SUMMARY, "Inf norm: %f\n", static_cast<float>(norm(actual, expected, NORM_INF)));
1519                 cvtest::TS::ptr()->printf(cvtest::TS::SUMMARY, "Error in : (%d, %d)\n", dx, dy);
1520
1521                 const int radius = 3;
1522                 int rmin = MAX(dy - radius, 0), rmax = MIN(dy + radius, dsize.height);
1523                 int cmin = MAX(dx - radius, 0), cmax = MIN(dx + radius, dsize.width);
1524
1525                 std::cout << "Abs diff:" << std::endl << diff << std::endl;
1526                 std::cout << "actual result:\n" << actual(Range(rmin, rmax), Range(cmin, cmax)) << std::endl;
1527                 std::cout << "expected result:\n" << expected(Range(rmin, rmax), Range(cmin, cmax)) << std::endl;
1528
1529                 next = false;
1530             }
1531     }
1532
1533     ASSERT_EQ(cvtest::norm(one_channel_diff, cv::NORM_INF), 0);
1534 }
1535
1536
1537 //////////////////////////////////////////////////////////////////////////
1538
1539 TEST(Imgproc_Resize, accuracy) { CV_ResizeTest test; test.safe_run(); }
1540 TEST(Imgproc_WarpAffine, accuracy) { CV_WarpAffineTest test; test.safe_run(); }
1541 TEST(Imgproc_WarpPerspective, accuracy) { CV_WarpPerspectiveTest test; test.safe_run(); }
1542 TEST(Imgproc_Remap, accuracy) { CV_RemapTest test; test.safe_run(); }
1543 TEST(Imgproc_Undistort, accuracy) { CV_UndistortTest test; test.safe_run(); }
1544 TEST(Imgproc_InitUndistortMap, accuracy) { CV_UndistortMapTest test; test.safe_run(); }
1545 TEST(Imgproc_GetRectSubPix, accuracy) { CV_GetRectSubPixTest test; test.safe_run(); }
1546 TEST(Imgproc_GetQuadSubPix, accuracy) { CV_GetQuadSubPixTest test; test.safe_run(); }
1547
1548 /* End of file. */