Update to 2.0.0 tree from current Fremantle build
[opencv] / tests / cv / src / ahistograms.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "cvtest.h"
43
44 class CV_BaseHistTest : public CvTest
45 {
46 public:
47     enum { MAX_HIST = 12 };
48
49     CV_BaseHistTest( const char* test_name, const char* test_funcs );
50     ~CV_BaseHistTest();
51     void clear();
52     int write_default_params(CvFileStorage* fs);
53
54 protected:
55     int read_params( CvFileStorage* fs );
56     void run_func(void);
57     int prepare_test_case( int test_case_idx );
58     int validate_test_results( int test_case_idx );
59     virtual void init_hist( int test_case_idx, int i );
60     
61     virtual void get_hist_params( int test_case_idx );
62     virtual float** get_hist_ranges( int test_case_idx );
63
64     int max_log_size;
65     int max_cdims;
66     int cdims;
67     int dims[CV_MAX_DIM];
68     int dims_sum[CV_MAX_DIM+1];
69     int total_size;
70     int hist_type;
71     int hist_count;
72     int uniform;
73     int gen_random_hist;
74     double gen_hist_max_val, gen_hist_sparse_nz_ratio;
75     
76     int init_ranges;
77     int img_type;
78     int img_max_log_size;
79     double low, high, range_delta;
80     CvSize img_size;
81
82     CvHistogram* hist[MAX_HIST];
83     float* _ranges;
84     float* ranges[CV_MAX_DIM];
85 };
86
87
88 CV_BaseHistTest::CV_BaseHistTest( const char* test_name, const char* test_funcs ):
89     CvTest( test_name, test_funcs )
90 {
91     int i;
92         
93     test_case_count = 100;
94     max_log_size = 20;
95     img_max_log_size = 8;
96     max_cdims = 6;
97     _ranges = 0;
98     hist_count = 1;
99     init_ranges = 0;
100     gen_random_hist = 0;
101     gen_hist_max_val = 100;
102
103     for( i = 0; i < MAX_HIST; i++ )
104         hist[i] = 0;
105
106     support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
107 }
108
109
110 CV_BaseHistTest::~CV_BaseHistTest()
111 {
112     clear();
113 }
114
115
116 void CV_BaseHistTest::clear()
117 {
118     int i;
119     CvTest::clear();
120     for( i = 0; i < MAX_HIST; i++ )
121         cvReleaseHist( &hist[i] );
122     delete[] _ranges;
123     _ranges = 0;
124 }
125
126
127 int CV_BaseHistTest::write_default_params( CvFileStorage* fs )
128 {
129     CvTest::write_default_params( fs );
130     if( ts->get_testing_mode() != CvTS::TIMING_MODE )
131     {
132         write_param( fs, "test_case_count", test_case_count );
133         write_param( fs, "max_log_size", max_log_size );
134         write_param( fs, "max_log_array_size", img_max_log_size );
135         write_param( fs, "max_dims", max_cdims );
136     }
137     return 0;
138 }
139
140
141 int CV_BaseHistTest::read_params( CvFileStorage* fs )
142 {
143     int code = CvTest::read_params( fs );
144     if( code < 0 )
145         return code;
146
147     test_case_count = cvReadInt( find_param( fs, "struct_count" ), test_case_count );
148     max_log_size = cvReadInt( find_param( fs, "max_log_size" ), max_log_size );
149     max_log_size = cvTsClipInt( max_log_size, 1, 20 );
150     img_max_log_size = cvReadInt( find_param( fs, "max_log_array_size" ), img_max_log_size );
151     img_max_log_size = cvTsClipInt( img_max_log_size, 1, 9 );
152     
153     max_cdims = cvReadInt( find_param( fs, "max_cdims" ), max_cdims );
154     max_cdims = cvTsClipInt( max_cdims, 1, 6 );
155
156     return 0;
157 }
158
159
160 void CV_BaseHistTest::get_hist_params( int /*test_case_idx*/ )
161 {
162     CvRNG* rng = ts->get_rng();
163     int i, max_dim_size, max_ni_dim_size = 31;
164     double hist_size;
165
166     cdims = cvTsRandInt(rng) % max_cdims + 1;
167     hist_size = exp(cvTsRandReal(rng)*max_log_size*CV_LOG2);
168     max_dim_size = cvRound(pow(hist_size,1./cdims));
169     total_size = 1;
170     uniform = cvTsRandInt(rng) % 2;
171     hist_type = cvTsRandInt(rng) % 2 ? CV_HIST_SPARSE : CV_HIST_ARRAY; 
172     
173     for( i = 0; i < cdims; i++ )
174     {
175         dims[i] = cvTsRandInt(rng) % (max_dim_size + 1) + 1;
176         if( !uniform )
177             dims[i] = MIN(dims[i], max_ni_dim_size);    
178         total_size *= dims[i];
179     }
180
181     img_type = cvTsRandInt(rng) % 2 ? CV_32F : CV_8U;
182     img_size.width = cvRound( exp(cvRandReal(rng) * img_max_log_size*CV_LOG2) );
183     img_size.height = cvRound( exp(cvRandReal(rng) * img_max_log_size*CV_LOG2) );
184
185     low = cvTsMinVal(img_type);
186     high = cvTsMaxVal(img_type);
187
188     range_delta = (cvTsRandInt(rng) % 2)*(high-low)*0.05;
189 }
190
191
192 float** CV_BaseHistTest::get_hist_ranges( int /*test_case_idx*/ )
193 {
194     double _low = low + range_delta, _high = high - range_delta;
195     
196     if( init_ranges )
197     {
198         int i;
199         dims_sum[0] = 0;
200         for( i = 0; i < cdims; i++ )
201             dims_sum[i+1] = dims_sum[i] + dims[i] + 1; 
202         
203         if( uniform )
204         {
205             _ranges = new float[cdims*2];
206             for( i = cdims-1; i >= 0; i-- )
207             {
208                 _ranges[i*2] = (float)_low;
209                 _ranges[i*2+1] = (float)_high;
210                 ranges[i] = _ranges + i*2;
211             }
212         }
213         else
214         {
215             _ranges = new float[dims_sum[cdims]];
216
217             for( i = 0; i < cdims; i++ )
218             {
219                 int j, n = dims[i], ofs = dims_sum[i];
220                 // generate logarithmic scale
221                 double delta, q, val;
222                 for( j = 0; j < 10; j++ )
223                 {
224                     q = 1. + (j+1)*0.1;
225                     if( (pow(q,(double)n)-1)/(q-1.) >= _high-_low )
226                         break;
227                 }
228                 
229                 if( j == 0 )
230                 {
231                     delta = (_high-_low)/n;
232                     q = 1.;
233                 }
234                 else
235                 {
236                     q = 1 + j*0.1;
237                     delta = cvFloor((_high-_low)*(q-1)/(pow(q,(double)n) - 1));
238                     delta = MAX(delta, 1.);
239                 } 
240                 val = _low;
241                 
242                 for( j = 0; j <= n; j++ )
243                 {
244                     _ranges[j+ofs] = (float)MIN(val,_high);
245                     val += delta;
246                     delta *= q;
247                 }
248                 ranges[i] = _ranges + ofs;
249             }
250         }
251         return ranges;
252     }
253
254     return 0;
255 }
256
257
258 void CV_BaseHistTest::init_hist( int /*test_case_idx*/, int hist_i )
259 {
260     if( gen_random_hist )
261     {
262         CvRNG* rng = ts->get_rng();
263         CvArr* h = hist[hist_i]->bins;
264         
265         if( hist_type == CV_HIST_ARRAY )
266         {
267             cvRandArr( rng, h, CV_RAND_UNI,
268                 cvScalarAll(0), cvScalarAll(gen_hist_max_val) );
269         }
270         else
271         {
272             int i, j, total_size = 1, nz_count;
273             int idx[CV_MAX_DIM];
274             for( i = 0; i < cdims; i++ )
275                 total_size *= dims[i];
276
277             nz_count = cvTsRandInt(rng) % MAX( total_size/4, 100 );
278             nz_count = MIN( nz_count, total_size );
279
280             // a zero number of non-zero elements should be allowed
281             for( i = 0; i < nz_count; i++ )
282             {
283                 for( j = 0; j < cdims; j++ )
284                     idx[j] = cvTsRandInt(rng) % dims[j];
285                 cvSetRealND( h, idx, cvTsRandReal(rng)*gen_hist_max_val );
286             }
287         }
288     }
289 }
290
291
292 int CV_BaseHistTest::prepare_test_case( int test_case_idx )
293 {
294     int i;
295     float** r;
296
297     clear();
298
299     CvTest::prepare_test_case( test_case_idx );
300     get_hist_params( test_case_idx );
301     r = get_hist_ranges( test_case_idx );
302
303     for( i = 0; i < hist_count; i++ )
304     {
305         hist[i] = cvCreateHist( cdims, dims, hist_type, r, uniform );
306         init_hist( test_case_idx, i );
307     }
308
309     return 1;
310 }
311
312
313 void CV_BaseHistTest::run_func(void)
314 {
315 }
316
317
318 int CV_BaseHistTest::validate_test_results( int /*test_case_idx*/ )
319 {
320     return 0;
321 }
322
323
324 CV_BaseHistTest hist_basetest( "hist", "" );
325
326
327
328 ////////////// testing operation for reading/writing individual histogram bins //////////////
329
330 class CV_QueryHistTest : public CV_BaseHistTest
331 {
332 public:
333     CV_QueryHistTest();
334     ~CV_QueryHistTest();
335     void clear();
336
337 protected:
338     void run_func(void);
339     int prepare_test_case( int test_case_idx );
340     int validate_test_results( int test_case_idx );
341     void init_hist( int test_case_idx, int i );
342     
343     CvMat* indices;
344     CvMat* values;
345     CvMat* values0;
346 };
347
348
349
350 CV_QueryHistTest::CV_QueryHistTest() : CV_BaseHistTest( "hist-query",
351     "cvGetReal1D, cvGetReal2D, cvGetReal3D, cvGetRealND, "
352     "cvPtr1D, cvPtr2D, cvPtr3D, cvPtrND, "
353     "cvSetReal1D, cvSetReal2D, cvSetReal3D, cvSetRealND" )
354 {
355     hist_count = 1;
356     indices = 0;
357     values = 0;
358     values0 = 0;
359 }
360
361
362 CV_QueryHistTest::~CV_QueryHistTest()
363 {
364     clear();
365 }
366
367
368 void CV_QueryHistTest::clear()
369 {
370     cvReleaseMat( &indices );
371     cvReleaseMat( &values );
372     cvReleaseMat( &values0 );
373     CV_BaseHistTest::clear();
374 }
375
376
377 void CV_QueryHistTest::init_hist( int /*test_case_idx*/, int i )
378 {
379     if( hist_type == CV_HIST_ARRAY )
380         cvZero( hist[i]->bins );
381 }
382
383
384 int CV_QueryHistTest::prepare_test_case( int test_case_idx )
385 {
386     int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
387
388     if( code > 0 )
389     {
390         int i, j, iters;
391         float default_value = 0.f;
392         CvRNG* rng = ts->get_rng();
393         CvMat* bit_mask = 0;
394         int* idx;
395
396         iters = (cvTsRandInt(rng) % MAX(total_size/10,100)) + 1;
397         iters = MIN( iters, total_size*9/10 + 1 );
398         
399         indices = cvCreateMat( 1, iters*cdims, CV_32S );
400         values = cvCreateMat( 1, iters, CV_32F );
401         values0 = cvCreateMat( 1, iters, CV_32F );
402         idx = indices->data.i;
403
404         //printf( "total_size = %d, cdims = %d, iters = %d\n", total_size, cdims, iters );
405
406         bit_mask = cvCreateMat( 1, (total_size + 7)/8, CV_8U );
407         cvZero( bit_mask );
408
409         #define GET_BIT(n) (bit_mask->data.ptr[(n)/8] & (1 << ((n)&7)))
410         #define SET_BIT(n) bit_mask->data.ptr[(n)/8] |= (1 << ((n)&7))
411
412         // set random histogram bins' values to the linear indices of the bins
413         for( i = 0; i < iters; i++ )
414         {
415             int lin_idx = 0;
416             for( j = 0; j < cdims; j++ )
417             {
418                 int t = cvTsRandInt(rng) % dims[j];
419                 idx[i*cdims + j] = t;
420                 lin_idx = lin_idx*dims[j] + t;
421             }
422
423             if( cvTsRandInt(rng) % 8 || GET_BIT(lin_idx) )
424             {
425                 values0->data.fl[i] = (float)(lin_idx+1);
426                 SET_BIT(lin_idx);
427             }
428             else
429                 // some histogram bins will not be initialized intentionally,
430                 // they should be equal to the default value
431                 values0->data.fl[i] = default_value;
432         }
433
434         // do the second pass to make values0 consistent with bit_mask
435         for( i = 0; i < iters; i++ )
436         {
437             int lin_idx = 0;
438             for( j = 0; j < cdims; j++ )
439                 lin_idx = lin_idx*dims[j] + idx[i*cdims + j];
440
441             if( GET_BIT(lin_idx) )
442                 values0->data.fl[i] = (float)(lin_idx+1);
443         }
444     
445         cvReleaseMat( &bit_mask );
446     }
447
448     return code;
449 }
450
451
452 void CV_QueryHistTest::run_func(void)
453 {
454     int i, iters = values->cols;
455     CvArr* h = hist[0]->bins;
456     const int* idx = indices->data.i;
457     float* val = values->data.fl;
458     float default_value = 0.f;
459
460     // stage 1: write bins
461     if( cdims == 1 )
462         for( i = 0; i < iters; i++ )
463         {
464             float v0 = values0->data.fl[i];
465             if( fabs(v0 - default_value) < FLT_EPSILON )
466                 continue;
467             if( !(i % 2) )
468             {
469                 if( !(i % 4) )
470                     cvSetReal1D( h, idx[i], v0 );
471                 else
472                     *(float*)cvPtr1D( h, idx[i] ) = v0;
473             }
474             else
475                 cvSetRealND( h, idx+i, v0 );
476         }
477     else if( cdims == 2 )
478         for( i = 0; i < iters; i++ )
479         {
480             float v0 = values0->data.fl[i];
481             if( fabs(v0 - default_value) < FLT_EPSILON )
482                 continue;
483             if( !(i % 2) )
484             {
485                 if( !(i % 4) )
486                     cvSetReal2D( h, idx[i*2], idx[i*2+1], v0 );
487                 else
488                     *(float*)cvPtr2D( h, idx[i*2], idx[i*2+1] ) = v0;
489             }
490             else
491                 cvSetRealND( h, idx+i*2, v0 );
492         }
493     else if( cdims == 3 )
494         for( i = 0; i < iters; i++ )
495         {
496             float v0 = values0->data.fl[i];
497             if( fabs(v0 - default_value) < FLT_EPSILON )
498                 continue;
499             if( !(i % 2) )
500             {
501                 if( !(i % 4) )
502                     cvSetReal3D( h, idx[i*3], idx[i*3+1], idx[i*3+2], v0 );
503                 else
504                     *(float*)cvPtr3D( h, idx[i*3], idx[i*3+1], idx[i*3+2] ) = v0;
505             }
506             else
507                 cvSetRealND( h, idx+i*3, v0 );
508         }
509     else
510         for( i = 0; i < iters; i++ )
511         {
512             float v0 = values0->data.fl[i];
513             if( fabs(v0 - default_value) < FLT_EPSILON )
514                 continue;
515             if( !(i % 2) )
516                 cvSetRealND( h, idx+i*cdims, v0 );
517             else
518                 *(float*)cvPtrND( h, idx+i*cdims ) = v0;
519         }
520
521     // stage 2: read bins
522     if( cdims == 1 )
523         for( i = 0; i < iters; i++ )
524         {
525             if( !(i % 2) )
526                 val[i] = *(float*)cvPtr1D( h, idx[i] );
527             else
528                 val[i] = (float)cvGetReal1D( h, idx[i] );
529         }
530     else if( cdims == 2 )
531         for( i = 0; i < iters; i++ )
532         {
533             if( !(i % 2) )
534                 val[i] = *(float*)cvPtr2D( h, idx[i*2], idx[i*2+1] );
535             else
536                 val[i] = (float)cvGetReal2D( h, idx[i*2], idx[i*2+1] );
537         }
538     else if( cdims == 3 )
539         for( i = 0; i < iters; i++ )
540         {
541             if( !(i % 2) )
542                 val[i] = *(float*)cvPtr3D( h, idx[i*3], idx[i*3+1], idx[i*3+2] );
543             else
544                 val[i] = (float)cvGetReal3D( h, idx[i*3], idx[i*3+1], idx[i*3+2] );
545         }
546     else
547         for( i = 0; i < iters; i++ )
548         {
549             if( !(i % 2) )
550                 val[i] = *(float*)cvPtrND( h, idx+i*cdims );
551             else
552                 val[i] = (float)cvGetRealND( h, idx+i*cdims );
553         }
554 }
555
556
557 int CV_QueryHistTest::validate_test_results( int /*test_case_idx*/ )
558 {
559     int code = CvTS::OK;
560     int i, j, iters = values->cols;
561     
562     for( i = 0; i < iters; i++ )
563     {
564         float v = values->data.fl[i], v0 = values0->data.fl[i];
565
566         if( cvIsNaN(v) || cvIsInf(v) )
567         {
568             ts->printf( CvTS::LOG, "The bin #%d has invalid value\n", i );
569             code = CvTS::FAIL_INVALID_OUTPUT;
570         }
571         else if( fabs(v - v0) > FLT_EPSILON )
572         {
573             ts->printf( CvTS::LOG, "The bin #%d = %g, while it should be %g\n", i, v, v0 );
574             code = CvTS::FAIL_BAD_ACCURACY;
575         }
576
577         if( code < 0 )
578         {
579             ts->printf( CvTS::LOG, "The bin index = (" );
580             for( j = 0; j < cdims; j++ )
581                 ts->printf( CvTS::LOG, "%d%s", indices->data.i[i*cdims + j],
582                                         j < cdims-1 ? ", " : ")\n" );
583             break;
584         }
585     }
586
587     if( code < 0 )
588         ts->set_failed_test_info( code );
589     return code;
590 }
591
592
593 CV_QueryHistTest hist_query_test;
594
595
596 ////////////// cvGetMinMaxHistValue //////////////
597
598 class CV_MinMaxHistTest : public CV_BaseHistTest
599 {
600 public:
601     CV_MinMaxHistTest();
602
603 protected:
604     void run_func(void);
605     void init_hist(int, int);
606     int validate_test_results( int test_case_idx );
607     int min_idx[CV_MAX_DIM], max_idx[CV_MAX_DIM];
608     float min_val, max_val;
609     int min_idx0[CV_MAX_DIM], max_idx0[CV_MAX_DIM];
610     float min_val0, max_val0;
611 };
612
613
614
615 CV_MinMaxHistTest::CV_MinMaxHistTest() :
616     CV_BaseHistTest( "hist-minmax", "cvGetMinMaxHistValue" )
617 {
618     hist_count = 1;
619     gen_random_hist = 1;
620 }
621
622
623 void CV_MinMaxHistTest::init_hist(int test_case_idx, int hist_i)
624 {
625     int i, eq = 1;
626     CvRNG* rng = ts->get_rng();
627     CV_BaseHistTest::init_hist( test_case_idx, hist_i );
628
629     for(;;)
630     {
631         for( i = 0; i < cdims; i++ )
632         {
633             min_idx0[i] = cvTsRandInt(rng) % dims[i];
634             max_idx0[i] = cvTsRandInt(rng) % dims[i];
635             eq &= min_idx0[i] == max_idx0[i];
636         }
637         if( !eq || total_size == 1 )
638             break;
639     }        
640
641     min_val0 = (float)(-cvTsRandReal(rng)*10 - FLT_EPSILON);
642     max_val0 = (float)(cvTsRandReal(rng)*10 + FLT_EPSILON + gen_hist_max_val);
643
644     if( total_size == 1 )
645         min_val0 = max_val0;
646
647     cvSetRealND( hist[0]->bins, min_idx0, min_val0 );
648     cvSetRealND( hist[0]->bins, max_idx0, max_val0 );
649 }
650
651
652 void CV_MinMaxHistTest::run_func(void)
653 {
654     cvGetMinMaxHistValue( hist[0], &min_val, &max_val, min_idx, max_idx );
655 }
656
657
658 int CV_MinMaxHistTest::validate_test_results( int /*test_case_idx*/ )
659 {
660     int code = CvTS::OK;
661     
662     if( cvIsNaN(min_val) || cvIsInf(min_val) ||
663         cvIsNaN(max_val) || cvIsInf(max_val) )
664     {
665         ts->printf( CvTS::LOG,
666             "The extrema histogram bin values are invalid (min = %g, max = %g)\n", min_val, max_val );
667         code = CvTS::FAIL_INVALID_OUTPUT;
668     }
669     else if( fabs(min_val - min_val0) > FLT_EPSILON ||
670              fabs(max_val - max_val0) > FLT_EPSILON )
671     {
672         ts->printf( CvTS::LOG,
673             "The extrema histogram bin values are incorrect: (min = %g, should be = %g), (max = %g, should be = %g)\n",
674             min_val, min_val0, max_val, max_val0 );
675         code = CvTS::FAIL_BAD_ACCURACY;
676     }
677     else
678     {
679         int i;
680         for( i = 0; i < cdims; i++ )
681         {
682             if( min_idx[i] != min_idx0[i] || max_idx[i] != max_idx0[i] )
683             {
684                 ts->printf( CvTS::LOG,
685                     "The %d-th coordinates of extrema histogram bin values are incorrect: "
686                     "(min = %d, should be = %d), (max = %d, should be = %d)\n",
687                     i, min_idx[i], min_idx0[i], max_idx[i], max_idx0[i] );
688                 code = CvTS::FAIL_BAD_ACCURACY;
689             }
690         }
691     }
692
693     if( code < 0 )
694         ts->set_failed_test_info( code );
695     return code;
696 }
697
698
699 CV_MinMaxHistTest hist_minmax_test;
700
701
702
703 ////////////// cvNormalizeHist //////////////
704
705 class CV_NormHistTest : public CV_BaseHistTest
706 {
707 public:
708     CV_NormHistTest();
709
710 protected:
711     int prepare_test_case( int test_case_idx );
712     void run_func(void);
713     int validate_test_results( int test_case_idx );
714     double factor;
715 };
716
717
718
719 CV_NormHistTest::CV_NormHistTest() :
720     CV_BaseHistTest( "hist-normalize", "cvNormalizeHist" )
721 {
722     hist_count = 1;
723     gen_random_hist = 1;
724     factor = 0;
725 }
726
727
728 int CV_NormHistTest::prepare_test_case( int test_case_idx )
729 {
730     int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
731
732     if( code > 0 )
733     {
734         CvRNG* rng = ts->get_rng();
735         factor = cvTsRandReal(rng)*10 + 0.1;
736         if( hist_type == CV_HIST_SPARSE &&
737             ((CvSparseMat*)hist[0]->bins)->heap->active_count == 0 )
738             factor = 0;
739     }
740
741     return code;
742 }
743
744
745 void CV_NormHistTest::run_func(void)
746 {
747     cvNormalizeHist( hist[0], factor );
748 }
749
750
751 int CV_NormHistTest::validate_test_results( int /*test_case_idx*/ )
752 {
753     int code = CvTS::OK;
754     double sum = 0;
755     
756     if( hist_type == CV_HIST_ARRAY )
757     {
758         int i;
759         const float* ptr = (float*)cvPtr1D( hist[0]->bins, 0 );
760
761         for( i = 0; i < total_size; i++ )
762             sum += ptr[i];
763     }
764     else
765     {
766         CvSparseMat* sparse = (CvSparseMat*)hist[0]->bins;
767         CvSparseMatIterator iterator;
768         CvSparseNode *node;
769         
770         for( node = cvInitSparseMatIterator( sparse, &iterator );
771              node != 0; node = cvGetNextSparseNode( &iterator ))
772         {
773             sum += *(float*)CV_NODE_VAL(sparse,node);
774         }
775     }
776
777     if( cvIsNaN(sum) || cvIsInf(sum) )
778     {
779         ts->printf( CvTS::LOG,
780             "The normalized histogram has invalid sum =%g\n", sum );
781         code = CvTS::FAIL_INVALID_OUTPUT;
782     }
783     else if( fabs(sum - factor) > FLT_EPSILON*10*fabs(factor) )
784     {
785         ts->printf( CvTS::LOG,
786             "The normalized histogram has incorrect sum =%g, while it should be =%g\n", sum, factor );
787         code = CvTS::FAIL_BAD_ACCURACY;
788     }
789
790     if( code < 0 )
791         ts->set_failed_test_info( code );
792     return code;
793 }
794
795
796 CV_NormHistTest hist_norm_test;
797
798
799
800 ////////////// cvThreshHist //////////////
801
802 class CV_ThreshHistTest : public CV_BaseHistTest
803 {
804 public:
805     CV_ThreshHistTest();
806     ~CV_ThreshHistTest();
807     void clear();
808
809 protected:
810     int prepare_test_case( int test_case_idx );
811     void run_func(void);
812     int validate_test_results( int test_case_idx );
813     CvMat* indices;
814     CvMat* values;
815     int orig_nz_count;
816
817     double threshold;
818 };
819
820
821
822 CV_ThreshHistTest::CV_ThreshHistTest() :
823     CV_BaseHistTest( "hist-threshold", "cvThreshHist" )
824 {
825     hist_count = 1;
826     gen_random_hist = 1;
827     threshold = 0;
828     indices = values = 0;
829 }
830
831
832 CV_ThreshHistTest::~CV_ThreshHistTest()
833 {
834     clear();
835 }
836
837
838 void CV_ThreshHistTest::clear()
839 {
840     cvReleaseMat( &indices );
841     cvReleaseMat( &values );
842     CV_BaseHistTest::clear();
843 }
844
845
846 int CV_ThreshHistTest::prepare_test_case( int test_case_idx )
847 {
848     int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
849
850     if( code > 0 )
851     {
852         CvRNG* rng = ts->get_rng();
853         threshold = cvTsRandReal(rng)*gen_hist_max_val;
854
855         if( hist_type == CV_HIST_ARRAY )
856         {
857             orig_nz_count = total_size;
858             
859             values = cvCreateMat( 1, total_size, CV_32F );
860             memcpy( values->data.fl, cvPtr1D( hist[0]->bins, 0 ), total_size*sizeof(float) );
861         }
862         else
863         {
864             CvSparseMat* sparse = (CvSparseMat*)hist[0]->bins;
865             CvSparseMatIterator iterator;
866             CvSparseNode* node;
867             int i, k;
868
869             orig_nz_count = sparse->heap->active_count;
870
871             values = cvCreateMat( 1, orig_nz_count+1, CV_32F );
872             indices = cvCreateMat( 1, (orig_nz_count+1)*cdims, CV_32S );
873
874             for( node = cvInitSparseMatIterator( sparse, &iterator ), i = 0;
875                  node != 0; node = cvGetNextSparseNode( &iterator ), i++ )
876             {
877                  const int* idx = CV_NODE_IDX(sparse,node);
878                      
879                  OPENCV_ASSERT( i < orig_nz_count, "CV_ThreshHistTest::prepare_test_case", "Buffer overflow" );
880
881                  values->data.fl[i] = *(float*)CV_NODE_VAL(sparse,node);
882                  for( k = 0; k < cdims; k++ )
883                      indices->data.i[i*cdims + k] = idx[k];
884             }
885
886             OPENCV_ASSERT( i == orig_nz_count, "Unmatched buffer size",
887                 "CV_ThreshHistTest::prepare_test_case" );
888         }
889     }
890
891     return code;
892 }
893
894
895 void CV_ThreshHistTest::run_func(void)
896 {
897     cvThreshHist( hist[0], threshold );
898 }
899
900
901 int CV_ThreshHistTest::validate_test_results( int /*test_case_idx*/ )
902 {
903     int code = CvTS::OK;
904     int i;
905     float* ptr0 = values->data.fl;
906     float* ptr = 0;
907     CvSparseMat* sparse = 0;
908
909     if( hist_type == CV_HIST_ARRAY )
910         ptr = (float*)cvPtr1D( hist[0]->bins, 0 );
911     else
912         sparse = (CvSparseMat*)hist[0]->bins;
913
914     if( code > 0 )
915     {
916         for( i = 0; i < orig_nz_count; i++ )
917         {
918             float v0 = ptr0[i], v;
919
920             if( hist_type == CV_HIST_ARRAY )
921                 v = ptr[i];
922             else
923             {
924                 v = (float)cvGetRealND( sparse, indices->data.i + i*cdims );
925                 cvClearND( sparse, indices->data.i + i*cdims );
926             }
927
928             if( v0 <= threshold ) v0 = 0.f;
929             if( cvIsNaN(v) || cvIsInf(v) )
930             {
931                 ts->printf( CvTS::LOG, "The %d-th bin is invalid (=%g)\n", i, v );
932                 code = CvTS::FAIL_INVALID_OUTPUT;
933                 break;
934             }
935             else if( fabs(v0 - v) > FLT_EPSILON*10*fabs(v0) )
936             {
937                 ts->printf( CvTS::LOG, "The %d-th bin is incorrect (=%g, should be =%g)\n", i, v, v0 );
938                 code = CvTS::FAIL_BAD_ACCURACY;
939                 break;
940             }
941         }
942     }
943     
944     if( code > 0 && hist_type == CV_HIST_SPARSE )
945     {
946         if( sparse->heap->active_count > 0 )
947         {
948             ts->printf( CvTS::LOG,
949                 "There some extra histogram bins in the sparse histogram after the thresholding\n" );
950             code = CvTS::FAIL_INVALID_OUTPUT;
951         }
952     }
953
954     if( code < 0 )
955         ts->set_failed_test_info( code );
956     return code;
957 }
958
959
960 CV_ThreshHistTest hist_thresh_test;
961
962
963 ////////////// cvCompareHist //////////////
964
965 class CV_CompareHistTest : public CV_BaseHistTest
966 {
967 public:
968     enum { MAX_METHOD = 4 };
969
970     CV_CompareHistTest();
971 protected:
972     int prepare_test_case( int test_case_idx );
973     void run_func(void);
974     int validate_test_results( int test_case_idx );
975     double result[MAX_METHOD+1];
976 };
977
978
979
980 CV_CompareHistTest::CV_CompareHistTest() :
981     CV_BaseHistTest( "hist-compare", "cvCompareHist" )
982 {
983     hist_count = 2;
984     gen_random_hist = 1;
985 }
986
987
988 int CV_CompareHistTest::prepare_test_case( int test_case_idx )
989 {
990     int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
991
992     return code;
993 }
994
995
996 void CV_CompareHistTest::run_func(void)
997 {
998     int k;
999     for( k = 0; k < MAX_METHOD; k++ )
1000         result[k] = cvCompareHist( hist[0], hist[1], k );
1001 }
1002
1003
1004 int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ )
1005 {
1006     int code = CvTS::OK;
1007     int i;
1008     double result0[MAX_METHOD+1];
1009     double s0 = 0, s1 = 0, sq0 = 0, sq1 = 0, t;
1010
1011     for( i = 0; i < MAX_METHOD; i++ )
1012         result0[i] = 0;
1013
1014     if( hist_type == CV_HIST_ARRAY )
1015     {
1016         float* ptr0 = (float*)cvPtr1D( hist[0]->bins, 0 );
1017         float* ptr1 = (float*)cvPtr1D( hist[1]->bins, 0 );
1018         
1019         for( i = 0; i < total_size; i++ )
1020         {
1021             double v0 = ptr0[i], v1 = ptr1[i];
1022             result0[CV_COMP_CORREL] += v0*v1;
1023             result0[CV_COMP_INTERSECT] += MIN(v0,v1);
1024             if( fabs(v0 + v1) > DBL_EPSILON )
1025                 result0[CV_COMP_CHISQR] += (v0 - v1)*(v0 - v1)/(v0 + v1);
1026             s0 += v0;
1027             s1 += v1;
1028             sq0 += v0*v0;
1029             sq1 += v1*v1;
1030             result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1);
1031         }
1032     }
1033     else
1034     {
1035         CvSparseMat* sparse0 = (CvSparseMat*)hist[0]->bins;
1036         CvSparseMat* sparse1 = (CvSparseMat*)hist[1]->bins;
1037         CvSparseMatIterator iterator;
1038         CvSparseNode* node;
1039
1040         for( node = cvInitSparseMatIterator( sparse0, &iterator );
1041              node != 0; node = cvGetNextSparseNode( &iterator ) )
1042         {
1043             const int* idx = CV_NODE_IDX(sparse0, node);
1044             double v0 = *(float*)CV_NODE_VAL(sparse0, node);
1045             double v1 = (float)cvGetRealND(sparse1, idx);
1046
1047             result0[CV_COMP_CORREL] += v0*v1;
1048             result0[CV_COMP_INTERSECT] += MIN(v0,v1);
1049             if( fabs(v0 + v1) > DBL_EPSILON )
1050                 result0[CV_COMP_CHISQR] += (v0 - v1)*(v0 - v1)/(v0 + v1);
1051             s0 += v0;
1052             sq0 += v0*v0;
1053             result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1);
1054         }
1055
1056         for( node = cvInitSparseMatIterator( sparse1, &iterator );
1057              node != 0; node = cvGetNextSparseNode( &iterator ) )
1058         {
1059             const int* idx = CV_NODE_IDX(sparse1, node);
1060             double v1 = *(float*)CV_NODE_VAL(sparse1, node);
1061             double v0 = (float)cvGetRealND(sparse0, idx);
1062
1063             if( fabs(v0) < DBL_EPSILON )
1064                 result0[CV_COMP_CHISQR] += v1;
1065             s1 += v1;
1066             sq1 += v1*v1;
1067         }
1068     }
1069
1070     t = (sq0 - s0*s0/total_size)*(sq1 - s1*s1/total_size);
1071     result0[CV_COMP_CORREL] = fabs(t) > DBL_EPSILON ?
1072         (result0[CV_COMP_CORREL] - s0*s1/total_size)/sqrt(t) : 1;
1073
1074     s1 *= s0;
1075     s0 = result0[CV_COMP_BHATTACHARYYA];
1076     s0 = 1. - s0*(s1 > FLT_EPSILON ? 1./sqrt(s1) : 1.);
1077     result0[CV_COMP_BHATTACHARYYA] = sqrt(MAX(s0,0.));
1078
1079     for( i = 0; i < MAX_METHOD; i++ )
1080     {
1081         double v = result[i], v0 = result0[i];
1082         const char* method_name =
1083             i == CV_COMP_CHISQR ? "Chi-Square" :
1084             i == CV_COMP_CORREL ? "Correlation" :
1085             i == CV_COMP_INTERSECT ? "Intersection" :
1086             i == CV_COMP_BHATTACHARYYA ? "Bhattacharyya" : "Unknown";
1087
1088         if( cvIsNaN(v) || cvIsInf(v) )
1089         {
1090             ts->printf( CvTS::LOG, "The comparison result using the method #%d (%s) is invalid (=%g)\n",
1091                 i, method_name, v );
1092             code = CvTS::FAIL_INVALID_OUTPUT;
1093             break;
1094         }
1095         else if( fabs(v0 - v) > FLT_EPSILON*10*MAX(fabs(v0),0.1) )
1096         {
1097             ts->printf( CvTS::LOG, "The comparison result using the method #%d (%s)\n\tis inaccurate (=%g, should be =%g)\n",
1098                 i, method_name, v, v0 );
1099             code = CvTS::FAIL_BAD_ACCURACY;
1100             break;
1101         }
1102     }
1103
1104     if( code < 0 )
1105         ts->set_failed_test_info( code );
1106     return code;
1107 }
1108
1109
1110 CV_CompareHistTest hist_compare_test;
1111
1112
1113
1114 ////////////// cvCalcHist //////////////
1115
1116 class CV_CalcHistTest : public CV_BaseHistTest
1117 {
1118 public:
1119     CV_CalcHistTest();
1120     ~CV_CalcHistTest();
1121     void clear();
1122
1123 protected:
1124     int prepare_test_case( int test_case_idx );
1125     void run_func(void);
1126     int validate_test_results( int test_case_idx );
1127     IplImage* images[CV_MAX_DIM+1];
1128     int channels[CV_MAX_DIM+1];
1129 };
1130
1131
1132
1133 CV_CalcHistTest::CV_CalcHistTest() :
1134     CV_BaseHistTest( "hist-calc", "cvCalcHist" )
1135 {
1136     int i;
1137
1138     hist_count = 2;
1139     gen_random_hist = 0;
1140     init_ranges = 1;
1141
1142     for( i = 0; i <= CV_MAX_DIM; i++ )
1143     {
1144         images[i] = 0;
1145         channels[i] = 0;
1146     }
1147 }
1148
1149
1150 CV_CalcHistTest::~CV_CalcHistTest()
1151 {
1152     clear();
1153 }
1154
1155
1156 void CV_CalcHistTest::clear()
1157 {
1158     int i;
1159     
1160     for( i = 0; i <= CV_MAX_DIM; i++ )
1161         cvReleaseImage( &images[i] );
1162
1163     CV_BaseHistTest::clear();
1164 }
1165
1166
1167 int CV_CalcHistTest::prepare_test_case( int test_case_idx )
1168 {
1169     int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
1170
1171     if( code > 0 )
1172     {
1173         CvRNG* rng = ts->get_rng();
1174         int i;
1175
1176         for( i = 0; i <= CV_MAX_DIM; i++ )
1177         {
1178             if( i < cdims )
1179             {
1180                 int nch = 1; //cvTsRandInt(rng) % 3 + 1;
1181                 images[i] = cvCreateImage( img_size,
1182                     img_type == CV_8U ? IPL_DEPTH_8U : IPL_DEPTH_32F, nch );
1183                 channels[i] = cvTsRandInt(rng) % nch;
1184
1185                 cvRandArr( rng, images[i], CV_RAND_UNI,
1186                     cvScalarAll(low), cvScalarAll(high) );
1187             }
1188             else if( i == CV_MAX_DIM && cvTsRandInt(rng) % 2 )
1189             {
1190                 // create mask
1191                 images[i] = cvCreateImage( img_size, IPL_DEPTH_8U, 1 );
1192                 // make ~25% pixels in the mask non-zero
1193                 cvRandArr( rng, images[i], CV_RAND_UNI,
1194                     cvScalarAll(-2), cvScalarAll(2) );
1195             }
1196         }
1197     }
1198
1199     return code;
1200 }
1201
1202
1203 void CV_CalcHistTest::run_func(void)
1204 {
1205     cvCalcHist( images, hist[0], 0, images[CV_MAX_DIM] );
1206 }
1207
1208
1209 static void
1210 cvTsCalcHist( IplImage** _images, CvHistogram* hist, IplImage* _mask, int* channels )
1211 {
1212     int x, y, k, cdims;
1213     union
1214     {
1215         float* fl;
1216         uchar* ptr;
1217     }
1218     plane[CV_MAX_DIM];
1219     int nch[CV_MAX_DIM];
1220     int dims[CV_MAX_DIM];
1221     int uniform = CV_IS_UNIFORM_HIST(hist);
1222     CvSize img_size = cvGetSize(_images[0]);
1223     CvMat images[CV_MAX_DIM], mask = cvMat(1,1,CV_8U);
1224     int img_depth = _images[0]->depth;
1225
1226     cdims = cvGetDims( hist->bins, dims );
1227
1228     cvZero( hist->bins );
1229
1230     for( k = 0; k < cdims; k++ )
1231     {
1232         cvGetMat( _images[k], &images[k] );
1233         nch[k] = _images[k]->nChannels;
1234     }
1235
1236     if( _mask )
1237         cvGetMat( _mask, &mask );
1238
1239     for( y = 0; y < img_size.height; y++ )
1240     {
1241         const uchar* mptr = _mask ? &CV_MAT_ELEM(mask, uchar, y, 0 ) : 0;
1242
1243         if( img_depth == IPL_DEPTH_8U )
1244             for( k = 0; k < cdims; k++ )
1245                 plane[k].ptr = &CV_MAT_ELEM(images[k], uchar, y, 0 ) + channels[k];
1246         else
1247             for( k = 0; k < cdims; k++ )
1248                 plane[k].fl = &CV_MAT_ELEM(images[k], float, y, 0 ) + channels[k];
1249
1250         for( x = 0; x < img_size.width; x++ )
1251         {
1252             float val[CV_MAX_DIM];
1253             int idx[CV_MAX_DIM];
1254             
1255             if( mptr && !mptr[x] )
1256                 continue;
1257             if( img_depth == IPL_DEPTH_8U )
1258                 for( k = 0; k < cdims; k++ )
1259                     val[k] = plane[k].ptr[x*nch[k]];
1260             else
1261                 for( k = 0; k < cdims; k++ )
1262                     val[k] = plane[k].fl[x*nch[k]];
1263
1264             idx[cdims-1] = -1;
1265
1266             if( uniform )
1267             {
1268                 for( k = 0; k < cdims; k++ )
1269                 {
1270                     double v = val[k], lo = hist->thresh[k][0], hi = hist->thresh[k][1];
1271                     idx[k] = cvFloor((v - lo)*dims[k]/(hi - lo));
1272                     if( idx[k] < 0 || idx[k] >= dims[k] )
1273                         break;
1274                 }
1275             }
1276             else
1277             {
1278                 for( k = 0; k < cdims; k++ )
1279                 {
1280                     float v = val[k];
1281                     float* t = hist->thresh2[k];
1282                     int j, n = dims[k];
1283
1284                     for( j = 0; j <= n; j++ )
1285                         if( v < t[j] )
1286                             break;
1287                     if( j <= 0 || j > n )
1288                         break;
1289                     idx[k] = j-1;
1290                 }
1291             }
1292
1293             if( k < cdims )
1294                 continue;
1295
1296             (*(float*)cvPtrND( hist->bins, idx ))++;
1297         }
1298     }
1299 }
1300
1301
1302 int CV_CalcHistTest::validate_test_results( int /*test_case_idx*/ )
1303 {
1304     int code = CvTS::OK;
1305     double diff;
1306     cvTsCalcHist( images, hist[1], images[CV_MAX_DIM], channels );
1307     diff = cvCompareHist( hist[0], hist[1], CV_COMP_CHISQR );
1308     if( diff > DBL_EPSILON )
1309     {
1310         ts->printf( CvTS::LOG, "The histogram does not match to the reference one\n" );
1311         code = CvTS::FAIL_BAD_ACCURACY;
1312         
1313     }
1314
1315     if( code < 0 )
1316         ts->set_failed_test_info( code );
1317     return code;
1318 }
1319
1320
1321 CV_CalcHistTest hist_calc_test;
1322
1323
1324
1325 ////////////// cvCalcBackProject //////////////
1326
1327 class CV_CalcBackProjectTest : public CV_BaseHistTest
1328 {
1329 public:
1330     CV_CalcBackProjectTest();
1331     ~CV_CalcBackProjectTest();
1332     void clear();
1333
1334 protected:
1335     int prepare_test_case( int test_case_idx );
1336     void run_func(void);
1337     int validate_test_results( int test_case_idx );
1338     IplImage* images[CV_MAX_DIM+3];
1339     int channels[CV_MAX_DIM+3];
1340 };
1341
1342
1343
1344 CV_CalcBackProjectTest::CV_CalcBackProjectTest() :
1345     CV_BaseHistTest( "hist-backproj", "cvCalcBackProject" )
1346 {
1347     int i;
1348
1349     hist_count = 1;
1350     gen_random_hist = 0;
1351     init_ranges = 1;
1352
1353     for( i = 0; i < CV_MAX_DIM+3; i++ )
1354     {
1355         images[i] = 0;
1356         channels[i] = 0;
1357     }
1358 }
1359
1360
1361 CV_CalcBackProjectTest::~CV_CalcBackProjectTest()
1362 {
1363     clear();
1364 }
1365
1366
1367 void CV_CalcBackProjectTest::clear()
1368 {
1369     int i;
1370     
1371     for( i = 0; i < CV_MAX_DIM+3; i++ )
1372         cvReleaseImage( &images[i] );
1373
1374     CV_BaseHistTest::clear();
1375 }
1376
1377
1378 int CV_CalcBackProjectTest::prepare_test_case( int test_case_idx )
1379 {
1380     int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
1381
1382     if( code > 0 )
1383     {
1384         CvRNG* rng = ts->get_rng();
1385         int i, j, n, img_len = img_size.width*img_size.height;
1386
1387         for( i = 0; i < CV_MAX_DIM + 3; i++ )
1388         {
1389             if( i < cdims )
1390             {
1391                 int nch = 1; //cvTsRandInt(rng) % 3 + 1;
1392                 images[i] = cvCreateImage( img_size,
1393                     img_type == CV_8U ? IPL_DEPTH_8U : IPL_DEPTH_32F, nch );
1394                 channels[i] = cvTsRandInt(rng) % nch;
1395
1396                 cvRandArr( rng, images[i], CV_RAND_UNI,
1397                     cvScalarAll(low), cvScalarAll(high) );
1398             }
1399             else if( i == CV_MAX_DIM && cvTsRandInt(rng) % 2 )
1400             {
1401                 // create mask
1402                 images[i] = cvCreateImage( img_size, IPL_DEPTH_8U, 1 );
1403                 // make ~25% pixels in the mask non-zero
1404                 cvRandArr( rng, images[i], CV_RAND_UNI,
1405                     cvScalarAll(-2), cvScalarAll(2) );
1406             }
1407             else if( i > CV_MAX_DIM )
1408             {
1409                 images[i] = cvCreateImage( img_size, images[0]->depth, 1 );
1410             }
1411         }
1412
1413         cvTsCalcHist( images, hist[0], images[CV_MAX_DIM], channels );
1414
1415         // now modify the images a bit to add some zeros go to the backprojection
1416         n = cvTsRandInt(rng) % (img_len/20+1);
1417         for( i = 0; i < cdims; i++ )
1418         {
1419             char* data = images[i]->imageData;
1420             for( j = 0; j < n; j++ )
1421             {
1422                 int idx = cvTsRandInt(rng) % img_len;
1423                 double val = cvTsRandReal(rng)*(high - low) + low;
1424                 
1425                 if( img_type == CV_8U )
1426                     ((uchar*)data)[idx] = (uchar)cvRound(val);
1427                 else
1428                     ((float*)data)[idx] = (float)val;
1429             }
1430         }
1431     }
1432
1433     return code;
1434 }
1435
1436
1437 void CV_CalcBackProjectTest::run_func(void)
1438 {
1439     cvCalcBackProject( images, images[CV_MAX_DIM+1], hist[0] );
1440 }
1441
1442
1443 static void
1444 cvTsCalcBackProject( IplImage** images, IplImage* dst, CvHistogram* hist, int* channels )
1445 {
1446     int x, y, k, cdims;
1447     union
1448     {
1449         float* fl;
1450         uchar* ptr;
1451     }
1452     plane[CV_MAX_DIM];
1453     int nch[CV_MAX_DIM];
1454     int dims[CV_MAX_DIM];
1455     int uniform = CV_IS_UNIFORM_HIST(hist);
1456     CvSize img_size = cvGetSize(images[0]);
1457     int img_depth = images[0]->depth;
1458
1459     cdims = cvGetDims( hist->bins, dims );
1460
1461     for( k = 0; k < cdims; k++ )
1462         nch[k] = images[k]->nChannels;
1463
1464     for( y = 0; y < img_size.height; y++ )
1465     {
1466         if( img_depth == IPL_DEPTH_8U )
1467             for( k = 0; k < cdims; k++ )
1468                 plane[k].ptr = &CV_IMAGE_ELEM(images[k], uchar, y, 0 ) + channels[k];
1469         else
1470             for( k = 0; k < cdims; k++ )
1471                 plane[k].fl = &CV_IMAGE_ELEM(images[k], float, y, 0 ) + channels[k];
1472
1473         for( x = 0; x < img_size.width; x++ )
1474         {
1475             float val[CV_MAX_DIM];
1476             float bin_val = 0;
1477             int idx[CV_MAX_DIM];
1478             
1479             if( img_depth == IPL_DEPTH_8U )
1480                 for( k = 0; k < cdims; k++ )
1481                     val[k] = plane[k].ptr[x*nch[k]];
1482             else
1483                 for( k = 0; k < cdims; k++ )
1484                     val[k] = plane[k].fl[x*nch[k]];
1485             idx[cdims-1] = -1;
1486
1487             if( uniform )
1488             {
1489                 for( k = 0; k < cdims; k++ )
1490                 {
1491                     double v = val[k], lo = hist->thresh[k][0], hi = hist->thresh[k][1];
1492                     idx[k] = cvFloor((v - lo)*dims[k]/(hi - lo));
1493                     if( idx[k] < 0 || idx[k] >= dims[k] )
1494                         break;
1495                 }
1496             }
1497             else
1498             {
1499                 for( k = 0; k < cdims; k++ )
1500                 {
1501                     float v = val[k];
1502                     float* t = hist->thresh2[k];
1503                     int j, n = dims[k];
1504
1505                     for( j = 0; j <= n; j++ )
1506                         if( v < t[j] )
1507                             break;
1508                     if( j <= 0 || j > n )
1509                         break;
1510                     idx[k] = j-1;
1511                 }
1512             }
1513
1514             if( k == cdims )
1515                 bin_val = (float)cvGetRealND( hist->bins, idx );
1516
1517             if( img_depth == IPL_DEPTH_8U )
1518             {
1519                 int t = cvRound(bin_val);
1520                 CV_IMAGE_ELEM( dst, uchar, y, x ) = CV_CAST_8U(t);
1521             }
1522             else
1523                 CV_IMAGE_ELEM( dst, float, y, x ) = bin_val;
1524         }
1525     }
1526 }
1527
1528
1529 int CV_CalcBackProjectTest::validate_test_results( int /*test_case_idx*/ )
1530 {
1531     int code = CvTS::OK;
1532
1533     cvTsCalcBackProject( images, images[CV_MAX_DIM+2], hist[0], channels );
1534     code = cvTsCmpEps2( ts, images[CV_MAX_DIM+1], images[CV_MAX_DIM+2], 0, true,
1535         "Back project image" );
1536
1537     if( code < 0 )
1538         ts->set_failed_test_info( code );
1539
1540     return code;
1541 }
1542
1543
1544 CV_CalcBackProjectTest hist_backproj_test;
1545
1546
1547 ////////////// cvCalcBackProjectPatch //////////////
1548
1549 class CV_CalcBackProjectPatchTest : public CV_BaseHistTest
1550 {
1551 public:
1552     CV_CalcBackProjectPatchTest();
1553     ~CV_CalcBackProjectPatchTest();
1554     void clear();
1555
1556 protected:
1557     int prepare_test_case( int test_case_idx );
1558     void run_func(void);
1559     int validate_test_results( int test_case_idx );
1560     IplImage* images[CV_MAX_DIM+2];
1561     int channels[CV_MAX_DIM+2];
1562
1563     CvSize patch_size;
1564     double factor;
1565     int method;
1566 };
1567
1568
1569
1570 CV_CalcBackProjectPatchTest::CV_CalcBackProjectPatchTest() :
1571     CV_BaseHistTest( "hist-backprojpatch", "cvCalcBackProjectPatch" )
1572 {
1573     int i;
1574
1575     hist_count = 1;
1576     gen_random_hist = 0;
1577     init_ranges = 1;
1578     img_max_log_size = 6;
1579
1580     for( i = 0; i < CV_MAX_DIM+2; i++ )
1581     {
1582         images[i] = 0;
1583         channels[i] = 0;
1584     }
1585 }
1586
1587
1588 CV_CalcBackProjectPatchTest::~CV_CalcBackProjectPatchTest()
1589 {
1590     clear();
1591 }
1592
1593
1594 void CV_CalcBackProjectPatchTest::clear()
1595 {
1596     int i;
1597     
1598     for( i = 0; i < CV_MAX_DIM+2; i++ )
1599         cvReleaseImage( &images[i] );
1600
1601     CV_BaseHistTest::clear();
1602 }
1603
1604
1605 int CV_CalcBackProjectPatchTest::prepare_test_case( int test_case_idx )
1606 {
1607     int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
1608
1609     if( code > 0 )
1610     {
1611         CvRNG* rng = ts->get_rng();
1612         int i, j, n, img_len = img_size.width*img_size.height;
1613
1614         patch_size.width = cvTsRandInt(rng) % img_size.width + 1;
1615         patch_size.height = cvTsRandInt(rng) % img_size.height + 1;
1616         patch_size.width = MIN( patch_size.width, 30 );
1617         patch_size.height = MIN( patch_size.height, 30 );
1618
1619         factor = 1.;
1620         method = cvTsRandInt(rng) % CV_CompareHistTest::MAX_METHOD;
1621
1622         for( i = 0; i < CV_MAX_DIM + 2; i++ )
1623         {
1624             if( i < cdims )
1625             {
1626                 int nch = 1; //cvTsRandInt(rng) % 3 + 1;
1627                 images[i] = cvCreateImage( img_size,
1628                     img_type == CV_8U ? IPL_DEPTH_8U : IPL_DEPTH_32F, nch );
1629                 channels[i] = cvTsRandInt(rng) % nch;
1630
1631                 cvRandArr( rng, images[i], CV_RAND_UNI,
1632                     cvScalarAll(low), cvScalarAll(high) );
1633             }
1634             else if( i >= CV_MAX_DIM )
1635             {
1636                 images[i] = cvCreateImage(
1637                     cvSize(img_size.width - patch_size.width + 1,
1638                            img_size.height - patch_size.height + 1),
1639                     IPL_DEPTH_32F, 1 );
1640             }
1641         }
1642
1643         cvTsCalcHist( images, hist[0], 0, channels );
1644         cvNormalizeHist( hist[0], factor );
1645
1646         // now modify the images a bit
1647         n = cvTsRandInt(rng) % (img_len/10+1);
1648         for( i = 0; i < cdims; i++ )
1649         {
1650             char* data = images[i]->imageData;
1651             for( j = 0; j < n; j++ )
1652             {
1653                 int idx = cvTsRandInt(rng) % img_len;
1654                 double val = cvTsRandReal(rng)*(high - low) + low;
1655                 
1656                 if( img_type == CV_8U )
1657                     ((uchar*)data)[idx] = (uchar)cvRound(val);
1658                 else
1659                     ((float*)data)[idx] = (float)val;
1660             }
1661         }
1662     }
1663
1664     return code;
1665 }
1666
1667
1668 void CV_CalcBackProjectPatchTest::run_func(void)
1669 {
1670     cvCalcBackProjectPatch( images, images[CV_MAX_DIM], patch_size, hist[0], method, factor );
1671 }
1672
1673
1674 static void
1675 cvTsCalcBackProjectPatch( IplImage** images, IplImage* dst, CvSize patch_size,
1676                           CvHistogram* hist, int method,
1677                           double factor, int* channels )
1678 {
1679     CvHistogram* model = 0;
1680     
1681     IplImage imgstub[CV_MAX_DIM], *img[CV_MAX_DIM];
1682     IplROI roi;
1683     int i, dims;
1684     int x, y;
1685     CvSize size = cvGetSize(dst);
1686
1687     dims = cvGetDims( hist->bins );
1688     cvCopyHist( hist, &model );
1689     cvNormalizeHist( hist, factor );
1690     cvZero( dst );
1691
1692     for( i = 0; i < dims; i++ )
1693     {
1694         CvMat stub, *mat;
1695         mat = cvGetMat( images[i], &stub, 0, 0 );
1696         img[i] = cvGetImage( mat, &imgstub[i] );
1697         img[i]->roi = &roi;
1698     }
1699
1700     roi.coi = 0;
1701
1702     for( y = 0; y < size.height; y++ )
1703     {
1704         for( x = 0; x < size.width; x++ )
1705         {
1706             double result;
1707             
1708             roi.xOffset = x;
1709             roi.yOffset = y;
1710             roi.width = patch_size.width;
1711             roi.height = patch_size.height;
1712
1713             cvTsCalcHist( img, model, 0, channels );
1714             cvNormalizeHist( model, factor );
1715             result = cvCompareHist( model, hist, method );
1716             CV_IMAGE_ELEM( dst, float, y, x ) = (float)result;
1717         }
1718     }
1719
1720     cvReleaseHist( &model );
1721 }
1722
1723
1724 int CV_CalcBackProjectPatchTest::validate_test_results( int /*test_case_idx*/ )
1725 {
1726     int code = CvTS::OK;
1727     double err_level = 5e-3;
1728
1729     cvTsCalcBackProjectPatch( images, images[CV_MAX_DIM+1],
1730         patch_size, hist[0], method, factor, channels );
1731     
1732     code = cvTsCmpEps2( ts, images[CV_MAX_DIM], images[CV_MAX_DIM+1], err_level, true,
1733         "BackProjectPatch result" );
1734
1735     if( code < 0 )
1736         ts->set_failed_test_info( code );
1737
1738     return code;
1739 }
1740
1741
1742 CV_CalcBackProjectPatchTest hist_backprojpatch_test;
1743
1744
1745 ////////////// cvCalcBayesianProb //////////////
1746
1747 class CV_BayesianProbTest : public CV_BaseHistTest
1748 {
1749 public:
1750     enum { MAX_METHOD = 4 };
1751
1752     CV_BayesianProbTest();
1753 protected:
1754     int prepare_test_case( int test_case_idx );
1755     void run_func(void);
1756     int validate_test_results( int test_case_idx );
1757     void init_hist( int test_case_idx, int i );
1758     void get_hist_params( int test_case_idx );
1759 };
1760
1761
1762
1763 CV_BayesianProbTest::CV_BayesianProbTest() :
1764     CV_BaseHistTest( "hist-bayesianprob", "cvBayesianProb" )
1765 {
1766     hist_count = CV_MAX_DIM;
1767     gen_random_hist = 1;
1768 }
1769
1770
1771 void CV_BayesianProbTest::get_hist_params( int test_case_idx )
1772 {
1773     CV_BaseHistTest::get_hist_params( test_case_idx );
1774     hist_type = CV_HIST_ARRAY;
1775 }
1776
1777
1778 void CV_BayesianProbTest::init_hist( int test_case_idx, int hist_i )
1779 {
1780     if( hist_i < hist_count/2 )
1781         CV_BaseHistTest::init_hist( test_case_idx, hist_i );
1782 }
1783
1784
1785 int CV_BayesianProbTest::prepare_test_case( int test_case_idx )
1786 {
1787     CvRNG* rng = ts->get_rng();
1788     
1789     hist_count = (cvTsRandInt(rng) % (MAX_HIST/2-1) + 2)*2;
1790     hist_count = MIN( hist_count, MAX_HIST );
1791     int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
1792
1793     return code;
1794 }
1795
1796
1797 void CV_BayesianProbTest::run_func(void)
1798 {
1799     cvCalcBayesianProb( hist, hist_count/2, hist + hist_count/2 );
1800 }
1801
1802
1803 int CV_BayesianProbTest::validate_test_results( int /*test_case_idx*/ )
1804 {
1805     int code = CvTS::OK;
1806     int i, j, n = hist_count/2;
1807     double s[CV_MAX_DIM];
1808     const double err_level = 1e-5;
1809
1810     for( i = 0; i < total_size; i++ )
1811     {
1812         double sum = 0;
1813         for( j = 0; j < n; j++ )
1814         {
1815             double v = hist[j]->mat.data.fl[i];
1816             sum += v;
1817             s[j] = v;
1818         }
1819         sum = sum > DBL_EPSILON ? 1./sum : 0;
1820
1821         for( j = 0; j < n; j++ )
1822         {
1823             double v0 = s[j]*sum;
1824             double v = hist[j+n]->mat.data.fl[i];
1825
1826             if( cvIsNaN(v) || cvIsInf(v) )
1827             {
1828                 ts->printf( CvTS::LOG,
1829                     "The element #%d in the destination histogram #%d is invalid (=%g)\n",
1830                     i, j, v );
1831                 code = CvTS::FAIL_INVALID_OUTPUT;
1832                 break;
1833             }
1834             else if( fabs(v0 - v) > err_level*fabs(v0) )
1835             {
1836                 ts->printf( CvTS::LOG,
1837                     "The element #%d in the destination histogram #%d is inaccurate (=%g, should be =%g)\n",
1838                     i, j, v, v0 );
1839                 code = CvTS::FAIL_BAD_ACCURACY;
1840                 break;
1841             }
1842         }
1843         if( j < n )
1844             break;
1845     }
1846
1847     if( code < 0 )
1848         ts->set_failed_test_info( code );
1849     return code;
1850 }
1851
1852
1853 CV_BayesianProbTest hist_bayesianprob_test;
1854
1855 /* End Of File */