dfbafcec29837056a08c3b7fe99f79d8d4c616f1
[opencv] / tests / cv / src / aimgwarp.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 "cvtest.h"
43
44 static const int imgwarp_depths[] = { CV_8U, CV_16U, CV_32F, -1 };
45 static const int imgwarp_channels[] = { 1, 3, 4, -1 };
46 static const CvSize imgwarp_sizes[] = {{320, 240}, {1024,768}, {-1,-1}};
47
48 static const double imgwarp_resize_coeffs[] = { 0.5, 0.333, 2, 2.9 };
49 static const char* imgwarp_resize_methods[] = { "nearest", "linear", "cubic", "area", 0 };
50 static const char* imgwarp_resize_param_names[] = { "method", "coeff", "size", "channels", "depth", 0 };
51
52 static const double imgwarp_affine_rotate_scale[][4] = { {0.5,0.5,30.,1.4}, {0.5,0.5,-130,0.4}, {-1,-1,-1,-1} };
53 static const char* imgwarp_affine_param_names[] = { "rotate_scale", "size", "channels", "depth", 0 };
54
55 static const double imgwarp_perspective_shift_vtx[][8] = { {0.03,0.01,0.04,0.02,0.01,0.01,0.01,0.02}, {-1} };
56 static const char* imgwarp_perspective_param_names[] = { "shift_vtx", "size", "channels", "depth", 0 };
57
58 class CV_ImgWarpBaseTestImpl : public CvArrTest
59 {
60 public:
61     CV_ImgWarpBaseTestImpl( const char* test_name, const char* test_funcs, bool warp_matrix );
62
63 protected:
64     int read_params( CvFileStorage* fs );
65     int prepare_test_case( int test_case_idx );
66     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
67     void get_minmax_bounds( int i, int j, int type, CvScalar* low, CvScalar* high );
68     void fill_array( int test_case_idx, int i, int j, CvMat* arr );
69
70     int interpolation;
71     int max_interpolation;
72     double spatial_scale_zoom, spatial_scale_decimate;
73 };
74
75
76 CV_ImgWarpBaseTestImpl::CV_ImgWarpBaseTestImpl( const char* test_name, const char* test_funcs, bool warp_matrix )
77     : CvArrTest( test_name, test_funcs, "" )
78 {
79     test_array[INPUT].push(NULL);
80     if( warp_matrix )
81         test_array[INPUT].push(NULL);
82     test_array[INPUT_OUTPUT].push(NULL);
83     test_array[REF_INPUT_OUTPUT].push(NULL);
84     max_interpolation = 4;
85     interpolation = 0;
86     element_wise_relative_error = false;
87     spatial_scale_zoom = 0.01;
88     spatial_scale_decimate = 0.005;
89
90     size_list = whole_size_list = imgwarp_sizes;
91     depth_list = imgwarp_depths;
92     cn_list = imgwarp_channels;
93     default_timing_param_names = 0;
94 }
95
96
97 int CV_ImgWarpBaseTestImpl::read_params( CvFileStorage* fs )
98 {
99     int code = CvArrTest::read_params( fs );
100     return code;
101 }
102
103
104 void CV_ImgWarpBaseTestImpl::get_minmax_bounds( int i, int j, int type, CvScalar* low, CvScalar* high )
105 {
106     CvArrTest::get_minmax_bounds( i, j, type, low, high );
107     if( CV_MAT_DEPTH(type) == CV_32F )
108     {
109         *low = cvScalarAll(-10.);
110         *high = cvScalarAll(10);
111     }
112 }
113
114
115 void CV_ImgWarpBaseTestImpl::get_test_array_types_and_sizes( int test_case_idx,
116                                                 CvSize** sizes, int** types )
117 {
118     CvRNG* rng = ts->get_rng();
119     int depth = cvTsRandInt(rng) % 3;
120     int cn = cvTsRandInt(rng) % 3 + 1;
121     CvArrTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
122     depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : CV_32F;
123     cn += cn == 2;
124
125     types[INPUT][0] = types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(depth, cn);
126     if( test_array[INPUT].size() > 1 )
127         types[INPUT][1] = cvTsRandInt(rng) & 1 ? CV_32FC1 : CV_64FC1;
128
129     interpolation = cvTsRandInt(rng) % max_interpolation;
130 }
131
132
133 void CV_ImgWarpBaseTestImpl::fill_array( int test_case_idx, int i, int j, CvMat* arr )
134 {
135     if( i != INPUT || j != 0 )
136         CvArrTest::fill_array( test_case_idx, i, j, arr );
137 }
138
139 int CV_ImgWarpBaseTestImpl::prepare_test_case( int test_case_idx )
140 {
141     int code = CvArrTest::prepare_test_case( test_case_idx );
142     CvMat* img = &test_mat[INPUT][0];
143     int i, j, cols = img->cols;
144     int type = CV_MAT_TYPE(img->type), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
145     double scale = depth == CV_16U ? 1000. : 255.*0.5;
146     double space_scale = spatial_scale_decimate;
147     float* buffer;
148
149     if( code <= 0 )
150         return code;
151
152     if( test_mat[INPUT_OUTPUT][0].cols >= img->cols &&
153         test_mat[INPUT_OUTPUT][0].rows >= img->rows )
154         space_scale = spatial_scale_zoom;
155
156     buffer = (float*)cvAlloc( img->cols*cn*sizeof(buffer[0]) );
157     
158     for( i = 0; i < img->rows; i++ )
159     {
160         uchar* ptr = img->data.ptr + i*img->step;
161         switch( cn )
162         {
163         case 1:
164             for( j = 0; j < cols; j++ )
165                 buffer[j] = (float)((sin((i+1)*space_scale)*sin((j+1)*space_scale)+1.)*scale);
166             break;
167         case 2:
168             for( j = 0; j < cols; j++ )
169             {
170                 buffer[j*2] = (float)((sin((i+1)*space_scale)+1.)*scale);
171                 buffer[j*2+1] = (float)((sin((i+j)*space_scale)+1.)*scale);
172             }
173             break;
174         case 3:
175             for( j = 0; j < cols; j++ )
176             {
177                 buffer[j*3] = (float)((sin((i+1)*space_scale)+1.)*scale);
178                 buffer[j*3+1] = (float)((sin(j*space_scale)+1.)*scale);
179                 buffer[j*3+2] = (float)((sin((i+j)*space_scale)+1.)*scale);
180             }
181             break;
182         case 4:
183             for( j = 0; j < cols; j++ )
184             {
185                 buffer[j*4] = (float)((sin((i+1)*space_scale)+1.)*scale);
186                 buffer[j*4+1] = (float)((sin(j*space_scale)+1.)*scale);
187                 buffer[j*4+2] = (float)((sin((i+j)*space_scale)+1.)*scale);
188                 buffer[j*4+3] = (float)((sin((i-j)*space_scale)+1.)*scale);
189             }
190             break;
191         default:
192             assert(0);
193         }
194
195         switch( depth )
196         {
197         case CV_8U:
198             for( j = 0; j < cols*cn; j++ )
199                 ptr[j] = (uchar)cvRound(buffer[j]);
200             break;
201         case CV_16U:
202             for( j = 0; j < cols*cn; j++ )
203                 ((ushort*)ptr)[j] = (ushort)cvRound(buffer[j]);
204             break;
205         case CV_32F:
206             for( j = 0; j < cols*cn; j++ )
207                 ((float*)ptr)[j] = (float)buffer[j];
208             break;
209         default:
210             assert(0);
211         }
212     }
213
214     cvFree( &buffer );
215
216     return code;
217 }
218
219 CV_ImgWarpBaseTestImpl imgwarp_base( "warp", "", false );
220
221
222 class CV_ImgWarpBaseTest : public CV_ImgWarpBaseTestImpl
223 {
224 public:
225     CV_ImgWarpBaseTest( const char* test_name, const char* test_funcs, bool warp_matrix );
226 };
227
228
229 CV_ImgWarpBaseTest::CV_ImgWarpBaseTest( const char* test_name, const char* test_funcs, bool warp_matrix )
230     : CV_ImgWarpBaseTestImpl( test_name, test_funcs, warp_matrix )
231 {
232     size_list = whole_size_list = 0;
233     depth_list = 0;
234     cn_list = 0;
235 }
236
237
238 /////////////////////////
239
240 class CV_ResizeTest : public CV_ImgWarpBaseTest
241 {
242 public:
243     CV_ResizeTest();
244
245 protected:
246     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
247     void run_func();
248     void prepare_to_validation( int /*test_case_idx*/ );
249     double get_success_error_level( int test_case_idx, int i, int j );
250
251     int write_default_params(CvFileStorage* fs);
252     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
253                                                 CvSize** whole_sizes, bool *are_images );
254     void print_timing_params( int test_case_idx, char* ptr, int params_left );
255 };
256
257
258 CV_ResizeTest::CV_ResizeTest()
259     : CV_ImgWarpBaseTest( "warp-resize", "cvResize", false )
260 {
261     default_timing_param_names = imgwarp_resize_param_names;
262 }
263
264
265 int CV_ResizeTest::write_default_params( CvFileStorage* fs )
266 {
267     int code = CV_ImgWarpBaseTest::write_default_params( fs );
268     if( code < 0 )
269         return code;
270     
271     if( ts->get_testing_mode() == CvTS::TIMING_MODE )
272     {
273         start_write_param( fs );
274         write_real_list( fs, "coeff", imgwarp_resize_coeffs, CV_DIM(imgwarp_resize_coeffs) );
275         write_string_list( fs, "method", imgwarp_resize_methods );
276     }
277
278     return code;
279 }
280
281
282 void CV_ResizeTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
283 {
284     CvRNG* rng = ts->get_rng();
285     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
286     CvSize sz;
287
288     sz.width = (cvTsRandInt(rng) % sizes[INPUT][0].width) + 1;
289     sz.height = (cvTsRandInt(rng) % sizes[INPUT][0].height) + 1;
290
291     if( cvTsRandInt(rng) & 1 )
292     {
293         int xfactor = cvTsRandInt(rng) % 10 + 1;
294         int yfactor = cvTsRandInt(rng) % 10 + 1;
295
296         if( cvTsRandInt(rng) & 1 )
297             yfactor = xfactor;
298
299         sz.width = sizes[INPUT][0].width / xfactor;
300         sz.width = MAX(sz.width,1);
301         sz.height = sizes[INPUT][0].height / yfactor;
302         sz.height = MAX(sz.height,1);
303         sizes[INPUT][0].width = sz.width * xfactor;
304         sizes[INPUT][0].height = sz.height * yfactor;
305     }
306
307     if( cvTsRandInt(rng) & 1 )
308         sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = sz;
309     else
310     {
311         sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = sizes[INPUT][0];
312         sizes[INPUT][0] = sz;
313     }
314 }
315
316
317 void CV_ResizeTest::get_timing_test_array_types_and_sizes( int test_case_idx,
318                 CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
319 {
320     CV_ImgWarpBaseTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
321                                                                whole_sizes, are_images );
322     const char* method_str = cvReadString( find_timing_param( "method" ), "linear" );
323     double coeff = cvReadReal( find_timing_param( "coeff" ), 1. );
324     CvSize size = sizes[INPUT][0];
325
326     size.width = cvRound(size.width*coeff);
327     size.height = cvRound(size.height*coeff);
328     sizes[INPUT_OUTPUT][0] = whole_sizes[INPUT_OUTPUT][0] = size;
329
330     interpolation = strcmp( method_str, "nearest" ) == 0 ? CV_INTER_NN :
331                     strcmp( method_str, "linear" ) == 0 ? CV_INTER_LINEAR :
332                     strcmp( method_str, "cubic" ) == 0 ? CV_INTER_CUBIC : CV_INTER_AREA;
333 }
334
335
336 void CV_ResizeTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
337 {
338     sprintf( ptr, "coeff=%.3f,", cvReadReal( find_timing_param( "coeff" ), 1. ) );
339     ptr += strlen(ptr);
340     sprintf( ptr, "method=%s,", cvReadString( find_timing_param( "method" ), "linear" ) );
341     ptr += strlen(ptr);
342     params_left -= 2;
343
344     CV_ImgWarpBaseTest::print_timing_params( test_case_idx, ptr, params_left );
345 }
346
347
348 void CV_ResizeTest::run_func()
349 {
350     cvResize( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], interpolation );
351 }
352
353
354 double CV_ResizeTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
355 {
356     int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
357     return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 1e-1;
358 }
359
360
361 void CV_ResizeTest::prepare_to_validation( int /*test_case_idx*/ )
362 {
363     CvMat* src = &test_mat[INPUT][0];
364     CvMat* dst = &test_mat[REF_INPUT_OUTPUT][0];
365     int i, j, k;
366     CvMat* x_idx = cvCreateMat( 1, dst->cols, CV_32SC1 );
367     CvMat* y_idx = cvCreateMat( 1, dst->rows, CV_32SC1 );
368     int* x_tab = x_idx->data.i;
369     int elem_size = CV_ELEM_SIZE(src->type); 
370     int drows = dst->rows, dcols = dst->cols;
371
372     if( interpolation == CV_INTER_NN )
373     {
374         for( j = 0; j < dcols; j++ )
375         {
376             int t = (j*src->cols*2 + MIN(src->cols,dcols) - 1)/(dcols*2);
377             t -= t >= src->cols;
378             x_idx->data.i[j] = t*elem_size;
379         }
380
381         for( j = 0; j < drows; j++ )
382         {
383             int t = (j*src->rows*2 + MIN(src->rows,drows) - 1)/(drows*2);
384             t -= t >= src->rows;
385             y_idx->data.i[j] = t;
386         }
387     }
388     else
389     {
390         double scale_x = (double)src->cols/dcols;
391         double scale_y = (double)src->rows/drows;
392         
393         for( j = 0; j < dcols; j++ )
394         {
395             double f = ((j+0.5)*scale_x - 0.5);
396             i = cvRound(f);
397             x_idx->data.i[j] = (i < 0 ? 0 : i >= src->cols ? src->cols - 1 : i)*elem_size;
398         }
399
400         for( j = 0; j < drows; j++ )
401         {
402             double f = ((j+0.5)*scale_y - 0.5);
403             i = cvRound(f);
404             y_idx->data.i[j] = i < 0 ? 0 : i >= src->rows ? src->rows - 1 : i;
405         }
406     }
407
408     for( i = 0; i < drows; i++ )
409     {
410         uchar* dptr = dst->data.ptr + dst->step*i;
411         const uchar* sptr0 = src->data.ptr + src->step*y_idx->data.i[i];
412         
413         for( j = 0; j < dcols; j++, dptr += elem_size )
414         {
415             const uchar* sptr = sptr0 + x_tab[j];
416             for( k = 0; k < elem_size; k++ )
417                 dptr[k] = sptr[k];
418         }
419     }
420
421     cvReleaseMat( &x_idx );
422     cvReleaseMat( &y_idx );
423 }
424
425 CV_ResizeTest warp_resize_test;
426
427
428 /////////////////////////
429
430 void cvTsRemap( const CvMat* src, CvMat* dst, CvMat* dst0,
431                 const CvMat* mapx, const CvMat* mapy,
432                 int interpolation=CV_INTER_LINEAR )
433 {
434     int x, y, k;
435     int drows = dst->rows, dcols = dst->cols;
436     int srows = src->rows, scols = src->cols;
437     uchar* sptr0 = src->data.ptr;
438     int depth = CV_MAT_DEPTH(src->type), cn = CV_MAT_CN(src->type);
439     int elem_size = CV_ELEM_SIZE(src->type);
440     int step = src->step / CV_ELEM_SIZE(depth);
441     int delta;
442
443     if( interpolation != CV_INTER_CUBIC )
444     {
445         delta = 0;
446         scols -= 1; srows -= 1;
447     }
448     else
449     {
450         delta = 1;
451         scols = MAX(scols - 3, 0);
452         srows = MAX(srows - 3, 0);
453     }
454
455     for( y = 0; y < drows; y++ )
456     {
457         uchar* dptr = dst->data.ptr + dst->step*y;
458         const float* mx = (const float*)(mapx->data.ptr + mapx->step*y);
459         const float* my = (const float*)(mapy->data.ptr + mapy->step*y);
460
461         for( x = 0; x < dcols; x++, dptr += elem_size )
462         {
463             double xs = mx[x];
464             double ys = my[x];
465             int ixs = cvFloor(xs);
466             int iys = cvFloor(ys);
467
468             if( (unsigned)(ixs - delta) >= (unsigned)scols ||
469                 (unsigned)(iys - delta) >= (unsigned)srows )
470             {
471                 for( k = 0; k < elem_size; k++ )
472                     dptr[k] = 0;
473                 if( dst0 )
474                 {
475                     uchar* dptr0 = dst0->data.ptr + dst0->step*y + x*elem_size;
476                     for( k = 0; k < elem_size; k++ )
477                         dptr0[k] = 0;
478                 }
479                 continue;
480             }
481
482             xs -= ixs;
483             ys -= iys;
484             
485             switch( depth )
486             {
487             case CV_8U:
488                 {
489                 const uchar* sptr = sptr0 + iys*step + ixs*cn;
490                 for( k = 0; k < cn; k++ )
491                 {
492                     double v00 = sptr[k];
493                     double v01 = sptr[cn + k];
494                     double v10 = sptr[step + k];
495                     double v11 = sptr[step + cn + k];
496
497                     v00 = v00 + xs*(v01 - v00);
498                     v10 = v10 + xs*(v11 - v10);
499                     v00 = v00 + ys*(v10 - v00);
500                     dptr[k] = (uchar)cvRound(v00);
501                 }
502                 }
503                 break;
504             case CV_16U:
505                 {
506                 const ushort* sptr = (const ushort*)sptr0 + iys*step + ixs*cn;
507                 for( k = 0; k < cn; k++ )
508                 {
509                     double v00 = sptr[k];
510                     double v01 = sptr[cn + k];
511                     double v10 = sptr[step + k];
512                     double v11 = sptr[step + cn + k];
513
514                     v00 = v00 + xs*(v01 - v00);
515                     v10 = v10 + xs*(v11 - v10);
516                     v00 = v00 + ys*(v10 - v00);
517                     ((ushort*)dptr)[k] = (ushort)cvRound(v00);
518                 }
519                 }
520                 break;
521             case CV_32F:
522                 {
523                 const float* sptr = (const float*)sptr0 + iys*step + ixs*cn;
524                 for( k = 0; k < cn; k++ )
525                 {
526                     double v00 = sptr[k];
527                     double v01 = sptr[cn + k];
528                     double v10 = sptr[step + k];
529                     double v11 = sptr[step + cn + k];
530
531                     v00 = v00 + xs*(v01 - v00);
532                     v10 = v10 + xs*(v11 - v10);
533                     v00 = v00 + ys*(v10 - v00);
534                     ((float*)dptr)[k] = (float)v00;
535                 }
536                 }
537                 break;
538             default:
539                 assert(0);
540             }
541         }
542     }
543 }
544
545 /////////////////////////
546
547 class CV_WarpAffineTest : public CV_ImgWarpBaseTest
548 {
549 public:
550     CV_WarpAffineTest();
551
552 protected:
553     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
554     void run_func();
555     int prepare_test_case( int test_case_idx );
556     void prepare_to_validation( int /*test_case_idx*/ );
557     double get_success_error_level( int test_case_idx, int i, int j );
558
559     int write_default_params(CvFileStorage* fs);
560     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
561                                                 CvSize** whole_sizes, bool *are_images );
562     void print_timing_params( int test_case_idx, char* ptr, int params_left );
563 };
564
565
566 CV_WarpAffineTest::CV_WarpAffineTest()
567     : CV_ImgWarpBaseTest( "warp-affine", "cvWarpAffine", true )
568 {
569     //spatial_scale_zoom = spatial_scale_decimate;
570     test_array[TEMP].push(NULL);
571     test_array[TEMP].push(NULL);
572     
573     spatial_scale_decimate = spatial_scale_zoom;
574
575     default_timing_param_names = imgwarp_affine_param_names;
576 }
577
578
579 int CV_WarpAffineTest::write_default_params( CvFileStorage* fs )
580 {
581     int code = CV_ImgWarpBaseTest::write_default_params( fs );
582     if( code < 0 )
583         return code;
584     
585     if( ts->get_testing_mode() == CvTS::TIMING_MODE )
586     {
587         int i;
588         start_write_param( fs );
589
590         cvStartWriteStruct( fs, "rotate_scale", CV_NODE_SEQ+CV_NODE_FLOW );
591         for( i = 0; imgwarp_affine_rotate_scale[i][0] >= 0; i++ )
592         {
593             cvStartWriteStruct( fs, 0, CV_NODE_SEQ+CV_NODE_FLOW );
594             cvWriteRawData( fs, imgwarp_affine_rotate_scale[i], 4, "d" );
595             cvEndWriteStruct(fs);
596         }
597         cvEndWriteStruct(fs);
598     }
599
600     return code;
601 }
602
603
604 void CV_WarpAffineTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
605 {
606     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
607     CvSize sz = sizes[INPUT][0];
608     // run for the second time to get output of a different size
609     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
610     sizes[INPUT][0] = sz;
611     sizes[INPUT][1] = cvSize( 3, 2 );
612     sizes[TEMP][0] = sizes[TEMP][1] = sizes[INPUT_OUTPUT][0];
613     types[TEMP][0] = types[TEMP][1] = CV_32FC1;
614 }
615
616
617 void CV_WarpAffineTest::get_timing_test_array_types_and_sizes( int test_case_idx,
618                 CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
619 {
620     CV_ImgWarpBaseTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
621                                                                whole_sizes, are_images );
622
623     sizes[INPUT][1] = whole_sizes[INPUT][1] = cvSize(3,2);
624     sizes[TEMP][0] = whole_sizes[TEMP][0] =
625         sizes[TEMP][1] = whole_sizes[TEMP][1] = cvSize(0,0);
626     types[INPUT][1] = CV_64FC1;
627
628     interpolation = CV_INTER_LINEAR;
629 }
630
631
632 void CV_WarpAffineTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
633 {
634     double coeffs[4];
635     const CvFileNode* node = find_timing_param( "rotate_scale" );
636     assert( node && CV_NODE_IS_SEQ(node->tag) );
637     cvReadRawData( ts->get_file_storage(), node, coeffs, "4d" );
638     
639     sprintf( ptr, "fx=%.2f,fy=%.2f,angle=%.1fdeg,scale=%.1f,", coeffs[0], coeffs[1], coeffs[2], coeffs[3] );
640     ptr += strlen(ptr);
641     params_left -= 4;
642
643     CV_ImgWarpBaseTest::print_timing_params( test_case_idx, ptr, params_left );
644 }
645
646
647 void CV_WarpAffineTest::run_func()
648 {
649     cvWarpAffine( test_array[INPUT][0], test_array[INPUT_OUTPUT][0],
650                   &test_mat[INPUT][1], interpolation );
651 }
652
653
654 double CV_WarpAffineTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
655 {
656     int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
657     return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2;
658 }
659
660
661 int CV_WarpAffineTest::prepare_test_case( int test_case_idx )
662 {
663     CvRNG* rng = ts->get_rng();
664     int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
665     const CvMat* src = &test_mat[INPUT][0];
666     const CvMat* dst = &test_mat[INPUT_OUTPUT][0]; 
667     CvMat* mat = &test_mat[INPUT][1];
668     CvPoint2D32f center;
669     double scale, angle;
670
671     if( code <= 0 )
672         return code;
673
674     if( ts->get_testing_mode() == CvTS::CORRECTNESS_CHECK_MODE )
675     {
676         double buf[6];
677         CvMat tmp = cvMat( 2, 3, mat->type, buf );
678
679         center.x = (float)((cvTsRandReal(rng)*1.2 - 0.1)*src->cols);
680         center.y = (float)((cvTsRandReal(rng)*1.2 - 0.1)*src->rows);
681         angle = cvTsRandReal(rng)*360;
682         scale = ((double)dst->rows/src->rows + (double)dst->cols/src->cols)*0.5;
683         cv2DRotationMatrix( center, angle, scale, mat );
684         cvRandArr( rng, &tmp, CV_RAND_NORMAL, cvScalarAll(1.), cvScalarAll(0.01) );
685         cvMaxS( &tmp, 0.9, &tmp );
686         cvMinS( &tmp, 1.1, &tmp );
687         cvMul( &tmp, mat, mat, 1. );
688     }
689     else
690     {
691         double coeffs[4];
692         const CvFileNode* node = find_timing_param( "rotate_scale" );
693
694         assert( node && CV_NODE_IS_SEQ(node->tag) );
695         cvReadRawData( ts->get_file_storage(), node, coeffs, "4d" );
696
697         center.x = (float)(coeffs[0]*src->cols);
698         center.y = (float)(coeffs[1]*src->rows);
699         angle = coeffs[2];
700         scale = coeffs[3];
701         cv2DRotationMatrix( center, angle, scale, mat );
702     }
703
704     return code;
705 }
706
707
708 void CV_WarpAffineTest::prepare_to_validation( int /*test_case_idx*/ )
709 {
710     CvMat* src = &test_mat[INPUT][0];
711     CvMat* dst = &test_mat[REF_INPUT_OUTPUT][0];
712     CvMat* dst0 = &test_mat[INPUT_OUTPUT][0];
713     CvMat* mapx = &test_mat[TEMP][0];
714     CvMat* mapy = &test_mat[TEMP][1];
715     int x, y;
716     double m[6], tm[6];
717     CvMat srcAb = cvMat(2, 3, CV_64FC1, tm ), A, b, invA, invAb, dstAb = cvMat( 2, 3, CV_64FC1, m );
718
719     //cvInvert( &tM, &M, CV_LU );
720     // [R|t] -> [R^-1 | -(R^-1)*t]
721     cvTsConvert( &test_mat[INPUT][1], &srcAb );
722     cvGetCols( &srcAb, &A, 0, 2 );
723     cvGetCol( &srcAb, &b, 2 );
724     cvGetCols( &dstAb, &invA, 0, 2 );
725     cvGetCol( &dstAb, &invAb, 2 );
726     cvInvert( &A, &invA, CV_SVD );
727     cvGEMM( &invA, &b, -1, 0, 0, &invAb );
728
729     for( y = 0; y < dst->rows; y++ )
730     {
731         float* mx = (float*)(mapx->data.ptr + y*mapx->step);
732         float* my = (float*)(mapy->data.ptr + y*mapy->step);
733
734         for( x = 0; x < dst->cols; x++ )
735         {
736             mx[x] = (float)(x*m[0] + y*m[1] + m[2]);
737             my[x] = (float)(x*m[3] + y*m[4] + m[5]);
738         }
739     }
740
741     cvTsRemap( src, dst, dst0, mapx, mapy );
742 }
743
744
745 CV_WarpAffineTest warp_affine_test;
746
747
748
749 /////////////////////////
750
751 class CV_WarpPerspectiveTest : public CV_ImgWarpBaseTest
752 {
753 public:
754     CV_WarpPerspectiveTest();
755
756 protected:
757     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
758     void run_func();
759     int prepare_test_case( int test_case_idx );
760     void prepare_to_validation( int /*test_case_idx*/ );
761     double get_success_error_level( int test_case_idx, int i, int j );
762
763     int write_default_params(CvFileStorage* fs);
764     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
765                                                 CvSize** whole_sizes, bool *are_images );
766     void print_timing_params( int test_case_idx, char* ptr, int params_left );
767 };
768
769
770 CV_WarpPerspectiveTest::CV_WarpPerspectiveTest()
771     : CV_ImgWarpBaseTest( "warp-perspective", "cvWarpPerspective", true )
772 {
773     //spatial_scale_zoom = spatial_scale_decimate;
774     test_array[TEMP].push(NULL);
775     test_array[TEMP].push(NULL);
776
777     spatial_scale_decimate = spatial_scale_zoom;
778     default_timing_param_names = imgwarp_perspective_param_names;
779 }
780
781
782 int CV_WarpPerspectiveTest::write_default_params( CvFileStorage* fs )
783 {
784     int code = CV_ImgWarpBaseTest::write_default_params( fs );
785     if( code < 0 )
786         return code;
787     
788     if( ts->get_testing_mode() == CvTS::TIMING_MODE )
789     {
790         int i;
791         start_write_param( fs );
792
793         cvStartWriteStruct( fs, "shift_vtx", CV_NODE_SEQ+CV_NODE_FLOW );
794         for( i = 0; imgwarp_perspective_shift_vtx[i][0] >= 0; i++ )
795         {
796             cvStartWriteStruct( fs, 0, CV_NODE_SEQ+CV_NODE_FLOW );
797             cvWriteRawData( fs, imgwarp_perspective_shift_vtx[i], 8, "d" );
798             cvEndWriteStruct(fs);
799         }
800         cvEndWriteStruct(fs);
801     }
802
803     return code;
804 }
805
806
807 void CV_WarpPerspectiveTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
808 {
809     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
810     CvSize sz = sizes[INPUT][0];
811     // run for the second time to get output of a different size
812     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
813     sizes[INPUT][0] = sz;
814     sizes[INPUT][1] = cvSize( 3, 3 );
815
816     sizes[TEMP][0] = sizes[TEMP][1] = sizes[INPUT_OUTPUT][0];
817     types[TEMP][0] = types[TEMP][1] = CV_32FC1;
818 }
819
820
821 void CV_WarpPerspectiveTest::get_timing_test_array_types_and_sizes( int test_case_idx,
822                 CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
823 {
824     CV_ImgWarpBaseTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
825                                                                whole_sizes, are_images );
826
827     sizes[INPUT][1] = whole_sizes[INPUT][1] = cvSize(3,3);
828     sizes[TEMP][0] = whole_sizes[TEMP][0] =
829         sizes[TEMP][1] = whole_sizes[TEMP][1] = cvSize(0,0);
830     types[INPUT][1] = CV_64FC1;
831
832     interpolation = CV_INTER_LINEAR;
833 }
834
835
836 void CV_WarpPerspectiveTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
837 {
838     CV_ImgWarpBaseTest::print_timing_params( test_case_idx, ptr, params_left );
839 }
840
841
842 void CV_WarpPerspectiveTest::run_func()
843 {
844     cvWarpPerspective( test_array[INPUT][0], test_array[INPUT_OUTPUT][0],
845                        &test_mat[INPUT][1], interpolation );
846 }
847
848
849 double CV_WarpPerspectiveTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
850 {
851     int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
852     return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2;
853 }
854
855
856 int CV_WarpPerspectiveTest::prepare_test_case( int test_case_idx )
857 {
858     CvRNG* rng = ts->get_rng();
859     int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
860     const CvMat* src = &test_mat[INPUT][0];
861     const CvMat* dst = &test_mat[INPUT_OUTPUT][0]; 
862     CvMat* mat = &test_mat[INPUT][1];
863     CvPoint2D32f s[4], d[4];
864     int i;
865
866     if( code <= 0 )
867         return code;
868
869     s[0] = cvPoint2D32f(0,0);
870     d[0] = cvPoint2D32f(0,0);
871     s[1] = cvPoint2D32f(src->cols-1,0);
872     d[1] = cvPoint2D32f(dst->cols-1,0);
873     s[2] = cvPoint2D32f(src->cols-1,src->rows-1);
874     d[2] = cvPoint2D32f(dst->cols-1,dst->rows-1);
875     s[3] = cvPoint2D32f(0,src->rows-1);
876     d[3] = cvPoint2D32f(0,dst->rows-1);
877
878     if( ts->get_testing_mode() == CvTS::CORRECTNESS_CHECK_MODE )
879     {
880         float buf[16];
881         CvMat tmp = cvMat( 1, 16, CV_32FC1, buf );
882
883         cvRandArr( rng, &tmp, CV_RAND_NORMAL, cvScalarAll(0.), cvScalarAll(0.1) );
884
885         for( i = 0; i < 4; i++ )
886         {
887             s[i].x += buf[i*4]*src->cols/2;
888             s[i].y += buf[i*4+1]*src->rows/2;
889             d[i].x += buf[i*4+2]*dst->cols/2;
890             d[i].y += buf[i*4+3]*dst->rows/2;
891         }
892     }
893     else
894     {
895         double coeffs[8];
896         const CvFileNode* node = find_timing_param( "shift_vtx" );
897
898         assert( node && CV_NODE_IS_SEQ(node->tag) );
899         cvReadRawData( ts->get_file_storage(), node, coeffs, "8d" );
900
901         for( i = 0; i < 4; i++ )
902         {
903             d[i].x += (float)(coeffs[i*2]*src->cols*(i == 0 || i == 3 ? 1 : -1));
904             d[i].y += (float)(coeffs[i*2+1]*src->rows*(i == 0 || i == 1 ? 1 : -1));
905         }
906     }
907
908     cvWarpPerspectiveQMatrix( s, d, mat );
909     return code;
910 }
911
912
913 void CV_WarpPerspectiveTest::prepare_to_validation( int /*test_case_idx*/ )
914 {
915     CvMat* src = &test_mat[INPUT][0];
916     CvMat* dst = &test_mat[REF_INPUT_OUTPUT][0];
917     CvMat* dst0 = &test_mat[INPUT_OUTPUT][0];
918     CvMat* mapx = &test_mat[TEMP][0];
919     CvMat* mapy = &test_mat[TEMP][1];
920     int x, y;
921     double m[9], tm[9];
922     CvMat srcM = cvMat(3, 3, CV_64FC1, tm ), dstM = cvMat( 3, 3, CV_64FC1, m );
923
924     //cvInvert( &tM, &M, CV_LU );
925     // [R|t] -> [R^-1 | -(R^-1)*t]
926     cvTsConvert( &test_mat[INPUT][1], &srcM );
927     cvInvert( &srcM, &dstM, CV_SVD );
928
929     for( y = 0; y < dst->rows; y++ )
930     {
931         float* mx = (float*)(mapx->data.ptr + y*mapx->step);
932         float* my = (float*)(mapy->data.ptr + y*mapy->step);
933
934         for( x = 0; x < dst->cols; x++ )
935         {
936             double xs = x*m[0] + y*m[1] + m[2];
937             double ys = x*m[3] + y*m[4] + m[5];
938             double ds = x*m[6] + y*m[7] + m[8];
939             
940             ds = ds ? 1./ds : 0;
941             xs *= ds;
942             ys *= ds;
943             
944             mx[x] = (float)xs;
945             my[x] = (float)ys;
946         }
947     }
948
949     cvTsRemap( src, dst, dst0, mapx, mapy );
950 }
951
952
953 CV_WarpPerspectiveTest warp_perspective_test;
954
955
956
957 /////////////////////////
958
959 void cvTsInitUndistortMap( const CvMat* _a0, const CvMat* _k0, CvMat* mapx, CvMat* mapy )
960 {
961     int u, v;
962     double a[9], k[4];
963     CvMat _a = cvMat(3, 3, CV_64F, a);
964     CvMat _k = cvMat(_k0->rows,_k0->cols,
965         CV_MAKETYPE(CV_64F,CV_MAT_CN(_k0->type)),k);
966     double fx, fy, cx, cy, ifx, ify;
967     
968     cvTsConvert( _a0, &_a );
969     cvTsConvert( _k0, &_k );
970     fx = a[0]; fy = a[4]; cx = a[2]; cy = a[5];
971     ifx = 1./fx; ify = 1./fy;
972
973     for( v = 0; v < mapy->rows; v++ )
974     {
975         float* mx = (float*)(mapx->data.ptr + v*mapx->step);
976         float* my = (float*)(mapy->data.ptr + v*mapy->step);
977         
978         for( u = 0; u < mapy->cols; u++ )
979         {
980             double x = (u - cx)*ifx;
981             double y = (v - cy)*ify;
982             double x2 = x*x, y2 = y*y;
983             double r2 = x2 + y2;
984             double cdist = 1 + r2*(k[0] + k[1]*r2);
985             double x1 = x*cdist + k[2]*2*x*y + k[3]*(r2 + 2*x2);
986             double y1 = y*cdist + k[3]*2*x*y + k[2]*(r2 + 2*y2);
987             mx[u] = (float)(x1*fx + cx);
988             my[u] = (float)(y1*fy + cy);
989         }
990     }
991 }
992
993
994 static double remap_undistort_params[] = { 0.5, 0.5, 0.5, 0.5, 0.01, -0.01, 0.001, -0.001 };
995
996 class CV_RemapTest : public CV_ImgWarpBaseTest
997 {
998 public:
999     CV_RemapTest();
1000
1001 protected:
1002     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1003     void run_func();
1004     int prepare_test_case( int test_case_idx );
1005     void prepare_to_validation( int /*test_case_idx*/ );
1006     double get_success_error_level( int test_case_idx, int i, int j );
1007     void fill_array( int test_case_idx, int i, int j, CvMat* arr );
1008
1009     int write_default_params(CvFileStorage* fs);
1010     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
1011                                                 CvSize** whole_sizes, bool *are_images );
1012     void print_timing_params( int test_case_idx, char* ptr, int params_left );
1013 };
1014
1015
1016 CV_RemapTest::CV_RemapTest()
1017     : CV_ImgWarpBaseTest( "warp-remap", "cvRemap", false )
1018 {
1019     //spatial_scale_zoom = spatial_scale_decimate;
1020     test_array[INPUT].push(NULL);
1021     test_array[INPUT].push(NULL);
1022
1023     spatial_scale_decimate = spatial_scale_zoom;
1024     //default_timing_param_names = imgwarp_perspective_param_names;
1025     support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
1026     default_timing_param_names = 0;
1027 }
1028
1029
1030 int CV_RemapTest::write_default_params( CvFileStorage* fs )
1031 {
1032     int code = CV_ImgWarpBaseTest::write_default_params( fs );
1033     if( code < 0 )
1034         return code;
1035     
1036     if( ts->get_testing_mode() == CvTS::TIMING_MODE )
1037     {
1038         int i;
1039         start_write_param( fs );
1040
1041         cvStartWriteStruct( fs, "params", CV_NODE_SEQ+CV_NODE_FLOW );
1042         for( i = 0; i < 8; i++ )
1043             cvWriteReal( fs, 0, remap_undistort_params[i] );
1044         cvEndWriteStruct(fs);
1045     }
1046
1047     return code;
1048 }
1049
1050
1051 void CV_RemapTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1052 {
1053     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1054     types[INPUT][1] = types[INPUT][2] = CV_32FC1;
1055 }
1056
1057
1058 void CV_RemapTest::fill_array( int test_case_idx, int i, int j, CvMat* arr )
1059 {
1060     if( i != INPUT )
1061         CV_ImgWarpBaseTestImpl::fill_array( test_case_idx, i, j, arr );
1062 }
1063
1064 void CV_RemapTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1065         CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
1066 {
1067     CV_ImgWarpBaseTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
1068                                                                whole_sizes, are_images );
1069     types[INPUT][1] = types[INPUT][2] = CV_32FC1;
1070     interpolation = CV_INTER_LINEAR;
1071 }
1072
1073
1074 void CV_RemapTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
1075 {
1076     CV_ImgWarpBaseTest::print_timing_params( test_case_idx, ptr, params_left );
1077 }
1078
1079
1080 void CV_RemapTest::run_func()
1081 {
1082     cvRemap( test_array[INPUT][0], test_array[INPUT_OUTPUT][0],
1083              test_array[INPUT][1], test_array[INPUT][2], interpolation );
1084 }
1085
1086
1087 double CV_RemapTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1088 {
1089     int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
1090     return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2;
1091 }
1092
1093
1094 int CV_RemapTest::prepare_test_case( int test_case_idx )
1095 {
1096     CvRNG* rng = ts->get_rng();
1097     int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
1098     const CvMat* src = &test_mat[INPUT][0];
1099     double a[9] = {0,0,0,0,0,0,0,0,1}, k[4];
1100     CvMat _a = cvMat( 3, 3, CV_64F, a );
1101     CvMat _k = cvMat( 4, 1, CV_64F, k );
1102     double sz = MAX(src->rows, src->cols);
1103
1104     if( code <= 0 )
1105         return code;
1106
1107     if( ts->get_testing_mode() == CvTS::CORRECTNESS_CHECK_MODE )
1108     {
1109         double aspect_ratio = cvTsRandReal(rng)*0.6 + 0.7;
1110         a[2] = (src->cols - 1)*0.5 + cvTsRandReal(rng)*10 - 5;
1111         a[5] = (src->rows - 1)*0.5 + cvTsRandReal(rng)*10 - 5;
1112         a[0] = sz/(0.9 - cvTsRandReal(rng)*0.6);
1113         a[4] = aspect_ratio*a[0];
1114         k[0] = cvTsRandReal(rng)*0.06 - 0.03;
1115         k[1] = cvTsRandReal(rng)*0.06 - 0.03;
1116         if( k[0]*k[1] > 0 )
1117             k[1] = -k[1];
1118         k[2] = cvTsRandReal(rng)*0.004 - 0.002;
1119         k[3] = cvTsRandReal(rng)*0.004 - 0.002;
1120     }
1121     else
1122     {
1123         int i;
1124         a[2] = (src->cols - 1)*remap_undistort_params[0];
1125         a[5] = (src->rows - 1)*remap_undistort_params[1];
1126         a[0] = sz/remap_undistort_params[2];
1127         a[4] = sz/remap_undistort_params[3];
1128         for( i = 0; i < 4; i++ )
1129             k[i] = remap_undistort_params[i+4];
1130     }
1131
1132     cvTsInitUndistortMap( &_a, &_k, &test_mat[INPUT][1], &test_mat[INPUT][2] );
1133     return code;
1134 }
1135
1136
1137 void CV_RemapTest::prepare_to_validation( int /*test_case_idx*/ )
1138 {
1139     CvMat* dst = &test_mat[REF_INPUT_OUTPUT][0];
1140     CvMat* dst0 = &test_mat[INPUT_OUTPUT][0];
1141     int nr = interpolation == CV_INTER_CUBIC ? 3 : 3, nc = nr;
1142     CvMat part;
1143     cvTsRemap( &test_mat[INPUT][0], dst, dst0,
1144                &test_mat[INPUT][1], &test_mat[INPUT][2],
1145                interpolation );
1146     nr = MIN(nr, dst->rows);
1147     nc = MIN(nc, dst->cols);
1148     cvGetRows( dst, &part, dst->rows - nr, dst->rows ); 
1149     cvTsZero( &part );
1150     cvGetRows( dst0, &part, dst->rows - nr, dst->rows ); 
1151     cvTsZero( &part );
1152     cvGetCols( dst, &part, dst->cols - nc, dst->cols ); 
1153     cvTsZero( &part );
1154     cvGetCols( dst0, &part, dst->cols - nc, dst->cols ); 
1155     cvTsZero( &part );
1156 }
1157
1158
1159 CV_RemapTest remap_test;
1160
1161
1162 ////////////////////////////// undistort /////////////////////////////////
1163
1164 class CV_UndistortTest : public CV_ImgWarpBaseTest
1165 {
1166 public:
1167     CV_UndistortTest();
1168
1169 protected:
1170     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1171     void run_func();
1172     int prepare_test_case( int test_case_idx );
1173     void prepare_to_validation( int /*test_case_idx*/ );
1174     double get_success_error_level( int test_case_idx, int i, int j );
1175     void fill_array( int test_case_idx, int i, int j, CvMat* arr );
1176
1177     int write_default_params(CvFileStorage* fs);
1178     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
1179                                                 CvSize** whole_sizes, bool *are_images );
1180     void print_timing_params( int test_case_idx, char* ptr, int params_left );
1181 };
1182
1183
1184 CV_UndistortTest::CV_UndistortTest()
1185     : CV_ImgWarpBaseTest( "warp-undistort", "cvUndistort2", false )
1186 {
1187     //spatial_scale_zoom = spatial_scale_decimate;
1188     test_array[INPUT].push(NULL);
1189     test_array[INPUT].push(NULL);
1190
1191     spatial_scale_decimate = spatial_scale_zoom;
1192     //default_timing_param_names = imgwarp_perspective_param_names;
1193     support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
1194     default_timing_param_names = 0;
1195 }
1196
1197
1198 int CV_UndistortTest::write_default_params( CvFileStorage* fs )
1199 {
1200     int code = CV_ImgWarpBaseTest::write_default_params( fs );
1201     if( code < 0 )
1202         return code;
1203     
1204     if( ts->get_testing_mode() == CvTS::TIMING_MODE )
1205     {
1206         int i;
1207         start_write_param( fs );
1208
1209         cvStartWriteStruct( fs, "params", CV_NODE_SEQ+CV_NODE_FLOW );
1210         for( i = 0; i < 8; i++ )
1211             cvWriteReal( fs, 0, remap_undistort_params[i] );
1212         cvEndWriteStruct(fs);
1213     }
1214
1215     return code;
1216 }
1217
1218
1219 void CV_UndistortTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1220 {
1221     CvRNG* rng = ts->get_rng();
1222     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1223     int type = types[INPUT][0];
1224     type = CV_MAKETYPE( CV_8U, CV_MAT_CN(type) ); 
1225     types[INPUT][0] = types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = type;
1226     types[INPUT][1] = cvTsRandInt(rng)%2 ? CV_64F : CV_32F;
1227     types[INPUT][2] = cvTsRandInt(rng)%2 ? CV_64F : CV_32F;
1228     sizes[INPUT][1] = cvSize(3,3);
1229     sizes[INPUT][2] = cvTsRandInt(rng)%2 ? cvSize(4,1) : cvSize(1,4);
1230     interpolation = CV_INTER_LINEAR;
1231 }
1232
1233
1234 void CV_UndistortTest::fill_array( int test_case_idx, int i, int j, CvMat* arr )
1235 {
1236     if( i != INPUT )
1237         CV_ImgWarpBaseTestImpl::fill_array( test_case_idx, i, j, arr );
1238 }
1239
1240 void CV_UndistortTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1241         CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
1242 {
1243     CV_ImgWarpBaseTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
1244                                                                whole_sizes, are_images );
1245     types[INPUT][1] = types[INPUT][2] = CV_32FC1;
1246     interpolation = CV_INTER_LINEAR;
1247 }
1248
1249
1250 void CV_UndistortTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
1251 {
1252     CV_ImgWarpBaseTest::print_timing_params( test_case_idx, ptr, params_left );
1253 }
1254
1255
1256 void CV_UndistortTest::run_func()
1257 {
1258     cvUndistort2( test_array[INPUT][0], test_array[INPUT_OUTPUT][0],
1259                   &test_mat[INPUT][1], &test_mat[INPUT][2] );
1260 }
1261
1262
1263 double CV_UndistortTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1264 {
1265     int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
1266     return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2;
1267 }
1268
1269
1270 int CV_UndistortTest::prepare_test_case( int test_case_idx )
1271 {
1272     CvRNG* rng = ts->get_rng();
1273     int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
1274     const CvMat* src = &test_mat[INPUT][0];
1275     double k[4], a[9] = {0,0,0,0,0,0,0,0,1};
1276     double sz = MAX(src->rows, src->cols);
1277     CvMat* _a0 = &test_mat[INPUT][1], *_k0 = &test_mat[INPUT][2];
1278     CvMat _a = cvMat(3,3,CV_64F,a);
1279     CvMat _k = cvMat(_k0->rows,_k0->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(_k0->type)),k);
1280
1281     if( code <= 0 )
1282         return code;
1283
1284     if( ts->get_testing_mode() == CvTS::CORRECTNESS_CHECK_MODE )
1285     {
1286         double aspect_ratio = cvTsRandReal(rng)*0.6 + 0.7;
1287         a[2] = (src->cols - 1)*0.5 + cvTsRandReal(rng)*10 - 5;
1288         a[5] = (src->rows - 1)*0.5 + cvTsRandReal(rng)*10 - 5;
1289         a[0] = sz/(0.9 - cvTsRandReal(rng)*0.6);
1290         a[4] = aspect_ratio*a[0];
1291         k[0] = cvTsRandReal(rng)*0.06 - 0.03;
1292         k[1] = cvTsRandReal(rng)*0.06 - 0.03;
1293         if( k[0]*k[1] > 0 )
1294             k[1] = -k[1];
1295         if( cvTsRandInt(rng)%4 != 0 )
1296         {
1297             k[2] = cvTsRandReal(rng)*0.004 - 0.002;
1298             k[3] = cvTsRandReal(rng)*0.004 - 0.002;
1299         }
1300         else
1301             k[2] = k[3] = 0;
1302     }
1303     else
1304     {
1305         int i;
1306         a[2] = (src->cols - 1)*remap_undistort_params[0];
1307         a[5] = (src->rows - 1)*remap_undistort_params[1];
1308         a[0] = sz/remap_undistort_params[2];
1309         a[4] = sz/remap_undistort_params[3];
1310         for( i = 0; i < 4; i++ )
1311             k[i] = remap_undistort_params[i+4];
1312     }
1313
1314     cvTsConvert( &_a, _a0 );
1315     cvTsConvert( &_k, _k0 );
1316
1317     return code;
1318 }
1319
1320
1321 void CV_UndistortTest::prepare_to_validation( int /*test_case_idx*/ )
1322 {
1323     CvMat* src = &test_mat[INPUT][0];
1324     CvMat* dst = &test_mat[REF_INPUT_OUTPUT][0];
1325     CvMat* dst0 = &test_mat[INPUT_OUTPUT][0];
1326     CvMat* mapx = cvCreateMat( dst->rows, dst->cols, CV_32FC1 );
1327     CvMat* mapy = cvCreateMat( dst->rows, dst->cols, CV_32FC1 );
1328     CvMat part;
1329     int nr = 2, nc = nr;
1330     cvTsInitUndistortMap( &test_mat[INPUT][1], &test_mat[INPUT][2],
1331                           mapx, mapy );
1332     cvTsRemap( src, dst, dst0, mapx, mapy, interpolation );
1333     nr = MIN(nr, dst->rows);
1334     nc = MIN(nc, dst->cols);
1335     cvGetRows( dst, &part, 0, nr ); 
1336     cvTsZero( &part );
1337     cvGetRows( dst0, &part, 0, nr ); 
1338     cvTsZero( &part );
1339     cvGetRows( dst, &part, dst->rows - nr, dst->rows ); 
1340     cvTsZero( &part );
1341     cvGetRows( dst0, &part, dst->rows - nr, dst->rows ); 
1342     cvTsZero( &part );
1343
1344     cvGetCols( dst, &part, 0, nc ); 
1345     cvTsZero( &part );
1346     cvGetCols( dst0, &part, 0, nc ); 
1347     cvTsZero( &part );
1348     cvGetCols( dst, &part, dst->cols - nc, dst->cols ); 
1349     cvTsZero( &part );
1350     cvGetCols( dst0, &part, dst->cols - nc, dst->cols ); 
1351     cvTsZero( &part );
1352
1353     cvReleaseMat( &mapx );
1354     cvReleaseMat( &mapy );
1355 }
1356
1357
1358 CV_UndistortTest undistort_test;
1359
1360
1361
1362 class CV_UndistortMapTest : public CvArrTest
1363 {
1364 public:
1365     CV_UndistortMapTest();
1366
1367 protected:
1368     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1369     void run_func();
1370     int prepare_test_case( int test_case_idx );
1371     void prepare_to_validation( int /*test_case_idx*/ );
1372     double get_success_error_level( int test_case_idx, int i, int j );
1373     void fill_array( int test_case_idx, int i, int j, CvMat* arr );
1374
1375     int write_default_params(CvFileStorage* fs);
1376     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
1377                                                 CvSize** whole_sizes, bool *are_images );
1378     void print_timing_params( int test_case_idx, char* ptr, int params_left );
1379 };
1380
1381
1382 CV_UndistortMapTest::CV_UndistortMapTest()
1383     : CvArrTest( "warp-undistort-map", "cvInitUndistortMap", "" )
1384 {
1385     test_array[INPUT].push(NULL);
1386     test_array[INPUT].push(NULL);
1387     test_array[OUTPUT].push(NULL);
1388     test_array[OUTPUT].push(NULL);
1389     test_array[REF_OUTPUT].push(NULL);
1390     test_array[REF_OUTPUT].push(NULL);
1391
1392     element_wise_relative_error = false;
1393
1394     support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
1395     default_timing_param_names = 0;
1396 }
1397
1398
1399 int CV_UndistortMapTest::write_default_params( CvFileStorage* fs )
1400 {
1401     int code = CvArrTest::write_default_params( fs );
1402     if( code < 0 )
1403         return code;
1404     
1405     if( ts->get_testing_mode() == CvTS::TIMING_MODE )
1406     {
1407         int i;
1408         start_write_param( fs );
1409
1410         cvStartWriteStruct( fs, "params", CV_NODE_SEQ+CV_NODE_FLOW );
1411         for( i = 0; i < 8; i++ )
1412             cvWriteReal( fs, 0, remap_undistort_params[i] );
1413         cvEndWriteStruct(fs);
1414     }
1415
1416     return code;
1417 }
1418
1419
1420 void CV_UndistortMapTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1421 {
1422     CvRNG* rng = ts->get_rng();
1423     CvArrTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1424     int depth = cvTsRandInt(rng)%2 ? CV_64F : CV_32F;
1425     CvSize sz = sizes[OUTPUT][0];
1426     types[INPUT][0] = types[INPUT][1] = depth;
1427     types[OUTPUT][0] = types[OUTPUT][1] = 
1428         types[REF_OUTPUT][0] = types[REF_OUTPUT][1] = CV_32F;
1429     sizes[INPUT][0] = cvSize(3,3);
1430     sizes[INPUT][1] = cvTsRandInt(rng)%2 ? cvSize(4,1) : cvSize(1,4);
1431
1432     sz.width = MAX(sz.width,16);
1433     sz.height = MAX(sz.height,16);
1434     sizes[OUTPUT][0] = sizes[OUTPUT][1] =
1435         sizes[REF_OUTPUT][0] = sizes[REF_OUTPUT][1] = sz;
1436 }
1437
1438
1439 void CV_UndistortMapTest::fill_array( int test_case_idx, int i, int j, CvMat* arr )
1440 {
1441     if( i != INPUT )
1442         CvArrTest::fill_array( test_case_idx, i, j, arr );
1443 }
1444
1445 void CV_UndistortMapTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1446         CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
1447 {
1448     CvArrTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
1449                                                       whole_sizes, are_images );
1450 }
1451
1452
1453 void CV_UndistortMapTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
1454 {
1455     CvArrTest::print_timing_params( test_case_idx, ptr, params_left );
1456 }
1457
1458
1459 void CV_UndistortMapTest::run_func()
1460 {
1461     cvInitUndistortMap( &test_mat[INPUT][0], &test_mat[INPUT][1],
1462                         test_array[OUTPUT][0], test_array[OUTPUT][1] );
1463 }
1464
1465
1466 double CV_UndistortMapTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1467 {
1468     return 1e-4;
1469 }
1470
1471
1472 int CV_UndistortMapTest::prepare_test_case( int test_case_idx )
1473 {
1474     CvRNG* rng = ts->get_rng();
1475     int code = CvArrTest::prepare_test_case( test_case_idx );
1476     const CvMat* mapx = &test_mat[OUTPUT][0];
1477     double k[4], a[9] = {0,0,0,0,0,0,0,0,1};
1478     double sz = MAX(mapx->rows, mapx->cols);
1479     CvMat* _a0 = &test_mat[INPUT][0], *_k0 = &test_mat[INPUT][1];
1480     CvMat _a = cvMat(3,3,CV_64F,a);
1481     CvMat _k = cvMat(_k0->rows,_k0->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(_k0->type)),k);
1482
1483     if( code <= 0 )
1484         return code;
1485
1486     if( ts->get_testing_mode() == CvTS::CORRECTNESS_CHECK_MODE )
1487     {
1488         double aspect_ratio = cvTsRandReal(rng)*0.6 + 0.7;
1489         a[2] = (mapx->cols - 1)*0.5 + cvTsRandReal(rng)*10 - 5;
1490         a[5] = (mapx->rows - 1)*0.5 + cvTsRandReal(rng)*10 - 5;
1491         a[0] = sz/(0.9 - cvTsRandReal(rng)*0.6);
1492         a[4] = aspect_ratio*a[0];
1493         k[0] = cvTsRandReal(rng)*0.06 - 0.03;
1494         k[1] = cvTsRandReal(rng)*0.06 - 0.03;
1495         if( k[0]*k[1] > 0 )
1496             k[1] = -k[1];
1497         k[2] = cvTsRandReal(rng)*0.004 - 0.002;
1498         k[3] = cvTsRandReal(rng)*0.004 - 0.002;
1499     }
1500     else
1501     {
1502         int i;
1503         a[2] = (mapx->cols - 1)*remap_undistort_params[0];
1504         a[5] = (mapx->rows - 1)*remap_undistort_params[1];
1505         a[0] = sz/remap_undistort_params[2];
1506         a[4] = sz/remap_undistort_params[3];
1507         for( i = 0; i < 4; i++ )
1508             k[i] = remap_undistort_params[i+4];
1509     }
1510
1511     cvTsConvert( &_a, _a0 );
1512     cvTsConvert( &_k, _k0 );
1513
1514     return code;
1515 }
1516
1517
1518 void CV_UndistortMapTest::prepare_to_validation( int /*test_case_idx*/ )
1519 {
1520     cvTsInitUndistortMap( &test_mat[INPUT][0], &test_mat[INPUT][1],
1521                           &test_mat[REF_OUTPUT][0], &test_mat[REF_OUTPUT][1] );
1522 }
1523
1524
1525 CV_UndistortMapTest undistortmap_test;
1526
1527
1528
1529 ////////////////////////////// GetRectSubPix /////////////////////////////////
1530
1531 static const CvSize rectsubpix_sizes[] = {{11, 11}, {21,21}, {41,41},{-1,-1}};
1532
1533 static void
1534 cvTsGetQuadrangeSubPix( const CvMat* src, CvMat* dst, double* a )
1535 {
1536     int y, x, k, cn;
1537     int sstep = src->step / sizeof(float);
1538     int scols = src->cols, srows = src->rows;
1539     
1540     assert( CV_MAT_DEPTH(src->type) == CV_32F &&
1541             CV_ARE_TYPES_EQ(src, dst));
1542
1543     cn = CV_MAT_CN(dst->type);
1544
1545     for( y = 0; y < dst->rows; y++ )
1546         for( x = 0; x < dst->cols; x++ )
1547         {
1548             float* d = (float*)(dst->data.ptr + y*dst->step) + x*cn;
1549             float sx = (float)(a[0]*x + a[1]*y + a[2]);
1550             float sy = (float)(a[3]*x + a[4]*y + a[5]);
1551             int ix = cvFloor(sx), iy = cvFloor(sy);
1552             int dx = cn, dy = sstep;
1553             const float* s;
1554             sx -= ix; sy -= iy;
1555
1556             if( (unsigned)ix >= (unsigned)(scols-1) )
1557                 ix = ix < 0 ? 0 : scols - 1, sx = 0, dx = 0;
1558             if( (unsigned)iy >= (unsigned)(srows-1) )
1559                 iy = iy < 0 ? 0 : srows - 1, sy = 0, dy = 0;
1560
1561             s = src->data.fl + sstep*iy + ix*cn;
1562             for( k = 0; k < cn; k++, s++ )
1563             {
1564                 float t0 = s[0] + sx*(s[dx] - s[0]);
1565                 float t1 = s[dy] + sx*(s[dy + dx] - s[dy]);
1566                 d[k] = t0 + sy*(t1 - t0);
1567             }
1568         }
1569 }
1570
1571
1572 class CV_GetRectSubPixTest : public CV_ImgWarpBaseTest
1573 {
1574 public:
1575     CV_GetRectSubPixTest();
1576
1577 protected:
1578     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1579     void run_func();
1580     int prepare_test_case( int test_case_idx );
1581     void prepare_to_validation( int /*test_case_idx*/ );
1582     double get_success_error_level( int test_case_idx, int i, int j );
1583     void fill_array( int test_case_idx, int i, int j, CvMat* arr );
1584
1585     int write_default_params(CvFileStorage* fs);
1586     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
1587                                                 CvSize** whole_sizes, bool *are_images );
1588     void print_timing_params( int test_case_idx, char* ptr, int params_left );
1589     CvPoint2D32f center;
1590 };
1591
1592
1593 CV_GetRectSubPixTest::CV_GetRectSubPixTest()
1594     : CV_ImgWarpBaseTest( "warp-subpix-rect", "cvGetRectSubPix", false )
1595 {
1596     //spatial_scale_zoom = spatial_scale_decimate;
1597     spatial_scale_decimate = spatial_scale_zoom;
1598     //default_timing_param_names = imgwarp_perspective_param_names;
1599     support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
1600     default_timing_param_names = 0;
1601 }
1602
1603
1604 int CV_GetRectSubPixTest::write_default_params( CvFileStorage* fs )
1605 {
1606     int code = CV_ImgWarpBaseTest::write_default_params( fs );
1607     if( code < 0 )
1608         return code;
1609     
1610     if( ts->get_testing_mode() == CvTS::TIMING_MODE )
1611     {
1612         int i;
1613         start_write_param( fs );
1614
1615         cvStartWriteStruct( fs, "rect_size", CV_NODE_SEQ+CV_NODE_FLOW );
1616         for( i = 0; rectsubpix_sizes[i].width > 0; i++ )
1617         {
1618             cvStartWriteStruct( fs, 0, CV_NODE_SEQ+CV_NODE_FLOW );
1619             cvWriteInt( fs, 0, rectsubpix_sizes[i].width );
1620             cvWriteInt( fs, 0, rectsubpix_sizes[i].height );
1621             cvEndWriteStruct(fs);
1622         }
1623         cvEndWriteStruct(fs);
1624     }
1625
1626     return code;
1627 }
1628
1629
1630 void CV_GetRectSubPixTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1631 {
1632     CvRNG* rng = ts->get_rng();
1633     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1634     int src_depth = cvTsRandInt(rng) % 2, dst_depth;
1635     int cn = cvTsRandInt(rng) % 2 ? 3 : 1;
1636     CvSize src_size, dst_size;
1637     
1638     dst_depth = src_depth = src_depth == 0 ? CV_8U : CV_32F;
1639     if( src_depth < CV_32F && cvTsRandInt(rng) % 2 )
1640         dst_depth = CV_32F;
1641     
1642     types[INPUT][0] = CV_MAKETYPE(src_depth,cn);
1643     types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(dst_depth,cn);
1644
1645     src_size = sizes[INPUT][0];
1646     dst_size.width = cvRound(sqrt(cvTsRandReal(rng)*src_size.width) + 1);
1647     dst_size.height = cvRound(sqrt(cvTsRandReal(rng)*src_size.height) + 1);
1648     dst_size.width = MIN(dst_size.width,src_size.width);
1649     dst_size.height = MIN(dst_size.width,src_size.height);
1650     sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = dst_size;
1651     
1652     center.x = (float)(cvTsRandReal(rng)*src_size.width);
1653     center.y = (float)(cvTsRandReal(rng)*src_size.height);
1654     interpolation = CV_INTER_LINEAR;
1655 }
1656
1657
1658 void CV_GetRectSubPixTest::fill_array( int test_case_idx, int i, int j, CvMat* arr )
1659 {
1660     if( i != INPUT )
1661         CV_ImgWarpBaseTestImpl::fill_array( test_case_idx, i, j, arr );
1662 }
1663
1664 void CV_GetRectSubPixTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1665         CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
1666 {
1667     CV_ImgWarpBaseTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
1668                                                                whole_sizes, are_images );
1669     interpolation = CV_INTER_LINEAR;
1670 }
1671
1672
1673 void CV_GetRectSubPixTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
1674 {
1675     CV_ImgWarpBaseTest::print_timing_params( test_case_idx, ptr, params_left );
1676 }
1677
1678
1679 void CV_GetRectSubPixTest::run_func()
1680 {
1681     cvGetRectSubPix( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], center );
1682 }
1683
1684
1685 double CV_GetRectSubPixTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1686 {
1687     int in_depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
1688     int out_depth = CV_MAT_DEPTH(test_mat[INPUT_OUTPUT][0].type);
1689
1690     return in_depth >= CV_32F ? 1e-3 : out_depth >= CV_32F ? 1e-2 : 1;
1691 }
1692
1693
1694 int CV_GetRectSubPixTest::prepare_test_case( int test_case_idx )
1695 {
1696     return CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
1697 }
1698
1699
1700 void CV_GetRectSubPixTest::prepare_to_validation( int /*test_case_idx*/ )
1701 {
1702     CvMat* src0 = &test_mat[INPUT][0];
1703     CvMat* dst0 = &test_mat[REF_INPUT_OUTPUT][0];
1704     CvMat* src = src0, *dst = dst0;
1705     int ftype = CV_MAKETYPE(CV_32F,CV_MAT_CN(src0->type));
1706     double a[] = { 1, 0, center.x - dst->cols*0.5 + 0.5,
1707                    0, 1, center.y - dst->rows*0.5 + 0.5 };
1708     if( CV_MAT_DEPTH(src->type) != CV_32F )
1709     {
1710         src = cvCreateMat( src0->rows, src0->cols, ftype );
1711         cvTsConvert( src0, src );
1712     }
1713
1714     if( CV_MAT_DEPTH(dst->type) != CV_32F )
1715         dst = cvCreateMat( dst0->rows, dst0->cols, ftype );
1716
1717     cvTsGetQuadrangeSubPix( src, dst, a );
1718
1719     if( dst != dst0 )
1720     {
1721         cvTsConvert( dst, dst0 );
1722         cvReleaseMat( &dst );
1723     }
1724     if( src != src0 )
1725         cvReleaseMat( &src );
1726 }
1727
1728
1729 CV_GetRectSubPixTest subpix_rect_test;
1730
1731
1732 class CV_GetQuadSubPixTest : public CV_ImgWarpBaseTest
1733 {
1734 public:
1735     CV_GetQuadSubPixTest();
1736
1737 protected:
1738     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1739     void run_func();
1740     int prepare_test_case( int test_case_idx );
1741     void prepare_to_validation( int /*test_case_idx*/ );
1742     double get_success_error_level( int test_case_idx, int i, int j );
1743
1744     int write_default_params(CvFileStorage* fs);
1745     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
1746                                                 CvSize** whole_sizes, bool *are_images );
1747     void print_timing_params( int test_case_idx, char* ptr, int params_left );
1748 };
1749
1750
1751 CV_GetQuadSubPixTest::CV_GetQuadSubPixTest()
1752     : CV_ImgWarpBaseTest( "warp-subpix-quad", "cvGetQuadSubPix", true )
1753 {
1754     //spatial_scale_zoom = spatial_scale_decimate;
1755     spatial_scale_decimate = spatial_scale_zoom;
1756     //default_timing_param_names = imgwarp_affine_param_names;
1757     support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
1758     default_timing_param_names = 0;
1759 }
1760
1761
1762 int CV_GetQuadSubPixTest::write_default_params( CvFileStorage* fs )
1763 {
1764     int code = CV_ImgWarpBaseTest::write_default_params( fs );
1765     if( code < 0 )
1766         return code;
1767     
1768     if( ts->get_testing_mode() == CvTS::TIMING_MODE )
1769     {
1770         int i;
1771         start_write_param( fs );
1772
1773         cvStartWriteStruct( fs, "rotate_scale", CV_NODE_SEQ+CV_NODE_FLOW );
1774         for( i = 0; imgwarp_affine_rotate_scale[i][0] >= 0; i++ )
1775         {
1776             cvStartWriteStruct( fs, 0, CV_NODE_SEQ+CV_NODE_FLOW );
1777             cvWriteRawData( fs, imgwarp_affine_rotate_scale[i], 4, "d" );
1778             cvEndWriteStruct(fs);
1779         }
1780         cvEndWriteStruct(fs);
1781     }
1782
1783     return code;
1784 }
1785
1786
1787 void CV_GetQuadSubPixTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1788 {
1789     int min_size = 4;
1790     CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1791     CvSize sz = sizes[INPUT][0], dsz;
1792     CvRNG* rng = ts->get_rng();
1793     int msz, src_depth = cvTsRandInt(rng) % 2, dst_depth;
1794     int cn = cvTsRandInt(rng) % 2 ? 3 : 1;
1795     
1796     dst_depth = src_depth = src_depth == 0 ? CV_8U : CV_32F;
1797     if( src_depth < CV_32F && cvTsRandInt(rng) % 2 )
1798         dst_depth = CV_32F;
1799     
1800     types[INPUT][0] = CV_MAKETYPE(src_depth,cn);
1801     types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(dst_depth,cn);
1802
1803     sz.width = MAX(sz.width,min_size);
1804     sz.height = MAX(sz.height,min_size);
1805     sizes[INPUT][0] = sz;
1806     msz = MIN( sz.width, sz.height );
1807
1808     dsz.width = cvRound(sqrt(cvTsRandReal(rng)*msz) + 1);
1809     dsz.height = cvRound(sqrt(cvTsRandReal(rng)*msz) + 1);
1810     dsz.width = MIN(dsz.width,msz);
1811     dsz.height = MIN(dsz.width,msz);
1812     dsz.width = MAX(dsz.width,min_size);
1813     dsz.height = MAX(dsz.height,min_size);
1814     sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = dsz;
1815     sizes[INPUT][1] = cvSize( 3, 2 );
1816 }
1817
1818
1819 void CV_GetQuadSubPixTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1820                 CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
1821 {
1822     CV_ImgWarpBaseTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
1823                                                                whole_sizes, are_images );
1824
1825     sizes[INPUT][1] = whole_sizes[INPUT][1] = cvSize(3,2);
1826     sizes[TEMP][0] = whole_sizes[TEMP][0] =
1827         sizes[TEMP][1] = whole_sizes[TEMP][1] = cvSize(0,0);
1828     types[INPUT][1] = CV_64FC1;
1829
1830     interpolation = CV_INTER_LINEAR;
1831 }
1832
1833
1834 void CV_GetQuadSubPixTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
1835 {
1836     double coeffs[4];
1837     const CvFileNode* node = find_timing_param( "rotate_scale" );
1838     assert( node && CV_NODE_IS_SEQ(node->tag) );
1839     cvReadRawData( ts->get_file_storage(), node, coeffs, "4d" );
1840     
1841     sprintf( ptr, "fx=%.2f,fy=%.2f,angle=%.1fdeg,scale=%.1f,", coeffs[0], coeffs[1], coeffs[2], coeffs[3] );
1842     ptr += strlen(ptr);
1843     params_left -= 4;
1844
1845     CV_ImgWarpBaseTest::print_timing_params( test_case_idx, ptr, params_left );
1846 }
1847
1848
1849 void CV_GetQuadSubPixTest::run_func()
1850 {
1851     cvGetQuadrangleSubPix( test_array[INPUT][0],
1852         test_array[INPUT_OUTPUT][0], &test_mat[INPUT][1] );
1853 }
1854
1855
1856 double CV_GetQuadSubPixTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1857 {
1858     int in_depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
1859     //int out_depth = CV_MAT_DEPTH(test_mat[INPUT_OUTPUT][0].type);
1860
1861     return in_depth >= CV_32F ? 1e-2 : 4;
1862 }
1863
1864
1865 int CV_GetQuadSubPixTest::prepare_test_case( int test_case_idx )
1866 {
1867     CvRNG* rng = ts->get_rng();
1868     int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
1869     const CvMat* src = &test_mat[INPUT][0];
1870     CvMat* mat = &test_mat[INPUT][1];
1871     CvPoint2D32f center;
1872     double scale, angle;
1873
1874     if( code <= 0 )
1875         return code;
1876
1877     if( ts->get_testing_mode() == CvTS::CORRECTNESS_CHECK_MODE )
1878     {
1879         double a[6];
1880         CvMat A = cvMat( 2, 3, CV_64FC1, a );
1881
1882         center.x = (float)((cvTsRandReal(rng)*1.2 - 0.1)*src->cols);
1883         center.y = (float)((cvTsRandReal(rng)*1.2 - 0.1)*src->rows);
1884         angle = cvTsRandReal(rng)*360;
1885         scale = cvTsRandReal(rng)*0.2 + 0.9;
1886         
1887         // y = Ax + b -> x = A^-1(y - b) = A^-1*y - A^-1*b
1888         scale = 1./scale;
1889         angle = angle*(CV_PI/180.);
1890         a[0] = a[4] = cos(angle)*scale;
1891         a[1] = sin(angle)*scale;
1892         a[3] = -a[1];
1893         a[2] = center.x - a[0]*center.x - a[1]*center.y;
1894         a[5] = center.y - a[3]*center.x - a[4]*center.y;
1895         cvTsConvert( &A, mat );
1896     }
1897
1898     return code;
1899 }
1900
1901
1902 void CV_GetQuadSubPixTest::prepare_to_validation( int /*test_case_idx*/ )
1903 {
1904     CvMat* src0 = &test_mat[INPUT][0];
1905     CvMat* dst0 = &test_mat[REF_INPUT_OUTPUT][0];
1906     CvMat* src = src0, *dst = dst0;
1907     int ftype = CV_MAKETYPE(CV_32F,CV_MAT_CN(src0->type));
1908     double a[6], dx = (dst0->cols - 1)*0.5, dy = (dst0->rows - 1)*0.5;
1909     CvMat A = cvMat( 2, 3, CV_64F, a );
1910
1911     if( CV_MAT_DEPTH(src->type) != CV_32F )
1912     {
1913         src = cvCreateMat( src0->rows, src0->cols, ftype );
1914         cvTsConvert( src0, src );
1915     }
1916
1917     if( CV_MAT_DEPTH(dst->type) != CV_32F )
1918         dst = cvCreateMat( dst0->rows, dst0->cols, ftype );
1919
1920     cvTsConvert( &test_mat[INPUT][1], &A );
1921     a[2] -= a[0]*dx + a[1]*dy;
1922     a[5] -= a[3]*dx + a[4]*dy;
1923     cvTsGetQuadrangeSubPix( src, dst, a );
1924
1925     if( dst != dst0 )
1926     {
1927         cvTsConvert( dst, dst0 );
1928         cvReleaseMat( &dst );
1929     }
1930
1931     if( src != src0 )
1932         cvReleaseMat( &src );
1933 }
1934
1935
1936 CV_GetQuadSubPixTest warp_subpix_quad_test;
1937
1938 /* End of file. */