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