e2413e7c010e895a1b80563a917429d04f01ebf3
[opencv] / tests / cxcore / src / aarithm.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 //////////////////////////////////////////////////////////////////////////////////////////
43 ////////////////// tests for arithmetic, logic and statistical functions /////////////////
44 //////////////////////////////////////////////////////////////////////////////////////////
45
46 #include "cxcoretest.h"
47 #include <float.h>
48
49 static const CvSize arithm_sizes[] = {{10,10}, {100,100}, {720,480}, {-1,-1}};
50 static const CvSize arithm_whole_sizes[] = {{10,10}, {720,480}, {720,480}, {-1,-1}};
51 static const int arithm_depths[] = { CV_8U, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F, -1 };
52 static const int arithm_channels[] = { 1, 2, 3, 4, -1 };
53 static const char* arithm_mask_param_names[] = { "size", "channels", "depth", "use_mask", 0 };
54 static const char* arithm_param_names[] = { "size", "channels", "depth", 0 };
55 static const char* minmax_param_names[] = { "size", "depth", 0 };
56
57 class CxCore_ArithmTestImpl : public CvArrTest
58 {
59 public:
60     CxCore_ArithmTestImpl( const char* test_name, const char* test_funcs,
61                            int _generate_scalars=0, bool _allow_mask=true, bool _calc_abs=false );
62 protected:
63     void prepare_to_validation( int test_case_idx );
64     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
65     void get_timing_test_array_types_and_sizes( int /*test_case_idx*/,
66                         CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images );
67     void generate_scalars( int depth );
68     CvScalar alpha, beta, gamma;
69     int gen_scalars;
70     bool calc_abs;
71 };
72
73
74 CxCore_ArithmTestImpl::CxCore_ArithmTestImpl( const char* test_name, const char* test_funcs,
75                                               int _generate_scalars, bool _allow_mask, bool _calc_abs )
76     : CvArrTest( test_name, test_funcs, "" ),
77     gen_scalars(_generate_scalars), calc_abs(_calc_abs)
78 {
79     test_array[INPUT].push(NULL);
80     test_array[INPUT].push(NULL);
81     optional_mask = _allow_mask;
82
83     if( optional_mask )
84     {
85         test_array[INPUT_OUTPUT].push(NULL);
86         test_array[REF_INPUT_OUTPUT].push(NULL);
87         test_array[TEMP].push(NULL);
88         test_array[MASK].push(NULL);
89     }
90     else
91     {
92         test_array[OUTPUT].push(NULL);
93         test_array[REF_OUTPUT].push(NULL);
94     }
95     alpha = beta = gamma = cvScalarAll(0);
96
97     size_list = arithm_sizes;
98     whole_size_list = arithm_whole_sizes;
99     depth_list = arithm_depths;
100     cn_list = arithm_channels;
101 }
102
103
104 void CxCore_ArithmTestImpl::generate_scalars( int depth )
105 {
106     bool is_timing = ts->get_testing_mode() == CvTS::TIMING_MODE;
107     double ab_min_val = -1.;
108     double ab_max_val = 1.;
109     double gamma_min_val = depth == CV_8U ? -100 : depth < CV_32F ? -10000 : -1e6;
110     double gamma_max_val = depth == CV_8U ? 100 : depth < CV_32F ? 10000 : 1e6;
111     
112     if( gen_scalars )
113     {
114         CvRNG* rng = ts->get_rng();
115         int i;
116         double m = 3.;
117         for( i = 0; i < 4; i++ )
118         {
119             if( gen_scalars & 1 )
120             {
121                 alpha.val[i] = exp((cvTsRandReal(rng)-0.5)*m*2*CV_LOG2);
122                 alpha.val[i] *= (cvTsRandInt(rng) & 1) ? 1 : -1;
123                 if( is_timing )
124                 {
125                     alpha.val[i] = MAX( alpha.val[i], ab_min_val );
126                     alpha.val[i] = MIN( alpha.val[i], ab_max_val );
127                 }
128             }
129             if( gen_scalars & 2 )
130             {
131                 beta.val[i] = exp((cvTsRandReal(rng)-0.5)*m*2*CV_LOG2);
132                 beta.val[i] *= (cvTsRandInt(rng) & 1) ? 1 : -1;
133                 if( is_timing )
134                 {
135                     beta.val[i] = MAX( beta.val[i], ab_min_val );
136                     beta.val[i] = MIN( beta.val[i], ab_max_val );
137                 }
138             }
139             if( gen_scalars & 4 )
140             {
141                 gamma.val[i] = exp((cvTsRandReal(rng)-0.5)*m*2*CV_LOG2);
142                 gamma.val[i] *= (cvTsRandInt(rng) & 1) ? 1 : -1;
143                 if( is_timing )
144                 {
145                     gamma.val[i] = MAX( gamma.val[i], gamma_min_val );
146                     gamma.val[i] = MIN( gamma.val[i], gamma_max_val );
147                 }
148             }
149         }
150     }
151
152     if( depth == CV_32F )
153     {
154         CvMat fl = cvMat( 1, 4, CV_32F, buf );
155         CvMat db = cvMat( 1, 4, CV_64F, 0 );
156
157         db.data.db = alpha.val;
158         cvTsConvert( &db, &fl );
159         cvTsConvert( &fl, &db );
160
161         db.data.db = beta.val;
162         cvTsConvert( &db, &fl );
163         cvTsConvert( &fl, &db );
164
165         db.data.db = gamma.val;
166         cvTsConvert( &db, &fl );
167         cvTsConvert( &fl, &db );
168     }
169 }
170
171 void CxCore_ArithmTestImpl::get_test_array_types_and_sizes( int test_case_idx,
172                                                             CvSize** sizes, int** types )
173 {
174     CvRNG* rng = ts->get_rng();
175     int depth = cvTsRandInt(rng)%CV_64F;
176     int cn = cvTsRandInt(rng) % 4 + 1;
177     int i, j;
178     CvArrTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
179     generate_scalars( depth );
180     depth += depth == CV_8S;
181
182     for( i = 0; i < max_arr; i++ )
183     {
184         int count = test_array[i].size();
185         int type = i != MASK ? CV_MAKETYPE(depth, cn) : CV_8UC1;
186         for( j = 0; j < count; j++ )
187         {
188             types[i][j] = type;
189         }
190     }
191 }
192
193
194 void CxCore_ArithmTestImpl::get_timing_test_array_types_and_sizes( int test_case_idx,
195                 CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images )
196 {
197     CvArrTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
198                                                       whole_sizes, are_images );
199     generate_scalars( types[INPUT][0] );
200 }
201
202
203 void CxCore_ArithmTestImpl::prepare_to_validation( int /*test_case_idx*/ )
204 {
205     const CvMat* mask = test_array[MASK].size() > 0 && test_array[MASK][0] ? &test_mat[MASK][0] : 0;
206     CvMat* output = test_array[REF_INPUT_OUTPUT].size() > 0 ?
207         &test_mat[REF_INPUT_OUTPUT][0] : &test_mat[REF_OUTPUT][0];
208     CvMat* temp_dst = mask ? &test_mat[TEMP][0] : output;
209     cvTsAdd( &test_mat[INPUT][0], alpha,
210              test_array[INPUT].size() > 1 ? &test_mat[INPUT][1] : 0, beta,
211              gamma, temp_dst, calc_abs );
212     if( mask )
213         cvTsCopy( temp_dst, output, mask );
214 }
215
216
217 CxCore_ArithmTestImpl arithm( "arithm", "", 0, false );
218
219
220 class CxCore_ArithmTest : public CxCore_ArithmTestImpl
221 {
222 public:
223     CxCore_ArithmTest( const char* test_name, const char* test_funcs,
224                        int _generate_scalars=0, bool _allow_mask=true, bool _calc_abs=false );
225 };
226
227
228 CxCore_ArithmTest::CxCore_ArithmTest( const char* test_name, const char* test_funcs,
229                                       int _generate_scalars, bool _allow_mask, bool _calc_abs ) :
230     CxCore_ArithmTestImpl( test_name, test_funcs, _generate_scalars, _allow_mask, _calc_abs )
231 {
232     default_timing_param_names = optional_mask ? arithm_mask_param_names : arithm_param_names;
233         
234     // inherit the default parameters from arithmetical test
235     size_list = 0;
236     whole_size_list = 0;
237     depth_list = 0;
238     cn_list = 0;
239 }
240
241
242 ////////////////////////////// add /////////////////////////////
243
244 class CxCore_AddTest : public CxCore_ArithmTest
245 {
246 public:
247     CxCore_AddTest();
248 protected:
249     void run_func();
250 };
251
252 CxCore_AddTest::CxCore_AddTest()
253     : CxCore_ArithmTest( "arithm-add", "cvAdd", 0, true )
254 {
255     alpha = beta = cvScalarAll(1.);
256 }
257
258 void CxCore_AddTest::run_func()
259 {
260     cvAdd( test_array[INPUT][0], test_array[INPUT][1],
261         test_array[INPUT_OUTPUT][0], test_array[MASK][0] );
262 }
263
264 CxCore_AddTest add_test;
265
266 ////////////////////////////// sub /////////////////////////////
267
268 class CxCore_SubTest : public CxCore_ArithmTest
269 {
270 public:
271     CxCore_SubTest();
272 protected:
273     void run_func();
274 };
275
276 CxCore_SubTest::CxCore_SubTest()
277     : CxCore_ArithmTest( "arithm-sub", "cvSub", 0, true )
278 {
279     alpha = cvScalarAll(1.);
280     beta = cvScalarAll(-1.);
281 }
282
283 void CxCore_SubTest::run_func()
284 {
285     cvSub( test_array[INPUT][0], test_array[INPUT][1],
286            test_array[INPUT_OUTPUT][0], test_array[MASK][0] );
287 }
288
289 CxCore_SubTest sub_test;
290
291
292 ////////////////////////////// adds /////////////////////////////
293
294 class CxCore_AddSTest : public CxCore_ArithmTest
295 {
296 public:
297     CxCore_AddSTest();
298 protected:
299     void run_func();
300 };
301
302 CxCore_AddSTest::CxCore_AddSTest()
303     : CxCore_ArithmTest( "arithm-adds", "cvAddS", 4, true )
304 {
305     test_array[INPUT].pop();
306     alpha = cvScalarAll(1.);
307 }
308
309 void CxCore_AddSTest::run_func()
310 {
311     cvAddS( test_array[INPUT][0], gamma,
312             test_array[INPUT_OUTPUT][0], test_array[MASK][0] );
313 }
314
315 CxCore_AddSTest adds_test;
316
317 ////////////////////////////// subrs /////////////////////////////
318
319 class CxCore_SubRSTest : public CxCore_ArithmTest
320 {
321 public:
322     CxCore_SubRSTest();
323 protected:
324     void run_func();
325 };
326
327 CxCore_SubRSTest::CxCore_SubRSTest()
328     : CxCore_ArithmTest( "arithm-subrs", "cvSubRS", 4, true )
329 {
330     test_array[INPUT].pop();
331     alpha = cvScalarAll(-1.);
332 }
333
334 void CxCore_SubRSTest::run_func()
335 {
336     cvSubRS( test_array[INPUT][0], gamma,
337              test_array[INPUT_OUTPUT][0], test_array[MASK][0] );
338 }
339
340 CxCore_SubRSTest subrs_test;
341
342 ////////////////////////////// addweighted /////////////////////////////
343
344 class CxCore_AddWeightedTest : public CxCore_ArithmTest
345 {
346 public:
347     CxCore_AddWeightedTest();
348 protected:
349     void get_test_array_types_and_sizes( int test_case_idx,
350                                           CvSize** sizes, int** types );
351     double get_success_error_level( int test_case_idx, int i, int j );
352     void run_func();
353 };
354
355 CxCore_AddWeightedTest::CxCore_AddWeightedTest()
356     : CxCore_ArithmTest( "arithm-addweighted", "cvAddWeighted", 7, false )
357 {
358 }
359
360 void CxCore_AddWeightedTest::get_test_array_types_and_sizes( int test_case_idx,
361                                                     CvSize** sizes, int** types )
362 {
363     CxCore_ArithmTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
364     alpha = cvScalarAll(alpha.val[0]);
365     beta = cvScalarAll(beta.val[0]);
366     gamma = cvScalarAll(gamma.val[0]);
367 }
368
369
370 double CxCore_AddWeightedTest::get_success_error_level( int test_case_idx, int i, int j )
371 {
372     int type = cvGetElemType(test_array[i][j]), depth = CV_MAT_DEPTH(type);
373     if( depth <= CV_32S )
374         return 2;
375     if( depth == CV_32F )
376     {
377         CvScalar low=cvScalarAll(0), high=low;
378         get_minmax_bounds(i,j,type, &low, &high);
379         double a = (fabs(alpha.val[0])+fabs(beta.val[0]))*(fabs(low.val[0])+fabs(high.val[0]));
380         double b = fabs(gamma.val[0]);
381         return (a+b)*500*FLT_EPSILON;
382     }
383     return CvArrTest::get_success_error_level( test_case_idx, i, j );
384 }
385
386
387 void CxCore_AddWeightedTest::run_func()
388 {
389     cvAddWeighted( test_array[INPUT][0], alpha.val[0],
390                    test_array[INPUT][1], beta.val[0],
391                    gamma.val[0], test_array[OUTPUT][0] );
392 }
393
394 CxCore_AddWeightedTest addweighted_test;
395
396
397 ////////////////////////////// absdiff /////////////////////////////
398
399 class CxCore_AbsDiffTest : public CxCore_ArithmTest
400 {
401 public:
402     CxCore_AbsDiffTest();
403 protected:
404     void run_func();
405 };
406
407 CxCore_AbsDiffTest::CxCore_AbsDiffTest()
408     : CxCore_ArithmTest( "arithm-absdiff", "cvAbsDiff", 0, false, true )
409 {
410     alpha = cvScalarAll(1.);
411     beta = cvScalarAll(-1.);
412 }
413
414 void CxCore_AbsDiffTest::run_func()
415 {
416     cvAbsDiff( test_array[INPUT][0], test_array[INPUT][1], test_array[OUTPUT][0] );
417 }
418
419 CxCore_AbsDiffTest absdiff_test;
420
421 ////////////////////////////// absdiffs /////////////////////////////
422
423 class CxCore_AbsDiffSTest : public CxCore_ArithmTest
424 {
425 public:
426     CxCore_AbsDiffSTest();
427 protected:
428     void run_func();
429 };
430
431 CxCore_AbsDiffSTest::CxCore_AbsDiffSTest()
432     : CxCore_ArithmTest( "arithm-absdiffs", "cvAbsDiffS", 4, false, true )
433 {
434     alpha = cvScalarAll(-1.);
435     test_array[INPUT].pop();
436 }
437
438 void CxCore_AbsDiffSTest::run_func()
439 {
440     cvAbsDiffS( test_array[INPUT][0], test_array[OUTPUT][0], gamma );
441 }
442
443 CxCore_AbsDiffSTest absdiffs_test;
444
445
446 ////////////////////////////// mul /////////////////////////////
447
448 static const char* mul_param_names[] = { "size", "scale", "channels", "depth", 0 };
449 static const char* mul_scale_flags[] = { "scale==1", "scale!=1", 0 };
450
451 class CxCore_MulTest : public CxCore_ArithmTest
452 {
453 public:
454     CxCore_MulTest();
455 protected:
456     void run_func();
457     void get_timing_test_array_types_and_sizes( int test_case_idx,
458                                                 CvSize** sizes, int** types,
459                                                 CvSize** whole_sizes, bool* are_images );
460     double get_success_error_level( int test_case_idx, int i, int j );
461     void print_timing_params( int test_case_idx, char* ptr, int params_left );
462     void prepare_to_validation( int test_case_idx );
463     int write_default_params( CvFileStorage* fs );
464 };
465
466
467 CxCore_MulTest::CxCore_MulTest()
468     : CxCore_ArithmTest( "arithm-mul", "cvMul", 4, false, false )
469 {
470     default_timing_param_names = mul_param_names;
471 }
472
473
474 int CxCore_MulTest::write_default_params( CvFileStorage* fs )
475 {
476     int code = CxCore_ArithmTest::write_default_params(fs);
477     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
478         return code;
479     write_string_list( fs, "scale", mul_scale_flags );
480     return code;
481 }
482
483
484 void CxCore_MulTest::get_timing_test_array_types_and_sizes( int test_case_idx,
485                                                     CvSize** sizes, int** types,
486                                                     CvSize** whole_sizes, bool* are_images )
487 {
488     CxCore_ArithmTest::get_timing_test_array_types_and_sizes( test_case_idx,
489                                     sizes, types, whole_sizes, are_images );
490     const char* scale_flag_str = cvReadString( find_timing_param( "scale" ), "scale==1" );
491     if( strstr( scale_flag_str, "==1" ) )
492         alpha.val[0] = 1.;
493     else
494     {
495         double val = alpha.val[0];
496         int depth = CV_MAT_DEPTH(types[INPUT][0]);
497         if( val == 1. )
498             val = 1./CV_PI;
499         if( depth == CV_16U || depth == CV_16S || depth == CV_32S )
500         {
501             double minmax = 1./cvTsMaxVal(depth);
502             if( val < -minmax )
503                 val = -minmax;
504             else if( val > minmax )
505                 val = minmax;
506             if( depth == CV_16U && val < 0 )
507                 val = -val;
508         }
509         alpha.val[0] = val;
510         ts->printf( CvTS::LOG, "alpha = %g\n", alpha.val[0] );
511     }
512 }
513
514
515 void CxCore_MulTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
516 {
517     sprintf( ptr, "%s,", alpha.val[0] == 1. ? "scale==1" : "scale!=1" );
518     ptr += strlen(ptr);
519     params_left--;
520     CxCore_ArithmTest::print_timing_params( test_case_idx, ptr, params_left );
521 }
522
523
524 double CxCore_MulTest::get_success_error_level( int test_case_idx, int i, int j )
525 {
526     if( CV_MAT_DEPTH(cvGetElemType(test_array[i][j])) <= CV_32S )
527     {
528         return gamma.val[0] != cvRound(gamma.val[0]);
529     }
530     else
531         return CvArrTest::get_success_error_level( test_case_idx, i, j );
532 }
533
534
535 void CxCore_MulTest::run_func()
536 {
537     cvMul( test_array[INPUT][0], test_array[INPUT][1],
538            test_array[OUTPUT][0], alpha.val[0] );
539 }
540
541 void CxCore_MulTest::prepare_to_validation( int /*test_case_idx*/ )
542 {
543     cvTsMul( &test_mat[INPUT][0], &test_mat[INPUT][1],
544              cvScalarAll(alpha.val[0]),
545              &test_mat[REF_OUTPUT][0] );
546 }
547
548 CxCore_MulTest mul_test;
549
550 ////////////////////////////// div /////////////////////////////
551
552 class CxCore_DivTest : public CxCore_ArithmTest
553 {
554 public:
555     CxCore_DivTest();
556 protected:
557     void run_func();
558     void print_timing_params( int test_case_idx, char* ptr, int params_left );
559     void prepare_to_validation( int /*test_case_idx*/ );
560 };
561
562 CxCore_DivTest::CxCore_DivTest()
563     : CxCore_ArithmTest( "arithm-div", "cvDiv", 4, false, false )
564 {
565 }
566
567 void CxCore_DivTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
568 {
569     sprintf( ptr, "s*A(i)/B(i)," );
570     ptr += strlen(ptr);
571     params_left--;
572     CxCore_ArithmTest::print_timing_params( test_case_idx, ptr, params_left );
573 }
574
575 void CxCore_DivTest::run_func()
576 {
577     cvDiv( test_array[INPUT][0], test_array[INPUT][1],
578            test_array[OUTPUT][0], alpha.val[0] );
579 }
580
581 void CxCore_DivTest::prepare_to_validation( int /*test_case_idx*/ )
582 {
583     cvTsDiv( &test_mat[INPUT][0], &test_mat[INPUT][1],
584              cvScalarAll(alpha.val[0]),
585              &test_mat[REF_OUTPUT][0] );
586 }
587
588 CxCore_DivTest div_test;
589
590 ////////////////////////////// recip /////////////////////////////
591
592 class CxCore_RecipTest : public CxCore_ArithmTest
593 {
594 public:
595     CxCore_RecipTest();
596 protected:
597     void run_func();
598     void print_timing_params( int test_case_idx, char* ptr, int params_left );
599     void prepare_to_validation( int /*test_case_idx*/ );
600 };
601
602 CxCore_RecipTest::CxCore_RecipTest()
603     : CxCore_ArithmTest( "arithm-recip", "cvDiv", 4, false, false )
604 {
605     test_array[INPUT].pop();
606 }
607
608 void CxCore_RecipTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
609 {
610     sprintf( ptr, "s/B(i)," );
611     ptr += strlen(ptr);
612     params_left--;
613     CxCore_ArithmTest::print_timing_params( test_case_idx, ptr, params_left );
614 }
615
616 void CxCore_RecipTest::run_func()
617 {
618     cvDiv( 0, test_array[INPUT][0],
619            test_array[OUTPUT][0], gamma.val[0] );
620 }
621
622 void CxCore_RecipTest::prepare_to_validation( int /*test_case_idx*/ )
623 {
624     cvTsDiv( 0, &test_mat[INPUT][0],
625              cvScalarAll(gamma.val[0]),
626              &test_mat[REF_OUTPUT][0] );
627 }
628
629 CxCore_RecipTest recip_test;
630
631
632 ///////////////// matrix copy/initializing/permutations /////////////////////
633                                                    
634 class CxCore_MemTestImpl : public CxCore_ArithmTestImpl
635 {
636 public:
637     CxCore_MemTestImpl( const char* test_name, const char* test_funcs,
638                         int _generate_scalars=0, bool _allow_mask=true );
639 protected:
640     double get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ );
641 };
642
643 CxCore_MemTestImpl::CxCore_MemTestImpl( const char* test_name, const char* test_funcs,
644                                         int _generate_scalars, bool _allow_mask ) :
645     CxCore_ArithmTestImpl( test_name, test_funcs, _generate_scalars, _allow_mask, false )
646 {
647 }
648
649 double CxCore_MemTestImpl::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
650 {
651     return 0;
652 }
653
654 CxCore_MemTestImpl mem_test( "mem", "", 0, false );
655
656
657 class CxCore_MemTest : public CxCore_MemTestImpl
658 {
659 public:
660     CxCore_MemTest( const char* test_name, const char* test_funcs,
661                     int _generate_scalars=0, bool _allow_mask=true );
662 };
663
664 CxCore_MemTest::CxCore_MemTest( const char* test_name, const char* test_funcs,
665                                 int _generate_scalars, bool _allow_mask ) :
666     CxCore_MemTestImpl( test_name, test_funcs, _generate_scalars, _allow_mask )
667 {
668     default_timing_param_names = optional_mask ? arithm_mask_param_names : arithm_param_names;
669         
670     // inherit the default parameters from arithmerical test
671     size_list = 0;
672     whole_size_list = 0;
673     depth_list = 0;
674     cn_list = 0;
675 }
676
677
678 ///////////////// setidentity /////////////////////
679
680 class CxCore_SetIdentityTest : public CxCore_MemTest
681 {
682 public:
683     CxCore_SetIdentityTest();
684 protected:
685     void run_func();
686     void prepare_to_validation( int test_case_idx );
687 };
688
689
690 CxCore_SetIdentityTest::CxCore_SetIdentityTest() :
691     CxCore_MemTest( "mem-setidentity", "cvSetIdentity", 4, false )
692 {
693     test_array[INPUT].clear();
694 }
695
696
697 void CxCore_SetIdentityTest::run_func()
698 {
699     cvSetIdentity(test_array[OUTPUT][0], gamma);
700 }
701
702
703 void CxCore_SetIdentityTest::prepare_to_validation( int )
704 {
705     cvTsSetIdentity( &test_mat[REF_OUTPUT][0], gamma );
706 }
707
708 CxCore_SetIdentityTest setidentity_test;
709
710
711 ///////////////// SetZero /////////////////////
712
713 class CxCore_SetZeroTest : public CxCore_MemTest
714 {
715 public:
716     CxCore_SetZeroTest();
717 protected:
718     void run_func();
719     void prepare_to_validation( int test_case_idx );
720 };
721
722
723 CxCore_SetZeroTest::CxCore_SetZeroTest() :
724     CxCore_MemTest( "mem-setzero", "cvSetZero", 0, false )
725 {
726     test_array[INPUT].clear();
727 }
728
729
730 void CxCore_SetZeroTest::run_func()
731 {
732     cvSetZero(test_array[OUTPUT][0]);
733 }
734
735
736 void CxCore_SetZeroTest::prepare_to_validation( int )
737 {
738     cvTsZero( &test_mat[REF_OUTPUT][0] );
739 }
740
741 CxCore_SetZeroTest setzero_test;
742
743
744 ///////////////// Set /////////////////////
745
746 class CxCore_FillTest : public CxCore_MemTest
747 {
748 public:
749     CxCore_FillTest();
750 protected:
751     void run_func();
752     void prepare_to_validation( int test_case_idx );
753 };
754
755
756 CxCore_FillTest::CxCore_FillTest() :
757     CxCore_MemTest( "mem-fill", "cvSet", 4, true )
758 {
759     test_array[INPUT].clear();
760 }
761
762
763 void CxCore_FillTest::run_func()
764 {
765     cvSet(test_array[INPUT_OUTPUT][0], gamma, test_array[MASK][0]);
766 }
767
768
769 void CxCore_FillTest::prepare_to_validation( int )
770 {
771     if( test_array[MASK][0] )
772     {
773         cvTsAdd( 0, cvScalarAll(0.), 0, cvScalarAll(0.), gamma, &test_mat[TEMP][0], 0 );
774         cvTsCopy( &test_mat[TEMP][0], &test_mat[REF_INPUT_OUTPUT][0], &test_mat[MASK][0] );
775     }
776     else
777     {
778         cvTsAdd( 0, cvScalarAll(0.), 0, cvScalarAll(0.), gamma, &test_mat[REF_INPUT_OUTPUT][0], 0 );
779     }
780 }
781
782 CxCore_FillTest fill_test;
783
784
785 ///////////////// Copy /////////////////////
786
787 class CxCore_CopyTest : public CxCore_MemTest
788 {
789 public:
790     CxCore_CopyTest();
791 protected:
792     double get_success_error_level( int test_case_idx, int i, int j );
793     void run_func();
794     void prepare_to_validation( int test_case_idx );
795 };
796
797
798 CxCore_CopyTest::CxCore_CopyTest() :
799     CxCore_MemTest( "mem-copy", "cvCopy", 0, true )
800 {
801     test_array[INPUT].pop();
802 }
803
804
805 double CxCore_CopyTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
806 {
807     return 0;
808 }
809
810
811 void CxCore_CopyTest::run_func()
812 {
813     cvCopy(test_array[INPUT][0], test_array[INPUT_OUTPUT][0], test_array[MASK][0]);
814 }
815
816
817 void CxCore_CopyTest::prepare_to_validation( int )
818 {
819     cvTsCopy( &test_mat[INPUT][0], &test_mat[REF_INPUT_OUTPUT][0],
820               test_array[MASK].size() > 0 && test_array[MASK][0] ? &test_mat[MASK][0] : 0 );
821 }
822
823 CxCore_CopyTest copy_test;
824
825 ///////////////// Transpose /////////////////////
826
827 class CxCore_TransposeTest : public CxCore_MemTest
828 {
829 public:
830     CxCore_TransposeTest();
831 protected:
832     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
833     void get_timing_test_array_types_and_sizes( int test_case_idx,
834                                                 CvSize** sizes, int** types,
835                                                 CvSize** whole_sizes, bool* are_images );
836     int prepare_test_case( int test_case_idx );
837     void run_func();
838     void prepare_to_validation( int test_case_idx );
839     bool inplace;
840 };
841
842
843 CxCore_TransposeTest::CxCore_TransposeTest() :
844     CxCore_MemTest( "mem-transpose", "cvTranspose", 0, false ), inplace(false)
845 {
846     test_array[INPUT].pop();
847 }
848
849
850 void CxCore_TransposeTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
851 {
852     int bits = cvTsRandInt(ts->get_rng());
853     CxCore_MemTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
854
855     inplace = false;
856     if( bits & 1 )
857     {
858         sizes[INPUT][0].height = sizes[INPUT][0].width;
859         inplace = (bits & 2) != 0;
860     }
861
862     sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(sizes[INPUT][0].height, sizes[INPUT][0].width );
863 }
864
865
866 void CxCore_TransposeTest::get_timing_test_array_types_and_sizes( int test_case_idx,
867                 CvSize** sizes, int** types, CvSize** whole_sizes, bool* are_images )
868 {
869     CxCore_MemTest::get_timing_test_array_types_and_sizes( test_case_idx,
870                                     sizes, types, whole_sizes, are_images );
871     CvSize size = sizes[INPUT][0];
872     if( size.width != size.height )
873     {
874         sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] =
875         whole_sizes[OUTPUT][0] = whole_sizes[REF_OUTPUT][0] = cvSize(size.height,size.width);
876     }
877 }
878
879
880 int CxCore_TransposeTest::prepare_test_case( int test_case_idx )
881 {
882     int code = CxCore_MemTest::prepare_test_case( test_case_idx );
883     if( inplace && code > 0 )
884         cvTsCopy( &test_mat[INPUT][0], &test_mat[OUTPUT][0] );
885     return code;
886 }
887
888 void CxCore_TransposeTest::run_func()
889 {
890     cvTranspose( inplace ? test_array[OUTPUT][0] : test_array[INPUT][0], test_array[OUTPUT][0]);
891 }
892
893
894 void CxCore_TransposeTest::prepare_to_validation( int )
895 {
896     cvTsTranspose( &test_mat[INPUT][0], &test_mat[REF_OUTPUT][0] );
897 }
898
899 CxCore_TransposeTest transpose_test;
900
901
902 ///////////////// Flip /////////////////////
903
904 static const int flip_codes[] = { 0, 1, -1, INT_MIN };
905 static const char* flip_strings[] = { "center", "vert", "horiz", 0 };
906 static const char* flip_param_names[] = { "size", "flip_op", "channels", "depth", 0 };
907
908 class CxCore_FlipTest : public CxCore_MemTest
909 {
910 public:
911     CxCore_FlipTest();
912 protected:
913     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
914     void get_timing_test_array_types_and_sizes( int test_case_idx,
915                                                 CvSize** sizes, int** types,
916                                                 CvSize** whole_sizes, bool* are_images );
917     int prepare_test_case( int test_case_idx );
918     void print_timing_params( int test_case_idx, char* ptr, int params_left );
919     void run_func();
920     void prepare_to_validation( int test_case_idx );
921     int write_default_params( CvFileStorage* fs );
922     int flip_type;
923     bool inplace;
924 };
925
926
927 CxCore_FlipTest::CxCore_FlipTest() :
928     CxCore_MemTest( "mem-flip", "cvFlip", 0, false ), flip_type(0), inplace(false)
929 {
930     test_array[INPUT].pop();
931     default_timing_param_names = flip_param_names;
932 }
933
934
935 int CxCore_FlipTest::write_default_params( CvFileStorage* fs )
936 {
937     int i, code = CxCore_MemTest::write_default_params(fs);
938     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
939         return code;
940     start_write_param( fs );
941     cvStartWriteStruct( fs, "flip_op", CV_NODE_SEQ + CV_NODE_FLOW );
942     for( i = 0; flip_codes[i] != INT_MIN; i++ )
943         cvWriteString( fs, 0, flip_strings[flip_codes[i]+1] );
944     cvEndWriteStruct(fs);
945     return code;
946 }
947
948
949 void CxCore_FlipTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
950 {
951     int bits = cvTsRandInt(ts->get_rng());
952     CxCore_MemTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
953
954     flip_type = (bits & 3) - 2;
955     flip_type += flip_type == -2;
956     inplace = (bits & 4) != 0;
957 }
958
959
960 void CxCore_FlipTest::get_timing_test_array_types_and_sizes( int test_case_idx,
961                                                     CvSize** sizes, int** types,
962                                                     CvSize** whole_sizes, bool* are_images )
963 {
964     CxCore_MemTest::get_timing_test_array_types_and_sizes( test_case_idx,
965                                     sizes, types, whole_sizes, are_images );
966     const char* flip_op_str = cvReadString( find_timing_param( "flip_op" ), "center" );
967     if( strcmp( flip_op_str, "vert" ) == 0 )
968         flip_type = 0;
969     else if( strcmp( flip_op_str, "horiz" ) == 0 )
970         flip_type = 1;
971     else
972         flip_type = -1;
973 }
974
975
976 void CxCore_FlipTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
977 {
978     sprintf( ptr, "%s,", flip_type > 0 ? "horiz" : flip_type < 0 ? "center" : "vert" );
979     ptr += strlen(ptr);
980     params_left--;
981     CxCore_MemTest::print_timing_params( test_case_idx, ptr, params_left );
982 }
983
984
985 int CxCore_FlipTest::prepare_test_case( int test_case_idx )
986 {
987     int code = CxCore_MemTest::prepare_test_case( test_case_idx );
988     if( inplace && code > 0 )
989         cvTsCopy( &test_mat[INPUT][0], &test_mat[OUTPUT][0] );
990     return code;
991 }
992
993
994 void CxCore_FlipTest::run_func()
995 {
996     cvFlip(inplace ? test_array[OUTPUT][0] : test_array[INPUT][0], test_array[OUTPUT][0], flip_type);
997 }
998
999
1000 void CxCore_FlipTest::prepare_to_validation( int )
1001 {
1002     cvTsFlip( &test_mat[INPUT][0], &test_mat[REF_OUTPUT][0], flip_type );
1003 }
1004
1005 CxCore_FlipTest flip_test;
1006
1007
1008 ///////////////// Split/Merge /////////////////////
1009
1010 static const char* split_merge_types[] = { "all", "single", 0 };
1011 static int split_merge_channels[] = { 2, 3, 4, -1 };
1012 static const char* split_merge_param_names[] = { "size", "planes", "channels", "depth", 0 };
1013
1014 class CxCore_SplitMergeBaseTest : public CxCore_MemTest
1015 {
1016 public:
1017     CxCore_SplitMergeBaseTest( const char* test_name, const char* test_funcs, int _is_split );
1018 protected:
1019     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1020     void get_timing_test_array_types_and_sizes( int test_case_idx,
1021                                                 CvSize** sizes, int** types,
1022                                                 CvSize** whole_sizes, bool* are_images );
1023     int prepare_test_case( int test_case_idx );
1024     void print_timing_params( int test_case_idx, char* ptr, int params_left );
1025     void prepare_to_validation( int test_case_idx );
1026     int write_default_params( CvFileStorage* fs );
1027     bool are_images;
1028     int is_split, coi; 
1029     void* hdrs[4];
1030 };
1031
1032
1033 CxCore_SplitMergeBaseTest::CxCore_SplitMergeBaseTest( const char* test_name,
1034     const char* test_funcs, int _is_split )
1035     : CxCore_MemTest( test_name, test_funcs, 0, false ), are_images(false), is_split(_is_split), coi(0)
1036 {
1037     test_array[INPUT].pop();
1038     if( is_split )
1039         ;
1040     else
1041     {
1042         test_array[OUTPUT].clear();
1043         test_array[REF_OUTPUT].clear();
1044         test_array[INPUT_OUTPUT].push(NULL);
1045         test_array[REF_INPUT_OUTPUT].push(NULL);
1046     }
1047     memset( hdrs, 0, sizeof(hdrs) );
1048
1049     default_timing_param_names = split_merge_param_names;
1050     cn_list = split_merge_channels;
1051 }
1052
1053
1054 int CxCore_SplitMergeBaseTest::write_default_params( CvFileStorage* fs )
1055 {
1056     int code = CxCore_MemTest::write_default_params(fs);
1057     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
1058         return code;
1059     write_string_list( fs, "planes", split_merge_types );
1060     return code;
1061 }
1062
1063
1064 void CxCore_SplitMergeBaseTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1065 {
1066     int cn, depth;
1067     CvRNG* rng = ts->get_rng();
1068     CxCore_MemTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1069     cn = cvTsRandInt(rng)%3 + 2;
1070     depth = CV_MAT_DEPTH(types[INPUT][0]);
1071     
1072     if( is_split )
1073     {
1074         types[INPUT][0] = CV_MAKETYPE(depth, cn);
1075         types[OUTPUT][0] = types[REF_OUTPUT][0] = depth;
1076     }
1077     else
1078     {
1079         types[INPUT][0] = depth;
1080         types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(depth, cn);
1081     }
1082
1083     if( (cvTsRandInt(rng) & 3) != 0 )
1084     {
1085         coi = cvTsRandInt(rng) % cn;
1086     }
1087     else
1088     {
1089         CvSize size = sizes[INPUT][0];
1090         size.height *= cn;
1091
1092         if( is_split )
1093             sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = size;
1094         else
1095             sizes[INPUT][0] = size;
1096         coi = -1;
1097     }
1098
1099     are_images = cvTsRandInt(rng)%2 != 0;
1100 }
1101
1102
1103 void CxCore_SplitMergeBaseTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1104                     CvSize** sizes, int** types, CvSize** whole_sizes, bool* _are_images )
1105 {
1106     CxCore_MemTest::get_timing_test_array_types_and_sizes( test_case_idx,
1107                                     sizes, types, whole_sizes, _are_images );
1108     const char* split_merge_type = cvReadString( find_timing_param( "planes" ), "all" );
1109     int type0 = types[INPUT][0];
1110     int depth = CV_MAT_DEPTH(type0);
1111     int cn = CV_MAT_CN(type0);
1112     CvSize size = sizes[INPUT][0];
1113
1114     if( strcmp( split_merge_type, "single" ) == 0 )
1115         coi = cvTsRandInt(ts->get_rng()) % cn;
1116     else
1117     {
1118         coi = -1;
1119         size.height *= cn;
1120     }
1121
1122     if( is_split )
1123     {
1124         types[OUTPUT][0] = types[REF_OUTPUT][0] = depth;
1125         sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = size;
1126         
1127         // planes are put into separate arrays, not ROI's
1128         whole_sizes[OUTPUT][0] = whole_sizes[REF_OUTPUT][0] = size;
1129     }
1130     else
1131     {
1132         types[INPUT][0] = depth;
1133         sizes[INPUT][0] = size;
1134         
1135         // planes are put into separate arrays, not ROI's
1136         whole_sizes[INPUT][0] = size;
1137     }
1138
1139     are_images = false;
1140 }
1141
1142
1143 void CxCore_SplitMergeBaseTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
1144 {
1145     int i;
1146     
1147     sprintf( ptr, "%s,", coi >= 0 ? "single" : "all" );
1148     ptr += strlen(ptr);
1149     params_left--;
1150
1151     // at once, delete the headers, though is not very good from structural point of view ...
1152     for( i = 0; i < 4; i++ )
1153         cvRelease( &hdrs[i] );
1154
1155     CxCore_MemTest::print_timing_params( test_case_idx, ptr, params_left );
1156 }
1157
1158
1159 int CxCore_SplitMergeBaseTest::prepare_test_case( int test_case_idx )
1160 {
1161     int code = CxCore_MemTest::prepare_test_case( test_case_idx );
1162     if( code > 0 )
1163     {
1164         CvMat* input = &test_mat[INPUT][0];
1165         CvMat* output = &test_mat[is_split ? OUTPUT : INPUT_OUTPUT][0];
1166         CvMat* merged = is_split ? input : output;
1167         CvMat* planes = is_split ? output : input;
1168         int depth = CV_MAT_DEPTH(merged->type);
1169         int i, cn = CV_MAT_CN(merged->type), y = 0;
1170         CvSize sz = cvGetMatSize(merged);
1171
1172         for( i = 0; i < cn; i++ )
1173         {
1174             if( coi < 0 || coi == i )
1175             {
1176                 if( are_images )
1177                     hdrs[i] = cvCreateImageHeader( sz, cvIplDepth(depth), 1 );
1178                 else
1179                     hdrs[i] = cvCreateMatHeader( sz.height, sz.width, depth );
1180                 cvSetData( hdrs[i], planes->data.ptr + planes->step*y, planes->step );
1181                 y += sz.height;
1182             }
1183         }
1184     }
1185
1186     return code;
1187 }
1188
1189
1190 void CxCore_SplitMergeBaseTest::prepare_to_validation( int )
1191 {
1192     CvMat* input = &test_mat[INPUT][0];
1193     CvMat* output = &test_mat[is_split ? REF_OUTPUT : REF_INPUT_OUTPUT][0];
1194     CvMat* merged = is_split ? input : output;
1195     CvMat* planes = is_split ? output : input;
1196     int i, cn = CV_MAT_CN(merged->type), y = 0;
1197     CvSize sz = cvGetSize(merged);
1198
1199     for( i = 0; i < cn; i++ )
1200     {
1201         if( coi < 0 || coi == i )
1202         {
1203             CvMat stub, *h;
1204             cvSetData( hdrs[i], planes->data.ptr + planes->step*y, planes->step );
1205             h = cvGetMat( hdrs[i], &stub );
1206             if( is_split )
1207                 cvTsExtract( input, h, i );
1208             else
1209                 cvTsInsert( h, output, i );
1210             cvSetData( hdrs[i], 0, 0 );
1211             cvRelease( &hdrs[i] );
1212             y += sz.height;
1213         }
1214     }
1215 }
1216
1217
1218 class CxCore_SplitTest : public CxCore_SplitMergeBaseTest
1219 {
1220 public:
1221     CxCore_SplitTest();
1222 protected:
1223     void run_func();
1224 };
1225
1226
1227 CxCore_SplitTest::CxCore_SplitTest() :
1228     CxCore_SplitMergeBaseTest( "mem-split", "cvSplit", 1 )
1229 {
1230 }
1231
1232
1233 void CxCore_SplitTest::run_func()
1234 {
1235     cvSplit( test_array[INPUT][0], hdrs[0], hdrs[1], hdrs[2], hdrs[3] );
1236 }
1237
1238 CxCore_SplitTest split_test;
1239
1240 class CxCore_MergeTest : public CxCore_SplitMergeBaseTest
1241 {
1242 public:
1243     CxCore_MergeTest();
1244 protected:
1245     void run_func();
1246 };
1247
1248
1249 CxCore_MergeTest::CxCore_MergeTest() :
1250     CxCore_SplitMergeBaseTest( "mem-merge", "cvMerge", 0 )
1251 {
1252 }
1253
1254
1255 void CxCore_MergeTest::run_func()
1256 {
1257     cvMerge( hdrs[0], hdrs[1], hdrs[2], hdrs[3], test_array[INPUT_OUTPUT][0] );
1258 }
1259
1260 CxCore_MergeTest merge_test;
1261
1262 ///////////////// CompleteSymm /////////////////////
1263
1264 class CxCore_CompleteSymm : public CvArrTest
1265 {
1266 public:
1267     CxCore_CompleteSymm();
1268 protected:
1269     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1270     int prepare_test_case( int test_case_idx );
1271     void run_func();
1272     void prepare_to_validation( int test_case_idx );
1273         int LtoR; //flags 
1274 };
1275
1276 CxCore_CompleteSymm::CxCore_CompleteSymm() :
1277     CvArrTest("matrix-symm", "cvCompleteSymm", "Test of cvCompleteSymm function")
1278 {
1279         /*Generates 1 input and 1 outputs (by default we have 2 inputs and 1 output)*/
1280         test_array[INPUT].clear();
1281         test_array[INPUT].push(NULL);
1282         test_array[OUTPUT].clear();
1283         test_array[OUTPUT].push(NULL);
1284         test_array[REF_OUTPUT].clear();
1285         test_array[REF_OUTPUT].push(NULL);
1286 }
1287
1288
1289 void CxCore_CompleteSymm::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1290 {
1291     CvArrTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1292     sizes[INPUT][0] =sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(sizes[INPUT][0].height, sizes[INPUT][0].height );
1293
1294         /*Making input and output matrixes one-channel*/
1295         int type;
1296         switch (test_case_idx % 3)
1297         {
1298                 case 0:
1299                         type = CV_32FC1;
1300                         break;
1301                 case 1:
1302                         type = CV_32SC1;
1303                         break;
1304                 default:
1305                         type = CV_64FC1;
1306         }
1307         types[OUTPUT][0] = types[INPUT][0] = types[REF_OUTPUT][0] = type;
1308 }
1309
1310 int CxCore_CompleteSymm::prepare_test_case( int test_case_idx )
1311 {
1312     int code = CvArrTest::prepare_test_case( test_case_idx );
1313         if (code)
1314         {
1315                 CvRNG* rng = ts->get_rng();
1316                 unsigned val = cvRandInt(rng);
1317                 LtoR = val % 2;
1318                 cvConvert(&test_mat[INPUT][0], &test_mat[OUTPUT][0]);
1319         }
1320         return code;
1321 }
1322
1323 void CxCore_CompleteSymm::run_func()
1324 {
1325         cvCompleteSymm(&test_mat[OUTPUT][0],LtoR);
1326 }
1327
1328 void CxCore_CompleteSymm::prepare_to_validation( int )
1329 {
1330         CvMat* ref_output = cvCreateMat(test_mat[OUTPUT][0].rows, test_mat[OUTPUT][0].cols, CV_64F); 
1331         CvMat* input = cvCreateMat(test_mat[INPUT][0].rows, test_mat[INPUT][0].cols, CV_64F);
1332         cvConvert(&test_mat[INPUT][0], input);
1333         
1334         for (int i=0;i<input->rows;i++)
1335         {
1336                 ref_output->data.db[i*input->cols+i]=input->data.db[i*input->cols+i];
1337                 if (LtoR)
1338                 {
1339                         for (int j=0;j<i;j++)
1340                         {
1341                                 ref_output->data.db[j*input->cols+i] = ref_output->data.db[i*input->cols+j]=input->data.db[i*input->cols+j];
1342                         }
1343                                 
1344                 }
1345                 else 
1346                 {
1347                         for (int j=0;j<i;j++)
1348                         {
1349                                 ref_output->data.db[j*input->cols+i] = ref_output->data.db[i*input->cols+j]=input->data.db[j*input->cols+i];
1350                         }
1351                 }
1352         }
1353
1354         cvConvert(ref_output, &test_mat[REF_OUTPUT][0]);
1355         cvReleaseMat(&input);
1356         cvReleaseMat(&ref_output);
1357 }
1358
1359 CxCore_CompleteSymm complete_symm;
1360
1361
1362 ////////////////////////////// Sort /////////////////////////////////
1363
1364 class CxCore_SortTest : public CxCore_MemTest
1365 {
1366 public:
1367     CxCore_SortTest();
1368 protected:
1369     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1370     int prepare_test_case( int test_case_idx );
1371     void run_func();
1372     void prepare_to_validation( int test_case_idx );
1373         int flags; //flags for sorting
1374 private:
1375         static int compareIndexes (const void * a, const void * b); // comparing two elements of the matrix with pointers sorting
1376         static int compare(const void * a, const void * b); // comparing two elements of the matrix with pointers sorting
1377         bool useIndexMatrix;
1378         bool useInPlaceSort;
1379         CvMat* input;
1380
1381 };
1382
1383 CxCore_SortTest::CxCore_SortTest() :
1384     CxCore_MemTest( "matrix-sort", "cvSort", 0, false )
1385 {
1386         /*Generates 1 input and 2 outputs (by default we have 2 inputs and 1 output)*/
1387         test_array[INPUT].clear();
1388         test_array[INPUT].push(NULL);
1389         test_array[OUTPUT].push(NULL);
1390         test_array[REF_OUTPUT].push(NULL);
1391 }
1392
1393
1394 void CxCore_SortTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1395 {
1396     CxCore_MemTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1397     sizes[INPUT][0] = sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] = cvSize(sizes[INPUT][0].height, sizes[INPUT][0].width );
1398         types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_32SC1;
1399
1400         /*Making input and output matrixes one-channel*/
1401         types[OUTPUT][0] = types[INPUT][0] = CV_MAKETYPE(CV_MAT_DEPTH(types[INPUT][0]), 1);
1402         types[REF_OUTPUT][0] = CV_MAKETYPE(CV_MAT_DEPTH(types[REF_OUTPUT][0]), 1);
1403 }
1404
1405 int CxCore_SortTest::prepare_test_case( int test_case_idx )
1406 {
1407         if (test_case_idx==0)
1408         {
1409                 useIndexMatrix=true;
1410                 useInPlaceSort=false;
1411         }
1412    int code = CxCore_MemTest::prepare_test_case( test_case_idx );
1413
1414    if( code > 0 )
1415         {
1416                 //Copying input data
1417                 input = cvCreateMat(test_mat[INPUT][0].rows, test_mat[INPUT][0].cols, CV_64F);
1418                 cvConvert(&test_mat[INPUT][0], input);
1419                 CvRNG* rng = ts->get_rng();
1420                 unsigned val = cvRandInt(rng);
1421         // Setting up flags
1422                 switch (val%4)
1423                 {
1424                         case 0:
1425                                 flags = CV_SORT_EVERY_ROW + CV_SORT_DESCENDING;
1426                                 break;
1427                         case 1:
1428                                 flags = CV_SORT_EVERY_ROW + CV_SORT_ASCENDING;
1429                                 break;
1430                         case 2:
1431                                 flags = CV_SORT_EVERY_COLUMN + CV_SORT_DESCENDING;
1432                                 break;
1433                         case 3:
1434                                 flags = CV_SORT_EVERY_COLUMN + CV_SORT_ASCENDING;
1435                                 break;
1436                 }
1437                 if (val%3) 
1438                         useIndexMatrix = !useIndexMatrix;
1439
1440                 if (val%5) 
1441                         useInPlaceSort = !useInPlaceSort;
1442
1443         }
1444     return code;
1445 }
1446
1447 void CxCore_SortTest::run_func()
1448 {
1449         //test_mat[OUTPUT][0] is sorted matrix
1450         //test_mat[OUTPUT][1] is index matrix
1451         if (useInPlaceSort)
1452         {
1453                 cvConvert(&test_mat[INPUT][0], &test_mat[OUTPUT][0]);
1454                 if (useIndexMatrix)
1455                         cvSort(&(test_mat[OUTPUT][0]),&(test_mat[OUTPUT][0]),&(test_mat[OUTPUT][1]),flags);
1456                 else
1457                 {
1458                         cvSort(&(test_mat[OUTPUT][0]),&(test_mat[OUTPUT][0]),0,flags);
1459                 }
1460
1461         }
1462         else
1463         {
1464                 if (useIndexMatrix)
1465                         cvSort(&(test_mat[INPUT][0]),&(test_mat[OUTPUT][0]),&(test_mat[OUTPUT][1]),flags);
1466                 else
1467                 {
1468                         cvSort(&(test_mat[INPUT][0]),&(test_mat[OUTPUT][0]),0,flags);
1469                 }
1470         }
1471 }
1472
1473 int CxCore_SortTest::compareIndexes (const void * a, const void * b)
1474 {
1475         double zero = 1e-30;
1476         double res=(**((double**)a)-**((double**)b));
1477         return res<-zero?-1:(res>zero?1:0);
1478 }
1479 int CxCore_SortTest::compare (const void * a, const void * b)
1480 {
1481         return *((int*)a)-*((int*)b);
1482 }
1483
1484 void CxCore_SortTest::prepare_to_validation(int)
1485 {
1486         /*Creating matrixes copies to work with*/
1487         CvMat* ref_indexes = cvCreateMat(test_mat[REF_OUTPUT][1].rows, test_mat[REF_OUTPUT][1].cols, CV_32SC1); 
1488         CvMat* indexes = cvCreateMat(test_mat[OUTPUT][1].rows, test_mat[OUTPUT][1].cols, CV_32SC1); 
1489         CvMat* ref_output = cvCreateMat(test_mat[OUTPUT][0].rows, test_mat[OUTPUT][0].cols,CV_64F); 
1490         
1491         /*Copying data*/
1492         cvConvert(&test_mat[REF_OUTPUT][1], ref_indexes);
1493         cvConvert(&test_mat[OUTPUT][1], indexes);
1494
1495         /*Following block generates REF_OUTPUT indexes matrix*/
1496         if ((flags == (CV_SORT_EVERY_ROW+CV_SORT_ASCENDING)) ||(flags == (CV_SORT_EVERY_ROW+CV_SORT_DESCENDING)))
1497         for (int i=0;i<test_mat[REF_OUTPUT][1].rows;i++)
1498                 for (int j=0;j<test_mat[REF_OUTPUT][1].cols;j++)
1499                         ref_indexes->data.i[ref_indexes->cols*i + j]=j;
1500         else 
1501         for (int i=0;i<test_mat[REF_OUTPUT][1].rows;i++)
1502                 for (int j=0;j<test_mat[REF_OUTPUT][1].cols;j++)
1503                         ref_indexes->data.i[ref_indexes->cols*i + j]=i;
1504         cvConvert(ref_indexes, &test_mat[REF_OUTPUT][1]);
1505         /*End of block*/
1506
1507         /* Matrix User's Sorting Algorithm */
1508         int order = -1; // order of sorting (ASCENDING or DESCENDING)
1509         //// Following to variables are for sorting rows or cols in one block without any conditions (if statements)
1510         short rowsSort=0;
1511         short colsSort=0;
1512         if ((flags == CV_SORT_EVERY_ROW+CV_SORT_ASCENDING)||(flags == CV_SORT_EVERY_COLUMN+CV_SORT_ASCENDING)) order=1;
1513         if ((flags == CV_SORT_EVERY_ROW+CV_SORT_ASCENDING)||(flags == CV_SORT_EVERY_ROW+CV_SORT_DESCENDING)) rowsSort=1;
1514         else colsSort=1;
1515         int i,j;
1516         
1517         // For accessing [i,j] element using index matrix we can use following formula
1518         // input->data.db[(input->cols*i+ref_indexes->cols*i+j)*rowsSort+(cols*(ref_indexes->cols*i+j)+j)*colsSort];
1519
1520     if ((flags == CV_SORT_EVERY_ROW+CV_SORT_ASCENDING)||(flags == CV_SORT_EVERY_ROW+CV_SORT_DESCENDING))
1521         {
1522                 double** row = new double*[input->cols];
1523                 for (i=0;i<input->rows; i++)
1524                 {
1525                         for (int j=0;j<input->cols;j++)
1526                                 row[j]=&(input->data.db[(input->cols*i+j)]);
1527                         qsort(row,input->cols,sizeof(row[0]),&CxCore_SortTest::compareIndexes);
1528                         for (int j=0;j<ref_indexes->cols;j++)
1529                         {
1530                                 if (order==1)
1531                                         ref_indexes->data.i[ref_indexes->cols*i+j]=(int)(row[j]-&(input->data.db[input->cols*i]));
1532                                 else
1533                                         ref_indexes->data.i[ref_indexes->cols*(i+1)-1-j]=(int)(row[j]-&(input->data.db[input->cols*i]));
1534                         }
1535                 }
1536                 delete[] row;
1537         }
1538         else
1539         {
1540                 double** col = new double*[input->rows];
1541                 for (j=0;j<input->cols; j++)
1542                 {
1543                         for (int i=0;i<input->rows;i++)
1544                                 col[i]=&(input->data.db[(input->cols*i+j)]);
1545                         qsort(col,input->rows,sizeof(col[0]),&CxCore_SortTest::compareIndexes);
1546                         for (int i=0;i<ref_indexes->rows;i++)
1547                         {
1548                                 if (order==1)
1549                                         ref_indexes->data.i[ref_indexes->cols*i+j]=(int)((col[i]-&(input->data.db[j]))/(ref_output->cols));
1550                                 else
1551                                         ref_indexes->data.i[ref_indexes->cols*(ref_indexes->rows-1-i)+j]=(int)(col[i]-&(input->data.db[j]))/(ref_output->cols);
1552                         }
1553                 }
1554                 delete[] col;
1555         }
1556
1557         /*End of Sort*/
1558
1559         int n;
1560         for (i=0;i<input->rows;i++)
1561                 for (j=0;j<input->cols;j++)
1562                 {
1563                         n=(input->cols*i+ref_indexes->data.i[ref_indexes->cols*i+j])*rowsSort+
1564                         (input->cols*(ref_indexes->data.i[ref_indexes->cols*i+j])+j)*colsSort;
1565                         ref_output->data.db[ref_output->cols*i+j] = input->data.db[n];
1566                 }
1567
1568         if (useIndexMatrix)
1569         {
1570                 /* Comparing indexes matrixes */
1571                 if ((flags == CV_SORT_EVERY_ROW+CV_SORT_ASCENDING)||(flags == CV_SORT_EVERY_ROW+CV_SORT_DESCENDING))
1572                 {
1573                         int begin=0,end=0;
1574                         double temp;
1575                         for (i=0;i<indexes->rows;i++)
1576                         {
1577                                 for (j=0;j<indexes->cols-1;j++)
1578                                         if (ref_output->data.db[ref_output->cols*i+j]==ref_output->data.db[ref_output->cols*i+j+1])
1579                                         {
1580                                                 temp=ref_output->data.db[ref_output->cols*i+j];
1581                                                 begin=j++;
1582                                                 while ((j<ref_output->cols)&&(temp==ref_output->data.db[ref_output->cols*i+j])) j++;
1583                                                 end=--j;
1584                                                 int* row = new int[end-begin+1];
1585                                                 int* row1 = new int[end-begin+1];
1586
1587                                                 for (int k=0;k<=end-begin;k++)
1588                                                 {
1589                                                         row[k]=ref_indexes->data.i[ref_indexes->cols*i+k+begin];
1590                                                         row1[k]=indexes->data.i[indexes->cols*i+k+begin];
1591                                                 }
1592                                                 qsort(row,end-begin+1,sizeof(row[0]),&CxCore_SortTest::compare);
1593                                                 qsort(row1,end-begin+1,sizeof(row1[0]),&CxCore_SortTest::compare);
1594                                                 for (int k=0;k<=end-begin;k++)
1595                                                 {
1596                                                         ref_indexes->data.i[ref_indexes->cols*i+k+begin]=row[k];
1597                                                         indexes->data.i[indexes->cols*i+k+begin]=row1[k];
1598                                                 }       
1599                                                 delete[] row;
1600                                                 delete[] row1;
1601                                         }
1602                         }
1603                 }
1604                 else
1605                 {
1606                         int begin=0,end=0;
1607                         double temp;
1608                         for (j=0;j<indexes->cols;j++)
1609                         {
1610                                 for (i=0;i<indexes->rows-1;i++)
1611                                         if (ref_output->data.db[ref_output->cols*i+j]==ref_output->data.db[ref_output->cols*(i+1)+j])
1612                                         {
1613                                                 temp=ref_output->data.db[ref_output->cols*i+j];
1614                                                 begin=i++;
1615                                                 while ((i<ref_output->rows)&&(temp==ref_output->data.db[ref_output->cols*i+j])) i++;
1616                                                 end=--i;
1617
1618                                                 int* col = new int[end-begin+1];
1619                                                 int* col1 = new int[end-begin+1];
1620
1621                                                 for (int k=0;k<=end-begin;k++)
1622                                                 {
1623                                                         col[k]=ref_indexes->data.i[ref_indexes->cols*(k+begin)+j];
1624                                                         col1[k]=indexes->data.i[indexes->cols*(k+begin)+j];
1625                                                 }
1626                                                 qsort(col,end-begin+1,sizeof(col[0]),&CxCore_SortTest::compare);
1627                                                 qsort(col1,end-begin+1,sizeof(col1[0]),&CxCore_SortTest::compare);
1628                                                 for (int k=0;k<=end-begin;k++)
1629                                                 {
1630                                                         ref_indexes->data.i[ref_indexes->cols*(k+begin)+j]=col[k];
1631                                                         indexes->data.i[indexes->cols*(k+begin)+j]=col1[k];
1632                                                 }       
1633                                                 delete[] col;
1634                                                 delete[] col1;
1635                                         }
1636                         }
1637                 }
1638         /* End of compare*/
1639         cvConvert(ref_indexes, &test_mat[REF_OUTPUT][1]);
1640         cvConvert(indexes, &test_mat[OUTPUT][1]);
1641         }
1642         else
1643         {
1644                 cvConvert(ref_indexes, &test_mat[REF_OUTPUT][1]);
1645                 cvConvert(ref_indexes, &test_mat[OUTPUT][1]);
1646         }
1647
1648         cvConvert(ref_output, &test_mat[REF_OUTPUT][0]);
1649
1650         /*releasing matrixes*/
1651         cvReleaseMat(&ref_output); 
1652         cvReleaseMat(&input); 
1653         cvReleaseMat(&indexes); 
1654         cvReleaseMat(&ref_indexes);   
1655 }
1656
1657 CxCore_SortTest sort_test;
1658
1659 ////////////////////////////// min/max  /////////////////////////////
1660
1661 class CxCore_MinMaxBaseTest : public CxCore_ArithmTest
1662 {
1663 public:
1664     CxCore_MinMaxBaseTest( const char* test_name, const char* test_funcs,
1665                            int _op_type, int _generate_scalars=0 );
1666 protected:
1667     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1668     double get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ );
1669     void prepare_to_validation( int /*test_case_idx*/ );
1670     int op_type;
1671 };
1672
1673 CxCore_MinMaxBaseTest::CxCore_MinMaxBaseTest( const char* test_name, const char* test_funcs,
1674                                               int _op_type, int _generate_scalars )
1675     : CxCore_ArithmTest( test_name, test_funcs, _generate_scalars, false, false ), op_type(_op_type)
1676 {
1677     if( _generate_scalars )
1678         test_array[INPUT].pop();
1679     default_timing_param_names = minmax_param_names;
1680 }
1681
1682 double CxCore_MinMaxBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1683 {
1684     return 0;
1685 }
1686
1687 void CxCore_MinMaxBaseTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1688 {
1689     int i, j;
1690     CxCore_ArithmTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1691     for( i = 0; i < max_arr; i++ )
1692     {
1693         int count = test_array[i].size();
1694         for( j = 0; j < count; j++ )
1695         {
1696             types[i][j] &= ~CV_MAT_CN_MASK;            
1697         }
1698     }
1699 }
1700
1701 void CxCore_MinMaxBaseTest::prepare_to_validation( int /*test_case_idx*/ )
1702 {
1703     if( !gen_scalars )
1704         cvTsMinMax( &test_mat[INPUT][0], &test_mat[INPUT][1],
1705                     &test_mat[REF_OUTPUT][0], op_type );
1706     else
1707         cvTsMinMaxS( &test_mat[INPUT][0], gamma.val[0],
1708                      &test_mat[REF_OUTPUT][0], op_type );
1709 }
1710
1711
1712 class CxCore_MinTest : public CxCore_MinMaxBaseTest
1713 {
1714 public:
1715     CxCore_MinTest();
1716 protected:
1717     void run_func();
1718 };
1719
1720
1721 CxCore_MinTest::CxCore_MinTest()
1722     : CxCore_MinMaxBaseTest( "arithm-min", "cvMin", CV_TS_MIN, 0 )
1723 {
1724 }
1725
1726 void CxCore_MinTest::run_func()
1727 {
1728     cvMin( test_array[INPUT][0], test_array[INPUT][1], test_array[OUTPUT][0] );
1729 }
1730
1731 CxCore_MinTest min_test;
1732
1733
1734 ////////////////////////////// max /////////////////////////////
1735
1736 class CxCore_MaxTest : public CxCore_MinMaxBaseTest
1737 {
1738 public:
1739     CxCore_MaxTest();
1740 protected:
1741     void run_func();
1742 };
1743
1744 CxCore_MaxTest::CxCore_MaxTest()
1745     : CxCore_MinMaxBaseTest( "arithm-max", "cvMax", CV_TS_MAX, 0 )
1746 {
1747 }
1748
1749 void CxCore_MaxTest::run_func()
1750 {
1751     cvMax( test_array[INPUT][0], test_array[INPUT][1], test_array[OUTPUT][0] );
1752 }
1753
1754 CxCore_MaxTest max_test;
1755
1756
1757 ////////////////////////////// mins /////////////////////////////
1758
1759 class CxCore_MinSTest : public CxCore_MinMaxBaseTest
1760 {
1761 public:
1762     CxCore_MinSTest();
1763 protected:
1764     void run_func();
1765 };
1766
1767 CxCore_MinSTest::CxCore_MinSTest()
1768     : CxCore_MinMaxBaseTest( "arithm-mins", "cvMinS", CV_TS_MIN, 4 )
1769 {
1770 }
1771
1772 void CxCore_MinSTest::run_func()
1773 {
1774     cvMinS( test_array[INPUT][0], gamma.val[0], test_array[OUTPUT][0] );
1775 }
1776
1777 CxCore_MinSTest mins_test;
1778
1779 ////////////////////////////// maxs /////////////////////////////
1780
1781 class CxCore_MaxSTest : public CxCore_MinMaxBaseTest
1782 {
1783 public:
1784     CxCore_MaxSTest();
1785 protected:
1786     void run_func();
1787 };
1788
1789 CxCore_MaxSTest::CxCore_MaxSTest()
1790     : CxCore_MinMaxBaseTest( "arithm-maxs", "cvMaxS", CV_TS_MAX, 4 )
1791 {
1792 }
1793
1794 void CxCore_MaxSTest::run_func()
1795 {
1796     cvMaxS( test_array[INPUT][0], gamma.val[0], test_array[OUTPUT][0] );
1797 }
1798
1799 CxCore_MaxSTest maxs_test;
1800
1801
1802 //////////////////////////////// logic ///////////////////////////////////////
1803
1804 class CxCore_LogicTestImpl : public CxCore_ArithmTestImpl
1805 {
1806 public:
1807     CxCore_LogicTestImpl( const char* test_name, const char* test_funcs, int _logic_op,
1808                       int _generate_scalars=0, bool _allow_mask=true );
1809 protected:
1810     void prepare_to_validation( int test_case_idx );
1811     int logic_op;
1812 };
1813
1814 CxCore_LogicTestImpl::CxCore_LogicTestImpl( const char* test_name, const char* test_funcs,
1815                             int _logic_op, int _generate_scalars, bool _allow_mask )
1816     : CxCore_ArithmTestImpl( test_name, test_funcs, _generate_scalars, _allow_mask, false ),
1817     logic_op(_logic_op)
1818 {
1819     if( _generate_scalars )
1820         test_array[INPUT].pop();
1821 }
1822
1823 void CxCore_LogicTestImpl::prepare_to_validation( int /*test_case_idx*/ )
1824 {
1825     int ref_output_idx = optional_mask ? REF_INPUT_OUTPUT : REF_OUTPUT;
1826     int output_idx = optional_mask ? INPUT_OUTPUT : OUTPUT;
1827     const CvMat* mask = test_array[MASK].size() > 0 && test_array[MASK][0] ? &test_mat[MASK][0] : 0;
1828     CvMat* dst = mask ? &test_mat[TEMP][0] : &test_mat[ref_output_idx][0];
1829     int i;
1830     if( test_array[INPUT].size() > 1 )
1831     {
1832         cvTsLogic( &test_mat[INPUT][0], &test_mat[INPUT][1], dst, logic_op );
1833     }
1834     else
1835     {
1836         cvTsLogicS( &test_mat[INPUT][0], gamma, dst, logic_op );
1837     }
1838     if( mask )
1839         cvTsCopy( dst, &test_mat[ref_output_idx][0], mask );
1840     
1841     for( i = 0; i < 2; i++ )
1842     {
1843         dst = i == 0 ? &test_mat[ref_output_idx][0] : &test_mat[output_idx][0];
1844
1845         if( CV_IS_MAT(dst) )
1846         {
1847             CvMat* mat = (CvMat*)dst;
1848             mat->cols *= CV_ELEM_SIZE(mat->type);
1849             mat->type = (mat->type & ~CV_MAT_TYPE_MASK) | CV_8UC1;
1850         }
1851         else
1852         {
1853             IplImage* img = (IplImage*)dst;
1854             int elem_size;
1855         
1856             assert( CV_IS_IMAGE(dst) );
1857             elem_size = ((img->depth & 255)>>3)*img->nChannels;
1858             img->width *= elem_size;
1859         
1860             if( img->roi )
1861             {
1862                 img->roi->xOffset *= elem_size;
1863                 img->roi->width *= elem_size;
1864             }
1865             img->depth = IPL_DEPTH_8U;
1866             img->nChannels = 1;
1867         }
1868     }
1869 }
1870
1871 CxCore_LogicTestImpl logic_test("logic", "", -1, 0, false );
1872
1873 class CxCore_LogicTest : public CxCore_LogicTestImpl
1874 {
1875 public:
1876     CxCore_LogicTest( const char* test_name, const char* test_funcs, int _logic_op,
1877                       int _generate_scalars=0, bool _allow_mask=true );
1878 };
1879
1880 CxCore_LogicTest::CxCore_LogicTest( const char* test_name, const char* test_funcs,
1881                             int _logic_op, int _generate_scalars, bool _allow_mask )
1882     : CxCore_LogicTestImpl( test_name, test_funcs, _logic_op, _generate_scalars, _allow_mask )
1883 {
1884     default_timing_param_names = optional_mask ? arithm_mask_param_names : arithm_param_names;
1885
1886     // inherit the default parameters from arithmerical test
1887     size_list = 0;
1888     whole_size_list = 0;
1889     depth_list = 0;
1890     cn_list = 0;
1891 }
1892
1893
1894 ///////////////////////// and //////////////////////////
1895
1896 class CxCore_AndTest : public CxCore_LogicTest
1897 {
1898 public:
1899     CxCore_AndTest();
1900 protected:
1901     void run_func();
1902 };
1903
1904 CxCore_AndTest::CxCore_AndTest()
1905     : CxCore_LogicTest( "logic-and", "cvAnd", CV_TS_LOGIC_AND )
1906 {
1907 }
1908
1909 void CxCore_AndTest::run_func()
1910 {
1911     cvAnd( test_array[INPUT][0], test_array[INPUT][1],
1912            test_array[INPUT_OUTPUT][0], test_array[MASK][0] );
1913 }
1914
1915 CxCore_AndTest and_test;
1916
1917
1918 class CxCore_AndSTest : public CxCore_LogicTest
1919 {
1920 public:
1921     CxCore_AndSTest();
1922 protected:
1923     void run_func();
1924 };
1925
1926 CxCore_AndSTest::CxCore_AndSTest()
1927     : CxCore_LogicTest( "logic-ands", "cvAndS", CV_TS_LOGIC_AND, 4 )
1928 {
1929 }
1930
1931 void CxCore_AndSTest::run_func()
1932 {
1933     cvAndS( test_array[INPUT][0], gamma,
1934             test_array[INPUT_OUTPUT][0], test_array[MASK][0] );
1935 }
1936
1937 CxCore_AndSTest ands_test;
1938
1939
1940 ///////////////////////// or /////////////////////////
1941
1942 class CxCore_OrTest : public CxCore_LogicTest
1943 {
1944 public:
1945     CxCore_OrTest();
1946 protected:
1947     void run_func();
1948 };
1949
1950 CxCore_OrTest::CxCore_OrTest()
1951     : CxCore_LogicTest( "logic-or", "cvOr", CV_TS_LOGIC_OR )
1952 {
1953 }
1954
1955 void CxCore_OrTest::run_func()
1956 {
1957     cvOr( test_array[INPUT][0], test_array[INPUT][1],
1958           test_array[INPUT_OUTPUT][0], test_array[MASK][0] );
1959 }
1960
1961 CxCore_OrTest or_test;
1962
1963
1964 class CxCore_OrSTest : public CxCore_LogicTest
1965 {
1966 public:
1967     CxCore_OrSTest();
1968 protected:
1969     void run_func();
1970 };
1971
1972 CxCore_OrSTest::CxCore_OrSTest()
1973     : CxCore_LogicTest( "logic-ors", "cvOrS", CV_TS_LOGIC_OR, 4 )
1974 {
1975 }
1976
1977 void CxCore_OrSTest::run_func()
1978 {
1979     cvOrS( test_array[INPUT][0], gamma,
1980            test_array[INPUT_OUTPUT][0], test_array[MASK][0] );
1981 }
1982
1983 CxCore_OrSTest ors_test;
1984
1985
1986 ////////////////////////// xor ////////////////////////////
1987
1988 class CxCore_XorTest : public CxCore_LogicTest
1989 {
1990 public:
1991     CxCore_XorTest();
1992 protected:
1993     void run_func();
1994 };
1995
1996 CxCore_XorTest::CxCore_XorTest()
1997     : CxCore_LogicTest( "logic-xor", "cvXor", CV_TS_LOGIC_XOR )
1998 {
1999 }
2000
2001 void CxCore_XorTest::run_func()
2002 {
2003     cvXor( test_array[INPUT][0], test_array[INPUT][1],
2004            test_array[INPUT_OUTPUT][0], test_array[MASK][0] );
2005 }
2006
2007 CxCore_XorTest xor_test;
2008
2009
2010 class CxCore_XorSTest : public CxCore_LogicTest
2011 {
2012 public:
2013     CxCore_XorSTest();
2014 protected:
2015     void run_func();
2016 };
2017
2018 CxCore_XorSTest::CxCore_XorSTest()
2019     : CxCore_LogicTest( "logic-xors", "cvXorS", CV_TS_LOGIC_XOR, 4 )
2020 {
2021 }
2022
2023 void CxCore_XorSTest::run_func()
2024 {
2025     cvXorS( test_array[INPUT][0], gamma,
2026             test_array[INPUT_OUTPUT][0], test_array[MASK][0] );
2027 }
2028
2029 CxCore_XorSTest xors_test;
2030
2031
2032 ////////////////////////// not ////////////////////////////
2033
2034 class CxCore_NotTest : public CxCore_LogicTest
2035 {
2036 public:
2037     CxCore_NotTest();
2038 protected:
2039     void run_func();
2040 };
2041
2042 CxCore_NotTest::CxCore_NotTest()
2043     : CxCore_LogicTest( "logic-not", "cvNot", CV_TS_LOGIC_NOT, 4, false )
2044 {
2045 }
2046
2047 void CxCore_NotTest::run_func()
2048 {
2049     cvNot( test_array[INPUT][0],
2050            test_array[OUTPUT][0] );
2051 }
2052
2053 CxCore_NotTest nots_test;
2054
2055 ///////////////////////// cmp //////////////////////////////
2056
2057 static int cmp_op_values[] = { CV_CMP_GE, CV_CMP_EQ, CV_CMP_NE, -1 };
2058
2059 class CxCore_CmpBaseTestImpl : public CxCore_ArithmTestImpl
2060 {
2061 public:
2062     CxCore_CmpBaseTestImpl( const char* test_name, const char* test_funcs,
2063                             int in_range, int _generate_scalars=0 );
2064 protected:
2065     double get_success_error_level( int test_case_idx, int i, int j );
2066     void get_test_array_types_and_sizes( int test_case_idx,
2067                                          CvSize** sizes, int** types );
2068     void get_timing_test_array_types_and_sizes( int test_case_idx, CvSize** sizes,
2069                             int** types, CvSize** whole_sizes, bool* are_images );
2070     void print_timing_params( int test_case_idx, char* ptr, int params_left );
2071     void prepare_to_validation( int test_case_idx );
2072     int write_default_params( CvFileStorage* fs );
2073     int in_range;
2074     int cmp_op;
2075     enum { CMP_OP_COUNT=6 };
2076     const char* cmp_op_strings[CMP_OP_COUNT];
2077 };
2078
2079 CxCore_CmpBaseTestImpl::CxCore_CmpBaseTestImpl( const char* test_name, const char* test_funcs,
2080                                         int _in_range, int _generate_scalars )
2081     : CxCore_ArithmTestImpl( test_name, test_funcs, _generate_scalars, 0, 0 ), in_range(_in_range)
2082 {
2083     static const char* cmp_param_names[] = { "size", "cmp_op", "depth", 0 };
2084     static const char* inrange_param_names[] = { "size", "channels", "depth", 0 };
2085
2086     if( in_range )
2087     {
2088         test_array[INPUT].push(NULL);
2089         test_array[TEMP].push(NULL);
2090         test_array[TEMP].push(NULL);
2091         if( !gen_scalars )
2092             test_array[TEMP].push(NULL);
2093     }
2094     if( gen_scalars )
2095         test_array[INPUT].pop();
2096
2097     default_timing_param_names = in_range == 1 ? inrange_param_names : cmp_param_names;
2098
2099     cmp_op_strings[CV_CMP_EQ] = "eq";
2100     cmp_op_strings[CV_CMP_LT] = "lt";
2101     cmp_op_strings[CV_CMP_LE] = "le";
2102     cmp_op_strings[CV_CMP_GE] = "ge";
2103     cmp_op_strings[CV_CMP_GT] = "gt";
2104     cmp_op_strings[CV_CMP_NE] = "ne";
2105
2106     cmp_op = -1;
2107 }
2108
2109 double CxCore_CmpBaseTestImpl::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
2110 {
2111     return 0;
2112 }
2113
2114
2115 void CxCore_CmpBaseTestImpl::get_test_array_types_and_sizes( int test_case_idx,
2116                                                     CvSize** sizes, int** types )
2117 {
2118     int j, count;
2119     CxCore_ArithmTestImpl::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2120     types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_8UC1;
2121     if( in_range == 0 )
2122     {
2123         // for cmp tests make all the input arrays single-channel
2124         count = test_array[INPUT].size();
2125         for( j = 0; j < count; j++ )
2126             types[INPUT][j] &= ~CV_MAT_CN_MASK;
2127
2128         cmp_op = cvTsRandInt(ts->get_rng()) % 6; // == > >= < <= !=
2129     }
2130     else if( in_range == 1 )
2131     {
2132         types[TEMP][0] = CV_8UC1;
2133         types[TEMP][1] &= ~CV_MAT_CN_MASK;
2134         if( !gen_scalars )
2135             types[TEMP][2] &= ~CV_MAT_CN_MASK;
2136     }
2137 }
2138
2139
2140 int CxCore_CmpBaseTestImpl::write_default_params( CvFileStorage* fs )
2141 {
2142     int code = CxCore_ArithmTestImpl::write_default_params(fs);
2143     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
2144         return code;
2145     if( in_range == 0 )
2146     {
2147         start_write_param( fs );
2148         int i;
2149         cvStartWriteStruct( fs, "cmp_op", CV_NODE_SEQ + CV_NODE_FLOW );
2150         for( i = 0; cmp_op_values[i] >= 0; i++ )
2151             cvWriteString( fs, 0, cmp_op_strings[cmp_op_values[i]] );
2152         cvEndWriteStruct(fs);
2153     }
2154     return code;
2155 }
2156
2157
2158 void CxCore_CmpBaseTestImpl::get_timing_test_array_types_and_sizes( int test_case_idx,
2159                                                     CvSize** sizes, int** types,
2160                                                     CvSize** whole_sizes, bool* are_images )
2161 {
2162     CxCore_ArithmTestImpl::get_timing_test_array_types_and_sizes( test_case_idx,
2163                                             sizes, types, whole_sizes, are_images );
2164     types[OUTPUT][0] = CV_8UC1;
2165     if( in_range == 0 )
2166     {
2167         const char* cmp_op_str = cvReadString( find_timing_param( "cmp_op" ), "ge" );
2168         int i;
2169         cmp_op = CV_CMP_GE;
2170         for( i = 0; i < CMP_OP_COUNT; i++ )
2171             if( strcmp( cmp_op_str, cmp_op_strings[i] ) == 0 )
2172             {
2173                 cmp_op = i;
2174                 break;
2175             }
2176     }
2177 }
2178
2179
2180 void CxCore_CmpBaseTestImpl::print_timing_params( int test_case_idx, char* ptr, int params_left )
2181 {
2182     if( in_range == 0 )
2183     {
2184         sprintf( ptr, "%s,", cmp_op_strings[cmp_op] );
2185         ptr += strlen(ptr);
2186         params_left--;
2187     }
2188     CxCore_ArithmTestImpl::print_timing_params( test_case_idx, ptr, params_left );
2189 }
2190
2191
2192 void CxCore_CmpBaseTestImpl::prepare_to_validation( int /*test_case_idx*/ )
2193 {
2194     CvMat* dst = &test_mat[REF_OUTPUT][0];
2195     if( !in_range )
2196     {
2197         if( test_array[INPUT].size() > 1 )
2198         {
2199             cvTsCmp( &test_mat[INPUT][0], &test_mat[INPUT][1], dst, cmp_op );
2200         }
2201         else
2202         {
2203             cvTsCmpS( &test_mat[INPUT][0], gamma.val[0], dst, cmp_op );
2204         }
2205     }
2206     else
2207     {
2208         int el_type = CV_MAT_TYPE( test_mat[INPUT][0].type );
2209         int i, cn = CV_MAT_CN(el_type);
2210         CvMat* tdst = dst;
2211
2212         for( i = 0; i < cn*2; i++ )
2213         {
2214             int coi = i / 2, is_lower = (i % 2) == 0;
2215             int cmp_op = is_lower ? CV_CMP_GE : CV_CMP_LT;
2216             const CvMat* src = &test_mat[INPUT][0];
2217             const CvMat* lu = gen_scalars ? 0 : &test_mat[INPUT][is_lower?1:2];
2218             double luS = is_lower ? alpha.val[coi] : gamma.val[coi];
2219             
2220             if( cn > 1 )
2221             {
2222                 cvTsExtract( src, &test_mat[TEMP][1], coi );
2223                 src = &test_mat[TEMP][1];
2224
2225                 if( !gen_scalars )
2226                 {
2227                     cvTsExtract( lu, &test_mat[TEMP][2], coi );
2228                     lu = &test_mat[TEMP][2];
2229                 }
2230             }
2231
2232             if( !gen_scalars )
2233                 cvTsCmp( src, lu, tdst, cmp_op );
2234             else
2235                 cvTsCmpS( src, luS, tdst, cmp_op );
2236             if( i > 0 )
2237                 cvTsLogic( tdst, dst, dst, CV_TS_LOGIC_AND );
2238             tdst = &test_mat[TEMP][0];
2239         }
2240     }
2241 }
2242
2243
2244 CxCore_CmpBaseTestImpl cmpbase_test( "cmp", "", -1 );
2245
2246
2247 class CxCore_CmpBaseTest : public CxCore_CmpBaseTestImpl
2248 {
2249 public:
2250     CxCore_CmpBaseTest( const char* test_name, const char* test_funcs,
2251                         int in_range, int _generate_scalars=0 );
2252 };
2253
2254 CxCore_CmpBaseTest::CxCore_CmpBaseTest( const char* test_name, const char* test_funcs,
2255                                         int _in_range, int _generate_scalars )
2256     : CxCore_CmpBaseTestImpl( test_name, test_funcs, _in_range, _generate_scalars )
2257 {
2258     // inherit the default parameters from arithmerical test
2259     size_list = 0;
2260     depth_list = 0;
2261     cn_list = 0;
2262 }
2263
2264
2265 class CxCore_CmpTest : public CxCore_CmpBaseTest
2266 {
2267 public:
2268     CxCore_CmpTest();
2269 protected:
2270     void run_func();
2271 };
2272
2273 CxCore_CmpTest::CxCore_CmpTest()
2274     : CxCore_CmpBaseTest( "cmp-cmp", "cvCmp", 0, 0 )
2275 {
2276 }
2277
2278 void CxCore_CmpTest::run_func()
2279 {
2280     cvCmp( test_array[INPUT][0], test_array[INPUT][1],
2281            test_array[OUTPUT][0], cmp_op );
2282 }
2283
2284 CxCore_CmpTest cmp_test;
2285
2286
2287 class CxCore_CmpSTest : public CxCore_CmpBaseTest
2288 {
2289 public:
2290     CxCore_CmpSTest();
2291 protected:
2292     void run_func();
2293 };
2294
2295 CxCore_CmpSTest::CxCore_CmpSTest()
2296     : CxCore_CmpBaseTest( "cmp-cmps", "cvCmpS", 0, 4 )
2297 {
2298 }
2299
2300 void CxCore_CmpSTest::run_func()
2301 {
2302     cvCmpS( test_array[INPUT][0], gamma.val[0],
2303             test_array[OUTPUT][0], cmp_op );
2304 }
2305
2306 CxCore_CmpSTest cmps_test;
2307
2308
2309 class CxCore_InRangeTest : public CxCore_CmpBaseTest
2310 {
2311 public:
2312     CxCore_InRangeTest();
2313 protected:
2314     void run_func();
2315 };
2316
2317 CxCore_InRangeTest::CxCore_InRangeTest()
2318     : CxCore_CmpBaseTest( "cmp-inrange", "cvInRange", 1, 0 )
2319 {
2320 }
2321
2322 void CxCore_InRangeTest::run_func()
2323 {
2324     cvInRange( test_array[INPUT][0], test_array[INPUT][1],
2325                test_array[INPUT][2], test_array[OUTPUT][0] );
2326 }
2327
2328 CxCore_InRangeTest inrange_test;
2329
2330
2331 class CxCore_InRangeSTest : public CxCore_CmpBaseTest
2332 {
2333 public:
2334     CxCore_InRangeSTest();
2335 protected:
2336     void run_func();
2337 };
2338
2339 CxCore_InRangeSTest::CxCore_InRangeSTest()
2340     : CxCore_CmpBaseTest( "cmp-inranges", "cvInRangeS", 1, 5 )
2341 {
2342 }
2343
2344 void CxCore_InRangeSTest::run_func()
2345 {
2346     cvInRangeS( test_array[INPUT][0], alpha, gamma, test_array[OUTPUT][0] );
2347 }
2348
2349 CxCore_InRangeSTest inranges_test;
2350
2351
2352 /////////////////////////// convertscale[abs] ////////////////////////////////////////
2353
2354 static const char* cvt_param_names[] = { "size", "scale", "dst_depth", "depth", 0 };
2355 static const char* cvt_abs_param_names[] = { "size", "depth", 0 };
2356 static const int cvt_scale_flags[] = { 0, 1 };
2357
2358 class CxCore_CvtBaseTestImpl : public CxCore_ArithmTestImpl
2359 {
2360 public:
2361     CxCore_CvtBaseTestImpl( const char* test_name, const char* test_funcs, bool calc_abs );
2362 protected:
2363     void get_test_array_types_and_sizes( int test_case_idx,
2364                                          CvSize** sizes, int** types );
2365     void get_timing_test_array_types_and_sizes( int test_case_idx,
2366                                         CvSize** sizes, int** types,
2367                                         CvSize** whole_sizes, bool *are_images );
2368     double get_success_error_level( int test_case_idx, int i, int j );
2369
2370     int prepare_test_case( int test_case_idx );
2371     void print_timing_params( int test_case_idx, char* ptr, int params_left );
2372     int write_default_params( CvFileStorage* fs );
2373
2374     void prepare_to_validation( int test_case_idx );
2375 };
2376
2377
2378 CxCore_CvtBaseTestImpl::CxCore_CvtBaseTestImpl( const char* test_name,
2379                                                 const char* test_funcs,
2380                                                 bool _calc_abs )
2381     : CxCore_ArithmTestImpl( test_name, test_funcs, 5, false, _calc_abs )
2382 {
2383     test_array[INPUT].pop();
2384     default_timing_param_names = 0;
2385     cn_list = 0;
2386 }
2387
2388
2389 // unlike many other arithmetic functions, conversion operations support 8s type,
2390 // also, for cvCvtScale output array depth may be arbitrary and
2391 // for cvCvtScaleAbs output depth = CV_8U
2392 void CxCore_CvtBaseTestImpl::get_test_array_types_and_sizes( int test_case_idx,
2393                                                 CvSize** sizes, int** types )
2394 {
2395     CxCore_ArithmTestImpl::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2396     CvRNG* rng = ts->get_rng();
2397     int depth = CV_8U, rbits;
2398     types[INPUT][0] = (types[INPUT][0] & ~CV_MAT_DEPTH_MASK)|
2399                     cvTsRandInt(rng)%(CV_64F+1);
2400     if( !calc_abs )
2401         depth = cvTsRandInt(rng) % (CV_64F+1);
2402     types[OUTPUT][0] = types[REF_OUTPUT][0] = (types[INPUT][0] & ~CV_MAT_DEPTH_MASK)|depth;
2403
2404     rbits = cvTsRandInt(rng);
2405     // check special cases: shift=0 and/or scale=1.
2406     if( (rbits & 3) == 0 )
2407         gamma.val[0] = 0;
2408     if( (rbits & 12) == 0 )
2409         alpha.val[0] = 1;
2410 }
2411
2412
2413 double CxCore_CvtBaseTestImpl::get_success_error_level( int, int, int )
2414 {
2415     if( CV_MAT_DEPTH(test_mat[OUTPUT][0].type) <= CV_32S )
2416         return alpha.val[0] != cvRound(alpha.val[0]) ||
2417                beta.val[0] != cvRound(beta.val[0]) ||
2418                gamma.val[0] != cvRound(gamma.val[0]);
2419
2420     CvScalar l1, h1, l2, h2;
2421     int stype = CV_MAT_TYPE(test_mat[INPUT][0].type);
2422     int dtype = CV_MAT_TYPE(test_mat[OUTPUT][0].type);
2423     get_minmax_bounds( INPUT, 0, stype, &l1, &h1 );
2424     get_minmax_bounds( OUTPUT, 0, dtype, &l2, &h2 );
2425     double maxval = 0;
2426     for( int i = 0; i < 4; i++ )
2427     {
2428         maxval = MAX(maxval, fabs(l1.val[i]));
2429         maxval = MAX(maxval, fabs(h1.val[i]));
2430         maxval = MAX(maxval, fabs(l2.val[i]));
2431         maxval = MAX(maxval, fabs(h2.val[i]));
2432     }
2433     double max_err = (CV_MAT_DEPTH(stype) == CV_64F || CV_MAT_DEPTH(dtype) == CV_64F ?
2434         DBL_EPSILON : FLT_EPSILON)*maxval*MAX(fabs(alpha.val[0]), 1.)*100;
2435     return max_err;
2436 }
2437
2438
2439 void CxCore_CvtBaseTestImpl::get_timing_test_array_types_and_sizes( int test_case_idx,
2440                     CvSize** sizes, int** types, CvSize** whole_sizes, bool* are_images )
2441 {
2442     CxCore_ArithmTestImpl::get_timing_test_array_types_and_sizes( test_case_idx,
2443                                     sizes, types, whole_sizes, are_images );
2444     bool scale = true;
2445     int dst_depth = CV_8U;
2446     int cn = CV_MAT_CN(types[INPUT][0]);
2447     if( !calc_abs )
2448     {
2449         scale = cvReadInt( find_timing_param( "scale" ), 1 ) != 0;
2450         dst_depth = cvTsTypeByName( cvReadString(find_timing_param( "dst_depth" ), "8u") );
2451     }
2452
2453     types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(dst_depth, cn);
2454
2455     if( scale )
2456     {
2457         alpha.val[0] = 2.1;
2458         gamma.val[0] = -100.;
2459     }
2460     else
2461     {
2462         alpha.val[0] = 1.;
2463         gamma.val[0] = 0.;
2464     }
2465 }
2466
2467
2468 int CxCore_CvtBaseTestImpl::prepare_test_case( int test_case_idx )
2469 {
2470     int code = CxCore_ArithmTestImpl::prepare_test_case( test_case_idx );
2471
2472     if( code > 0 && ts->get_testing_mode() == CvTS::TIMING_MODE )
2473     {
2474         if( CV_ARE_TYPES_EQ( &test_mat[INPUT][0], &test_mat[OUTPUT][0] ) &&
2475             !calc_abs && alpha.val[0] == 1 && gamma.val[0] == 0 )
2476             code = 0; // skip the case when no any transformation is done
2477     }
2478
2479     return code;
2480 }
2481
2482
2483 void CxCore_CvtBaseTestImpl::print_timing_params( int test_case_idx, char* ptr, int params_left )
2484 {
2485     sprintf( ptr, "%s,", alpha.val[0] == 1. && gamma.val[0] == 0. ? "no_scale" : "scale" );
2486     ptr += strlen(ptr);
2487     params_left--;
2488     CxCore_ArithmTestImpl::print_timing_params( test_case_idx, ptr, params_left );
2489 }
2490
2491
2492 int CxCore_CvtBaseTestImpl::write_default_params( CvFileStorage* fs )
2493 {
2494     int i, code = CxCore_ArithmTestImpl::write_default_params(fs);
2495     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
2496         return code;
2497     if( !calc_abs )
2498     {
2499         start_write_param( fs );
2500         cvStartWriteStruct( fs, "dst_depth", CV_NODE_SEQ + CV_NODE_FLOW );
2501         for( i = 0; arithm_depths[i] >= 0; i++ )
2502             cvWriteString( fs, 0, cvTsGetTypeName(arithm_depths[i]) );
2503         cvEndWriteStruct(fs);
2504         write_int_list( fs, "scale", cvt_scale_flags, CV_DIM(cvt_scale_flags) );
2505     }
2506     return code;
2507 }
2508
2509
2510 void CxCore_CvtBaseTestImpl::prepare_to_validation( int /*test_case_idx*/ )
2511 {
2512     cvTsAdd( &test_mat[INPUT][0], cvScalarAll(alpha.val[0]), 0, beta,
2513              cvScalarAll(gamma.val[0]), &test_mat[REF_OUTPUT][0], calc_abs );
2514 }
2515
2516 CxCore_CvtBaseTestImpl cvt_test( "cvt", "", true );
2517
2518
2519 class CxCore_CvtBaseTest : public CxCore_CvtBaseTestImpl
2520 {
2521 public:
2522     CxCore_CvtBaseTest( const char* test_name, const char* test_funcs, bool calc_abs );
2523 };
2524
2525
2526 CxCore_CvtBaseTest::CxCore_CvtBaseTest( const char* test_name, const char* test_funcs, bool _calc_abs )
2527     : CxCore_CvtBaseTestImpl( test_name, test_funcs, _calc_abs )
2528 {
2529     // inherit the default parameters from arithmerical test
2530     size_list = 0;
2531     whole_size_list = 0;
2532     depth_list = 0;
2533     cn_list = 0;
2534 }
2535
2536
2537 class CxCore_CvtScaleTest : public CxCore_CvtBaseTest
2538 {
2539 public:
2540     CxCore_CvtScaleTest();
2541 protected:
2542     void run_func();
2543 };
2544
2545 CxCore_CvtScaleTest::CxCore_CvtScaleTest()
2546     : CxCore_CvtBaseTest( "cvt-scale", "cvCvtScale", false )
2547 {
2548     default_timing_param_names = cvt_param_names;
2549 }
2550
2551 void CxCore_CvtScaleTest::run_func()
2552 {
2553     cvConvertScale( test_array[INPUT][0], test_array[OUTPUT][0],
2554                     alpha.val[0], gamma.val[0] );
2555 }
2556
2557 CxCore_CvtScaleTest cvtscale_test;
2558
2559
2560 class CxCore_CvtScaleAbsTest : public CxCore_CvtBaseTest
2561 {
2562 public:
2563     CxCore_CvtScaleAbsTest();
2564 protected:
2565     void run_func();
2566 };
2567
2568 CxCore_CvtScaleAbsTest::CxCore_CvtScaleAbsTest()
2569     : CxCore_CvtBaseTest( "cvt-scaleabs", "cvCvtScaleAbs", true )
2570 {
2571     default_timing_param_names = cvt_abs_param_names;
2572 }
2573
2574 void CxCore_CvtScaleAbsTest::run_func()
2575 {
2576     cvConvertScaleAbs( test_array[INPUT][0], test_array[OUTPUT][0],
2577                        alpha.val[0], gamma.val[0] );
2578 }
2579
2580 CxCore_CvtScaleAbsTest cvtscaleabs_test;
2581
2582
2583 /////////////////////////////// statistics //////////////////////////////////
2584
2585 static const char* stat_param_names[] = { "size", "coi", "channels", "depth", 0 };
2586 static const char* stat_mask_param_names[] = { "size", "coi", "channels", "depth", "use_mask", 0 };
2587 static const char* stat_single_param_names[] = { "size", "channels", "depth", 0 };
2588 static const char* stat_single_mask_param_names[] = { "size", "channels", "depth", "use_mask", 0 };
2589 static const char* stat_coi_modes[] = { "all", "single", 0 };
2590
2591 class CxCore_StatTestImpl : public CvArrTest
2592 {
2593 public:
2594     CxCore_StatTestImpl( const char* test_name, const char* test_funcs,
2595                      int _output_count, bool _single_channel,
2596                      bool _allow_mask=true, bool _is_binary=false );
2597 protected:
2598     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
2599     void get_timing_test_array_types_and_sizes( int test_case_idx,
2600                                                 CvSize** sizes, int** types,
2601                                                 CvSize** whole_sizes, bool* are_images );
2602     void print_timing_params( int test_case_idx, char* ptr, int params_left );
2603     int write_default_params( CvFileStorage* fs );    
2604     int prepare_test_case( int test_case_idx );
2605     double get_success_error_level( int test_case_idx, int i, int j );
2606
2607     int coi;
2608     int output_count;
2609     bool single_channel;
2610     bool is_binary;
2611 };
2612
2613
2614 CxCore_StatTestImpl::CxCore_StatTestImpl( const char* test_name,
2615                         const char* test_funcs, int _output_count,
2616                         bool _single_channel, bool _allow_mask, bool _is_binary )
2617     : CvArrTest( test_name, test_funcs, "" ), output_count(_output_count),
2618     single_channel(_single_channel), is_binary(_is_binary)
2619 {
2620     test_array[INPUT].push(NULL);
2621     if( is_binary )
2622         test_array[INPUT].push(NULL);
2623     optional_mask = _allow_mask;
2624     if( optional_mask )
2625         test_array[MASK].push(NULL);
2626     test_array[OUTPUT].push(NULL);
2627     test_array[REF_OUTPUT].push(NULL);
2628     coi = 0;
2629
2630     size_list = arithm_sizes;
2631     whole_size_list = arithm_whole_sizes;
2632     depth_list = arithm_depths;
2633     cn_list = arithm_channels;
2634 }
2635
2636
2637 void CxCore_StatTestImpl::get_test_array_types_and_sizes( int test_case_idx,
2638                                             CvSize** sizes, int** types )
2639 {
2640     CvRNG* rng = ts->get_rng();
2641     int depth = cvTsRandInt(rng)%(CV_64F+1);
2642     int cn = cvTsRandInt(rng) % 4 + 1;
2643     int j, count = test_array[INPUT].size();
2644     
2645     CvArrTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2646     depth += depth == CV_8S;
2647
2648     for( j = 0; j < count; j++ )
2649         types[INPUT][j] = CV_MAKETYPE(depth, cn);
2650
2651     // regardless of the test case, the output is always a fixed-size tuple of numbers
2652     sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize( output_count, 1 );
2653     types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;
2654
2655     coi = 0;
2656     cvmat_allowed = true;
2657     if( cn > 1 && (single_channel || (cvTsRandInt(rng) & 3) == 0) )
2658     {
2659         coi = cvTsRandInt(rng) % cn + 1;
2660         cvmat_allowed = false;
2661     }
2662 }
2663
2664
2665 void CxCore_StatTestImpl::get_timing_test_array_types_and_sizes( int test_case_idx,
2666                 CvSize** sizes, int** types, CvSize** whole_sizes, bool* are_images )
2667 {
2668     CvArrTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
2669                                                       whole_sizes, are_images );
2670     const char* coi_mode_str = cvReadString(find_timing_param("coi"), single_channel ? "single" : "all");
2671
2672     // regardless of the test case, the output is always a fixed-size tuple of numbers
2673     sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize( output_count, 1 );
2674     types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;
2675
2676     int cn = CV_MAT_CN(types[INPUT][0]);
2677     coi = 0;
2678     cvmat_allowed = true;
2679     if( strcmp( coi_mode_str, "single" ) == 0 )
2680     {
2681         CvRNG* rng = ts->get_rng();
2682         coi = cvTsRandInt(rng) % cn + 1;
2683         cvmat_allowed = false;
2684         *are_images = true;
2685     }
2686 }
2687
2688
2689 int CxCore_StatTestImpl::write_default_params( CvFileStorage* fs )
2690 {
2691     int code = CvArrTest::write_default_params(fs);
2692     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
2693         return code;
2694     if( !single_channel )
2695         write_string_list( fs, "coi", stat_coi_modes );
2696     return code;
2697 }
2698
2699
2700 int CxCore_StatTestImpl::prepare_test_case( int test_case_idx )
2701 {
2702     int code = CvArrTest::prepare_test_case( test_case_idx );
2703     
2704     if( coi && code > 0 )
2705     {
2706         int j, count = test_array[INPUT].size();
2707
2708         if( ts->get_testing_mode() == CvTS::TIMING_MODE && CV_MAT_CN(test_mat[INPUT][0].type) == 1 )
2709             return 0;
2710
2711         for( j = 0; j < count; j++ )
2712         {
2713             IplImage* img = (IplImage*)test_array[INPUT][j];
2714             if( img )
2715                 cvSetImageCOI( img, coi );
2716         }
2717     }
2718
2719     return code;
2720 }
2721
2722
2723 void CxCore_StatTestImpl::print_timing_params( int test_case_idx, char* ptr, int params_left )
2724 {
2725     sprintf( ptr, "%s,", coi > 0 || CV_MAT_CN(test_mat[INPUT][0].type) == 1 ? "single" : "all" );
2726     ptr += strlen(ptr);
2727     params_left--;
2728     CvArrTest::print_timing_params( test_case_idx, ptr, params_left );
2729 }
2730
2731
2732 double CxCore_StatTestImpl::get_success_error_level( int test_case_idx, int i, int j )
2733 {
2734     int depth = CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0]));
2735     if( depth == CV_32F )
2736         return FLT_EPSILON*1000;
2737     if( depth == CV_64F )
2738         return DBL_EPSILON*100000;
2739     else
2740         return CvArrTest::get_success_error_level( test_case_idx, i, j );
2741 }
2742
2743 CxCore_StatTestImpl stat_test( "stat", "", 0, true, false );
2744
2745
2746 class CxCore_StatTest : public CxCore_StatTestImpl
2747 {
2748 public:
2749     CxCore_StatTest( const char* test_name, const char* test_funcs,
2750                      int _output_count, bool _single_channel,
2751                      bool _allow_mask=1, bool _is_binary=0 );
2752 };
2753
2754 CxCore_StatTest::CxCore_StatTest( const char* test_name, const char* test_funcs,
2755                      int _output_count, bool _single_channel,
2756                      bool _allow_mask, bool _is_binary )
2757     : CxCore_StatTestImpl( test_name, test_funcs, _output_count, _single_channel, _allow_mask, _is_binary )
2758 {
2759     if( !single_channel )
2760         default_timing_param_names = optional_mask ? stat_single_mask_param_names : stat_single_param_names;
2761     else
2762         default_timing_param_names = optional_mask ? stat_mask_param_names : stat_param_names;
2763     
2764     // inherit the default parameters from arithmerical test
2765     size_list = 0;
2766     whole_size_list = 0;
2767     depth_list = 0;
2768     cn_list = 0;
2769 }
2770
2771 ////////////////// sum /////////////////
2772 class CxCore_SumTest : public CxCore_StatTest
2773 {
2774 public:
2775     CxCore_SumTest();
2776 protected:
2777     void run_func();
2778     void prepare_to_validation( int test_case_idx );
2779     double get_success_error_level( int test_case_idx, int i, int j );
2780 };
2781
2782
2783 CxCore_SumTest::CxCore_SumTest()
2784     : CxCore_StatTest( "stat-sum", "cvSum", 4 /* CvScalar */, false, false, false )
2785 {
2786 }
2787
2788 double CxCore_SumTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
2789 {
2790     int depth = CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0]));
2791     if( depth == CV_32F )
2792         return FLT_EPSILON*1000;
2793     return DBL_EPSILON*100000;
2794 }
2795
2796
2797 void CxCore_SumTest::run_func()
2798 {
2799     *(CvScalar*)(test_mat[OUTPUT][0].data.db) = cvSum(test_array[INPUT][0]);
2800 }
2801
2802 void CxCore_SumTest::prepare_to_validation( int /*test_case_idx*/ )
2803 {
2804     CvScalar mean;
2805     int nonzero = cvTsMeanStdDevNonZero( &test_mat[INPUT][0], 0, &mean, 0, coi );
2806
2807     *(CvScalar*)(test_mat[REF_OUTPUT][0].data.db) = mean;
2808     mean = *(CvScalar*)(test_mat[OUTPUT][0].data.db);
2809
2810     mean.val[0] /= nonzero;
2811     mean.val[1] /= nonzero;
2812     mean.val[2] /= nonzero;
2813     mean.val[3] /= nonzero;
2814     *(CvScalar*)(test_mat[OUTPUT][0].data.db) = mean;
2815 }
2816
2817 CxCore_SumTest sum_test;
2818
2819
2820 ////////////////// nonzero /////////////////
2821 class CxCore_NonZeroTest : public CxCore_StatTest
2822 {
2823 public:
2824     CxCore_NonZeroTest();
2825 protected:
2826     void run_func();
2827     void prepare_to_validation( int test_case_idx );
2828     void get_test_array_types_and_sizes( int test_case_idx,
2829                                          CvSize** sizes, int** types );
2830 };
2831
2832
2833 CxCore_NonZeroTest::CxCore_NonZeroTest()
2834     : CxCore_StatTest( "stat-nonzero", "cvCountNonZero", 1 /* int */, true, false, false )
2835 {
2836     test_array[TEMP].push(NULL);
2837     test_array[TEMP].push(NULL);
2838 }
2839
2840 void CxCore_NonZeroTest::run_func()
2841 {
2842     test_mat[OUTPUT][0].data.db[0] = cvCountNonZero(test_array[INPUT][0]);
2843 }
2844
2845 void CxCore_NonZeroTest::get_test_array_types_and_sizes( int test_case_idx,
2846                                               CvSize** sizes, int** types )
2847 {
2848     CxCore_StatTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2849     types[TEMP][0] = CV_8UC1;
2850     if( CV_MAT_CN(types[INPUT][0]) > 1 )
2851         types[TEMP][1] = types[INPUT][0] & ~CV_MAT_CN_MASK;
2852     else
2853         sizes[TEMP][1] = cvSize(0,0);
2854 }
2855
2856
2857 void CxCore_NonZeroTest::prepare_to_validation( int /*test_case_idx*/ )
2858 {
2859     CvMat* plane = &test_mat[INPUT][0];
2860     if( CV_MAT_CN(plane->type) > 1 )
2861     {
2862         plane = &test_mat[TEMP][1];
2863         assert( coi > 0 );
2864         cvTsExtract( &test_mat[INPUT][0], plane, coi-1 );
2865     }
2866     cvTsCmpS( plane, 0, &test_mat[TEMP][0], CV_CMP_NE );
2867     int nonzero = cvTsMeanStdDevNonZero( &test_mat[INPUT][0], &test_mat[TEMP][0], 0, 0, coi );
2868     test_mat[REF_OUTPUT][0].data.db[0] = nonzero;
2869 }
2870
2871
2872 CxCore_NonZeroTest nonzero_test;
2873
2874
2875 /////////////////// mean //////////////////////
2876 class CxCore_MeanTest : public CxCore_StatTest
2877 {
2878 public:
2879     CxCore_MeanTest();
2880 protected:
2881     void run_func();
2882     void prepare_to_validation( int test_case_idx );
2883 };
2884
2885
2886 CxCore_MeanTest::CxCore_MeanTest()
2887     : CxCore_StatTest( "stat-mean", "cvAvg", 4 /* CvScalar */, false, true, false )
2888 {
2889 }
2890
2891 void CxCore_MeanTest::run_func()
2892 {
2893     *(CvScalar*)(test_mat[OUTPUT][0].data.db) =
2894         cvAvg(test_array[INPUT][0], test_array[MASK][0]);
2895 }
2896
2897 void CxCore_MeanTest::prepare_to_validation( int /*test_case_idx*/ )
2898 {
2899     CvScalar mean;
2900     cvTsMeanStdDevNonZero( &test_mat[INPUT][0],
2901         test_array[MASK][0] ? &test_mat[MASK][0] : 0,
2902         &mean, 0, coi );
2903     *(CvScalar*)(test_mat[REF_OUTPUT][0].data.db) = mean;
2904 }
2905
2906 CxCore_MeanTest mean_test;
2907
2908
2909 /////////////////// mean_stddev //////////////////////
2910 class CxCore_MeanStdDevTest : public CxCore_StatTest
2911 {
2912 public:
2913     CxCore_MeanStdDevTest();
2914 protected:
2915     void run_func();
2916     void prepare_to_validation( int test_case_idx );
2917     double get_success_error_level( int test_case_idx, int i, int j );
2918 };
2919
2920
2921 CxCore_MeanStdDevTest::CxCore_MeanStdDevTest()
2922     : CxCore_StatTest( "stat-mean_stddev", "cvAvgSdv", 8 /* CvScalar x 2 */, false, true, false )
2923 {
2924 }
2925
2926 void CxCore_MeanStdDevTest::run_func()
2927 {
2928     /*CvScalar s;
2929     CvRNG* rng = ts->get_rng();
2930     s.val[0] = cvTsRandReal(rng)*100. - 50.;
2931     s.val[1] = cvTsRandReal(rng)*100. - 50.;
2932     s.val[2] = cvTsRandReal(rng)*100. - 50.;
2933     s.val[3] = cvTsRandReal(rng)*100. - 50.;
2934     cvSet( &test_mat[INPUT][0], s );*/
2935     cvAvgSdv( test_array[INPUT][0],
2936               &((CvScalar*)(test_mat[OUTPUT][0].data.db))[0],
2937               &((CvScalar*)(test_mat[OUTPUT][0].data.db))[1],
2938               test_array[MASK][0] );
2939 }
2940
2941 double CxCore_MeanStdDevTest::get_success_error_level( int test_case_idx, int i, int j )
2942 {
2943     int depth = CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0]));
2944     if( depth < CV_64F && depth != CV_32S )
2945         return CxCore_StatTest::get_success_error_level( test_case_idx, i, j );
2946     return DBL_EPSILON*1e6;
2947 }
2948
2949 void CxCore_MeanStdDevTest::prepare_to_validation( int /*test_case_idx*/ )
2950 {
2951     CvScalar mean, stddev;
2952     int i;
2953     CvMat* output = &test_mat[OUTPUT][0];
2954     CvMat* ref_output = &test_mat[REF_OUTPUT][0];
2955     cvTsMeanStdDevNonZero( &test_mat[INPUT][0],
2956         test_array[MASK][0] ? &test_mat[MASK][0] : 0,
2957         &mean, &stddev, coi );
2958     ((CvScalar*)(ref_output->data.db))[0] = mean;
2959     ((CvScalar*)(ref_output->data.db))[1] = stddev;
2960     for( i = 0; i < 4; i++ )
2961     {
2962         output->data.db[i] *= output->data.db[i];
2963         output->data.db[i+4] = output->data.db[i+4]*output->data.db[i+4] + 1000;
2964         ref_output->data.db[i] *= ref_output->data.db[i];
2965         ref_output->data.db[i+4] = ref_output->data.db[i+4]*ref_output->data.db[i+4] + 1000;
2966     }
2967 }
2968
2969 CxCore_MeanStdDevTest mean_stddev_test;
2970
2971
2972 /////////////////// minmaxloc //////////////////////
2973 class CxCore_MinMaxLocTest : public CxCore_StatTest
2974 {
2975 public:
2976     CxCore_MinMaxLocTest();
2977 protected:
2978     void run_func();
2979     void prepare_to_validation( int test_case_idx );
2980 };
2981
2982
2983 CxCore_MinMaxLocTest::CxCore_MinMaxLocTest()
2984     : CxCore_StatTest( "stat-minmaxloc", "cvMinMaxLoc", 6 /* double x 2 + CvPoint x 2 */, true, true, false )
2985 {
2986 }
2987
2988 void CxCore_MinMaxLocTest::run_func()
2989 {
2990     CvPoint minloc = {0,0}, maxloc = {0,0};
2991     double* output = test_mat[OUTPUT][0].data.db;
2992
2993     cvMinMaxLoc( test_array[INPUT][0],
2994         output, output+1, &minloc, &maxloc,
2995         test_array[MASK][0] );
2996     output[2] = minloc.x;
2997     output[3] = minloc.y;
2998     output[4] = maxloc.x;
2999     output[5] = maxloc.y;
3000 }
3001
3002 void CxCore_MinMaxLocTest::prepare_to_validation( int /*test_case_idx*/ )
3003 {
3004     double minval = 0, maxval = 0;
3005     CvPoint minloc = {0,0}, maxloc = {0,0};
3006     double* ref_output = test_mat[REF_OUTPUT][0].data.db;
3007     cvTsMinMaxLoc( &test_mat[INPUT][0], test_array[MASK][0] ?
3008         &test_mat[MASK][0] : 0, &minval, &maxval, &minloc, &maxloc, coi );
3009     ref_output[0] = minval;
3010     ref_output[1] = maxval;
3011     ref_output[2] = minloc.x;
3012     ref_output[3] = minloc.y;
3013     ref_output[4] = maxloc.x;
3014     ref_output[5] = maxloc.y;
3015 }
3016
3017 CxCore_MinMaxLocTest minmaxloc_test;
3018
3019
3020 /////////////////// norm //////////////////////
3021
3022 static const char* stat_norm_param_names[] = { "size", "coi", "norm_type", "channels", "depth", "use_mask", 0 };
3023 static const char* stat_norm_type_names[] = { "Inf", "L1", "L2", "diff_Inf", "diff_L1", "diff_L2", 0 };
3024
3025 class CxCore_NormTest : public CxCore_StatTest
3026 {
3027 public:
3028     CxCore_NormTest();
3029 protected:
3030     void run_func();
3031     void prepare_to_validation( int test_case_idx );
3032     void get_test_array_types_and_sizes( int test_case_idx,
3033                                          CvSize** sizes, int** types );
3034     void get_timing_test_array_types_and_sizes( int /*test_case_idx*/,
3035         CvSize** sizes, int** types, CvSize** whole_sizes, bool *are_images );
3036     int prepare_test_case( int test_case_idx );
3037     void print_timing_params( int test_case_idx, char* ptr, int params_left );
3038     int write_default_params( CvFileStorage* fs );
3039     double get_success_error_level( int test_case_idx, int i, int j );
3040     int norm_type;
3041 };
3042
3043
3044 CxCore_NormTest::CxCore_NormTest()
3045     : CxCore_StatTest( "stat-norm", "cvNorm", 1 /* double */, false, true, true )
3046 {
3047     test_array[TEMP].push(NULL);
3048     default_timing_param_names = stat_norm_param_names;
3049 }
3050
3051
3052 double CxCore_NormTest::get_success_error_level( int test_case_idx, int i, int j )
3053 {
3054     int depth = CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0]));
3055     if( (depth == CV_16U || depth == CV_16S) /*&& (norm_type&3) != CV_C*/ )
3056         return 1e-4;
3057     else
3058         return CxCore_StatTest::get_success_error_level( test_case_idx, i, j );
3059 }
3060
3061
3062 void CxCore_NormTest::get_test_array_types_and_sizes( int test_case_idx,
3063                                                CvSize** sizes, int** types )
3064 {
3065     int intype;
3066     int norm_kind;
3067     CxCore_StatTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
3068     norm_type = cvTsRandInt(ts->get_rng()) % 3; // CV_C, CV_L1 or CV_L2
3069     norm_kind = cvTsRandInt(ts->get_rng()) % 3; // simple, difference or relative difference
3070     if( norm_kind == 0 )
3071         sizes[INPUT][1] = cvSize(0,0);
3072     norm_type = (1 << norm_type) | (norm_kind*8);
3073     intype = types[INPUT][0];
3074     if( CV_MAT_CN(intype) > 1 && coi == 0 )
3075         sizes[MASK][0] = cvSize(0,0);
3076     sizes[TEMP][0] = cvSize(0,0);
3077     if( (norm_type & (CV_DIFF|CV_RELATIVE)) && CV_MAT_DEPTH(intype) <= CV_32F )
3078     {
3079         sizes[TEMP][0] = sizes[INPUT][0];
3080         types[TEMP][0] = (intype & ~CV_MAT_DEPTH_MASK)|
3081             (CV_MAT_DEPTH(intype) < CV_32F ? CV_32S : CV_64F);
3082     }
3083 }
3084
3085
3086 void CxCore_NormTest::get_timing_test_array_types_and_sizes( int test_case_idx,
3087                                                     CvSize** sizes, int** types,
3088                                                     CvSize** whole_sizes, bool* are_images )
3089 {
3090     CxCore_StatTest::get_timing_test_array_types_and_sizes( test_case_idx,
3091                                     sizes, types, whole_sizes, are_images );
3092     const char* norm_type_str = cvReadString( find_timing_param( "norm_type" ), "L2" );
3093     bool diff = false;
3094     if( strncmp( norm_type_str, "diff_", 5 ) == 0 )
3095     {
3096         diff = true;
3097         norm_type_str += 5;
3098     }
3099     
3100     if( strcmp( norm_type_str, "L1" ) == 0 )
3101         norm_type = CV_L1;
3102     else if( strcmp( norm_type_str, "L2" ) == 0 )
3103         norm_type = CV_L2;
3104     else
3105         norm_type = CV_C;
3106
3107     if( diff )
3108         norm_type += CV_DIFF;
3109     else
3110         sizes[INPUT][1] = cvSize(0,0);
3111 }
3112
3113
3114 int CxCore_NormTest::prepare_test_case( int test_case_idx )
3115 {
3116     int code = CxCore_StatTest::prepare_test_case( test_case_idx );
3117     if( code > 0 && ts->get_testing_mode() == CvTS::TIMING_MODE )
3118     {
3119         // currently it is not supported
3120         if( test_array[MASK][0] && CV_MAT_CN(test_mat[INPUT][0].type) > 1 && coi == 0 )
3121             return 0;
3122     }
3123     return code;
3124 }
3125
3126
3127 int CxCore_NormTest::write_default_params( CvFileStorage* fs )
3128 {
3129     int code = CxCore_StatTest::write_default_params(fs);
3130     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
3131         return code;
3132     write_string_list( fs, "norm_type", stat_norm_type_names );
3133     return code;
3134 }
3135
3136
3137 void CxCore_NormTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
3138 {
3139     int nt = norm_type & CV_NORM_MASK;
3140     sprintf( ptr, "%s%s,", norm_type & CV_DIFF ? "diff_" : "",
3141              nt == CV_C ? "Inf" : nt == CV_L1 ? "L1" : "L2" );
3142     ptr += strlen(ptr);
3143     params_left--;
3144     CxCore_StatTest::print_timing_params( test_case_idx, ptr, params_left );
3145 }
3146
3147
3148 void CxCore_NormTest::run_func()
3149 {
3150     test_mat[OUTPUT][0].data.db[0] = cvNorm( test_array[INPUT][0],
3151             test_array[INPUT][1], norm_type, test_array[MASK][0] );
3152 }
3153
3154 void CxCore_NormTest::prepare_to_validation( int /*test_case_idx*/ )
3155 {
3156     double a_norm = 0, b_norm = 0;
3157     CvMat* a = &test_mat[INPUT][0];
3158     CvMat* b = &test_mat[INPUT][1];
3159     CvMat* mask = test_array[MASK][0] ? &test_mat[MASK][0] : 0;
3160     CvMat* diff = a;
3161
3162     if( norm_type & (CV_DIFF|CV_RELATIVE) )
3163     {
3164         diff = test_array[TEMP][0] ? &test_mat[TEMP][0] : a;
3165         cvTsAdd( a, cvScalarAll(1.), b, cvScalarAll(-1.),
3166                  cvScalarAll(0.), diff, 0 );
3167     }
3168     a_norm = cvTsNorm( diff, mask, norm_type & CV_NORM_MASK, coi );
3169     if( norm_type & CV_RELATIVE )
3170     {
3171         b_norm = cvTsNorm( b, mask, norm_type & CV_NORM_MASK, coi );
3172         a_norm /= (b_norm + DBL_EPSILON );
3173     }
3174     test_mat[REF_OUTPUT][0].data.db[0] = a_norm;
3175 }
3176
3177 CxCore_NormTest norm_test;
3178
3179 // TODO: repeat(?), reshape(?), lut
3180
3181 /* End of file. */