1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
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.
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.
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.
44 class CV_BaseHistTest : public CvTest
47 enum { MAX_HIST = 12 };
49 CV_BaseHistTest( const char* test_name, const char* test_funcs );
52 int write_default_params(CvFileStorage* fs);
55 int read_params( CvFileStorage* fs );
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 );
61 virtual void get_hist_params( int test_case_idx );
62 virtual float** get_hist_ranges( int test_case_idx );
68 int dims_sum[CV_MAX_DIM+1];
74 double gen_hist_max_val, gen_hist_sparse_nz_ratio;
79 double low, high, range_delta;
82 CvHistogram* hist[MAX_HIST];
84 float* ranges[CV_MAX_DIM];
88 CV_BaseHistTest::CV_BaseHistTest( const char* test_name, const char* test_funcs ):
89 CvTest( test_name, test_funcs )
93 test_case_count = 100;
101 gen_hist_max_val = 100;
103 for( i = 0; i < MAX_HIST; i++ )
106 support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
110 CV_BaseHistTest::~CV_BaseHistTest()
116 void CV_BaseHistTest::clear()
120 for( i = 0; i < MAX_HIST; i++ )
121 cvReleaseHist( &hist[i] );
127 int CV_BaseHistTest::write_default_params( CvFileStorage* fs )
129 CvTest::write_default_params( fs );
130 if( ts->get_testing_mode() != CvTS::TIMING_MODE )
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 );
141 int CV_BaseHistTest::read_params( CvFileStorage* fs )
143 int code = CvTest::read_params( fs );
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 );
153 max_cdims = cvReadInt( find_param( fs, "max_cdims" ), max_cdims );
154 max_cdims = cvTsClipInt( max_cdims, 1, 6 );
160 void CV_BaseHistTest::get_hist_params( int /*test_case_idx*/ )
162 CvRNG* rng = ts->get_rng();
163 int i, max_dim_size, max_ni_dim_size = 31;
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));
170 uniform = cvTsRandInt(rng) % 2;
171 hist_type = cvTsRandInt(rng) % 2 ? CV_HIST_SPARSE : CV_HIST_ARRAY;
173 for( i = 0; i < cdims; i++ )
175 dims[i] = cvTsRandInt(rng) % (max_dim_size + 1) + 1;
177 dims[i] = MIN(dims[i], max_ni_dim_size);
178 total_size *= dims[i];
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) );
185 low = cvTsMinVal(img_type);
186 high = cvTsMaxVal(img_type);
188 range_delta = (cvTsRandInt(rng) % 2)*(high-low)*0.05;
192 float** CV_BaseHistTest::get_hist_ranges( int /*test_case_idx*/ )
194 double _low = low + range_delta, _high = high - range_delta;
200 for( i = 0; i < cdims; i++ )
201 dims_sum[i+1] = dims_sum[i] + dims[i] + 1;
205 _ranges = new float[cdims*2];
206 for( i = cdims-1; i >= 0; i-- )
208 _ranges[i*2] = (float)_low;
209 _ranges[i*2+1] = (float)_high;
210 ranges[i] = _ranges + i*2;
215 _ranges = new float[dims_sum[cdims]];
217 for( i = 0; i < cdims; i++ )
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++ )
225 if( (pow(q,(double)n)-1)/(q-1.) >= _high-_low )
231 delta = (_high-_low)/n;
237 delta = cvFloor((_high-_low)*(q-1)/(pow(q,(double)n) - 1));
238 delta = MAX(delta, 1.);
242 for( j = 0; j <= n; j++ )
244 _ranges[j+ofs] = (float)MIN(val,_high);
248 ranges[i] = _ranges + ofs;
258 void CV_BaseHistTest::init_hist( int /*test_case_idx*/, int hist_i )
260 if( gen_random_hist )
262 CvRNG* rng = ts->get_rng();
263 CvArr* h = hist[hist_i]->bins;
265 if( hist_type == CV_HIST_ARRAY )
267 cvRandArr( rng, h, CV_RAND_UNI,
268 cvScalarAll(0), cvScalarAll(gen_hist_max_val) );
272 int i, j, total_size = 1, nz_count;
274 for( i = 0; i < cdims; i++ )
275 total_size *= dims[i];
277 nz_count = cvTsRandInt(rng) % MAX( total_size/4, 100 );
278 nz_count = MIN( nz_count, total_size );
280 // a zero number of non-zero elements should be allowed
281 for( i = 0; i < nz_count; i++ )
283 for( j = 0; j < cdims; j++ )
284 idx[j] = cvTsRandInt(rng) % dims[j];
285 cvSetRealND( h, idx, cvTsRandReal(rng)*gen_hist_max_val );
292 int CV_BaseHistTest::prepare_test_case( int test_case_idx )
299 CvTest::prepare_test_case( test_case_idx );
300 get_hist_params( test_case_idx );
301 r = get_hist_ranges( test_case_idx );
303 for( i = 0; i < hist_count; i++ )
305 hist[i] = cvCreateHist( cdims, dims, hist_type, r, uniform );
306 init_hist( test_case_idx, i );
313 void CV_BaseHistTest::run_func(void)
318 int CV_BaseHistTest::validate_test_results( int /*test_case_idx*/ )
324 CV_BaseHistTest hist_basetest( "hist", "" );
328 ////////////// testing operation for reading/writing individual histogram bins //////////////
330 class CV_QueryHistTest : public CV_BaseHistTest
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 );
350 CV_QueryHistTest::CV_QueryHistTest() : CV_BaseHistTest( "hist-query",
351 "cvGetReal1D, cvGetReal2D, cvGetReal3D, cvGetRealND, "
352 "cvPtr1D, cvPtr2D, cvPtr3D, cvPtrND, "
353 "cvSetReal1D, cvSetReal2D, cvSetReal3D, cvSetRealND" )
362 CV_QueryHistTest::~CV_QueryHistTest()
368 void CV_QueryHistTest::clear()
370 cvReleaseMat( &indices );
371 cvReleaseMat( &values );
372 cvReleaseMat( &values0 );
373 CV_BaseHistTest::clear();
377 void CV_QueryHistTest::init_hist( int /*test_case_idx*/, int i )
379 if( hist_type == CV_HIST_ARRAY )
380 cvZero( hist[i]->bins );
384 int CV_QueryHistTest::prepare_test_case( int test_case_idx )
386 int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
391 float default_value = 0.f;
392 CvRNG* rng = ts->get_rng();
396 iters = (cvTsRandInt(rng) % MAX(total_size/10,100)) + 1;
397 iters = MIN( iters, total_size*9/10 + 1 );
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;
404 //printf( "total_size = %d, cdims = %d, iters = %d\n", total_size, cdims, iters );
406 bit_mask = cvCreateMat( 1, (total_size + 7)/8, CV_8U );
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))
412 // set random histogram bins' values to the linear indices of the bins
413 for( i = 0; i < iters; i++ )
416 for( j = 0; j < cdims; j++ )
418 int t = cvTsRandInt(rng) % dims[j];
419 idx[i*cdims + j] = t;
420 lin_idx = lin_idx*dims[j] + t;
423 if( cvTsRandInt(rng) % 8 || GET_BIT(lin_idx) )
425 values0->data.fl[i] = (float)(lin_idx+1);
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;
434 // do the second pass to make values0 consistent with bit_mask
435 for( i = 0; i < iters; i++ )
438 for( j = 0; j < cdims; j++ )
439 lin_idx = lin_idx*dims[j] + idx[i*cdims + j];
441 if( GET_BIT(lin_idx) )
442 values0->data.fl[i] = (float)(lin_idx+1);
445 cvReleaseMat( &bit_mask );
452 void CV_QueryHistTest::run_func(void)
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;
460 // stage 1: write bins
462 for( i = 0; i < iters; i++ )
464 float v0 = values0->data.fl[i];
465 if( fabs(v0 - default_value) < FLT_EPSILON )
470 cvSetReal1D( h, idx[i], v0 );
472 *(float*)cvPtr1D( h, idx[i] ) = v0;
475 cvSetRealND( h, idx+i, v0 );
477 else if( cdims == 2 )
478 for( i = 0; i < iters; i++ )
480 float v0 = values0->data.fl[i];
481 if( fabs(v0 - default_value) < FLT_EPSILON )
486 cvSetReal2D( h, idx[i*2], idx[i*2+1], v0 );
488 *(float*)cvPtr2D( h, idx[i*2], idx[i*2+1] ) = v0;
491 cvSetRealND( h, idx+i*2, v0 );
493 else if( cdims == 3 )
494 for( i = 0; i < iters; i++ )
496 float v0 = values0->data.fl[i];
497 if( fabs(v0 - default_value) < FLT_EPSILON )
502 cvSetReal3D( h, idx[i*3], idx[i*3+1], idx[i*3+2], v0 );
504 *(float*)cvPtr3D( h, idx[i*3], idx[i*3+1], idx[i*3+2] ) = v0;
507 cvSetRealND( h, idx+i*3, v0 );
510 for( i = 0; i < iters; i++ )
512 float v0 = values0->data.fl[i];
513 if( fabs(v0 - default_value) < FLT_EPSILON )
516 cvSetRealND( h, idx+i*cdims, v0 );
518 *(float*)cvPtrND( h, idx+i*cdims ) = v0;
521 // stage 2: read bins
523 for( i = 0; i < iters; i++ )
526 val[i] = *(float*)cvPtr1D( h, idx[i] );
528 val[i] = (float)cvGetReal1D( h, idx[i] );
530 else if( cdims == 2 )
531 for( i = 0; i < iters; i++ )
534 val[i] = *(float*)cvPtr2D( h, idx[i*2], idx[i*2+1] );
536 val[i] = (float)cvGetReal2D( h, idx[i*2], idx[i*2+1] );
538 else if( cdims == 3 )
539 for( i = 0; i < iters; i++ )
542 val[i] = *(float*)cvPtr3D( h, idx[i*3], idx[i*3+1], idx[i*3+2] );
544 val[i] = (float)cvGetReal3D( h, idx[i*3], idx[i*3+1], idx[i*3+2] );
547 for( i = 0; i < iters; i++ )
550 val[i] = *(float*)cvPtrND( h, idx+i*cdims );
552 val[i] = (float)cvGetRealND( h, idx+i*cdims );
557 int CV_QueryHistTest::validate_test_results( int /*test_case_idx*/ )
560 int i, j, iters = values->cols;
562 for( i = 0; i < iters; i++ )
564 float v = values->data.fl[i], v0 = values0->data.fl[i];
566 if( cvIsNaN(v) || cvIsInf(v) )
568 ts->printf( CvTS::LOG, "The bin #%d has invalid value\n", i );
569 code = CvTS::FAIL_INVALID_OUTPUT;
571 else if( fabs(v - v0) > FLT_EPSILON )
573 ts->printf( CvTS::LOG, "The bin #%d = %g, while it should be %g\n", i, v, v0 );
574 code = CvTS::FAIL_BAD_ACCURACY;
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" );
588 ts->set_failed_test_info( code );
593 CV_QueryHistTest hist_query_test;
596 ////////////// cvGetMinMaxHistValue //////////////
598 class CV_MinMaxHistTest : public CV_BaseHistTest
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;
615 CV_MinMaxHistTest::CV_MinMaxHistTest() :
616 CV_BaseHistTest( "hist-minmax", "cvGetMinMaxHistValue" )
623 void CV_MinMaxHistTest::init_hist(int test_case_idx, int hist_i)
626 CvRNG* rng = ts->get_rng();
627 CV_BaseHistTest::init_hist( test_case_idx, hist_i );
631 for( i = 0; i < cdims; i++ )
633 min_idx0[i] = cvTsRandInt(rng) % dims[i];
634 max_idx0[i] = cvTsRandInt(rng) % dims[i];
635 eq &= min_idx0[i] == max_idx0[i];
637 if( !eq || total_size == 1 )
641 min_val0 = (float)(-cvTsRandReal(rng)*10 - FLT_EPSILON);
642 max_val0 = (float)(cvTsRandReal(rng)*10 + FLT_EPSILON + gen_hist_max_val);
644 if( total_size == 1 )
647 cvSetRealND( hist[0]->bins, min_idx0, min_val0 );
648 cvSetRealND( hist[0]->bins, max_idx0, max_val0 );
652 void CV_MinMaxHistTest::run_func(void)
654 cvGetMinMaxHistValue( hist[0], &min_val, &max_val, min_idx, max_idx );
658 int CV_MinMaxHistTest::validate_test_results( int /*test_case_idx*/ )
662 if( cvIsNaN(min_val) || cvIsInf(min_val) ||
663 cvIsNaN(max_val) || cvIsInf(max_val) )
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;
669 else if( fabs(min_val - min_val0) > FLT_EPSILON ||
670 fabs(max_val - max_val0) > FLT_EPSILON )
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;
680 for( i = 0; i < cdims; i++ )
682 if( min_idx[i] != min_idx0[i] || max_idx[i] != max_idx0[i] )
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;
694 ts->set_failed_test_info( code );
699 CV_MinMaxHistTest hist_minmax_test;
703 ////////////// cvNormalizeHist //////////////
705 class CV_NormHistTest : public CV_BaseHistTest
711 int prepare_test_case( int test_case_idx );
713 int validate_test_results( int test_case_idx );
719 CV_NormHistTest::CV_NormHistTest() :
720 CV_BaseHistTest( "hist-normalize", "cvNormalizeHist" )
728 int CV_NormHistTest::prepare_test_case( int test_case_idx )
730 int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
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 )
745 void CV_NormHistTest::run_func(void)
747 cvNormalizeHist( hist[0], factor );
751 int CV_NormHistTest::validate_test_results( int /*test_case_idx*/ )
756 if( hist_type == CV_HIST_ARRAY )
759 const float* ptr = (float*)cvPtr1D( hist[0]->bins, 0 );
761 for( i = 0; i < total_size; i++ )
766 CvSparseMat* sparse = (CvSparseMat*)hist[0]->bins;
767 CvSparseMatIterator iterator;
770 for( node = cvInitSparseMatIterator( sparse, &iterator );
771 node != 0; node = cvGetNextSparseNode( &iterator ))
773 sum += *(float*)CV_NODE_VAL(sparse,node);
777 if( cvIsNaN(sum) || cvIsInf(sum) )
779 ts->printf( CvTS::LOG,
780 "The normalized histogram has invalid sum =%g\n", sum );
781 code = CvTS::FAIL_INVALID_OUTPUT;
783 else if( fabs(sum - factor) > FLT_EPSILON*10*fabs(factor) )
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;
791 ts->set_failed_test_info( code );
796 CV_NormHistTest hist_norm_test;
800 ////////////// cvThreshHist //////////////
802 class CV_ThreshHistTest : public CV_BaseHistTest
806 ~CV_ThreshHistTest();
810 int prepare_test_case( int test_case_idx );
812 int validate_test_results( int test_case_idx );
822 CV_ThreshHistTest::CV_ThreshHistTest() :
823 CV_BaseHistTest( "hist-threshold", "cvThreshHist" )
828 indices = values = 0;
832 CV_ThreshHistTest::~CV_ThreshHistTest()
838 void CV_ThreshHistTest::clear()
840 cvReleaseMat( &indices );
841 cvReleaseMat( &values );
842 CV_BaseHistTest::clear();
846 int CV_ThreshHistTest::prepare_test_case( int test_case_idx )
848 int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
852 CvRNG* rng = ts->get_rng();
853 threshold = cvTsRandReal(rng)*gen_hist_max_val;
855 if( hist_type == CV_HIST_ARRAY )
857 orig_nz_count = total_size;
859 values = cvCreateMat( 1, total_size, CV_32F );
860 memcpy( values->data.fl, cvPtr1D( hist[0]->bins, 0 ), total_size*sizeof(float) );
864 CvSparseMat* sparse = (CvSparseMat*)hist[0]->bins;
865 CvSparseMatIterator iterator;
869 orig_nz_count = sparse->heap->active_count;
871 values = cvCreateMat( 1, orig_nz_count+1, CV_32F );
872 indices = cvCreateMat( 1, (orig_nz_count+1)*cdims, CV_32S );
874 for( node = cvInitSparseMatIterator( sparse, &iterator ), i = 0;
875 node != 0; node = cvGetNextSparseNode( &iterator ), i++ )
877 const int* idx = CV_NODE_IDX(sparse,node);
879 OPENCV_ASSERT( i < orig_nz_count, "CV_ThreshHistTest::prepare_test_case", "Buffer overflow" );
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];
886 OPENCV_ASSERT( i == orig_nz_count, "Unmatched buffer size",
887 "CV_ThreshHistTest::prepare_test_case" );
895 void CV_ThreshHistTest::run_func(void)
897 cvThreshHist( hist[0], threshold );
901 int CV_ThreshHistTest::validate_test_results( int /*test_case_idx*/ )
905 float* ptr0 = values->data.fl;
907 CvSparseMat* sparse = 0;
909 if( hist_type == CV_HIST_ARRAY )
910 ptr = (float*)cvPtr1D( hist[0]->bins, 0 );
912 sparse = (CvSparseMat*)hist[0]->bins;
916 for( i = 0; i < orig_nz_count; i++ )
918 float v0 = ptr0[i], v;
920 if( hist_type == CV_HIST_ARRAY )
924 v = (float)cvGetRealND( sparse, indices->data.i + i*cdims );
925 cvClearND( sparse, indices->data.i + i*cdims );
928 if( v0 <= threshold ) v0 = 0.f;
929 if( cvIsNaN(v) || cvIsInf(v) )
931 ts->printf( CvTS::LOG, "The %d-th bin is invalid (=%g)\n", i, v );
932 code = CvTS::FAIL_INVALID_OUTPUT;
935 else if( fabs(v0 - v) > FLT_EPSILON*10*fabs(v0) )
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;
944 if( code > 0 && hist_type == CV_HIST_SPARSE )
946 if( sparse->heap->active_count > 0 )
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;
955 ts->set_failed_test_info( code );
960 CV_ThreshHistTest hist_thresh_test;
963 ////////////// cvCompareHist //////////////
965 class CV_CompareHistTest : public CV_BaseHistTest
968 enum { MAX_METHOD = 4 };
970 CV_CompareHistTest();
972 int prepare_test_case( int test_case_idx );
974 int validate_test_results( int test_case_idx );
975 double result[MAX_METHOD+1];
980 CV_CompareHistTest::CV_CompareHistTest() :
981 CV_BaseHistTest( "hist-compare", "cvCompareHist" )
988 int CV_CompareHistTest::prepare_test_case( int test_case_idx )
990 int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
996 void CV_CompareHistTest::run_func(void)
999 for( k = 0; k < MAX_METHOD; k++ )
1000 result[k] = cvCompareHist( hist[0], hist[1], k );
1004 int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ )
1006 int code = CvTS::OK;
1008 double result0[MAX_METHOD+1];
1009 double s0 = 0, s1 = 0, sq0 = 0, sq1 = 0, t;
1011 for( i = 0; i < MAX_METHOD; i++ )
1014 if( hist_type == CV_HIST_ARRAY )
1016 float* ptr0 = (float*)cvPtr1D( hist[0]->bins, 0 );
1017 float* ptr1 = (float*)cvPtr1D( hist[1]->bins, 0 );
1019 for( i = 0; i < total_size; i++ )
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);
1030 result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1);
1035 CvSparseMat* sparse0 = (CvSparseMat*)hist[0]->bins;
1036 CvSparseMat* sparse1 = (CvSparseMat*)hist[1]->bins;
1037 CvSparseMatIterator iterator;
1040 for( node = cvInitSparseMatIterator( sparse0, &iterator );
1041 node != 0; node = cvGetNextSparseNode( &iterator ) )
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);
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);
1053 result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1);
1056 for( node = cvInitSparseMatIterator( sparse1, &iterator );
1057 node != 0; node = cvGetNextSparseNode( &iterator ) )
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);
1063 if( fabs(v0) < DBL_EPSILON )
1064 result0[CV_COMP_CHISQR] += v1;
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;
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.));
1079 for( i = 0; i < MAX_METHOD; i++ )
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";
1088 if( cvIsNaN(v) || cvIsInf(v) )
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;
1095 else if( fabs(v0 - v) > FLT_EPSILON*10*MAX(fabs(v0),0.1) )
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;
1105 ts->set_failed_test_info( code );
1110 CV_CompareHistTest hist_compare_test;
1114 ////////////// cvCalcHist //////////////
1116 class CV_CalcHistTest : public CV_BaseHistTest
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];
1133 CV_CalcHistTest::CV_CalcHistTest() :
1134 CV_BaseHistTest( "hist-calc", "cvCalcHist" )
1139 gen_random_hist = 0;
1142 for( i = 0; i <= CV_MAX_DIM; i++ )
1150 CV_CalcHistTest::~CV_CalcHistTest()
1156 void CV_CalcHistTest::clear()
1160 for( i = 0; i <= CV_MAX_DIM; i++ )
1161 cvReleaseImage( &images[i] );
1163 CV_BaseHistTest::clear();
1167 int CV_CalcHistTest::prepare_test_case( int test_case_idx )
1169 int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
1173 CvRNG* rng = ts->get_rng();
1176 for( i = 0; i <= CV_MAX_DIM; i++ )
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;
1185 cvRandArr( rng, images[i], CV_RAND_UNI,
1186 cvScalarAll(low), cvScalarAll(high) );
1188 else if( i == CV_MAX_DIM && cvTsRandInt(rng) % 2 )
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) );
1203 void CV_CalcHistTest::run_func(void)
1205 cvCalcHist( images, hist[0], 0, images[CV_MAX_DIM] );
1210 cvTsCalcHist( IplImage** _images, CvHistogram* hist, IplImage* _mask, int* channels )
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;
1226 cdims = cvGetDims( hist->bins, dims );
1228 cvZero( hist->bins );
1230 for( k = 0; k < cdims; k++ )
1232 cvGetMat( _images[k], &images[k] );
1233 nch[k] = _images[k]->nChannels;
1237 cvGetMat( _mask, &mask );
1239 for( y = 0; y < img_size.height; y++ )
1241 const uchar* mptr = _mask ? &CV_MAT_ELEM(mask, uchar, y, 0 ) : 0;
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];
1247 for( k = 0; k < cdims; k++ )
1248 plane[k].fl = &CV_MAT_ELEM(images[k], float, y, 0 ) + channels[k];
1250 for( x = 0; x < img_size.width; x++ )
1252 float val[CV_MAX_DIM];
1253 int idx[CV_MAX_DIM];
1255 if( mptr && !mptr[x] )
1257 if( img_depth == IPL_DEPTH_8U )
1258 for( k = 0; k < cdims; k++ )
1259 val[k] = plane[k].ptr[x*nch[k]];
1261 for( k = 0; k < cdims; k++ )
1262 val[k] = plane[k].fl[x*nch[k]];
1268 for( k = 0; k < cdims; k++ )
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] )
1278 for( k = 0; k < cdims; k++ )
1281 float* t = hist->thresh2[k];
1284 for( j = 0; j <= n; j++ )
1287 if( j <= 0 || j > n )
1296 (*(float*)cvPtrND( hist->bins, idx ))++;
1302 int CV_CalcHistTest::validate_test_results( int /*test_case_idx*/ )
1304 int code = CvTS::OK;
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 )
1310 ts->printf( CvTS::LOG, "The histogram does not match to the reference one\n" );
1311 code = CvTS::FAIL_BAD_ACCURACY;
1316 ts->set_failed_test_info( code );
1321 CV_CalcHistTest hist_calc_test;
1325 ////////////// cvCalcBackProject //////////////
1327 class CV_CalcBackProjectTest : public CV_BaseHistTest
1330 CV_CalcBackProjectTest();
1331 ~CV_CalcBackProjectTest();
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];
1344 CV_CalcBackProjectTest::CV_CalcBackProjectTest() :
1345 CV_BaseHistTest( "hist-backproj", "cvCalcBackProject" )
1350 gen_random_hist = 0;
1353 for( i = 0; i < CV_MAX_DIM+3; i++ )
1361 CV_CalcBackProjectTest::~CV_CalcBackProjectTest()
1367 void CV_CalcBackProjectTest::clear()
1371 for( i = 0; i < CV_MAX_DIM+3; i++ )
1372 cvReleaseImage( &images[i] );
1374 CV_BaseHistTest::clear();
1378 int CV_CalcBackProjectTest::prepare_test_case( int test_case_idx )
1380 int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
1384 CvRNG* rng = ts->get_rng();
1385 int i, j, n, img_len = img_size.width*img_size.height;
1387 for( i = 0; i < CV_MAX_DIM + 3; i++ )
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;
1396 cvRandArr( rng, images[i], CV_RAND_UNI,
1397 cvScalarAll(low), cvScalarAll(high) );
1399 else if( i == CV_MAX_DIM && cvTsRandInt(rng) % 2 )
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) );
1407 else if( i > CV_MAX_DIM )
1409 images[i] = cvCreateImage( img_size, images[0]->depth, 1 );
1413 cvTsCalcHist( images, hist[0], images[CV_MAX_DIM], channels );
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++ )
1419 char* data = images[i]->imageData;
1420 for( j = 0; j < n; j++ )
1422 int idx = cvTsRandInt(rng) % img_len;
1423 double val = cvTsRandReal(rng)*(high - low) + low;
1425 if( img_type == CV_8U )
1426 ((uchar*)data)[idx] = (uchar)cvRound(val);
1428 ((float*)data)[idx] = (float)val;
1437 void CV_CalcBackProjectTest::run_func(void)
1439 cvCalcBackProject( images, images[CV_MAX_DIM+1], hist[0] );
1444 cvTsCalcBackProject( IplImage** images, IplImage* dst, CvHistogram* hist, int* channels )
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;
1459 cdims = cvGetDims( hist->bins, dims );
1461 for( k = 0; k < cdims; k++ )
1462 nch[k] = images[k]->nChannels;
1464 for( y = 0; y < img_size.height; y++ )
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];
1470 for( k = 0; k < cdims; k++ )
1471 plane[k].fl = &CV_IMAGE_ELEM(images[k], float, y, 0 ) + channels[k];
1473 for( x = 0; x < img_size.width; x++ )
1475 float val[CV_MAX_DIM];
1477 int idx[CV_MAX_DIM];
1479 if( img_depth == IPL_DEPTH_8U )
1480 for( k = 0; k < cdims; k++ )
1481 val[k] = plane[k].ptr[x*nch[k]];
1483 for( k = 0; k < cdims; k++ )
1484 val[k] = plane[k].fl[x*nch[k]];
1489 for( k = 0; k < cdims; k++ )
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] )
1499 for( k = 0; k < cdims; k++ )
1502 float* t = hist->thresh2[k];
1505 for( j = 0; j <= n; j++ )
1508 if( j <= 0 || j > n )
1515 bin_val = (float)cvGetRealND( hist->bins, idx );
1517 if( img_depth == IPL_DEPTH_8U )
1519 int t = cvRound(bin_val);
1520 CV_IMAGE_ELEM( dst, uchar, y, x ) = CV_CAST_8U(t);
1523 CV_IMAGE_ELEM( dst, float, y, x ) = bin_val;
1529 int CV_CalcBackProjectTest::validate_test_results( int /*test_case_idx*/ )
1531 int code = CvTS::OK;
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" );
1538 ts->set_failed_test_info( code );
1544 CV_CalcBackProjectTest hist_backproj_test;
1547 ////////////// cvCalcBackProjectPatch //////////////
1549 class CV_CalcBackProjectPatchTest : public CV_BaseHistTest
1552 CV_CalcBackProjectPatchTest();
1553 ~CV_CalcBackProjectPatchTest();
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];
1570 CV_CalcBackProjectPatchTest::CV_CalcBackProjectPatchTest() :
1571 CV_BaseHistTest( "hist-backprojpatch", "cvCalcBackProjectPatch" )
1576 gen_random_hist = 0;
1578 img_max_log_size = 6;
1580 for( i = 0; i < CV_MAX_DIM+2; i++ )
1588 CV_CalcBackProjectPatchTest::~CV_CalcBackProjectPatchTest()
1594 void CV_CalcBackProjectPatchTest::clear()
1598 for( i = 0; i < CV_MAX_DIM+2; i++ )
1599 cvReleaseImage( &images[i] );
1601 CV_BaseHistTest::clear();
1605 int CV_CalcBackProjectPatchTest::prepare_test_case( int test_case_idx )
1607 int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
1611 CvRNG* rng = ts->get_rng();
1612 int i, j, n, img_len = img_size.width*img_size.height;
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 );
1620 method = cvTsRandInt(rng) % CV_CompareHistTest::MAX_METHOD;
1622 for( i = 0; i < CV_MAX_DIM + 2; i++ )
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;
1631 cvRandArr( rng, images[i], CV_RAND_UNI,
1632 cvScalarAll(low), cvScalarAll(high) );
1634 else if( i >= CV_MAX_DIM )
1636 images[i] = cvCreateImage(
1637 cvSize(img_size.width - patch_size.width + 1,
1638 img_size.height - patch_size.height + 1),
1643 cvTsCalcHist( images, hist[0], 0, channels );
1644 cvNormalizeHist( hist[0], factor );
1646 // now modify the images a bit
1647 n = cvTsRandInt(rng) % (img_len/10+1);
1648 for( i = 0; i < cdims; i++ )
1650 char* data = images[i]->imageData;
1651 for( j = 0; j < n; j++ )
1653 int idx = cvTsRandInt(rng) % img_len;
1654 double val = cvTsRandReal(rng)*(high - low) + low;
1656 if( img_type == CV_8U )
1657 ((uchar*)data)[idx] = (uchar)cvRound(val);
1659 ((float*)data)[idx] = (float)val;
1668 void CV_CalcBackProjectPatchTest::run_func(void)
1670 cvCalcBackProjectPatch( images, images[CV_MAX_DIM], patch_size, hist[0], method, factor );
1675 cvTsCalcBackProjectPatch( IplImage** images, IplImage* dst, CvSize patch_size,
1676 CvHistogram* hist, int method,
1677 double factor, int* channels )
1679 CvHistogram* model = 0;
1681 IplImage imgstub[CV_MAX_DIM], *img[CV_MAX_DIM];
1685 CvSize size = cvGetSize(dst);
1687 dims = cvGetDims( hist->bins );
1688 cvCopyHist( hist, &model );
1689 cvNormalizeHist( hist, factor );
1692 for( i = 0; i < dims; i++ )
1695 mat = cvGetMat( images[i], &stub, 0, 0 );
1696 img[i] = cvGetImage( mat, &imgstub[i] );
1702 for( y = 0; y < size.height; y++ )
1704 for( x = 0; x < size.width; x++ )
1710 roi.width = patch_size.width;
1711 roi.height = patch_size.height;
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;
1720 cvReleaseHist( &model );
1724 int CV_CalcBackProjectPatchTest::validate_test_results( int /*test_case_idx*/ )
1726 int code = CvTS::OK;
1727 double err_level = 5e-3;
1729 cvTsCalcBackProjectPatch( images, images[CV_MAX_DIM+1],
1730 patch_size, hist[0], method, factor, channels );
1732 code = cvTsCmpEps2( ts, images[CV_MAX_DIM], images[CV_MAX_DIM+1], err_level, true,
1733 "BackProjectPatch result" );
1736 ts->set_failed_test_info( code );
1742 CV_CalcBackProjectPatchTest hist_backprojpatch_test;
1745 ////////////// cvCalcBayesianProb //////////////
1747 class CV_BayesianProbTest : public CV_BaseHistTest
1750 enum { MAX_METHOD = 4 };
1752 CV_BayesianProbTest();
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 );
1763 CV_BayesianProbTest::CV_BayesianProbTest() :
1764 CV_BaseHistTest( "hist-bayesianprob", "cvBayesianProb" )
1766 hist_count = CV_MAX_DIM;
1767 gen_random_hist = 1;
1771 void CV_BayesianProbTest::get_hist_params( int test_case_idx )
1773 CV_BaseHistTest::get_hist_params( test_case_idx );
1774 hist_type = CV_HIST_ARRAY;
1778 void CV_BayesianProbTest::init_hist( int test_case_idx, int hist_i )
1780 if( hist_i < hist_count/2 )
1781 CV_BaseHistTest::init_hist( test_case_idx, hist_i );
1785 int CV_BayesianProbTest::prepare_test_case( int test_case_idx )
1787 CvRNG* rng = ts->get_rng();
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 );
1797 void CV_BayesianProbTest::run_func(void)
1799 cvCalcBayesianProb( hist, hist_count/2, hist + hist_count/2 );
1803 int CV_BayesianProbTest::validate_test_results( int /*test_case_idx*/ )
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;
1810 for( i = 0; i < total_size; i++ )
1813 for( j = 0; j < n; j++ )
1815 double v = hist[j]->mat.data.fl[i];
1819 sum = sum > DBL_EPSILON ? 1./sum : 0;
1821 for( j = 0; j < n; j++ )
1823 double v0 = s[j]*sum;
1824 double v = hist[j+n]->mat.data.fl[i];
1826 if( cvIsNaN(v) || cvIsInf(v) )
1828 ts->printf( CvTS::LOG,
1829 "The element #%d in the destination histogram #%d is invalid (=%g)\n",
1831 code = CvTS::FAIL_INVALID_OUTPUT;
1834 else if( fabs(v0 - v) > err_level*fabs(v0) )
1836 ts->printf( CvTS::LOG,
1837 "The element #%d in the destination histogram #%d is inaccurate (=%g, should be =%g)\n",
1839 code = CvTS::FAIL_BAD_ACCURACY;
1848 ts->set_failed_test_info( code );
1853 CV_BayesianProbTest hist_bayesianprob_test;