Move the sources to trunk
[opencv] / tests / cv / src / afilter.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 CvSize filter_sizes[] = {{30,30}, {320, 240}, {720,480}, {-1,-1}};
45 static const CvSize filter_whole_sizes[] = {{320,240}, {320, 240}, {720,480}, {-1,-1}};
46 static const int filter_depths[] = { CV_8U, CV_16U, CV_32F, -1 };
47 static const int filter_channels[] = { 1, 3, 4, -1 };
48
49 class CV_FilterBaseTestImpl : public CvArrTest
50 {
51 public:
52     CV_FilterBaseTestImpl( const char* test_name, const char* test_funcs, bool _fp_kernel );
53
54 protected:
55     int prepare_test_case( int test_case_idx );
56     void prepare_to_validation( int /*test_case_idx*/ );
57     int read_params( CvFileStorage* fs );
58     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
59     void get_minmax_bounds( int i, int j, int type, CvScalar* low, CvScalar* high );
60     int write_default_params(CvFileStorage* fs);
61     CvSize aperture_size;
62     CvPoint anchor;
63     int max_aperture_size;
64     bool fp_kernel;
65     bool inplace;
66 };
67
68
69 CV_FilterBaseTestImpl::CV_FilterBaseTestImpl( const char* test_name, const char* test_funcs, bool _fp_kernel )
70     : CvArrTest( test_name, test_funcs, "" ), fp_kernel(_fp_kernel)
71 {
72     test_array[INPUT].push(NULL);
73     test_array[INPUT].push(NULL);
74     test_array[TEMP].push(NULL);
75     test_array[OUTPUT].push(NULL);
76     test_array[REF_OUTPUT].push(NULL);
77     max_aperture_size = 13;
78     inplace = false;
79     aperture_size = cvSize(0,0);
80     anchor = cvPoint(0,0);
81     element_wise_relative_error = false;
82
83     size_list = filter_sizes;
84     whole_size_list = filter_whole_sizes;
85     depth_list = filter_depths;
86     cn_list = filter_channels;
87 }
88
89
90 int CV_FilterBaseTestImpl::read_params( CvFileStorage* fs )
91 {
92     int code = CvArrTest::read_params( fs );
93     if( code < 0 )
94         return code;
95
96     if( ts->get_testing_mode() == CvTS::CORRECTNESS_CHECK_MODE )
97     {
98         max_aperture_size = cvReadInt( find_param( fs, "max_aperture_size" ), max_aperture_size );
99         max_aperture_size = cvTsClipInt( max_aperture_size, 1, 100 );
100     }
101
102     return code;
103 }
104
105
106 int CV_FilterBaseTestImpl::write_default_params( CvFileStorage* fs )
107 {
108     int code = CvArrTest::write_default_params( fs );
109     if( code < 0 )
110         return code;
111     
112     if( ts->get_testing_mode() == CvTS::CORRECTNESS_CHECK_MODE )
113     {
114         write_param( fs, "max_aperture_size", max_aperture_size );
115     }
116
117     return code;
118 }
119
120
121 void CV_FilterBaseTestImpl::get_minmax_bounds( int i, int j, int type, CvScalar* low, CvScalar* high )
122 {
123     CvArrTest::get_minmax_bounds( i, j, type, low, high );
124     if( i == INPUT )
125     {
126         if( j == 1 )
127         {
128             if( fp_kernel )
129             {
130                 if( ts->get_testing_mode() == CvTS::TIMING_MODE )
131                 {
132                     *low = cvScalarAll(-1);
133                     *high = cvScalarAll(1);
134                 }
135                 else
136                 {
137                     CvRNG* rng = ts->get_rng();
138                     double val = exp( cvTsRandReal(rng)*10 - 4 );
139                     *low = cvScalarAll(-val);
140                     *high = cvScalarAll(val);
141                 }
142             }
143             else
144             {
145                 *low = cvScalarAll(0);
146                 *high = cvScalarAll(2);
147             }
148         }
149         else if( CV_MAT_DEPTH(type) == CV_32F )
150         {
151             *low = cvScalarAll(-10.);
152             *high = cvScalarAll(10.);
153         }
154     }
155 }
156
157
158 void CV_FilterBaseTestImpl::get_test_array_types_and_sizes( int test_case_idx,
159                                                 CvSize** sizes, int** types )
160 {
161     CvRNG* rng = ts->get_rng();
162     int depth = cvTsRandInt(rng) % CV_32F;
163     int cn = cvTsRandInt(rng) % 3 + 1;
164     CvArrTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
165     depth += depth == CV_8S;
166     cn += cn == 2;
167
168     types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = types[TEMP][0] = CV_MAKETYPE(depth, cn);
169
170     aperture_size.width = cvTsRandInt(rng) % max_aperture_size + 1;
171     aperture_size.height = cvTsRandInt(rng) % max_aperture_size + 1;
172     anchor.x = cvTsRandInt(rng) % aperture_size.width;
173     anchor.y = cvTsRandInt(rng) % aperture_size.height;
174
175     types[INPUT][1] = fp_kernel ? CV_32FC1 : CV_8UC1;
176     sizes[INPUT][1] = aperture_size;
177     sizes[TEMP][0].width += aperture_size.width - 1;
178     sizes[TEMP][0].height += aperture_size.height - 1;
179
180     inplace = cvTsRandInt(rng) % 2 != 0;
181 }
182
183
184 int CV_FilterBaseTestImpl::prepare_test_case( int test_case_idx )
185 {
186     int code = CvArrTest::prepare_test_case( test_case_idx );
187     if( code > 0 )
188     {
189         if( inplace && CV_ARE_TYPES_EQ(&test_mat[INPUT][0],&test_mat[OUTPUT][0]))
190             cvTsCopy( &test_mat[INPUT][0], &test_mat[OUTPUT][0] );
191         else
192             inplace = false;
193     }
194     return code;
195 }
196
197
198 void CV_FilterBaseTestImpl::prepare_to_validation( int /*test_case_idx*/ )
199 {
200     CvMat* src = &test_mat[INPUT][0];
201     
202     if( !CV_ARE_TYPES_EQ( src, &test_mat[TEMP][0] ))
203     {
204         cvTsConvert( src, &test_mat[REF_OUTPUT][0] );
205         src = &test_mat[REF_OUTPUT][0];
206     }
207     cvTsPrepareToFilter( src, &test_mat[TEMP][0],
208                          anchor, CV_TS_BORDER_REPLICATE );
209 }
210
211
212 CV_FilterBaseTestImpl filter_base( "filter", "", false );
213
214
215 class CV_FilterBaseTest : public CV_FilterBaseTestImpl
216 {
217 public:
218     CV_FilterBaseTest( const char* test_name, const char* test_funcs, bool _fp_kernel );
219 };
220
221
222 CV_FilterBaseTest::CV_FilterBaseTest( const char* test_name, const char* test_funcs, bool _fp_kernel )
223     : CV_FilterBaseTestImpl( test_name, test_funcs, _fp_kernel )
224 {
225     size_list = 0;
226     whole_size_list = 0;
227     depth_list = 0;
228     cn_list = 0;
229 }
230
231
232 /////////////////////////
233
234 static const char* morph_param_names[] = { "mask_size", "shape", "size", "channels", "depth", 0 };
235 static const int morph_depths[] = { CV_8U, CV_32F, -1 };
236 static const int morph_mask_size[] = { 3, 5, 11 };
237 static const char* morph_mask_shape[] = { "rect", "ellipse", 0 };
238
239 class CV_MorphologyBaseTestImpl : public CV_FilterBaseTest
240 {
241 public:
242     CV_MorphologyBaseTestImpl( const char* test_name, const char* test_funcs, int optype );
243
244 protected:
245     void prepare_to_validation( int test_case_idx );
246     int prepare_test_case( int test_case_idx );
247     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
248     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
249                                                 CvSize** whole_sizes, bool *are_images );
250     void print_timing_params( int test_case_idx, char* ptr, int params_left );
251     double get_success_error_level( int test_case_idx, int i, int j );
252     int write_default_params(CvFileStorage* fs);
253     int optype;
254     int shape;
255     IplConvKernel* element;
256 };
257
258
259 CV_MorphologyBaseTestImpl::CV_MorphologyBaseTestImpl( const char* test_name, const char* test_funcs, int _optype )
260     : CV_FilterBaseTest( test_name, test_funcs, false ), optype(_optype)
261 {
262     shape = -1;
263     element = 0;
264     size_list = filter_sizes;
265     whole_size_list = filter_whole_sizes;
266     depth_list = morph_depths;
267     cn_list = filter_channels;
268
269     element = 0;
270 }
271
272
273 int CV_MorphologyBaseTestImpl::write_default_params( CvFileStorage* fs )
274 {
275     int code = CV_FilterBaseTest::write_default_params( fs );
276     if( code >= 0 && ts->get_testing_mode() == CvTS::TIMING_MODE && strcmp(tested_functions,"") == 0 )
277     {
278         start_write_param( fs );
279         write_int_list( fs, "mask_size", morph_mask_size, CV_DIM(morph_mask_size) );
280         write_string_list( fs, "shape", morph_mask_shape );
281     }
282     return code;
283 }
284
285
286 void CV_MorphologyBaseTestImpl::get_test_array_types_and_sizes( int test_case_idx,
287                                                 CvSize** sizes, int** types )
288 {
289     CvRNG* rng = ts->get_rng();
290     CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
291     int depth = cvTsRandInt(rng) % 2 ? CV_32F : CV_8U;
292     int cn = CV_MAT_CN(types[INPUT][0]);
293
294     types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = types[TEMP][0] = CV_MAKETYPE(depth, cn);
295     shape = cvTsRandInt(rng) % 4;
296     if( shape >= 3 )
297         shape = CV_SHAPE_CUSTOM;
298     else
299         sizes[INPUT][1] = cvSize(0,0);
300 }
301
302
303 void CV_MorphologyBaseTestImpl::get_timing_test_array_types_and_sizes( int test_case_idx,
304                 CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
305 {
306     CV_FilterBaseTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
307                                                               whole_sizes, are_images );
308     const char* shape_str = cvReadString( find_timing_param( "shape" ), "rect" );
309     shape = strcmp( shape_str, "rect" ) == 0 ? CV_SHAPE_RECT : CV_SHAPE_ELLIPSE;
310     aperture_size.width = cvReadInt( find_timing_param( "mask_size" ), 3 );
311     aperture_size.height = aperture_size.width;
312     anchor.x = anchor.y = aperture_size.width / 2;
313 }
314
315
316 void CV_MorphologyBaseTestImpl::print_timing_params( int test_case_idx, char* ptr, int params_left )
317 {
318     sprintf( ptr, "%dx%d,", aperture_size.width, aperture_size.height );
319     ptr += strlen(ptr);
320     sprintf( ptr, "%s,", shape == CV_SHAPE_RECT ? "rect" : "ellipse" );
321     ptr += strlen(ptr);
322     params_left -= 2;
323
324     CV_FilterBaseTest::print_timing_params( test_case_idx, ptr, params_left );
325 }
326
327
328 double CV_MorphologyBaseTestImpl::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
329 {
330     return 0;
331 }
332
333
334 int CV_MorphologyBaseTestImpl::prepare_test_case( int test_case_idx )
335 {
336     int code = CV_FilterBaseTest::prepare_test_case( test_case_idx );
337     int* eldata = 0;
338
339     if( code <= 0 )
340         return code;
341     
342     if( shape == CV_SHAPE_CUSTOM )
343     {
344         eldata = (int*)alloca( aperture_size.width*aperture_size.height*sizeof(eldata[0]) );
345         uchar* src = test_mat[INPUT][1].data.ptr;
346         int srcstep = test_mat[INPUT][1].step;
347         int i, j, nonzero = 0;
348
349         for( i = 0; i < aperture_size.height; i++ )
350         {
351             for( j = 0; j < aperture_size.width; j++ )
352             {
353                 eldata[i*aperture_size.width + j] = src[i*srcstep + j];
354                 nonzero += src[i*srcstep + j] != 0;
355             }
356         }
357
358         if( nonzero == 0 )
359             eldata[anchor.y*aperture_size.width + anchor.x] = 1;
360     }
361     
362     cvReleaseStructuringElement( &element );
363     element = cvCreateStructuringElementEx( aperture_size.width, aperture_size.height,
364                                             anchor.x, anchor.y, shape, eldata );
365     return code;
366 }
367
368
369 void CV_MorphologyBaseTestImpl::prepare_to_validation( int test_case_idx )
370 {
371     CV_FilterBaseTest::prepare_to_validation( test_case_idx );
372     cvTsMinMaxFilter( &test_mat[TEMP][0], &test_mat[REF_OUTPUT][0], element, optype );
373     cvReleaseStructuringElement( &element );
374 }
375
376
377 CV_MorphologyBaseTestImpl morph( "morph", "", -1 );
378
379
380 class CV_MorphologyBaseTest : public CV_MorphologyBaseTestImpl
381 {
382 public:
383     CV_MorphologyBaseTest( const char* test_name, const char* test_funcs, int optype );
384 };
385
386
387 CV_MorphologyBaseTest::CV_MorphologyBaseTest( const char* test_name, const char* test_funcs, int _optype )
388     : CV_MorphologyBaseTestImpl( test_name, test_funcs, _optype )
389 {
390     default_timing_param_names = morph_param_names;
391     depth_list = 0;
392     size_list = 0;
393     cn_list = 0;
394 }
395
396
397 /////////////// erode ///////////////
398
399 class CV_ErodeTest : public CV_MorphologyBaseTest
400 {
401 public:
402     CV_ErodeTest();
403 protected:
404     void run_func();
405 };
406
407
408 CV_ErodeTest::CV_ErodeTest()
409     : CV_MorphologyBaseTest( "morph-erode", "cvErode", CV_TS_MIN )
410 {
411 }
412
413
414 void CV_ErodeTest::run_func()
415 {
416     cvErode( inplace ? test_array[OUTPUT][0] : test_array[INPUT][0],
417              test_array[OUTPUT][0], element, 1 );
418 }
419
420 CV_ErodeTest erode_test;
421
422
423 /////////////// dilate ///////////////
424
425 class CV_DilateTest : public CV_MorphologyBaseTest
426 {
427 public:
428     CV_DilateTest();
429 protected:
430     void run_func();
431 };
432
433
434 CV_DilateTest::CV_DilateTest()
435     : CV_MorphologyBaseTest( "morph-dilate", "cvDilate", CV_TS_MAX )
436 {
437 }
438
439
440 void CV_DilateTest::run_func()
441 {
442     cvDilate( inplace ? test_array[OUTPUT][0] : test_array[INPUT][0],
443              test_array[OUTPUT][0], element, 1 );
444 }
445
446 CV_DilateTest dilate_test;
447
448
449 /////////////// generic filter ///////////////
450
451 static const char* filter_generic_param_names[] = { "mask_size", "size", "channels", "depth", 0 };
452
453 class CV_FilterTest : public CV_FilterBaseTest
454 {
455 public:
456     CV_FilterTest();
457
458 protected:
459     void prepare_to_validation( int test_case_idx );
460     void run_func();
461     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
462     double get_success_error_level( int test_case_idx, int i, int j );
463     
464     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
465                                                 CvSize** whole_sizes, bool *are_images );
466     void print_timing_params( int test_case_idx, char* ptr, int params_left );
467     int write_default_params(CvFileStorage* fs);
468 };
469
470
471 CV_FilterTest::CV_FilterTest()
472     : CV_FilterBaseTest( "filter-generic", "cvFilter2D", true )
473 {
474     default_timing_param_names = filter_generic_param_names;
475 }
476
477
478 int CV_FilterTest::write_default_params( CvFileStorage* fs )
479 {
480     int code = CV_FilterBaseTest::write_default_params( fs );
481     if( code >= 0 && ts->get_testing_mode() == CvTS::TIMING_MODE )
482     {
483         start_write_param( fs );
484         write_int_list( fs, "mask_size", morph_mask_size, CV_DIM(morph_mask_size) );
485     }
486     return code;
487 }
488
489
490 void CV_FilterTest::get_test_array_types_and_sizes( int test_case_idx,
491                                                 CvSize** sizes, int** types )
492 {
493     CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
494     CvRNG* rng = ts->get_rng();
495     int depth = cvTsRandInt(rng)%3;
496     int cn = CV_MAT_CN(types[INPUT][0]);
497     depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : CV_32F;
498     types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = types[TEMP][0] = CV_MAKETYPE(depth, cn);
499 }
500
501
502 void CV_FilterTest::get_timing_test_array_types_and_sizes( int test_case_idx,
503                 CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
504 {
505     CV_FilterBaseTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
506                                                               whole_sizes, are_images );
507     aperture_size.width = cvReadInt( find_timing_param( "mask_size" ), 3 );
508     aperture_size.height = aperture_size.width;
509     anchor.x = anchor.y = aperture_size.width / 2;
510     sizes[INPUT][1] = aperture_size;
511     types[INPUT][1] = CV_32FC1;
512 }
513
514
515 void CV_FilterTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
516 {
517     sprintf( ptr, "%dx%d,", aperture_size.width, aperture_size.height );
518     ptr += strlen(ptr);
519     params_left--;
520
521     CV_FilterBaseTest::print_timing_params( test_case_idx, ptr, params_left );
522 }
523
524
525 double CV_FilterTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
526 {
527     int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
528     return depth <= CV_8S ? 2 : depth <= CV_32S ? 32 :
529            depth == CV_32F ? 1e-5 : 1e-10;
530 }
531
532
533 void CV_FilterTest::run_func()
534 {
535     cvFilter2D( inplace ? test_array[OUTPUT][0] : test_array[INPUT][0],
536                 test_array[OUTPUT][0], &test_mat[INPUT][1], anchor );
537 }
538
539
540 void CV_FilterTest::prepare_to_validation( int test_case_idx )
541 {
542     CV_FilterBaseTest::prepare_to_validation( test_case_idx );
543     cvTsConvolve2D( &test_mat[TEMP][0], &test_mat[REF_OUTPUT][0], &test_mat[INPUT][1], anchor );
544 }
545
546 CV_FilterTest filter;
547
548
549 ////////////////////////
550
551 static const int laplace_aperture[] = { 3, 5, 7 };
552 static const int sobel_aperture[] = { -1, 3, 5, 7 };
553 static const char* laplace_param_names[] = { "aperture", "size", "depth", 0 };
554 static const char* sobel_param_names[] = { "deriv_type", "aperture", "size", "depth", 0 };
555 static const char* sobel_deriv_type[] = { "dx", "dy", "d2x", "d2y", "dxdy", 0 };
556
557 class CV_DerivBaseTest : public CV_FilterBaseTest
558 {
559 public:
560     CV_DerivBaseTest( const char* test_name, const char* test_funcs );
561 protected:
562     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
563     double get_success_error_level( int test_case_idx, int i, int j );
564     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
565                                                 CvSize** whole_sizes, bool *are_images );
566     int _aperture_size;
567 };
568
569
570 CV_DerivBaseTest::CV_DerivBaseTest( const char* test_name, const char* test_funcs )
571     : CV_FilterBaseTest( test_name, test_funcs, true )
572 {
573     max_aperture_size = 7;
574     depth_list = morph_depths;
575     cn_list = 0;
576 }
577
578
579 void CV_DerivBaseTest::get_test_array_types_and_sizes( int test_case_idx,
580                                                 CvSize** sizes, int** types )
581 {
582     CvRNG* rng = ts->get_rng();
583     CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
584     int depth = cvTsRandInt(rng) % 2;
585     depth = depth == 0 ? CV_8U : CV_32F;
586     types[INPUT][0] = CV_MAKETYPE(depth,1);
587     types[TEMP][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth==CV_8U?CV_16S:CV_32F,1);
588     _aperture_size = (cvTsRandInt(rng)%5)*2 - 1;
589     sizes[INPUT][1] = aperture_size = cvSize(_aperture_size, _aperture_size);
590 }
591
592
593 double CV_DerivBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
594 {
595     int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
596     return depth <= CV_8S ? 1 : 5e-4;
597 }
598
599
600 void CV_DerivBaseTest::get_timing_test_array_types_and_sizes( int test_case_idx,
601                 CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
602 {
603     CV_FilterBaseTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
604                                                               whole_sizes, are_images );
605     _aperture_size = cvReadInt( find_timing_param( "aperture" ), 3 );
606     aperture_size.width = aperture_size.height = _aperture_size < 0 ? 3 : _aperture_size;
607     anchor.x = anchor.y = aperture_size.width / 2;
608     sizes[INPUT][1] = aperture_size;
609     types[INPUT][1] = CV_32FC1;
610     types[OUTPUT][0] = types[INPUT][0] == CV_8UC1 ? CV_16SC1 : types[INPUT][0];
611 }
612
613
614 /////////////// sobel ///////////////
615
616 class CV_SobelTest : public CV_DerivBaseTest
617 {
618 public:
619     CV_SobelTest();
620
621 protected:
622     int prepare_test_case( int test_case_idx );
623     void prepare_to_validation( int test_case_idx );
624     void run_func();
625     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
626     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
627                                                 CvSize** whole_sizes, bool *are_images );
628     int write_default_params( CvFileStorage* fs );
629     void print_timing_params( int test_case_idx, char* ptr, int params_left );
630     int dx, dy, origin;
631     IplImage img;
632     void* src;
633 };
634
635
636 CV_SobelTest::CV_SobelTest() : CV_DerivBaseTest( "filter-sobel", "cvSobel" )
637 {
638     src = 0;
639     default_timing_param_names = sobel_param_names;
640 }
641
642
643 int CV_SobelTest::write_default_params( CvFileStorage* fs )
644 {
645     int code = CV_DerivBaseTest::write_default_params( fs );
646     if( code >= 0 && ts->get_testing_mode() == CvTS::TIMING_MODE )
647     {
648         start_write_param( fs );
649         write_int_list( fs, "aperture", sobel_aperture, CV_DIM(sobel_aperture) );
650         write_string_list( fs, "deriv_type", sobel_deriv_type );
651     }
652     return code;
653 }
654
655
656 void CV_SobelTest::get_test_array_types_and_sizes( int test_case_idx,
657                                                 CvSize** sizes, int** types )
658 {
659     CvRNG* rng = ts->get_rng();
660     CV_DerivBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
661     int max_d = _aperture_size > 0 ? 2 : 1;
662     origin = cvTsRandInt(rng) % 2;
663     dx = cvTsRandInt(rng) % (max_d + 1);
664     dy = cvTsRandInt(rng) % (max_d + 1 - dx);
665     if( dx == 0 && dy == 0 )
666         dx = 1;
667     if( cvTsRandInt(rng) % 2 )
668     {
669         int t;
670         CV_SWAP( dx, dy, t );
671     }
672     
673     if( _aperture_size < 0 )
674         aperture_size = cvSize(3, 3);
675     else if( _aperture_size == 1 )
676     {
677         if( dx == 0 )
678             aperture_size = cvSize(1, 3);
679         else if( dy == 0 )
680             aperture_size = cvSize(3, 1);
681         else
682         {
683             _aperture_size = 3;
684             aperture_size = cvSize(3, 3);
685         }
686     }
687     else
688         aperture_size = cvSize(_aperture_size, _aperture_size);
689
690     sizes[INPUT][1] = aperture_size;
691     sizes[TEMP][0].width = sizes[INPUT][0].width + aperture_size.width - 1;
692     sizes[TEMP][0].height = sizes[INPUT][0].height + aperture_size.height - 1;
693     anchor.x = aperture_size.width / 2;
694     anchor.y = aperture_size.height / 2;
695 }
696
697
698 void CV_SobelTest::get_timing_test_array_types_and_sizes( int test_case_idx,
699                 CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
700 {
701     CV_DerivBaseTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
702                                                             whole_sizes, are_images );
703     //_aperture_size = cvReadInt( find_timing_param( "mask_size" ), 3 );
704     const char* mask_type = cvReadString( find_timing_param( "deriv_type" ), "dx" );
705     if( strcmp( mask_type, "dx" ) == 0 )
706         dx = 1, dy = 0;
707     else if( strcmp( mask_type, "dy" ) == 0 )
708         dx = 0, dy = 1;
709     else if( strcmp( mask_type, "d2x" ) == 0 )
710         dx = 2, dy = 0;
711     else if( strcmp( mask_type, "d2y" ) == 0 )
712         dx = 0, dy = 2;
713     else
714         dx = 1, dy = 1;
715     origin = 0;
716
717     aperture_size.width = aperture_size.height = _aperture_size < 0 ? 3 : _aperture_size;
718     anchor.x = anchor.y = aperture_size.width / 2;
719     sizes[INPUT][1] = aperture_size;
720     types[INPUT][1] = CV_32FC1;
721     types[OUTPUT][0] = types[INPUT][0] == CV_8UC1 ? CV_16SC1 : types[INPUT][0];
722 }
723
724
725 int CV_SobelTest::prepare_test_case( int test_case_idx )
726 {
727     int code = CV_DerivBaseTest::prepare_test_case( test_case_idx );
728     
729     if( code > 0 )
730     {
731         if( _aperture_size < 0 && ((dx != 1 || dy != 0) && (dx != 0 || dy != 1)) )
732             return 0;
733
734         if( origin )
735         {
736             src = inplace ? &test_mat[OUTPUT][0] : &test_mat[INPUT][0];
737             cvGetImage( src, &img );
738             img.origin = origin;
739             src = &img;
740         }
741         else
742             src = inplace ? test_array[OUTPUT][0] : test_array[INPUT][0];
743     }
744     return code;
745 }
746
747
748 void CV_SobelTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
749 {
750     const char* mask_type = cvReadString( find_timing_param( "deriv_type" ), "dx" );
751     sprintf( ptr, "%dx%d,%s_%s,", aperture_size.width, aperture_size.height,
752              _aperture_size > 0 ? "Sobel" : "Scharr", mask_type );
753     ptr += strlen(ptr);
754     params_left -= 2;
755
756     CV_DerivBaseTest::print_timing_params( test_case_idx, ptr, params_left );
757 }
758
759
760 void CV_SobelTest::run_func()
761 {
762     cvSobel( src, test_array[OUTPUT][0], dx, dy, _aperture_size );
763 }
764
765
766 static void cvTsCalcSobelKernel1D( int order, int _aperture_size, int size, int* kernel )
767 {
768     int i, j, oldval, newval;
769
770     if( _aperture_size < 0 )
771     {
772         static const int scharr[] = { 3, 10, 3, -1, 0, 1 };
773         assert( size == 3 );
774         memcpy( kernel, scharr + order*3, 3*sizeof(scharr[0]));
775         return;
776     }
777
778     memset( kernel + 1, 0, size * sizeof(kernel[0]));
779     kernel[0] = 1;
780
781     for( i = 0; i < size - order - 1; i++ )
782     {
783         oldval = kernel[0];
784         for( j = 1; j <= size; j++ )
785         {
786             newval = kernel[j] + kernel[j-1];
787             kernel[j-1] = oldval;
788             oldval = newval;
789         }
790     }
791
792     for( i = 0; i < order; i++ )
793     {
794         oldval = -kernel[0];
795         for( j = 1; j <= size; j++ )
796         {
797             newval = kernel[j-1] - kernel[j];
798             kernel[j-1] = oldval;
799             oldval = newval;
800         }
801     }
802 }
803
804
805 void cvTsCalcSobelKernel2D( int dx, int dy, int _aperture_size, int origin, CvMat* kernel )
806 {
807     int i, j;
808     int* kx = (int*)alloca( (kernel->cols+1)*sizeof(kx[0]) );
809     int* ky = (int*)alloca( (kernel->rows+1)*sizeof(ky[0]) );
810
811     assert( CV_MAT_TYPE(kernel->type) == CV_32F );
812
813     cvTsCalcSobelKernel1D( dx, _aperture_size, kernel->cols, kx );
814     cvTsCalcSobelKernel1D( dy, _aperture_size, kernel->rows, ky );
815
816     for( i = 0; i < kernel->rows; i++ )
817     {
818         float* kdata = (float*)(kernel->data.ptr + i*kernel->step);
819         float ay = (float)ky[i]*(origin && (dy & 1) ? -1 : 1);
820         for( j = 0; j < kernel->cols; j++ )
821         {
822             kdata[j] = kx[j]*ay;
823         }
824     }
825 }
826
827
828 void CV_SobelTest::prepare_to_validation( int test_case_idx )
829 {
830     CV_DerivBaseTest::prepare_to_validation( test_case_idx );
831     cvTsCalcSobelKernel2D( dx, dy, _aperture_size, origin, &test_mat[INPUT][1] );
832     cvTsConvolve2D( &test_mat[TEMP][0], &test_mat[REF_OUTPUT][0], &test_mat[INPUT][1], anchor );
833 }
834
835 CV_SobelTest sobel_test;
836
837
838 /////////////// laplace ///////////////
839
840 class CV_LaplaceTest : public CV_DerivBaseTest
841 {
842 public:
843     CV_LaplaceTest();
844
845 protected:
846     int prepare_test_case( int test_case_idx );
847     void prepare_to_validation( int test_case_idx );
848     void run_func();
849     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
850     int write_default_params( CvFileStorage* fs );
851     void print_timing_params( int test_case_idx, char* ptr, int params_left );
852 };
853
854
855 CV_LaplaceTest::CV_LaplaceTest() : CV_DerivBaseTest( "filter-laplace", "cvLaplace" )
856 {
857     default_timing_param_names = laplace_param_names;
858 }
859
860
861 int CV_LaplaceTest::write_default_params( CvFileStorage* fs )
862 {
863     int code = CV_DerivBaseTest::write_default_params( fs );
864     if( code >= 0 && ts->get_testing_mode() == CvTS::TIMING_MODE )
865     {
866         start_write_param( fs );
867         write_int_list( fs, "aperture", laplace_aperture, CV_DIM(laplace_aperture) );
868     }
869     return code;
870 }
871
872
873 void CV_LaplaceTest::get_test_array_types_and_sizes( int test_case_idx,
874                                                 CvSize** sizes, int** types )
875 {
876     CV_DerivBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
877     if( _aperture_size <= 1 )
878     {
879         if( _aperture_size < 0 )
880             _aperture_size = 1;
881         aperture_size = cvSize(3, 3);
882     }
883     else
884         aperture_size = cvSize(_aperture_size, _aperture_size);
885         
886     sizes[INPUT][1] = aperture_size;
887     sizes[TEMP][0].width = sizes[INPUT][0].width + aperture_size.width - 1;
888     sizes[TEMP][0].height = sizes[INPUT][0].height + aperture_size.height - 1;
889     anchor.x = aperture_size.width / 2;
890     anchor.y = aperture_size.height / 2;
891 }
892
893
894 void CV_LaplaceTest::run_func()
895 {
896     cvLaplace( inplace ? test_array[OUTPUT][0] : test_array[INPUT][0],
897                test_array[OUTPUT][0], _aperture_size );
898 }
899
900
901 static void cvTsCalcLaplaceKernel2D( int _aperture_size, CvMat* kernel )
902 {
903     int i, j;
904     int* kx = (int*)alloca( (kernel->cols+1)*sizeof(kx[0]) );
905     int* ky = (int*)alloca( (kernel->rows+1)*sizeof(ky[0]) );
906
907     cvTsCalcSobelKernel1D( 2, _aperture_size, kernel->cols, kx );
908     if( _aperture_size > 1 )
909         cvTsCalcSobelKernel1D( 0, _aperture_size, kernel->rows, ky );
910     else
911         ky[0] = ky[2] = 0, ky[1] = 1;
912
913     for( i = 0; i < kernel->rows; i++ )
914     {
915         float* kdata = (float*)(kernel->data.ptr + i*kernel->step);
916         for( j = 0; j < kernel->cols; j++ )
917         {
918             kdata[j] = (float)(kx[j]*ky[i] + kx[i]*ky[j]);
919         }
920     }
921 }
922
923
924 int CV_LaplaceTest::prepare_test_case( int test_case_idx )
925 {
926     int code = CV_DerivBaseTest::prepare_test_case( test_case_idx );
927     return _aperture_size < 0 ? 0 : code;
928 }
929
930
931 void CV_LaplaceTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
932 {
933     sprintf( ptr, "%dx%d,", aperture_size.width, aperture_size.height );
934     ptr += strlen(ptr);
935     params_left--;
936
937     CV_DerivBaseTest::print_timing_params( test_case_idx, ptr, params_left );
938 }
939
940
941 void CV_LaplaceTest::prepare_to_validation( int test_case_idx )
942 {
943     CV_DerivBaseTest::prepare_to_validation( test_case_idx );
944     cvTsCalcLaplaceKernel2D( _aperture_size, &test_mat[INPUT][1] );
945     cvTsConvolve2D( &test_mat[TEMP][0], &test_mat[REF_OUTPUT][0], &test_mat[INPUT][1], anchor );
946 }
947
948
949 CV_LaplaceTest laplace_test;
950
951
952 ////////////////////////////////////////////////////////////
953
954 static const char* smooth_param_names[] = { "mask_size", "size", "channels", "depth", 0 };
955 static const int smooth_depths[] = { CV_8U, CV_32F, -1 };
956
957 class CV_SmoothBaseTest : public CV_FilterBaseTest
958 {
959 public:
960     CV_SmoothBaseTest( const char* test_name, const char* test_funcs );
961
962 protected:
963     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
964     double get_success_error_level( int test_case_idx, int i, int j );
965     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
966                                                 CvSize** whole_sizes, bool *are_images );
967     int write_default_params( CvFileStorage* fs );
968     void print_timing_params( int test_case_idx, char* ptr, int params_left );
969     const char* smooth_type;
970 };
971
972
973 CV_SmoothBaseTest::CV_SmoothBaseTest( const char* test_name, const char* test_funcs )
974     : CV_FilterBaseTest( test_name, test_funcs, true )
975 {
976     default_timing_param_names = smooth_param_names;
977     depth_list = smooth_depths;
978     smooth_type = "";
979 }
980
981
982 int CV_SmoothBaseTest::write_default_params( CvFileStorage* fs )
983 {
984     int code = CV_FilterBaseTest::write_default_params( fs );
985     if( code >= 0 && ts->get_testing_mode() == CvTS::TIMING_MODE )
986     {
987         start_write_param( fs );
988         write_int_list( fs, "mask_size", morph_mask_size, CV_DIM(morph_mask_size) );
989     }
990     return code;
991 }
992
993 void CV_SmoothBaseTest::get_test_array_types_and_sizes( int test_case_idx,
994                                                 CvSize** sizes, int** types )
995 {
996     CvRNG* rng = ts->get_rng();
997     CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
998     int depth = cvTsRandInt(rng) % 2;
999     int cn = CV_MAT_CN(types[INPUT][0]);
1000     depth = depth == 0 ? CV_8U : CV_32F;
1001     types[INPUT][0] = types[TEMP][0] =
1002         types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth,cn);
1003     anchor.x = cvTsRandInt(rng)%(max_aperture_size/2+1);
1004     anchor.y = cvTsRandInt(rng)%(max_aperture_size/2+1);
1005     aperture_size.width = anchor.x*2 + 1;
1006     aperture_size.height = anchor.y*2 + 1;
1007     sizes[INPUT][1] = aperture_size;
1008     sizes[TEMP][0].width = sizes[INPUT][0].width + aperture_size.width - 1;
1009     sizes[TEMP][0].height = sizes[INPUT][0].height + aperture_size.height - 1;
1010 }
1011
1012
1013 double CV_SmoothBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1014 {
1015     int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
1016     return depth <= CV_8S ? 1 : 1e-5;
1017 }
1018
1019
1020 void CV_SmoothBaseTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1021                 CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
1022 {
1023     CV_FilterBaseTest::get_timing_test_array_types_and_sizes( test_case_idx,
1024                                     sizes, types, whole_sizes, are_images );
1025     
1026     aperture_size.width = aperture_size.height = cvReadInt( find_timing_param( "mask_size" ), 3 );
1027     anchor.x = anchor.y = aperture_size.width / 2;
1028     sizes[INPUT][1] = aperture_size;
1029     types[INPUT][1] = CV_32FC1;
1030 }
1031
1032
1033 void CV_SmoothBaseTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
1034 {
1035     sprintf( ptr, "%dx%d,%s,", aperture_size.width, aperture_size.height, smooth_type );
1036     ptr += strlen(ptr);
1037     params_left -= 2;
1038
1039     CV_FilterBaseTest::print_timing_params( test_case_idx, ptr, params_left );
1040 }
1041
1042
1043 /////////////// blur ///////////////
1044
1045 static const char* blur_param_names[] = { "normalize", "mask_size", "size", "channels", "depth", 0 };
1046 static const int blur_normalize[] = { 0, 1 };
1047
1048 class CV_BlurTest : public CV_SmoothBaseTest
1049 {
1050 public:
1051     CV_BlurTest();
1052
1053 protected:
1054     int prepare_test_case( int test_case_idx );
1055     void prepare_to_validation( int test_case_idx );
1056     void run_func();
1057     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1058     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
1059                                                 CvSize** whole_sizes, bool *are_images );
1060     int write_default_params( CvFileStorage* fs );
1061     bool normalize;
1062 };
1063
1064
1065 CV_BlurTest::CV_BlurTest() : CV_SmoothBaseTest( "filter-blur", "cvSmooth" )
1066 {
1067     default_timing_param_names = blur_param_names;
1068 }
1069
1070
1071 void CV_BlurTest::get_test_array_types_and_sizes( int test_case_idx,
1072                                                 CvSize** sizes, int** types )
1073 {
1074     CvRNG* rng = ts->get_rng();
1075     CV_SmoothBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1076     normalize = cvTsRandInt(rng) % 2 != 0;
1077     if( !normalize )
1078     {
1079         int depth = CV_MAT_DEPTH(types[INPUT][0]);
1080         types[INPUT][0] = CV_MAKETYPE(depth, 1); 
1081         types[TEMP][0] = types[OUTPUT][0] =
1082             types[REF_OUTPUT][0] = CV_MAKETYPE(depth==CV_8U?CV_16S:CV_32F,1);
1083     }
1084 }
1085
1086
1087 int CV_BlurTest::write_default_params( CvFileStorage* fs )
1088 {
1089     int code = CV_SmoothBaseTest::write_default_params( fs );
1090     if( code >= 0 && ts->get_testing_mode() == CvTS::TIMING_MODE )
1091     {
1092         write_int_list( fs, "normalize", blur_normalize, CV_DIM(blur_normalize) );
1093     }
1094     return code;
1095 }
1096
1097
1098 void CV_BlurTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1099                 CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
1100 {
1101     CV_SmoothBaseTest::get_timing_test_array_types_and_sizes( test_case_idx,
1102                                     sizes, types, whole_sizes, are_images );
1103     normalize = cvReadInt( find_timing_param( "normalize" ), 1 ) != 0;
1104     smooth_type = normalize ? "Blur" : "Blur_NoScale";
1105     sizes[INPUT][1] = aperture_size;
1106     types[INPUT][1] = CV_32FC1;
1107     if( !normalize && types[INPUT][0] == CV_8UC1 )
1108         types[OUTPUT][0] = CV_16SC1;
1109 }
1110
1111
1112 void CV_BlurTest::run_func()
1113 {
1114     cvSmooth( inplace ? test_array[OUTPUT][0] : test_array[INPUT][0],
1115               test_array[OUTPUT][0], normalize ? CV_BLUR : CV_BLUR_NO_SCALE,
1116               aperture_size.width, aperture_size.height );
1117 }
1118
1119
1120 int CV_BlurTest::prepare_test_case( int test_case_idx )
1121 {
1122     int code = CV_SmoothBaseTest::prepare_test_case( test_case_idx );
1123     return code > 0 && !normalize && CV_MAT_CN(test_mat[INPUT][0].type) > 1 ? 0 : code;
1124 }
1125
1126
1127 void CV_BlurTest::prepare_to_validation( int test_case_idx )
1128 {
1129     CvMat* kernel = &test_mat[INPUT][1];
1130     CV_SmoothBaseTest::prepare_to_validation( test_case_idx );
1131     cvTsAdd( 0, cvScalarAll(0.), 0, cvScalarAll(0.),
1132         cvScalarAll(normalize ? 1./(kernel->rows*kernel->cols) : 1.), kernel, 0 );
1133     cvTsConvolve2D( &test_mat[TEMP][0], &test_mat[REF_OUTPUT][0], kernel, anchor );
1134 }
1135
1136
1137 CV_BlurTest blur_test;
1138
1139
1140 /////////////// gaussian ///////////////
1141
1142 class CV_GaussianBlurTest : public CV_SmoothBaseTest
1143 {
1144 public:
1145     CV_GaussianBlurTest();
1146
1147 protected:
1148     void prepare_to_validation( int test_case_idx );
1149     void run_func();
1150     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1151     double get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ );
1152     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
1153                                                 CvSize** whole_sizes, bool *are_images );
1154     double sigma;
1155     int param1, param2;
1156 };
1157
1158
1159 CV_GaussianBlurTest::CV_GaussianBlurTest() : CV_SmoothBaseTest( "filter-gaussian", "cvSmooth" )
1160 {
1161     sigma = 0.;
1162     smooth_type = "Gaussian";
1163 }
1164
1165
1166 double CV_GaussianBlurTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1167 {
1168     int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
1169     return depth <= CV_8S ? 8 : 1e-5;
1170 }
1171
1172
1173 void CV_GaussianBlurTest::get_test_array_types_and_sizes( int test_case_idx,
1174                                                 CvSize** sizes, int** types )
1175 {
1176     CvRNG* rng = ts->get_rng();
1177     int kernel_case = cvTsRandInt(rng) % 2;
1178     CV_SmoothBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1179     anchor = cvPoint(aperture_size.width/2,aperture_size.height/2);
1180     sizes[TEMP][0].width = sizes[INPUT][0].width + aperture_size.width - 1;
1181     sizes[TEMP][0].height = sizes[INPUT][0].height + aperture_size.height - 1;
1182     
1183     sigma = exp(cvTsRandReal(rng)*5-2);
1184     param1 = aperture_size.width;
1185     param2 = aperture_size.height;
1186
1187     if( kernel_case == 0 )
1188         sigma = 0.;
1189     /*else if( kernel_case == 2 )
1190     {
1191         int depth = CV_MAT_DEPTH(types[INPUT][0]);
1192         // !!! Copied from cvSmooth, if this formula is changed in cvSmooth,
1193         // make sure to update this one too.
1194         aperture_size.width = cvRound(sigma*(depth == CV_8U ? 3 : 4)*2 + 1)|1;
1195         aperture_size.width = MIN( aperture_size.width, 31 );
1196         aperture_size.height = aperture_size.width;
1197         anchor.x = aperture_size.width / 2;
1198         anchor.y = aperture_size.height / 2;
1199         sizes[INPUT][1] = aperture_size;
1200         sizes[TEMP][0].width = sizes[INPUT][0].width + aperture_size.width - 1;
1201         sizes[TEMP][0].height = sizes[INPUT][0].height + aperture_size.height - 1;
1202         param1 = aperture_size.width; param2 = aperture_size.height;
1203     }*/
1204 }
1205
1206
1207 void CV_GaussianBlurTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1208                 CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
1209 {
1210     CV_SmoothBaseTest::get_timing_test_array_types_and_sizes( test_case_idx,
1211                                     sizes, types, whole_sizes, are_images );
1212     param1 = aperture_size.width;
1213     param2 = aperture_size.height;
1214     sigma = sqrt(2.);
1215 }
1216
1217 void CV_GaussianBlurTest::run_func()
1218 {
1219     cvSmooth( inplace ? test_array[OUTPUT][0] : test_array[INPUT][0],
1220               test_array[OUTPUT][0], CV_GAUSSIAN, param1, param2, sigma );
1221 }
1222
1223
1224 // !!! Copied from cvSmooth, if the code is changed in cvSmooth,
1225 // make sure to update this one too.
1226 #define SMALL_GAUSSIAN_SIZE 7
1227 static void
1228 icvCalcGaussianKernel( int n, double sigma, float* kernel )
1229 {
1230     static const float small_gaussian_tab[][SMALL_GAUSSIAN_SIZE] = 
1231     {
1232         {1.f},
1233         {0.25f, 0.5f, 0.25f},
1234         {0.0625f, 0.25f, 0.375f, 0.25f, 0.0625f},
1235         {0.03125, 0.109375, 0.21875, 0.28125, 0.21875, 0.109375, 0.03125}
1236     };
1237
1238     if( n <= SMALL_GAUSSIAN_SIZE && sigma <= 0 )
1239     {
1240         assert( n%2 == 1 );
1241         memcpy( kernel, small_gaussian_tab[n>>1], n*sizeof(kernel[0]));
1242     }
1243     else
1244     {
1245         double sigmaX = sigma > 0 ? sigma : (n/2 - 1)*0.3 + 0.8;
1246         double scale2X = -0.5/(sigmaX*sigmaX);
1247         double sum = 1.;
1248         int i;
1249         sum = kernel[n/2] = 1.f;
1250     
1251         for( i = 1; i <= n/2; i++ )
1252         {
1253             kernel[n/2+i] = kernel[n/2-i] = (float)exp(scale2X*i*i);
1254             sum += kernel[n/2+i]*2;
1255         }
1256
1257         sum = 1./sum;
1258         for( i = 0; i <= n/2; i++ )
1259             kernel[n/2+i] = kernel[n/2-i] = (float)(kernel[n/2+i]*sum);
1260     }
1261 }
1262
1263
1264 static void cvTsCalcGaussianKernel2D( double sigma, CvMat* kernel )
1265 {
1266     int i, j;
1267     float* kx = (float*)alloca( kernel->cols*sizeof(kx[0]) );
1268     float* ky = (float*)alloca( kernel->rows*sizeof(ky[0]) );
1269
1270     icvCalcGaussianKernel( kernel->cols, sigma, kx );
1271     icvCalcGaussianKernel( kernel->rows, sigma, ky );
1272
1273     for( i = 0; i < kernel->rows; i++ )
1274     {
1275         float* kdata = (float*)(kernel->data.ptr + i*kernel->step);
1276         for( j = 0; j < kernel->cols; j++ )
1277             kdata[j] = kx[j]*ky[i];
1278     }
1279 }
1280
1281
1282 void CV_GaussianBlurTest::prepare_to_validation( int test_case_idx )
1283 {
1284     CvMat* kernel = &test_mat[INPUT][1];
1285     CV_SmoothBaseTest::prepare_to_validation( test_case_idx );
1286     cvTsCalcGaussianKernel2D( sigma, &test_mat[INPUT][1] );
1287     cvTsConvolve2D( &test_mat[TEMP][0], &test_mat[REF_OUTPUT][0], kernel, anchor );
1288 }
1289
1290
1291 CV_GaussianBlurTest gaussianblur_test;
1292
1293
1294 /////////////// median ///////////////
1295
1296 static const int smooth_median_depths[] = { CV_8U, -1 };
1297
1298 class CV_MedianBlurTest : public CV_SmoothBaseTest
1299 {
1300 public:
1301     CV_MedianBlurTest();
1302
1303 protected:
1304     void prepare_to_validation( int test_case_idx );
1305     double get_success_error_level( int test_case_idx, int i, int j );
1306     void run_func();
1307     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1308 };
1309
1310
1311 CV_MedianBlurTest::CV_MedianBlurTest() : CV_SmoothBaseTest( "filter-median", "cvSmooth" )
1312 {
1313     test_array[TEMP].push(NULL);
1314     smooth_type = "Median";
1315     depth_list = smooth_median_depths;
1316 }
1317
1318
1319 void CV_MedianBlurTest::get_test_array_types_and_sizes( int test_case_idx,
1320                                                 CvSize** sizes, int** types )
1321 {
1322     CV_SmoothBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1323     int depth = CV_8U;
1324     int cn = CV_MAT_CN(types[INPUT][0]);
1325     types[INPUT][0] = types[TEMP][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth,cn);
1326     types[INPUT][1] = types[TEMP][0] = types[TEMP][1] = CV_MAKETYPE(depth,1);
1327     
1328     aperture_size.height = aperture_size.width;
1329     anchor.x = anchor.y = aperture_size.width / 2;
1330     sizes[INPUT][1] = cvSize(aperture_size.width,aperture_size.height);
1331
1332     sizes[INPUT][0].width = MAX( sizes[INPUT][0].width, aperture_size.width );
1333     sizes[INPUT][0].height = MAX( sizes[INPUT][0].height, aperture_size.width );
1334     sizes[OUTPUT][0] = sizes[INPUT][0];
1335     sizes[REF_OUTPUT][0] = sizes[INPUT][0];
1336
1337     sizes[TEMP][0].width = sizes[INPUT][0].width + aperture_size.width - 1;
1338     sizes[TEMP][0].height = sizes[INPUT][0].height + aperture_size.height - 1;
1339     
1340     sizes[TEMP][1] = cn > 1 ? sizes[INPUT][0] : cvSize(0,0);
1341     inplace = false;
1342 }
1343
1344
1345 double CV_MedianBlurTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1346 {
1347     return 0;
1348 }
1349
1350
1351 void CV_MedianBlurTest::run_func()
1352 {
1353     cvSmooth( test_array[INPUT][0], test_array[OUTPUT][0],
1354               CV_MEDIAN, aperture_size.width );
1355 }
1356
1357
1358 struct median_pair
1359 {
1360     int col;
1361     int val;
1362     median_pair() {};
1363     median_pair( int _col, int _val ) : col(_col), val(_val) {};
1364 };
1365
1366
1367 static void cvTsMedianFilter( const CvMat* src, CvMat* dst, int m )
1368 {
1369     int i, j, k, l, m2 = m*m, n;
1370     int* col_buf = (int*)cvAlloc( (m+1)*sizeof(col_buf[0]));
1371     median_pair* buf0 = (median_pair*)cvAlloc( (m*m+1)*sizeof(buf0[0]));
1372     median_pair* buf1 = (median_pair*)cvAlloc( (m*m+1)*sizeof(buf1[0]));
1373     median_pair* tbuf;
1374     int step = src->step/CV_ELEM_SIZE(src->type);
1375
1376     assert( src->rows == dst->rows + m - 1 && src->cols == dst->cols + m - 1 &&
1377             CV_ARE_TYPES_EQ(src,dst) && CV_MAT_TYPE(src->type) == CV_8UC1 );
1378
1379     for( i = 0; i < dst->rows; i++ )
1380     {
1381         uchar* dst1 = (uchar*)(dst->data.ptr + dst->step*i);
1382         for( k = 0; k < m; k++ )
1383         {
1384             const uchar* src1 = (const uchar*)(src->data.ptr + (i+k)*src->step);
1385             for( j = 0; j < m-1; j++ )
1386                 *buf0++ = median_pair(j, src1[j]);
1387         }
1388
1389         n = m2 - m;
1390         buf0 -= n;
1391         for( k = n-1; k > 0; k-- )
1392         {
1393             int f = 0;
1394             for( j = 0; j < k; j++ )
1395             {
1396                 if( buf0[j].val > buf0[j+1].val )
1397                 {
1398                     median_pair t;
1399                     CV_SWAP( buf0[j], buf0[j+1], t );
1400                     f = 1;
1401                 }
1402             }
1403             if( !f )
1404                 break;
1405         }
1406
1407         for( j = 0; j < dst->cols; j++ )
1408         {
1409             int ins_col = j + m - 1;
1410             int del_col = j - 1;
1411             const uchar* src1 = (const uchar*)(src->data.ptr + src->step*i) + ins_col;
1412             for( k = 0; k < m; k++, src1 += step )
1413             {
1414                 col_buf[k] = src1[0];
1415                 for( l = k-1; l >= 0; l-- )
1416                 {
1417                     int t;
1418                     if( col_buf[l] < col_buf[l+1] )
1419                         break;
1420                     CV_SWAP( col_buf[l], col_buf[l+1], t );
1421                 }
1422             }
1423
1424             col_buf[m] = INT_MAX;
1425
1426             for( k = 0, l = 0; k < n; )
1427             {
1428                 if( buf0[k].col == del_col )
1429                     k++;
1430                 else if( buf0[k].val < col_buf[l] )
1431                     *buf1++ = buf0[k++];
1432                 else
1433                 {
1434                     assert( col_buf[l] < INT_MAX );
1435                     *buf1++ = median_pair(ins_col,col_buf[l++]);
1436                 }
1437             }
1438
1439             for( ; l < m; l++ )
1440                 *buf1++ = median_pair(ins_col,col_buf[l]);
1441
1442             if( del_col < 0 )
1443                 n += m;
1444             buf1 -= n;
1445             assert( n == m2 );
1446             dst1[j] = (uchar)buf1[n/2].val;
1447             CV_SWAP( buf0, buf1, tbuf );
1448         }
1449     }
1450
1451     cvFree(&col_buf);
1452     cvFree(&buf0);
1453     cvFree(&buf1);
1454 }
1455
1456
1457 void CV_MedianBlurTest::prepare_to_validation( int /*test_case_idx*/ )
1458 {
1459     // CV_SmoothBaseTest::prepare_to_validation( test_case_idx );
1460     CvMat* src0 = &test_mat[INPUT][0];
1461     CvMat* dst0 = &test_mat[REF_OUTPUT][0];
1462     int i, cn = CV_MAT_CN(src0->type);
1463     CvMat* src = &test_mat[TEMP][0], *dst = dst0;
1464     if( cn > 1 )
1465         dst = &test_mat[TEMP][1];
1466
1467     for( i = 0; i < cn; i++ )
1468     {
1469         CvMat* ptr = src0;
1470         if( cn > 1 )
1471         {
1472             cvTsExtract( src0, dst, i );
1473             ptr = dst;
1474         }
1475         cvTsPrepareToFilter( ptr, src, anchor, CV_TS_BORDER_REPLICATE );
1476         cvTsMedianFilter( src, dst, aperture_size.width );
1477         if( cn > 1 )
1478             cvTsInsert( dst, dst0, i );
1479     }
1480 }
1481
1482
1483 CV_MedianBlurTest medianblur_test;
1484
1485
1486 /////////////// pyramid tests ///////////////
1487
1488 static const char* pyramid_param_names[] = { "size", "channels", "depth", 0 };
1489 static int pyramid_channels[] = { 1, 3, -1 };
1490
1491 class CV_PyramidBaseTest : public CV_FilterBaseTest
1492 {
1493 public:
1494     CV_PyramidBaseTest( const char* test_name, const char* test_funcs, bool downsample );
1495
1496 protected:
1497     int prepare_test_case( int test_case_idx );
1498     double get_success_error_level( int test_case_idx, int i, int j );
1499     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1500     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
1501                                                 CvSize** whole_sizes, bool *are_images );
1502     bool downsample;
1503 };
1504
1505
1506 CV_PyramidBaseTest::CV_PyramidBaseTest( const char* test_name, const char* test_funcs, bool _downsample )
1507     : CV_FilterBaseTest( test_name, test_funcs, true ), downsample(_downsample)
1508 {
1509     test_array[TEMP].push(NULL);
1510     depth_list = smooth_depths;
1511     cn_list = pyramid_channels;
1512     default_timing_param_names = 0;
1513     if( strcmp( test_funcs, "" ) != 0 )
1514     {
1515         default_timing_param_names = pyramid_param_names;
1516         cn_list = 0;
1517         depth_list = 0;
1518     }
1519 }
1520
1521
1522 double CV_PyramidBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1523 {
1524     int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
1525     return depth <= CV_8S ? 1 : 1e-5;
1526 }
1527
1528
1529 void CV_PyramidBaseTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1530 {
1531     CvRNG* rng = ts->get_rng();
1532     CvSize sz;
1533     CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1534
1535     int depth = cvTsRandInt(rng) % 2 ? CV_32F : CV_8U;
1536     int cn = cvTsRandInt(rng) & 1 ? 3 : 1;
1537
1538     aperture_size = cvSize(5,5);
1539     anchor = cvPoint(aperture_size.width/2, aperture_size.height/2);
1540
1541     types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] =
1542         types[TEMP][0] = types[TEMP][1] = CV_MAKETYPE(depth, cn);
1543
1544     sz.width = MAX( sizes[INPUT][0].width/2, 1 );
1545     sz.height = MAX( sizes[INPUT][0].height/2, 1 );
1546
1547     if( downsample )
1548     {
1549         sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sz;
1550         sz.width *= 2;
1551         sz.height *= 2;
1552         sizes[INPUT][0] = sizes[TEMP][1] = sz;
1553     }
1554     else
1555     {
1556         sizes[INPUT][0] = sz;
1557         sz.width *= 2;
1558         sz.height *= 2;
1559         sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sz;
1560         sizes[TEMP][1] = cvSize(0,0);
1561     }
1562     
1563     sizes[INPUT][1] = aperture_size;
1564     sizes[TEMP][0].width = sz.width + aperture_size.width - 1;
1565     sizes[TEMP][0].height = sz.height + aperture_size.height - 1;
1566     inplace = false;
1567 }
1568
1569
1570 void CV_PyramidBaseTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1571                 CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
1572 {
1573     CV_FilterBaseTest::get_timing_test_array_types_and_sizes( test_case_idx,
1574                                     sizes, types, whole_sizes, are_images );
1575     CvSize sz = sizes[INPUT][0];
1576     sz.width /= 2;
1577     sz.height /= 2;
1578     if( downsample )
1579         sizes[OUTPUT][0] = sz;
1580     else
1581         sizes[INPUT][0] = sz;
1582     aperture_size.width = aperture_size.height = 5;
1583     anchor.x = anchor.y = aperture_size.width / 2;
1584     sizes[INPUT][1] = aperture_size;
1585     types[INPUT][1] = CV_32FC1;
1586 }
1587
1588
1589 int CV_PyramidBaseTest::prepare_test_case( int test_case_idx )
1590 {
1591     static const float kdata[] = { 1.f, 4.f, 6.f, 4.f, 1.f };
1592     int i, j;
1593     double scale = 1./256;
1594     CvMat* kernel;
1595     int code = CV_FilterBaseTest::prepare_test_case( test_case_idx );
1596     
1597     if( code <= 0 )
1598         return code;
1599
1600     if( !downsample )
1601         scale *= 4;
1602
1603     kernel = &test_mat[INPUT][1];
1604
1605     for( i = 0; i < aperture_size.height; i++ )
1606     {
1607         float* krow = (float*)(kernel->data.ptr + i*kernel->step);
1608         for( j = 0; j < aperture_size.width; j++ )
1609             krow[j] = (float)(scale*kdata[i]*kdata[j]);
1610     }
1611     return code;
1612 }
1613
1614
1615 CV_PyramidBaseTest pyr_base( "pyramid", "", false );
1616
1617
1618 /////// pyrdown ////////
1619
1620 static void cvTsDownsample( const CvMat* src, CvMat* dst )
1621 {
1622     int i, j, k;
1623     int elem_size = CV_ELEM_SIZE(src->type);
1624     int ncols = dst->cols*elem_size;
1625     int is_dword = elem_size % sizeof(int) == 0;
1626
1627     if( is_dword )
1628     {
1629         elem_size /= sizeof(int);
1630         ncols /= sizeof(int);
1631     }
1632     
1633     for( i = 0; i < dst->rows; i++ )
1634     {
1635         const uchar* src_row = src->data.ptr + i*2*src->step;
1636         uchar* dst_row = dst->data.ptr + i*dst->step;
1637
1638         if( !is_dword )
1639         {
1640             for( j = 0; j < ncols; j += elem_size )
1641             {
1642                 for( k = 0; k < elem_size; k++ )
1643                     dst_row[j+k] = src_row[j*2+k];
1644             }
1645         }
1646         else
1647         {
1648             for( j = 0; j < ncols; j += elem_size )
1649             {
1650                 for( k = 0; k < elem_size; k++ )
1651                     ((int*)dst_row)[j+k] = ((const int*)src_row)[j*2+k];
1652             }
1653         }
1654     }
1655 }
1656
1657
1658 class CV_PyramidDownTest : public CV_PyramidBaseTest
1659 {
1660 public:
1661     CV_PyramidDownTest();
1662
1663 protected:
1664     void run_func();
1665     void prepare_to_validation( int );
1666 };
1667
1668
1669 CV_PyramidDownTest::CV_PyramidDownTest()
1670     : CV_PyramidBaseTest( "pyramid-down", "cvPyrDown", true )
1671 {
1672 }
1673
1674
1675 void CV_PyramidDownTest::run_func()
1676 {
1677     cvPyrDown( test_array[INPUT][0], test_array[OUTPUT][0], CV_GAUSSIAN_5x5 );
1678 }
1679
1680
1681 void CV_PyramidDownTest::prepare_to_validation( int /*test_case_idx*/ )
1682 {
1683     cvTsPrepareToFilter( &test_mat[INPUT][0], &test_mat[TEMP][0],
1684                          anchor, CV_TS_BORDER_REFLECT );
1685     cvTsConvolve2D( &test_mat[TEMP][0], &test_mat[TEMP][1],
1686                     &test_mat[INPUT][1], anchor );
1687     cvTsDownsample( &test_mat[TEMP][1], &test_mat[REF_OUTPUT][0] );
1688 }
1689
1690
1691 CV_PyramidDownTest pyrdown;
1692
1693
1694 /////// pyrup ////////
1695
1696 static void cvTsUpsample( const CvMat* src, CvMat* dst )
1697 {
1698     int i, j, k;
1699     int elem_size = CV_ELEM_SIZE(src->type);
1700     int ncols = src->cols*elem_size;
1701     int is_dword = elem_size % sizeof(int) == 0;
1702
1703     if( is_dword )
1704     {
1705         elem_size /= sizeof(int);
1706         ncols /= sizeof(int);
1707     }
1708     
1709     for( i = 0; i < src->rows; i++ )
1710     {
1711         const uchar* src_row = src->data.ptr + i*src->step;
1712         uchar* dst_row = dst->data.ptr + i*2*dst->step;
1713
1714         if( !is_dword )
1715         {
1716             memset( dst_row + dst->step, 0, dst->cols*elem_size );
1717             for( j = 0; j < ncols; j += elem_size )
1718             {
1719                 for( k = 0; k < elem_size; k++ )
1720                 {
1721                     dst_row[j*2+k] = src_row[j+k];
1722                     dst_row[j*2+k+elem_size] = 0;
1723                 }
1724             }
1725         }
1726         else
1727         {
1728             memset( dst_row + dst->step, 0, dst->cols*elem_size*sizeof(int) );
1729             for( j = 0; j < ncols; j += elem_size )
1730             {
1731                 for( k = 0; k < elem_size; k++ )
1732                 {
1733                     ((int*)dst_row)[j*2+k] = ((const int*)src_row)[j+k];
1734                     ((int*)dst_row)[j*2+k+elem_size] = 0;
1735                 }
1736             }
1737         }
1738     }
1739 }
1740
1741
1742 class CV_PyramidUpTest : public CV_PyramidBaseTest
1743 {
1744 public:
1745     CV_PyramidUpTest();
1746
1747 protected:
1748     void run_func();
1749     void prepare_to_validation( int );
1750 };
1751
1752
1753 CV_PyramidUpTest::CV_PyramidUpTest()
1754     : CV_PyramidBaseTest( "pyramid-up", "cvPyrUp", false )
1755 {
1756 }
1757
1758
1759 void CV_PyramidUpTest::run_func()
1760 {
1761     cvPyrUp( test_array[INPUT][0], test_array[OUTPUT][0], CV_GAUSSIAN_5x5 );
1762 }
1763
1764
1765 void CV_PyramidUpTest::prepare_to_validation( int /*test_case_idx*/ )
1766 {
1767     CvMat src2, dst2;
1768     CvSize sz;
1769     cvTsUpsample( &test_mat[INPUT][0], &test_mat[REF_OUTPUT][0] );
1770     cvTsPrepareToFilter( &test_mat[REF_OUTPUT][0], &test_mat[TEMP][0],
1771                          anchor, CV_TS_BORDER_REFLECT );
1772     cvTsConvolve2D( &test_mat[TEMP][0], &test_mat[REF_OUTPUT][0],
1773                     &test_mat[INPUT][1], anchor );
1774     // currently IPP and OpenCV process right/bottom part of the image differently, so
1775     // we just patch the last two rows/columns to have consistent test results.
1776     sz = cvGetMatSize( &test_mat[REF_OUTPUT][0]);
1777     cvTsSelect( &test_mat[REF_OUTPUT][0], &src2, cvRect(sz.width-2,0,2,sz.height) );
1778     cvTsSelect( &test_mat[OUTPUT][0], &dst2, cvRect(sz.width-2,0,2,sz.height) );
1779     cvTsCopy( &src2, &dst2, 0 );
1780     cvTsSelect( &test_mat[REF_OUTPUT][0], &src2, cvRect(0,sz.height-2,sz.width,2) );
1781     cvTsSelect( &test_mat[OUTPUT][0], &dst2, cvRect(0,sz.height-2,sz.width,2) );
1782     cvTsCopy( &src2, &dst2, 0 );
1783 }
1784
1785
1786 CV_PyramidUpTest pyrup;
1787
1788
1789
1790 //////////////////////// feature selection //////////////////////////
1791
1792 static const char* featuresel_param_names[] = { "block_size", "aperture", "size", "depth", 0 };
1793 static const int featuresel_block_size[] = { 3, 5, 11 }; 
1794
1795 class CV_FeatureSelBaseTestImpl : public CvArrTest
1796 {
1797 public:
1798     CV_FeatureSelBaseTestImpl( const char* test_name, const char* test_funcs, int width_factor );
1799
1800 protected:
1801     int read_params( CvFileStorage* fs );
1802     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1803     void get_minmax_bounds( int i, int j, int type, CvScalar* low, CvScalar* high );
1804     double get_success_error_level( int test_case_idx, int i, int j );
1805     int write_default_params(CvFileStorage* fs);
1806     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
1807                                                 CvSize** whole_sizes, bool *are_images );
1808     void print_timing_params( int test_case_idx, char* ptr, int params_left );
1809     int aperture_size, block_size;
1810     int max_aperture_size;
1811     int max_block_size;
1812     int width_factor;
1813 };
1814
1815
1816 CV_FeatureSelBaseTestImpl::CV_FeatureSelBaseTestImpl( const char* test_name, const char* test_funcs, int _width_factor )
1817     : CvArrTest( test_name, test_funcs, "" )
1818 {
1819     max_aperture_size = 7;
1820     max_block_size = 21;
1821     // 1 input, 1 output, temp arrays are allocated in the reference functions
1822     test_array[INPUT].push(NULL);
1823     test_array[OUTPUT].push(NULL);
1824     test_array[REF_OUTPUT].push(NULL);
1825     element_wise_relative_error = false;
1826     width_factor = _width_factor;
1827
1828     size_list = filter_sizes;
1829     whole_size_list = filter_whole_sizes;
1830     depth_list = morph_depths;
1831     cn_list = 0;
1832 }
1833
1834
1835 int CV_FeatureSelBaseTestImpl::read_params( CvFileStorage* fs )
1836 {
1837     int code = CvTest::read_params( fs );
1838     if( code < 0 )
1839         return code;
1840
1841     if( ts->get_testing_mode() == CvTS::CORRECTNESS_CHECK_MODE )
1842     {
1843         max_aperture_size = cvReadInt( find_param( fs, "max_aperture_size" ), max_aperture_size );
1844         max_aperture_size = cvTsClipInt( max_aperture_size, 1, 9 );
1845         max_block_size = cvReadInt( find_param( fs, "max_block_size" ), max_block_size );
1846         max_block_size = cvTsClipInt( max_aperture_size, 1, 100 );
1847     }
1848
1849     return code;
1850 }
1851
1852
1853 int CV_FeatureSelBaseTestImpl::write_default_params( CvFileStorage* fs )
1854 {
1855     int code = CvArrTest::write_default_params( fs );
1856     if( code < 0 )
1857         return code;
1858     
1859     if( ts->get_testing_mode() == CvTS::CORRECTNESS_CHECK_MODE )
1860     {
1861         write_param( fs, "max_aperture_size", max_aperture_size );
1862         write_param( fs, "max_block_size", max_block_size );
1863     }
1864     else if( ts->get_testing_mode() == CvTS::TIMING_MODE && strcmp( tested_functions, "" ) == 0 )
1865     {
1866         start_write_param( fs );
1867         write_int_list( fs, "aperture", sobel_aperture, CV_DIM(sobel_aperture) );
1868         write_int_list( fs, "block_size", featuresel_block_size, CV_DIM(featuresel_block_size) );
1869     }
1870
1871     return code;
1872 }
1873
1874
1875 double CV_FeatureSelBaseTestImpl::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1876 {
1877     int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
1878     return depth <= CV_8S ? 3e-2 : depth == CV_32F ? 1e-3 : 1e-10;
1879 }
1880
1881
1882 void CV_FeatureSelBaseTestImpl::get_minmax_bounds( int i, int j, int type, CvScalar* low, CvScalar* high )
1883 {
1884     CvArrTest::get_minmax_bounds( i, j, type, low, high );
1885     if( i == INPUT && CV_MAT_DEPTH(type) == CV_32F )
1886     {
1887         *low = cvScalarAll(-10.);
1888         *high = cvScalarAll(10.);
1889     }
1890 }
1891
1892
1893 void CV_FeatureSelBaseTestImpl::get_test_array_types_and_sizes( int test_case_idx,
1894                                                 CvSize** sizes, int** types )
1895 {
1896     CvRNG* rng = ts->get_rng();
1897     CvArrTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1898     int depth = cvTsRandInt(rng) % 2, asz;
1899
1900     depth = depth == 0 ? CV_8U : CV_32F;
1901     types[INPUT][0] = depth;
1902     types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_32FC1;
1903
1904     aperture_size = (cvTsRandInt(rng) % (max_aperture_size+2) - 1) | 1;
1905     if( aperture_size == 1 )
1906         aperture_size = 3;
1907     if( depth == CV_8U )
1908         aperture_size = MIN( aperture_size, 5 );
1909     block_size = (cvTsRandInt(rng) % max_block_size + 1) | 1;
1910     if( block_size <= 3 )
1911         block_size = 3;
1912     asz = aperture_size > 0 ? aperture_size : 3;
1913
1914     sizes[INPUT][0].width = MAX( sizes[INPUT][0].width, asz + block_size );
1915     sizes[INPUT][0].height = MAX( sizes[INPUT][0].height, asz + block_size );
1916     sizes[OUTPUT][0].height = sizes[REF_OUTPUT][0].height = sizes[INPUT][0].height;
1917     sizes[OUTPUT][0].width = sizes[REF_OUTPUT][0].width = sizes[INPUT][0].width*width_factor;
1918 }
1919
1920
1921 void CV_FeatureSelBaseTestImpl::get_timing_test_array_types_and_sizes( int test_case_idx,
1922                     CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
1923 {
1924     CvArrTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
1925                                                       whole_sizes, are_images );
1926     aperture_size = cvReadInt( find_timing_param( "aperture" ), 3 );
1927     block_size = cvReadInt( find_timing_param( "block_size" ), 0 );
1928     int asz = aperture_size < 0 ? 3 : aperture_size;
1929
1930     sizes[INPUT][0].width = MAX( sizes[INPUT][0].width, asz + block_size );
1931     sizes[INPUT][0].height = MAX( sizes[INPUT][0].height, asz + block_size );
1932     whole_sizes[INPUT][0].width = MAX( whole_sizes[INPUT][0].width, asz + block_size );
1933     whole_sizes[INPUT][0].height = MAX( whole_sizes[INPUT][0].height, asz + block_size );
1934     sizes[OUTPUT][0].height = sizes[INPUT][0].height;
1935     sizes[OUTPUT][0].width = sizes[INPUT][0].width*width_factor;
1936     whole_sizes[OUTPUT][0].height = whole_sizes[INPUT][0].height;
1937     whole_sizes[OUTPUT][0].width = MAX(whole_sizes[OUTPUT][0].width,sizes[OUTPUT][0].width);
1938     types[OUTPUT][0] = CV_32FC1;
1939 }
1940
1941
1942 void CV_FeatureSelBaseTestImpl::print_timing_params( int test_case_idx, char* ptr, int params_left )
1943 {
1944     int asz = aperture_size < 0 ? 3 : aperture_size;
1945     sprintf( ptr, "%s(%dx%d),", aperture_size < 0 ? "Scharr" : "Sobel", asz, asz );
1946     ptr += strlen(ptr);
1947     params_left--;
1948     if( block_size > 0 )
1949     {
1950         sprintf( ptr, "block_size=%dx%d,", block_size, block_size );
1951         ptr += strlen(ptr);
1952         params_left--;
1953     }
1954
1955     CvArrTest::print_timing_params( test_case_idx, ptr, params_left );
1956 }
1957
1958
1959 CV_FeatureSelBaseTestImpl featuresel_base( "features", "", 0 );
1960
1961
1962
1963 class CV_FeatureSelBaseTest : public CV_FeatureSelBaseTestImpl
1964 {
1965 public:
1966     CV_FeatureSelBaseTest( const char* test_name, const char* test_funcs, int width_factor );
1967 };
1968
1969
1970 CV_FeatureSelBaseTest::CV_FeatureSelBaseTest( const char* test_name, const char* test_funcs, int _width_factor )
1971     : CV_FeatureSelBaseTestImpl( test_name, test_funcs, _width_factor )
1972 {
1973     depth_list = 0;
1974     size_list = whole_size_list = 0;
1975     default_timing_param_names = featuresel_param_names;
1976 }
1977
1978
1979 static void
1980 cvTsCornerEigenValsVecs( const CvMat* _src, CvMat* eigenv, CvMat* ocv_eigenv,
1981                          int block_size, int _aperture_size, int mode )
1982 {
1983     CvMat *dx2 = 0, *dxdy = 0, *dy2 = 0;
1984     CvMat* kernel = 0, *src2 = 0;
1985     const CvMat* src = _src;
1986     
1987     int type, ftype;
1988     double denom;
1989
1990     CV_FUNCNAME( "cvTsCornerEigenValsVecs" );
1991
1992     __BEGIN__;
1993
1994     int i, j;
1995     int aperture_size = _aperture_size < 0 ? 3 : _aperture_size;
1996     CvPoint anchor = { aperture_size/2, aperture_size/2 };
1997
1998     assert( (CV_MAT_TYPE(src->type) == CV_8UC1 ||
1999             CV_MAT_TYPE(src->type) == CV_32FC1) &&
2000             CV_MAT_TYPE(eigenv->type) == CV_32FC1 );
2001
2002     assert( src->rows == eigenv->rows &&
2003             (mode > 0 && src->cols == eigenv->cols ||
2004             mode == 0 && src->cols*6 == eigenv->cols) );
2005
2006     type = CV_MAT_TYPE(src->type);
2007     ftype = CV_32FC1;
2008     
2009     CV_CALL( dx2 = cvCreateMat( src->rows, src->cols, ftype ));
2010     CV_CALL( dy2 = cvCreateMat( src->rows, src->cols, ftype ));
2011     CV_CALL( dxdy = cvCreateMat( src->rows, src->cols, ftype ));
2012
2013     CV_CALL( kernel = cvCreateMat( aperture_size, aperture_size, CV_32FC1 ));
2014     CV_CALL( src2 = cvCreateMat( src->rows + aperture_size - 1,
2015                                  src->cols + aperture_size - 1, ftype ));
2016
2017     if( type != ftype )
2018     {
2019         cvTsAdd( src, cvScalarAll(1./255), 0, cvScalarAll(0.), cvScalarAll(0.), dx2, 0 );
2020         src = dx2;
2021     }
2022     
2023     cvTsPrepareToFilter( src, src2, anchor, CV_TS_BORDER_REPLICATE );
2024     cvTsCalcSobelKernel2D( 1, 0, _aperture_size, 0, kernel );
2025     cvTsConvolve2D( src2, dx2, kernel, anchor );
2026     cvTsCalcSobelKernel2D( 0, 1, _aperture_size, 0, kernel );
2027     cvTsConvolve2D( src2, dy2, kernel, anchor );
2028     cvReleaseMat( &src2 );
2029     cvReleaseMat( &kernel );
2030
2031     denom = (1 << (aperture_size-1))*block_size;
2032     denom = denom * denom;
2033     if( _aperture_size < 0 )
2034         denom *= 4;
2035     denom = 1./denom;
2036
2037     for( i = 0; i < src->rows; i++ )
2038     {
2039         float* dxdyp = (float*)(dxdy->data.ptr + i*dxdy->step);
2040         float* dx2p = (float*)(dx2->data.ptr + i*dx2->step);
2041         float* dy2p = (float*)(dy2->data.ptr + i*dy2->step);
2042
2043         for( j = 0; j < src->cols; j++ )
2044         {
2045             double xval = dx2p[j], yval = dy2p[j];
2046             dxdyp[j] = (float)(xval*yval*denom);
2047             dx2p[j] = (float)(xval*xval*denom);
2048             dy2p[j] = (float)(yval*yval*denom);
2049         }
2050     }
2051
2052     CV_CALL( src2 = cvCreateMat( src->rows + block_size - 1, src->cols + block_size - 1, CV_32F ));
2053     CV_CALL( kernel = cvCreateMat( block_size, block_size, CV_32F ));
2054     cvTsAdd( 0, cvScalarAll(0), 0, cvScalarAll(0), cvScalarAll(1./*(block_size*block_size)*/), kernel, 0 );
2055     anchor = cvPoint( block_size/2, block_size/2 );
2056     
2057     cvTsPrepareToFilter( dx2, src2, anchor, CV_TS_BORDER_REPLICATE );
2058     cvTsConvolve2D( src2, dx2, kernel, anchor );
2059     cvTsPrepareToFilter( dy2, src2, anchor, CV_TS_BORDER_REPLICATE );
2060     cvTsConvolve2D( src2, dy2, kernel, anchor );
2061     cvTsPrepareToFilter( dxdy, src2, anchor, CV_TS_BORDER_REPLICATE );
2062     cvTsConvolve2D( src2, dxdy, kernel, anchor );
2063
2064     if( mode == 0 )
2065     {
2066         for( i = 0; i < src->rows; i++ )
2067         {
2068             float* eigenvp = (float*)(eigenv->data.ptr + i*eigenv->step);
2069             float* ocv_eigenvp = (float*)(ocv_eigenv->data.ptr + i*ocv_eigenv->step);
2070             const float* dxdyp = (float*)(dxdy->data.ptr + i*dxdy->step);
2071             const float* dx2p = (float*)(dx2->data.ptr + i*dx2->step);
2072             const float* dy2p = (float*)(dy2->data.ptr + i*dy2->step);
2073
2074             for( j = 0; j < src->cols; j++ )
2075             {
2076                 double a = dx2p[j], b = dxdyp[j], c = dy2p[j];
2077                 double d = sqrt((a-c)*(a-c) + 4*b*b);
2078                 double l1 = 0.5*(a + c + d);
2079                 double l2 = 0.5*(a + c - d);
2080                 double x1, y1, x2, y2, s;
2081
2082                 if( fabs(a - l1) + fabs(b) >= 1e-3 )
2083                     x1 = b, y1 = l1 - a;
2084                 else
2085                     x1 = l1 - c, y1 = b;
2086                 s = 1./(sqrt(x1*x1+y1*y1)+DBL_EPSILON);
2087                 x1 *= s; y1 *= s;
2088
2089                 if( fabs(a - l2) + fabs(b) >= 1e-3 )
2090                     x2 = b, y2 = l2 - a;
2091                 else
2092                     x2 = l2 - c, y2 = b;
2093                 s = 1./(sqrt(x2*x2+y2*y2)+DBL_EPSILON);
2094                 x2 *= s; y2 *= s;
2095
2096                 /* the orientation of eigen vectors might be inversed relative to OpenCV function,
2097                    which is normal */
2098                 if( fabs(x1) >= fabs(y1) && ocv_eigenvp[j*6+2]*x1 < 0 ||
2099                     fabs(x1) < fabs(y1) && ocv_eigenvp[j*6+3]*y1 < 0 )
2100                     x1 = -x1, y1 = -y1;
2101
2102                 if( fabs(x2) >= fabs(y2) && ocv_eigenvp[j*6+4]*x2 < 0 ||
2103                     fabs(x2) < fabs(y2) && ocv_eigenvp[j*6+5]*y2 < 0 )
2104                     x2 = -x2, y2 = -y2;
2105
2106                 eigenvp[j*6] = (float)l1;
2107                 eigenvp[j*6+1] = (float)l2;
2108                 eigenvp[j*6+2] = (float)x1;
2109                 eigenvp[j*6+3] = (float)y1;
2110                 eigenvp[j*6+4] = (float)x2;
2111                 eigenvp[j*6+5] = (float)y2;
2112             }
2113         }
2114     }
2115     else if( mode == 1 )
2116     {
2117         for( i = 0; i < src->rows; i++ )
2118         {
2119             float* eigenvp = (float*)(eigenv->data.ptr + i*eigenv->step);
2120             const float* dxdyp = (float*)(dxdy->data.ptr + i*dxdy->step);
2121             const float* dx2p = (float*)(dx2->data.ptr + i*dx2->step);
2122             const float* dy2p = (float*)(dy2->data.ptr + i*dy2->step);
2123
2124             for( j = 0; j < src->cols; j++ )
2125             {
2126                 double a = dx2p[j], b = dxdyp[j], c = dy2p[j];
2127                 double d = sqrt((a-c)*(a-c) + 4*b*b);
2128                 eigenvp[j] = (float)(0.5*(a + c - d));
2129             }
2130         }
2131     }
2132
2133     __END__;
2134
2135     cvReleaseMat( &dx2 );
2136     cvReleaseMat( &dy2 );
2137     cvReleaseMat( &dxdy );
2138     cvReleaseMat( &src2 );
2139     cvReleaseMat( &kernel );
2140 }
2141
2142
2143 // min eigenval
2144 class CV_MinEigenValTest : public CV_FeatureSelBaseTest
2145 {
2146 public:
2147     CV_MinEigenValTest();
2148
2149 protected:
2150     void run_func();
2151     void prepare_to_validation( int );
2152 };
2153
2154
2155 CV_MinEigenValTest::CV_MinEigenValTest()
2156     : CV_FeatureSelBaseTest( "features-mineval", "cvCornerMinEigenVal", 1 )
2157 {
2158 }
2159
2160
2161 void CV_MinEigenValTest::run_func()
2162 {
2163     cvCornerMinEigenVal( test_array[INPUT][0], test_array[OUTPUT][0],
2164                          block_size, aperture_size );
2165 }
2166
2167
2168 void CV_MinEigenValTest::prepare_to_validation( int /*test_case_idx*/ )
2169 {
2170     cvTsCornerEigenValsVecs( &test_mat[INPUT][0], &test_mat[REF_OUTPUT][0],
2171                     &test_mat[OUTPUT][0], block_size, aperture_size, 1 );
2172 }
2173
2174
2175 CV_MinEigenValTest features_mineval;
2176
2177
2178 // eigenval's & vec's
2179 class CV_EigenValVecTest : public CV_FeatureSelBaseTest
2180 {
2181 public:
2182     CV_EigenValVecTest();
2183
2184 protected:
2185     void run_func();
2186     void prepare_to_validation( int );
2187 };
2188
2189
2190 CV_EigenValVecTest::CV_EigenValVecTest()
2191     : CV_FeatureSelBaseTest( "features-evalvec", "cvCornerEigenValsAndVecs", 6 )
2192 {
2193 }
2194
2195
2196 void CV_EigenValVecTest::run_func()
2197 {
2198     cvCornerEigenValsAndVecs( test_array[INPUT][0], test_array[OUTPUT][0],
2199                               block_size, aperture_size );
2200 }
2201
2202
2203 void CV_EigenValVecTest::prepare_to_validation( int /*test_case_idx*/ )
2204 {
2205     cvTsCornerEigenValsVecs( &test_mat[INPUT][0], &test_mat[REF_OUTPUT][0],
2206                     &test_mat[OUTPUT][0], block_size, aperture_size, 0 );
2207 }
2208
2209
2210 CV_EigenValVecTest features_evalvec;
2211
2212
2213
2214 static const char* precorner_param_names[] = { "aperture", "size", "depth", 0 };
2215 static const int precorner_aperture[] = { 3, 5, 7 }; 
2216
2217 // precornerdetect
2218 class CV_PreCornerDetectTest : public CV_FeatureSelBaseTest
2219 {
2220 public:
2221     CV_PreCornerDetectTest();
2222
2223 protected:
2224     void run_func();
2225     void prepare_to_validation( int );
2226     int prepare_test_case( int );
2227     int write_default_params(CvFileStorage* fs);
2228 };
2229
2230
2231 CV_PreCornerDetectTest::CV_PreCornerDetectTest()
2232     : CV_FeatureSelBaseTest( "features-precorner", "cvPreCornerDetect", 1 )
2233 {
2234     default_timing_param_names = precorner_param_names;
2235 }
2236
2237
2238 int CV_PreCornerDetectTest::write_default_params( CvFileStorage* fs )
2239 {
2240     int code = CV_FeatureSelBaseTest::write_default_params( fs );
2241     if( code < 0 )
2242         return code;
2243     
2244     if( ts->get_testing_mode() == CvTS::TIMING_MODE )
2245     {
2246         start_write_param( fs );
2247         write_int_list( fs, "aperture", precorner_aperture, CV_DIM(precorner_aperture) );
2248     }
2249
2250     return code;
2251 }
2252
2253
2254 void CV_PreCornerDetectTest::run_func()
2255 {
2256     cvPreCornerDetect( test_array[INPUT][0], test_array[OUTPUT][0], aperture_size );
2257 }
2258
2259
2260 int CV_PreCornerDetectTest::prepare_test_case( int test_case_idx )
2261 {
2262     int code = CV_FeatureSelBaseTest::prepare_test_case( test_case_idx );
2263     if( aperture_size < 0 )
2264         aperture_size = 3;
2265     return code;
2266 }
2267
2268
2269 void CV_PreCornerDetectTest::prepare_to_validation( int /*test_case_idx*/ )
2270 {
2271     /*cvTsCornerEigenValsVecs( &test_mat[INPUT][0], &test_mat[REF_OUTPUT][0],
2272                              block_size, aperture_size, 0 );*/
2273     const CvMat* src = &test_mat[INPUT][0];
2274     CvMat* dst = &test_mat[REF_OUTPUT][0];
2275
2276     int type = CV_MAT_TYPE(src->type), ftype = CV_32FC1;
2277     CvPoint anchor = { aperture_size/2, aperture_size/2 };
2278     double denom;
2279     int i, j;
2280
2281     CvMat* dx = cvCreateMat( src->rows, src->cols, ftype );
2282     CvMat* dy = cvCreateMat( src->rows, src->cols, ftype );
2283     CvMat* d2x = cvCreateMat( src->rows, src->cols, ftype );
2284     CvMat* d2y = cvCreateMat( src->rows, src->cols, ftype );
2285     CvMat* dxy = cvCreateMat( src->rows, src->cols, ftype );
2286     CvMat* tmp = cvCreateMat( src->rows + aperture_size - 1,
2287                         src->cols + aperture_size - 1, ftype );
2288     CvMat* kernel = cvCreateMat( aperture_size, aperture_size, ftype );
2289
2290     if( type != ftype )
2291     {
2292         cvTsAdd( src, cvScalarAll(1./255), 0, cvScalarAll(0.), cvScalarAll(0.), dx, 0 );
2293         src = dx;
2294     }
2295
2296     cvTsPrepareToFilter( src, tmp, anchor, CV_TS_BORDER_REPLICATE );
2297
2298     cvTsCalcSobelKernel2D( 1, 0, aperture_size, 0, kernel );
2299     cvTsConvolve2D( tmp, dx, kernel, anchor );
2300     cvTsCalcSobelKernel2D( 0, 1, aperture_size, 0, kernel );
2301     cvTsConvolve2D( tmp, dy, kernel, anchor );
2302     cvTsCalcSobelKernel2D( 2, 0, aperture_size, 0, kernel );
2303     cvTsConvolve2D( tmp, d2x, kernel, anchor );
2304     cvTsCalcSobelKernel2D( 0, 2, aperture_size, 0, kernel );
2305     cvTsConvolve2D( tmp, d2y, kernel, anchor );
2306     cvTsCalcSobelKernel2D( 1, 1, aperture_size, 0, kernel );
2307     cvTsConvolve2D( tmp, dxy, kernel, anchor );
2308
2309     denom = 1 << (aperture_size-1);
2310     denom = denom * denom * denom;
2311     denom = 1./denom;
2312
2313     for( i = 0; i < src->rows; i++ )
2314     {
2315         const float* _dx = (const float*)(dx->data.ptr + i*dx->step);
2316         const float* _dy = (const float*)(dy->data.ptr + i*dy->step);
2317         const float* _d2x = (const float*)(d2x->data.ptr + i*d2x->step);
2318         const float* _d2y = (const float*)(d2y->data.ptr + i*d2y->step);
2319         const float* _dxy = (const float*)(dxy->data.ptr + i*dxy->step);
2320         float* corner = (float*)(dst->data.ptr + i*dst->step);
2321
2322         for( j = 0; j < src->cols; j++ )
2323         {
2324             double x = _dx[j];
2325             double y = _dy[j];
2326
2327             corner[j] = (float)(denom*(x*x*_d2y[j] + y*y*_d2x[j] - 2*x*y*_dxy[j]));
2328         }
2329     }
2330
2331     cvReleaseMat( &dx );
2332     cvReleaseMat( &dy );
2333     cvReleaseMat( &d2x );
2334     cvReleaseMat( &d2y );
2335     cvReleaseMat( &dxy );
2336     cvReleaseMat( &tmp );
2337     cvReleaseMat( &kernel );
2338 }
2339
2340
2341 CV_PreCornerDetectTest precorner;
2342
2343
2344 ///////// integral /////////
2345
2346 static const char* integral_param_names[] = { "output", "size", "channels", "sum_depth", "depth", 0 };
2347 static const int integral_sum_depth[] = { CV_32S, CV_64F, -1 };
2348 static const int integral_block_size[] = { 3, 5, 11 };
2349 static const char* integral_output[] = { "sum", "sum+sqsum", "all", 0 };
2350
2351 class CV_IntegralTest : public CvArrTest
2352 {
2353 public:
2354     CV_IntegralTest();
2355
2356 protected:
2357     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
2358     void get_minmax_bounds( int i, int j, int type, CvScalar* low, CvScalar* high );
2359     double get_success_error_level( int test_case_idx, int i, int j );
2360     void run_func();
2361     void prepare_to_validation( int );
2362
2363     int prepare_test_case( int test_case_idx );
2364     int write_default_params(CvFileStorage* fs);
2365     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types,
2366                                                 CvSize** whole_sizes, bool *are_images );
2367     void print_timing_params( int test_case_idx, char* ptr, int params_left );
2368 };
2369
2370
2371 CV_IntegralTest::CV_IntegralTest()
2372     : CvArrTest( "integral", "cvIntegral", "" )
2373 {
2374     test_array[INPUT].push(NULL);
2375     test_array[OUTPUT].push(NULL);
2376     test_array[OUTPUT].push(NULL);
2377     test_array[OUTPUT].push(NULL);
2378     test_array[REF_OUTPUT].push(NULL);
2379     test_array[REF_OUTPUT].push(NULL);
2380     test_array[REF_OUTPUT].push(NULL);
2381     test_array[TEMP].push(NULL);
2382     test_array[TEMP].push(NULL);
2383     test_array[TEMP].push(NULL);
2384     test_array[TEMP].push(NULL);
2385     test_array[TEMP].push(NULL);
2386     element_wise_relative_error = false;
2387
2388     size_list = filter_sizes;
2389     whole_size_list = filter_whole_sizes;
2390     default_timing_param_names = integral_param_names;
2391     depth_list = morph_depths;
2392     cn_list = filter_channels;
2393 }
2394
2395
2396 void CV_IntegralTest::get_minmax_bounds( int i, int j, int type, CvScalar* low, CvScalar* high )
2397 {
2398     CvArrTest::get_minmax_bounds( i, j, type, low, high );
2399     int depth = CV_MAT_DEPTH(type);
2400     if( depth == CV_32F )
2401     {
2402         *low = cvScalarAll(-10.);
2403         *high = cvScalarAll(10.);
2404     }
2405 }
2406
2407
2408 int CV_IntegralTest::write_default_params( CvFileStorage* fs )
2409 {
2410     int code = CvArrTest::write_default_params( fs );
2411     if( code < 0 )
2412         return code;
2413     
2414     if( ts->get_testing_mode() == CvTS::TIMING_MODE )
2415     {
2416         int i;
2417         start_write_param( fs );        
2418         
2419         cvStartWriteStruct( fs, "sum_depth", CV_NODE_SEQ+CV_NODE_FLOW );
2420         for( i = 0; integral_sum_depth[i] >= 0; i++ )
2421             cvWriteString( fs, 0, cvTsGetTypeName(integral_sum_depth[i]) );
2422         cvEndWriteStruct(fs);
2423
2424         write_string_list( fs, "output", integral_output );
2425     }
2426
2427     return code;
2428 }
2429
2430
2431 void CV_IntegralTest::get_test_array_types_and_sizes( int test_case_idx,
2432                                                 CvSize** sizes, int** types )
2433 {
2434     CvRNG* rng = ts->get_rng();
2435     int depth = cvTsRandInt(rng) % 2, sum_depth;
2436     int cn = cvTsRandInt(rng) % 3 + 1;
2437     CvArrTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2438     CvSize sum_size;
2439     
2440     depth = depth == 0 ? CV_8U : CV_32F;
2441     cn += cn == 2;
2442     sum_depth = depth == CV_8U && (cvTsRandInt(rng) & 1) == 1 ? CV_32S : CV_64F;
2443
2444     //sizes[INPUT][0].width = 1;
2445
2446     types[INPUT][0] = CV_MAKETYPE(depth,cn);
2447     types[OUTPUT][0] = types[REF_OUTPUT][0] =
2448         types[OUTPUT][2] = types[REF_OUTPUT][2] = CV_MAKETYPE(sum_depth, cn);
2449     types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_MAKETYPE(CV_64F, cn);
2450
2451     sum_size.width = sizes[INPUT][0].width + 1;
2452     sum_size.height = sizes[INPUT][0].height + 1;
2453
2454     sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sum_size;
2455     sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] =
2456         sizes[OUTPUT][2] = sizes[REF_OUTPUT][2] = cvSize(0,0);
2457
2458     if( cvTsRandInt(rng) % 3 > 0 )
2459     {
2460         sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] = sum_size;
2461         if( cvTsRandInt(rng) % 2 > 0 && cn == 1 )
2462             sizes[REF_OUTPUT][2] = sizes[OUTPUT][2] = sum_size;
2463     }
2464
2465     types[TEMP][0] = CV_MAKETYPE(depth,1);
2466     types[TEMP][1] = CV_MAKETYPE(CV_32F,1);
2467     types[TEMP][2] = types[TEMP][3] = types[TEMP][4] = CV_MAKETYPE(CV_64F,1);
2468
2469     sizes[TEMP][0] = cn > 1 ? sizes[INPUT][0] : cvSize(0,0);
2470     sizes[TEMP][1] = depth == CV_8U ? sum_size : cvSize(0,0);
2471
2472     sizes[TEMP][2] = cn > 1 || sum_depth == CV_32S ? sizes[OUTPUT][0] : cvSize(0,0);
2473     sizes[TEMP][3] = cn > 1 ? sizes[OUTPUT][1] : cvSize(0,0);
2474     sizes[TEMP][4] = cn > 1 || sum_depth == CV_32S ? sizes[OUTPUT][2] : cvSize(0,0);
2475 }
2476
2477
2478 double CV_IntegralTest::get_success_error_level( int /*test_case_idx*/, int i, int j )
2479 {
2480     int depth = CV_MAT_DEPTH(test_mat[i][j].type);
2481     return depth == CV_32S ? 0 : 1e-10;
2482 }
2483
2484
2485 void CV_IntegralTest::get_timing_test_array_types_and_sizes( int test_case_idx,
2486                 CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
2487 {
2488     CvArrTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
2489                                                       whole_sizes, are_images );
2490     const char* output = cvReadString( find_timing_param( "output" ), "sum" );
2491     CvSize sum_size = { sizes[INPUT][0].width + 1, sizes[INPUT][0].height + 1 };
2492     const char* _sum_depth = cvReadString( find_timing_param( "sum_depth" ), "64f" );
2493     int cn = CV_MAT_CN(types[INPUT][0]);
2494     int sum_depth = strcmp( _sum_depth, "32s" ) == 0 ? CV_32S : CV_64F;
2495
2496     sizes[OUTPUT][0] = sizes[OUTPUT][1] = sizes[OUTPUT][2] = cvSize(0,0);
2497     whole_sizes[OUTPUT][0] = whole_sizes[OUTPUT][1] = whole_sizes[OUTPUT][2] = cvSize(0,0);
2498
2499     if( strcmp( output, "sum" ) == 0 )
2500         sizes[OUTPUT][0] = whole_sizes[OUTPUT][0] = sum_size;
2501     else if( strcmp( output, "all" ) == 0 )
2502         sizes[OUTPUT][0] = sizes[OUTPUT][1] = sizes[OUTPUT][2] =
2503             whole_sizes[OUTPUT][0] = whole_sizes[OUTPUT][1] = whole_sizes[OUTPUT][2] = sum_size;
2504     else
2505         sizes[OUTPUT][0] = sizes[OUTPUT][1] =
2506             whole_sizes[OUTPUT][0] = whole_sizes[OUTPUT][1] = sum_size;
2507
2508     sizes[TEMP][0] = sizes[TEMP][1] = sizes[TEMP][2] = sizes[TEMP][3] = sizes[TEMP][4] = cvSize(0,0);
2509
2510     types[OUTPUT][0] = types[OUTPUT][2] = CV_MAKETYPE( sum_depth, cn );
2511     types[OUTPUT][1] = CV_MAKETYPE( CV_64F, cn );
2512 }
2513
2514
2515 void CV_IntegralTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
2516 {
2517     sprintf( ptr, "%s,", cvReadString( find_timing_param( "output" ), "sum" ) );
2518     ptr += strlen(ptr);
2519     params_left--;
2520
2521     CvArrTest::print_timing_params( test_case_idx, ptr, params_left );
2522 }
2523
2524
2525 int CV_IntegralTest::prepare_test_case( int test_case_idx )
2526 {
2527     int code = CvArrTest::prepare_test_case( test_case_idx );
2528     return code > 0 && (test_array[OUTPUT][2] && CV_MAT_CN(test_mat[OUTPUT][2].type) > 1 ||
2529         CV_MAT_DEPTH(test_mat[OUTPUT][0].type) < CV_MAT_DEPTH(test_mat[INPUT][0].type)) ? 0 : code;
2530 }
2531
2532
2533 void CV_IntegralTest::run_func()
2534 {
2535     cvIntegral( test_array[INPUT][0], test_array[OUTPUT][0],
2536                 test_array[OUTPUT][1], test_array[OUTPUT][2] );
2537 }
2538
2539
2540 static void
2541 cvTsIntegral( const CvMat* img, const CvMat* sum, const CvMat* sqsum, const CvMat* tilted )
2542 {
2543     const float* data = img->data.fl;
2544     double* sdata = sum->data.db;
2545     double* sqdata = sqsum ? sqsum->data.db : 0;
2546     double* tdata = tilted ? tilted->data.db : 0;
2547     int step = img->step/sizeof(data[0]);
2548     int sstep = sum->step/sizeof(sdata[0]);
2549     int sqstep = sqsum ? sqsum->step/sizeof(sqdata[0]) : 0;
2550     int tstep = tilted ? tilted->step/sizeof(tdata[0]) : 0;
2551     CvSize size = cvGetMatSize( img );
2552
2553     memset( sdata, 0, (size.width+1)*sizeof(sdata[0]) );
2554     if( sqsum )
2555         memset( sqdata, 0, (size.width+1)*sizeof(sqdata[0]) );
2556     if( tilted )
2557         memset( tdata, 0, (size.width+1)*sizeof(tdata[0]) );
2558
2559     for( ; size.height--; data += step )
2560     {
2561         double s = 0, sq = 0;
2562         int x;
2563         sdata += sstep;
2564         sqdata += sqstep;
2565         tdata += tstep;
2566
2567         for( x = 0; x <= size.width; x++ )
2568         {
2569             double t = x > 0 ? data[x-1] : 0, ts = t;
2570             s += t;
2571             sq += t*t;
2572             
2573             sdata[x] = s + sdata[x - sstep];
2574             if( sqdata )
2575                 sqdata[x] = sq + sqdata[x - sqstep];
2576             
2577             if( !tdata )
2578                 continue;
2579             
2580             if( x == 0 )
2581                 ts += tdata[-tstep+1];
2582             else
2583             {
2584                 ts += tdata[x-tstep-1];
2585                 if( data > img->data.fl )
2586                 {
2587                     ts += data[x-step-1];
2588                     if( x < size.width )
2589                         ts += tdata[x-tstep+1] - tdata[x-tstep*2];
2590                 }
2591             }
2592
2593             tdata[x] = ts;
2594         }
2595     }
2596 }
2597
2598
2599 void CV_IntegralTest::prepare_to_validation( int /*test_case_idx*/ )
2600 {
2601     CvMat* src0 = &test_mat[INPUT][0];
2602     int i, cn = CV_MAT_CN(src0->type), depth = CV_MAT_DEPTH(src0->type);
2603     CvMat* plane = cn > 1 ? &test_mat[TEMP][0] : 0;
2604     CvMat  ibuf, *plane32f = 0;
2605
2606     CvMat* sum0 = &test_mat[REF_OUTPUT][0];
2607     CvMat* sqsum0 = test_array[REF_OUTPUT][1] ? &test_mat[REF_OUTPUT][1] : 0;
2608     CvMat* tsum0 = test_array[REF_OUTPUT][2] ? &test_mat[REF_OUTPUT][2] : 0;
2609
2610     CvMat* sum1 = test_array[TEMP][2] ? &test_mat[TEMP][2] : sum0;
2611     CvMat* sqsum1 = test_array[TEMP][3] ? &test_mat[TEMP][3] : sqsum0;
2612     CvMat* tsum1 = test_array[TEMP][4] ? &test_mat[TEMP][4] : tsum0;
2613     CvMat  buf, *ptr = 0;
2614
2615     if( depth == CV_8U )
2616     {
2617         ibuf = test_mat[TEMP][1];
2618         plane32f = &ibuf;
2619         plane32f->cols--;
2620         plane32f->rows--;
2621         plane32f->type &= ~CV_MAT_CONT_FLAG;
2622
2623         if( CV_MAT_DEPTH(sum0->type) == CV_32S && cn > 1 )
2624         {
2625             // in case of 8u->32s integral transform aliase the temporary output buffer with temporary input buffer
2626             buf = test_mat[TEMP][1];
2627             ptr = &buf;
2628             ptr->type = (ptr->type & ~CV_MAT_DEPTH_MASK) | CV_32S;
2629         }
2630     }
2631
2632     for( i = 0; i < cn; i++ )
2633     {
2634         CvMat* sptr = src0;
2635         CvMat* dptr;
2636         if( cn > 1 )
2637         {
2638             cvTsExtract( sptr, plane, i );
2639             sptr = plane;
2640         }
2641
2642         if( CV_MAT_DEPTH(sptr->type) != CV_32F )
2643         {
2644             cvTsConvert( sptr, plane32f );
2645             sptr = plane32f;
2646         }
2647
2648         cvTsIntegral( sptr, sum1, sqsum1, tsum1 );
2649         if( sum1 != sum0 )
2650         {
2651             dptr = sum1;
2652             if( ptr )
2653             {
2654                 cvTsConvert( dptr, ptr );
2655                 dptr = ptr;
2656             }
2657             if( cn == 1 )
2658                 cvTsConvert( dptr, sum0 );
2659             else
2660                 cvTsInsert( dptr, sum0, i );
2661         }
2662
2663         if( tsum1 != tsum0 )
2664         {
2665             dptr = tsum1;
2666             if( ptr )
2667             {
2668                 cvTsConvert( dptr, ptr );
2669                 dptr = ptr;
2670             }
2671             if( cn == 1 )
2672                 cvTsConvert( dptr, tsum0 );
2673             else
2674                 cvTsInsert( dptr, tsum0, i );
2675         }
2676
2677         if( sqsum1 != sqsum0 )
2678             cvTsInsert( sqsum1, sqsum0, i );
2679     }
2680 }
2681
2682
2683 CV_IntegralTest integral_test;
2684
2685