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