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