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