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