Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/core/test/test_math.cpp
16337 views
1
// This file is part of OpenCV project.
2
// It is subject to the license terms in the LICENSE file found in the top-level directory
3
// of this distribution and at http://opencv.org/license.html.
4
5
//////////////////////////////////////////////////////////////////////////////////////////
6
/////////////////// tests for matrix operations and math functions ///////////////////////
7
//////////////////////////////////////////////////////////////////////////////////////////
8
9
#include "test_precomp.hpp"
10
#include <float.h>
11
#include <math.h>
12
#include "opencv2/core/softfloat.hpp"
13
14
namespace opencv_test { namespace {
15
16
/// !!! NOTE !!! These tests happily avoid overflow cases & out-of-range arguments
17
/// so that output arrays contain neigher Inf's nor Nan's.
18
/// Handling such cases would require special modification of check function
19
/// (validate_test_results) => TBD.
20
/// Also, need some logarithmic-scale generation of input data. Right now it is done (in some tests)
21
/// by generating min/max boundaries for random data in logarimithic scale, but
22
/// within the same test case all the input array elements are of the same order.
23
24
class Core_MathTest : public cvtest::ArrayTest
25
{
26
public:
27
typedef cvtest::ArrayTest Base;
28
Core_MathTest();
29
protected:
30
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes,
31
vector<vector<int> >& types);
32
double get_success_error_level( int /*test_case_idx*/, int i, int j );
33
bool test_nd;
34
};
35
36
37
Core_MathTest::Core_MathTest()
38
{
39
optional_mask = false;
40
41
test_array[INPUT].push_back(NULL);
42
test_array[OUTPUT].push_back(NULL);
43
test_array[REF_OUTPUT].push_back(NULL);
44
45
test_nd = false;
46
}
47
48
49
double Core_MathTest::get_success_error_level( int /*test_case_idx*/, int i, int j )
50
{
51
return test_mat[i][j].depth() == CV_32F ? FLT_EPSILON*128 : DBL_EPSILON*1024;
52
}
53
54
55
void Core_MathTest::get_test_array_types_and_sizes( int test_case_idx,
56
vector<vector<Size> >& sizes,
57
vector<vector<int> >& types)
58
{
59
RNG& rng = ts->get_rng();
60
int depth = cvtest::randInt(rng)%2 + CV_32F;
61
int cn = cvtest::randInt(rng) % 4 + 1, type = CV_MAKETYPE(depth, cn);
62
size_t i, j;
63
Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
64
65
for( i = 0; i < test_array.size(); i++ )
66
{
67
size_t count = test_array[i].size();
68
for( j = 0; j < count; j++ )
69
types[i][j] = type;
70
}
71
test_nd = cvtest::randInt(rng)%3 == 0;
72
}
73
74
75
////////// pow /////////////
76
77
class Core_PowTest : public Core_MathTest
78
{
79
public:
80
typedef Core_MathTest Base;
81
Core_PowTest();
82
protected:
83
void get_test_array_types_and_sizes( int test_case_idx,
84
vector<vector<Size> >& sizes,
85
vector<vector<int> >& types );
86
void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
87
void run_func();
88
void prepare_to_validation( int test_case_idx );
89
double get_success_error_level( int test_case_idx, int i, int j );
90
double power;
91
};
92
93
94
Core_PowTest::Core_PowTest()
95
{
96
power = 0;
97
}
98
99
100
void Core_PowTest::get_test_array_types_and_sizes( int test_case_idx,
101
vector<vector<Size> >& sizes,
102
vector<vector<int> >& types )
103
{
104
RNG& rng = ts->get_rng();
105
int depth = cvtest::randInt(rng) % (CV_64F+1);
106
int cn = cvtest::randInt(rng) % 4 + 1;
107
size_t i, j;
108
Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
109
depth += depth == CV_8S;
110
111
if( depth < CV_32F || cvtest::randInt(rng)%8 == 0 )
112
// integer power
113
power = (int)(cvtest::randInt(rng)%21 - 10);
114
else
115
{
116
i = cvtest::randInt(rng)%17;
117
power = i == 16 ? 1./3 : i == 15 ? 0.5 : i == 14 ? -0.5 : cvtest::randReal(rng)*10 - 5;
118
}
119
120
for( i = 0; i < test_array.size(); i++ )
121
{
122
size_t count = test_array[i].size();
123
int type = CV_MAKETYPE(depth, cn);
124
for( j = 0; j < count; j++ )
125
types[i][j] = type;
126
}
127
test_nd = cvtest::randInt(rng)%3 == 0;
128
}
129
130
131
double Core_PowTest::get_success_error_level( int test_case_idx, int i, int j )
132
{
133
int depth = test_mat[i][j].depth();
134
if( depth < CV_32F )
135
return power == cvRound(power) && power >= 0 ? 0 : 1;
136
else
137
{
138
return depth != CV_64F ? Base::get_success_error_level( test_case_idx, i, j ) : DBL_EPSILON*1024*1.1;
139
}
140
}
141
142
143
void Core_PowTest::get_minmax_bounds( int /*i*/, int /*j*/, int type, Scalar& low, Scalar& high )
144
{
145
double l, u = cvtest::randInt(ts->get_rng())%1000 + 1;
146
if( power > 0 )
147
{
148
double mval = cvtest::getMaxVal(type);
149
double u1 = pow(mval,1./power)*2;
150
u = MIN(u,u1);
151
}
152
153
l = power == cvRound(power) ? -u : FLT_EPSILON;
154
low = Scalar::all(l);
155
high = Scalar::all(u);
156
}
157
158
159
void Core_PowTest::run_func()
160
{
161
if(!test_nd)
162
{
163
if( fabs(power-1./3) <= DBL_EPSILON && test_mat[INPUT][0].depth() == CV_32F )
164
{
165
Mat a = test_mat[INPUT][0], b = test_mat[OUTPUT][0];
166
167
a = a.reshape(1);
168
b = b.reshape(1);
169
for( int i = 0; i < a.rows; i++ )
170
{
171
b.at<float>(i,0) = (float)fabs(cvCbrt(a.at<float>(i,0)));
172
for( int j = 1; j < a.cols; j++ )
173
b.at<float>(i,j) = (float)fabs(cv::cubeRoot(a.at<float>(i,j)));
174
}
175
}
176
else
177
cvPow( test_array[INPUT][0], test_array[OUTPUT][0], power );
178
}
179
else
180
{
181
Mat& a = test_mat[INPUT][0];
182
Mat& b = test_mat[OUTPUT][0];
183
if(power == 0.5)
184
cv::sqrt(a, b);
185
else
186
cv::pow(a, power, b);
187
}
188
}
189
190
191
inline static int ipow( int a, int power )
192
{
193
int b = 1;
194
while( power > 0 )
195
{
196
if( power&1 )
197
b *= a, power--;
198
else
199
a *= a, power >>= 1;
200
}
201
return b;
202
}
203
204
205
inline static double ipow( double a, int power )
206
{
207
double b = 1.;
208
while( power > 0 )
209
{
210
if( power&1 )
211
b *= a, power--;
212
else
213
a *= a, power >>= 1;
214
}
215
return b;
216
}
217
218
219
void Core_PowTest::prepare_to_validation( int /*test_case_idx*/ )
220
{
221
const Mat& a = test_mat[INPUT][0];
222
Mat& b = test_mat[REF_OUTPUT][0];
223
224
int depth = a.depth();
225
int ncols = a.cols*a.channels();
226
int ipower = cvRound(power), apower = abs(ipower);
227
int i, j;
228
229
for( i = 0; i < a.rows; i++ )
230
{
231
const uchar* a_data = a.ptr(i);
232
uchar* b_data = b.ptr(i);
233
234
switch( depth )
235
{
236
case CV_8U:
237
if( ipower < 0 )
238
for( j = 0; j < ncols; j++ )
239
{
240
int val = ((uchar*)a_data)[j];
241
((uchar*)b_data)[j] = (uchar)(val == 0 ? 255 : val == 1 ? 1 :
242
val == 2 && ipower == -1 ? 1 : 0);
243
}
244
else
245
for( j = 0; j < ncols; j++ )
246
{
247
int val = ((uchar*)a_data)[j];
248
val = ipow( val, ipower );
249
((uchar*)b_data)[j] = saturate_cast<uchar>(val);
250
}
251
break;
252
case CV_8S:
253
if( ipower < 0 )
254
for( j = 0; j < ncols; j++ )
255
{
256
int val = ((schar*)a_data)[j];
257
((schar*)b_data)[j] = (schar)(val == 0 ? 127 : val == 1 ? 1 :
258
val ==-1 ? 1-2*(ipower&1) :
259
val == 2 && ipower == -1 ? 1 : 0);
260
}
261
else
262
for( j = 0; j < ncols; j++ )
263
{
264
int val = ((schar*)a_data)[j];
265
val = ipow( val, ipower );
266
((schar*)b_data)[j] = saturate_cast<schar>(val);
267
}
268
break;
269
case CV_16U:
270
if( ipower < 0 )
271
for( j = 0; j < ncols; j++ )
272
{
273
int val = ((ushort*)a_data)[j];
274
((ushort*)b_data)[j] = (ushort)(val == 0 ? 65535 : val == 1 ? 1 :
275
val ==-1 ? 1-2*(ipower&1) :
276
val == 2 && ipower == -1 ? 1 : 0);
277
}
278
else
279
for( j = 0; j < ncols; j++ )
280
{
281
int val = ((ushort*)a_data)[j];
282
val = ipow( val, ipower );
283
((ushort*)b_data)[j] = saturate_cast<ushort>(val);
284
}
285
break;
286
case CV_16S:
287
if( ipower < 0 )
288
for( j = 0; j < ncols; j++ )
289
{
290
int val = ((short*)a_data)[j];
291
((short*)b_data)[j] = (short)(val == 0 ? 32767 : val == 1 ? 1 :
292
val ==-1 ? 1-2*(ipower&1) :
293
val == 2 && ipower == -1 ? 1 : 0);
294
}
295
else
296
for( j = 0; j < ncols; j++ )
297
{
298
int val = ((short*)a_data)[j];
299
val = ipow( val, ipower );
300
((short*)b_data)[j] = saturate_cast<short>(val);
301
}
302
break;
303
case CV_32S:
304
if( ipower < 0 )
305
for( j = 0; j < ncols; j++ )
306
{
307
int val = ((int*)a_data)[j];
308
((int*)b_data)[j] = val == 0 ? INT_MAX : val == 1 ? 1 :
309
val ==-1 ? 1-2*(ipower&1) :
310
val == 2 && ipower == -1 ? 1 : 0;
311
}
312
else
313
for( j = 0; j < ncols; j++ )
314
{
315
int val = ((int*)a_data)[j];
316
val = ipow( val, ipower );
317
((int*)b_data)[j] = val;
318
}
319
break;
320
case CV_32F:
321
if( power != ipower )
322
for( j = 0; j < ncols; j++ )
323
{
324
double val = ((float*)a_data)[j];
325
val = pow( fabs(val), power );
326
((float*)b_data)[j] = (float)val;
327
}
328
else
329
for( j = 0; j < ncols; j++ )
330
{
331
double val = ((float*)a_data)[j];
332
if( ipower < 0 )
333
val = 1./val;
334
val = ipow( val, apower );
335
((float*)b_data)[j] = (float)val;
336
}
337
break;
338
case CV_64F:
339
if( power != ipower )
340
for( j = 0; j < ncols; j++ )
341
{
342
double val = ((double*)a_data)[j];
343
val = pow( fabs(val), power );
344
((double*)b_data)[j] = (double)val;
345
}
346
else
347
for( j = 0; j < ncols; j++ )
348
{
349
double val = ((double*)a_data)[j];
350
if( ipower < 0 )
351
val = 1./val;
352
val = ipow( val, apower );
353
((double*)b_data)[j] = (double)val;
354
}
355
break;
356
}
357
}
358
}
359
360
///////////////////////////////////////// matrix tests ////////////////////////////////////////////
361
362
class Core_MatrixTest : public cvtest::ArrayTest
363
{
364
public:
365
typedef cvtest::ArrayTest Base;
366
Core_MatrixTest( int in_count, int out_count,
367
bool allow_int, bool scalar_output, int max_cn );
368
protected:
369
void get_test_array_types_and_sizes( int test_case_idx,
370
vector<vector<Size> >& sizes,
371
vector<vector<int> >& types );
372
double get_success_error_level( int test_case_idx, int i, int j );
373
bool allow_int;
374
bool scalar_output;
375
int max_cn;
376
};
377
378
379
Core_MatrixTest::Core_MatrixTest( int in_count, int out_count,
380
bool _allow_int, bool _scalar_output, int _max_cn )
381
: allow_int(_allow_int), scalar_output(_scalar_output), max_cn(_max_cn)
382
{
383
int i;
384
for( i = 0; i < in_count; i++ )
385
test_array[INPUT].push_back(NULL);
386
387
for( i = 0; i < out_count; i++ )
388
{
389
test_array[OUTPUT].push_back(NULL);
390
test_array[REF_OUTPUT].push_back(NULL);
391
}
392
393
element_wise_relative_error = false;
394
}
395
396
397
void Core_MatrixTest::get_test_array_types_and_sizes( int test_case_idx,
398
vector<vector<Size> >& sizes,
399
vector<vector<int> >& types )
400
{
401
RNG& rng = ts->get_rng();
402
int depth = cvtest::randInt(rng) % (allow_int ? CV_64F+1 : 2);
403
int cn = cvtest::randInt(rng) % max_cn + 1;
404
size_t i, j;
405
406
if( allow_int )
407
depth += depth == CV_8S;
408
else
409
depth += CV_32F;
410
411
Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
412
413
for( i = 0; i < test_array.size(); i++ )
414
{
415
size_t count = test_array[i].size();
416
int flag = (i == OUTPUT || i == REF_OUTPUT) && scalar_output;
417
int type = !flag ? CV_MAKETYPE(depth, cn) : CV_64FC1;
418
419
for( j = 0; j < count; j++ )
420
{
421
types[i][j] = type;
422
if( flag )
423
sizes[i][j] = Size( 4, 1 );
424
}
425
}
426
}
427
428
429
double Core_MatrixTest::get_success_error_level( int test_case_idx, int i, int j )
430
{
431
int input_depth = test_mat[INPUT][0].depth();
432
double input_precision = input_depth < CV_32F ? 0 : input_depth == CV_32F ? 5e-5 : 5e-10;
433
double output_precision = Base::get_success_error_level( test_case_idx, i, j );
434
return MAX(input_precision, output_precision);
435
}
436
437
438
///////////////// Trace /////////////////////
439
440
class Core_TraceTest : public Core_MatrixTest
441
{
442
public:
443
Core_TraceTest();
444
protected:
445
void run_func();
446
void prepare_to_validation( int test_case_idx );
447
};
448
449
450
Core_TraceTest::Core_TraceTest() : Core_MatrixTest( 1, 1, true, true, 4 )
451
{
452
}
453
454
455
void Core_TraceTest::run_func()
456
{
457
test_mat[OUTPUT][0].at<Scalar>(0,0) = cvTrace(test_array[INPUT][0]);
458
}
459
460
461
void Core_TraceTest::prepare_to_validation( int )
462
{
463
Mat& mat = test_mat[INPUT][0];
464
int count = MIN( mat.rows, mat.cols );
465
Mat diag(count, 1, mat.type(), mat.ptr(), mat.step + mat.elemSize());
466
Scalar r = cvtest::mean(diag);
467
r *= (double)count;
468
469
test_mat[REF_OUTPUT][0].at<Scalar>(0,0) = r;
470
}
471
472
473
///////// dotproduct //////////
474
475
class Core_DotProductTest : public Core_MatrixTest
476
{
477
public:
478
Core_DotProductTest();
479
protected:
480
void run_func();
481
void prepare_to_validation( int test_case_idx );
482
};
483
484
485
Core_DotProductTest::Core_DotProductTest() : Core_MatrixTest( 2, 1, true, true, 4 )
486
{
487
}
488
489
490
void Core_DotProductTest::run_func()
491
{
492
test_mat[OUTPUT][0].at<Scalar>(0,0) = Scalar(cvDotProduct( test_array[INPUT][0], test_array[INPUT][1] ));
493
}
494
495
496
void Core_DotProductTest::prepare_to_validation( int )
497
{
498
test_mat[REF_OUTPUT][0].at<Scalar>(0,0) = Scalar(cvtest::crossCorr( test_mat[INPUT][0], test_mat[INPUT][1] ));
499
}
500
501
502
///////// crossproduct //////////
503
504
class Core_CrossProductTest : public Core_MatrixTest
505
{
506
public:
507
Core_CrossProductTest();
508
protected:
509
void get_test_array_types_and_sizes( int test_case_idx,
510
vector<vector<Size> >& sizes,
511
vector<vector<int> >& types );
512
void run_func();
513
void prepare_to_validation( int test_case_idx );
514
};
515
516
517
Core_CrossProductTest::Core_CrossProductTest() : Core_MatrixTest( 2, 1, false, false, 1 )
518
{
519
}
520
521
522
void Core_CrossProductTest::get_test_array_types_and_sizes( int,
523
vector<vector<Size> >& sizes,
524
vector<vector<int> >& types )
525
{
526
RNG& rng = ts->get_rng();
527
int depth = cvtest::randInt(rng) % 2 + CV_32F;
528
int cn = cvtest::randInt(rng) & 1 ? 3 : 1, type = CV_MAKETYPE(depth, cn);
529
Size sz;
530
531
types[INPUT][0] = types[INPUT][1] = types[OUTPUT][0] = types[REF_OUTPUT][0] = type;
532
533
if( cn == 3 )
534
sz = Size(1,1);
535
else if( cvtest::randInt(rng) & 1 )
536
sz = Size(3,1);
537
else
538
sz = Size(1,3);
539
540
sizes[INPUT][0] = sizes[INPUT][1] = sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sz;
541
}
542
543
544
void Core_CrossProductTest::run_func()
545
{
546
cvCrossProduct( test_array[INPUT][0], test_array[INPUT][1], test_array[OUTPUT][0] );
547
}
548
549
550
void Core_CrossProductTest::prepare_to_validation( int )
551
{
552
cv::Scalar a, b, c;
553
554
if( test_mat[INPUT][0].rows > 1 )
555
{
556
a.val[0] = cvGetReal2D( test_array[INPUT][0], 0, 0 );
557
a.val[1] = cvGetReal2D( test_array[INPUT][0], 1, 0 );
558
a.val[2] = cvGetReal2D( test_array[INPUT][0], 2, 0 );
559
560
b.val[0] = cvGetReal2D( test_array[INPUT][1], 0, 0 );
561
b.val[1] = cvGetReal2D( test_array[INPUT][1], 1, 0 );
562
b.val[2] = cvGetReal2D( test_array[INPUT][1], 2, 0 );
563
}
564
else if( test_mat[INPUT][0].cols > 1 )
565
{
566
a.val[0] = cvGetReal1D( test_array[INPUT][0], 0 );
567
a.val[1] = cvGetReal1D( test_array[INPUT][0], 1 );
568
a.val[2] = cvGetReal1D( test_array[INPUT][0], 2 );
569
570
b.val[0] = cvGetReal1D( test_array[INPUT][1], 0 );
571
b.val[1] = cvGetReal1D( test_array[INPUT][1], 1 );
572
b.val[2] = cvGetReal1D( test_array[INPUT][1], 2 );
573
}
574
else
575
{
576
a = cvGet1D( test_array[INPUT][0], 0 );
577
b = cvGet1D( test_array[INPUT][1], 0 );
578
}
579
580
c.val[2] = a.val[0]*b.val[1] - a.val[1]*b.val[0];
581
c.val[1] = -a.val[0]*b.val[2] + a.val[2]*b.val[0];
582
c.val[0] = a.val[1]*b.val[2] - a.val[2]*b.val[1];
583
584
if( test_mat[REF_OUTPUT][0].rows > 1 )
585
{
586
cvSetReal2D( test_array[REF_OUTPUT][0], 0, 0, c.val[0] );
587
cvSetReal2D( test_array[REF_OUTPUT][0], 1, 0, c.val[1] );
588
cvSetReal2D( test_array[REF_OUTPUT][0], 2, 0, c.val[2] );
589
}
590
else if( test_mat[REF_OUTPUT][0].cols > 1 )
591
{
592
cvSetReal1D( test_array[REF_OUTPUT][0], 0, c.val[0] );
593
cvSetReal1D( test_array[REF_OUTPUT][0], 1, c.val[1] );
594
cvSetReal1D( test_array[REF_OUTPUT][0], 2, c.val[2] );
595
}
596
else
597
{
598
cvSet1D( test_array[REF_OUTPUT][0], 0, cvScalar(c) );
599
}
600
}
601
602
603
///////////////// gemm /////////////////////
604
605
class Core_GEMMTest : public Core_MatrixTest
606
{
607
public:
608
typedef Core_MatrixTest Base;
609
Core_GEMMTest();
610
protected:
611
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
612
void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
613
int prepare_test_case( int test_case_idx );
614
void run_func();
615
void prepare_to_validation( int test_case_idx );
616
int tabc_flag;
617
double alpha, beta;
618
};
619
620
Core_GEMMTest::Core_GEMMTest() : Core_MatrixTest( 5, 1, false, false, 2 )
621
{
622
test_case_count = 100;
623
max_log_array_size = 10;
624
tabc_flag = 0;
625
alpha = beta = 0;
626
}
627
628
629
void Core_GEMMTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
630
{
631
RNG& rng = ts->get_rng();
632
Size sizeA;
633
Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
634
sizeA = sizes[INPUT][0];
635
Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
636
sizes[INPUT][0] = sizeA;
637
sizes[INPUT][2] = sizes[INPUT][3] = Size(1,1);
638
types[INPUT][2] = types[INPUT][3] &= ~CV_MAT_CN_MASK;
639
640
tabc_flag = cvtest::randInt(rng) & 7;
641
642
switch( tabc_flag & (CV_GEMM_A_T|CV_GEMM_B_T) )
643
{
644
case 0:
645
sizes[INPUT][1].height = sizes[INPUT][0].width;
646
sizes[OUTPUT][0].height = sizes[INPUT][0].height;
647
sizes[OUTPUT][0].width = sizes[INPUT][1].width;
648
break;
649
case CV_GEMM_B_T:
650
sizes[INPUT][1].width = sizes[INPUT][0].width;
651
sizes[OUTPUT][0].height = sizes[INPUT][0].height;
652
sizes[OUTPUT][0].width = sizes[INPUT][1].height;
653
break;
654
case CV_GEMM_A_T:
655
sizes[INPUT][1].height = sizes[INPUT][0].height;
656
sizes[OUTPUT][0].height = sizes[INPUT][0].width;
657
sizes[OUTPUT][0].width = sizes[INPUT][1].width;
658
break;
659
case CV_GEMM_A_T | CV_GEMM_B_T:
660
sizes[INPUT][1].width = sizes[INPUT][0].height;
661
sizes[OUTPUT][0].height = sizes[INPUT][0].width;
662
sizes[OUTPUT][0].width = sizes[INPUT][1].height;
663
break;
664
}
665
666
sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
667
668
if( cvtest::randInt(rng) & 1 )
669
sizes[INPUT][4] = Size(0,0);
670
else if( !(tabc_flag & CV_GEMM_C_T) )
671
sizes[INPUT][4] = sizes[OUTPUT][0];
672
else
673
{
674
sizes[INPUT][4].width = sizes[OUTPUT][0].height;
675
sizes[INPUT][4].height = sizes[OUTPUT][0].width;
676
}
677
}
678
679
680
int Core_GEMMTest::prepare_test_case( int test_case_idx )
681
{
682
int code = Base::prepare_test_case( test_case_idx );
683
if( code > 0 )
684
{
685
alpha = cvGetReal2D( test_array[INPUT][2], 0, 0 );
686
beta = cvGetReal2D( test_array[INPUT][3], 0, 0 );
687
}
688
return code;
689
}
690
691
692
void Core_GEMMTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
693
{
694
low = Scalar::all(-10.);
695
high = Scalar::all(10.);
696
}
697
698
699
void Core_GEMMTest::run_func()
700
{
701
cvGEMM( test_array[INPUT][0], test_array[INPUT][1], alpha,
702
test_array[INPUT][4], beta, test_array[OUTPUT][0], tabc_flag );
703
}
704
705
706
void Core_GEMMTest::prepare_to_validation( int )
707
{
708
cvtest::gemm( test_mat[INPUT][0], test_mat[INPUT][1], alpha,
709
test_array[INPUT][4] ? test_mat[INPUT][4] : Mat(),
710
beta, test_mat[REF_OUTPUT][0], tabc_flag );
711
}
712
713
714
///////////////// multransposed /////////////////////
715
716
class Core_MulTransposedTest : public Core_MatrixTest
717
{
718
public:
719
Core_MulTransposedTest();
720
protected:
721
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
722
void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
723
void run_func();
724
void prepare_to_validation( int test_case_idx );
725
int order;
726
};
727
728
729
Core_MulTransposedTest::Core_MulTransposedTest() : Core_MatrixTest( 2, 1, false, false, 1 )
730
{
731
test_case_count = 100;
732
order = 0;
733
test_array[TEMP].push_back(NULL);
734
}
735
736
737
void Core_MulTransposedTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
738
{
739
RNG& rng = ts->get_rng();
740
int bits = cvtest::randInt(rng);
741
int src_type = cvtest::randInt(rng) % 5;
742
int dst_type = cvtest::randInt(rng) % 2;
743
744
src_type = src_type == 0 ? CV_8U : src_type == 1 ? CV_16U : src_type == 2 ? CV_16S :
745
src_type == 3 ? CV_32F : CV_64F;
746
dst_type = dst_type == 0 ? CV_32F : CV_64F;
747
dst_type = MAX( dst_type, src_type );
748
749
Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
750
751
if( bits & 1 )
752
sizes[INPUT][1] = Size(0,0);
753
else
754
{
755
sizes[INPUT][1] = sizes[INPUT][0];
756
if( bits & 2 )
757
sizes[INPUT][1].height = 1;
758
if( bits & 4 )
759
sizes[INPUT][1].width = 1;
760
}
761
762
sizes[TEMP][0] = sizes[INPUT][0];
763
types[INPUT][0] = src_type;
764
types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][1] = types[TEMP][0] = dst_type;
765
766
order = (bits & 8) != 0;
767
sizes[OUTPUT][0].width = sizes[OUTPUT][0].height = order == 0 ?
768
sizes[INPUT][0].height : sizes[INPUT][0].width;
769
sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
770
}
771
772
773
void Core_MulTransposedTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
774
{
775
low = cvScalarAll(-10.);
776
high = cvScalarAll(10.);
777
}
778
779
780
void Core_MulTransposedTest::run_func()
781
{
782
cvMulTransposed( test_array[INPUT][0], test_array[OUTPUT][0],
783
order, test_array[INPUT][1] );
784
}
785
786
787
void Core_MulTransposedTest::prepare_to_validation( int )
788
{
789
const Mat& src = test_mat[INPUT][0];
790
Mat delta = test_mat[INPUT][1];
791
Mat& temp = test_mat[TEMP][0];
792
if( !delta.empty() )
793
{
794
if( delta.rows < src.rows || delta.cols < src.cols )
795
{
796
cv::repeat( delta, src.rows/delta.rows, src.cols/delta.cols, temp);
797
delta = temp;
798
}
799
cvtest::add( src, 1, delta, -1, Scalar::all(0), temp, temp.type());
800
}
801
else
802
src.convertTo(temp, temp.type());
803
804
cvtest::gemm( temp, temp, 1., Mat(), 0, test_mat[REF_OUTPUT][0], order == 0 ? GEMM_2_T : GEMM_1_T );
805
}
806
807
808
///////////////// Transform /////////////////////
809
810
class Core_TransformTest : public Core_MatrixTest
811
{
812
public:
813
typedef Core_MatrixTest Base;
814
Core_TransformTest();
815
protected:
816
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
817
double get_success_error_level( int test_case_idx, int i, int j );
818
int prepare_test_case( int test_case_idx );
819
void run_func();
820
void prepare_to_validation( int test_case_idx );
821
822
double scale;
823
bool diagMtx;
824
};
825
826
827
Core_TransformTest::Core_TransformTest() : Core_MatrixTest( 3, 1, true, false, 4 )
828
{
829
scale = 1;
830
diagMtx = false;
831
}
832
833
834
void Core_TransformTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
835
{
836
RNG& rng = ts->get_rng();
837
int bits = cvtest::randInt(rng);
838
int depth, dst_cn, mat_cols, mattype;
839
Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
840
841
mat_cols = CV_MAT_CN(types[INPUT][0]);
842
depth = CV_MAT_DEPTH(types[INPUT][0]);
843
dst_cn = cvtest::randInt(rng) % 4 + 1;
844
types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, dst_cn);
845
846
mattype = depth < CV_32S ? CV_32F : depth == CV_64F ? CV_64F : bits & 1 ? CV_32F : CV_64F;
847
types[INPUT][1] = mattype;
848
types[INPUT][2] = CV_MAKETYPE(mattype, dst_cn);
849
850
scale = 1./((cvtest::randInt(rng)%4)*50+1);
851
852
if( bits & 2 )
853
{
854
sizes[INPUT][2] = Size(0,0);
855
mat_cols += (bits & 4) != 0;
856
}
857
else if( bits & 4 )
858
sizes[INPUT][2] = Size(1,1);
859
else
860
{
861
if( bits & 8 )
862
sizes[INPUT][2] = Size(dst_cn,1);
863
else
864
sizes[INPUT][2] = Size(1,dst_cn);
865
types[INPUT][2] &= ~CV_MAT_CN_MASK;
866
}
867
diagMtx = (bits & 16) != 0;
868
869
sizes[INPUT][1] = Size(mat_cols,dst_cn);
870
}
871
872
873
int Core_TransformTest::prepare_test_case( int test_case_idx )
874
{
875
int code = Base::prepare_test_case( test_case_idx );
876
if( code > 0 )
877
{
878
Mat& m = test_mat[INPUT][1];
879
cvtest::add(m, scale, m, 0, Scalar::all(0), m, m.type() );
880
if(diagMtx)
881
{
882
Mat mask = Mat::eye(m.rows, m.cols, CV_8U)*255;
883
mask = ~mask;
884
m.setTo(Scalar::all(0), mask);
885
}
886
}
887
return code;
888
}
889
890
891
double Core_TransformTest::get_success_error_level( int test_case_idx, int i, int j )
892
{
893
int depth = test_mat[INPUT][0].depth();
894
return depth <= CV_8S ? 1 : depth <= CV_32S ? 9 : Base::get_success_error_level( test_case_idx, i, j );
895
}
896
897
void Core_TransformTest::run_func()
898
{
899
CvMat _m = cvMat(test_mat[INPUT][1]), _shift = cvMat(test_mat[INPUT][2]);
900
cvTransform( test_array[INPUT][0], test_array[OUTPUT][0], &_m, _shift.data.ptr ? &_shift : 0);
901
}
902
903
904
void Core_TransformTest::prepare_to_validation( int )
905
{
906
Mat transmat = test_mat[INPUT][1];
907
Mat shift = test_mat[INPUT][2];
908
909
cvtest::transform( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], transmat, shift );
910
}
911
912
class Core_TransformLargeTest : public Core_TransformTest
913
{
914
public:
915
typedef Core_MatrixTest Base;
916
protected:
917
void get_test_array_types_and_sizes(int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types);
918
};
919
920
void Core_TransformLargeTest::get_test_array_types_and_sizes(int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types)
921
{
922
RNG& rng = ts->get_rng();
923
int bits = cvtest::randInt(rng);
924
int depth, dst_cn, mat_cols, mattype;
925
Base::get_test_array_types_and_sizes(test_case_idx, sizes, types);
926
for (unsigned int j = 0; j < sizes.size(); j++)
927
{
928
for (unsigned int i = 0; i < sizes[j].size(); i++)
929
{
930
sizes[j][i].width *= 4;
931
}
932
}
933
934
mat_cols = CV_MAT_CN(types[INPUT][0]);
935
depth = CV_MAT_DEPTH(types[INPUT][0]);
936
dst_cn = cvtest::randInt(rng) % 4 + 1;
937
types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, dst_cn);
938
939
mattype = depth < CV_32S ? CV_32F : depth == CV_64F ? CV_64F : bits & 1 ? CV_32F : CV_64F;
940
types[INPUT][1] = mattype;
941
types[INPUT][2] = CV_MAKETYPE(mattype, dst_cn);
942
943
scale = 1. / ((cvtest::randInt(rng) % 4) * 50 + 1);
944
945
if (bits & 2)
946
{
947
sizes[INPUT][2] = Size(0, 0);
948
mat_cols += (bits & 4) != 0;
949
}
950
else if (bits & 4)
951
sizes[INPUT][2] = Size(1, 1);
952
else
953
{
954
if (bits & 8)
955
sizes[INPUT][2] = Size(dst_cn, 1);
956
else
957
sizes[INPUT][2] = Size(1, dst_cn);
958
types[INPUT][2] &= ~CV_MAT_CN_MASK;
959
}
960
diagMtx = (bits & 16) != 0;
961
962
sizes[INPUT][1] = Size(mat_cols, dst_cn);
963
}
964
965
966
967
///////////////// PerspectiveTransform /////////////////////
968
969
class Core_PerspectiveTransformTest : public Core_MatrixTest
970
{
971
public:
972
Core_PerspectiveTransformTest();
973
protected:
974
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
975
double get_success_error_level( int test_case_idx, int i, int j );
976
void run_func();
977
void prepare_to_validation( int test_case_idx );
978
};
979
980
981
Core_PerspectiveTransformTest::Core_PerspectiveTransformTest() : Core_MatrixTest( 2, 1, false, false, 2 )
982
{
983
}
984
985
986
void Core_PerspectiveTransformTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
987
{
988
RNG& rng = ts->get_rng();
989
int bits = cvtest::randInt(rng);
990
int depth, cn, mattype;
991
Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
992
993
cn = CV_MAT_CN(types[INPUT][0]) + 1;
994
depth = CV_MAT_DEPTH(types[INPUT][0]);
995
types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn);
996
997
mattype = depth == CV_64F ? CV_64F : bits & 1 ? CV_32F : CV_64F;
998
types[INPUT][1] = mattype;
999
sizes[INPUT][1] = Size(cn + 1, cn + 1);
1000
}
1001
1002
1003
double Core_PerspectiveTransformTest::get_success_error_level( int test_case_idx, int i, int j )
1004
{
1005
int depth = test_mat[INPUT][0].depth();
1006
return depth == CV_32F ? 1e-4 : depth == CV_64F ? 1e-8 :
1007
Core_MatrixTest::get_success_error_level(test_case_idx, i, j);
1008
}
1009
1010
1011
void Core_PerspectiveTransformTest::run_func()
1012
{
1013
CvMat _m = cvMat(test_mat[INPUT][1]);
1014
cvPerspectiveTransform( test_array[INPUT][0], test_array[OUTPUT][0], &_m );
1015
}
1016
1017
1018
static void cvTsPerspectiveTransform( const CvArr* _src, CvArr* _dst, const CvMat* transmat )
1019
{
1020
int i, j, cols;
1021
int cn, depth, mat_depth;
1022
CvMat astub, bstub, *a, *b;
1023
double mat[16];
1024
1025
a = cvGetMat( _src, &astub, 0, 0 );
1026
b = cvGetMat( _dst, &bstub, 0, 0 );
1027
1028
cn = CV_MAT_CN(a->type);
1029
depth = CV_MAT_DEPTH(a->type);
1030
mat_depth = CV_MAT_DEPTH(transmat->type);
1031
cols = transmat->cols;
1032
1033
// prepare cn x (cn + 1) transform matrix
1034
if( mat_depth == CV_32F )
1035
{
1036
for( i = 0; i < transmat->rows; i++ )
1037
for( j = 0; j < cols; j++ )
1038
mat[i*cols + j] = ((float*)(transmat->data.ptr + transmat->step*i))[j];
1039
}
1040
else
1041
{
1042
assert( mat_depth == CV_64F );
1043
for( i = 0; i < transmat->rows; i++ )
1044
for( j = 0; j < cols; j++ )
1045
mat[i*cols + j] = ((double*)(transmat->data.ptr + transmat->step*i))[j];
1046
}
1047
1048
// transform data
1049
cols = a->cols * cn;
1050
vector<double> buf(cols);
1051
1052
for( i = 0; i < a->rows; i++ )
1053
{
1054
uchar* src = a->data.ptr + i*a->step;
1055
uchar* dst = b->data.ptr + i*b->step;
1056
1057
switch( depth )
1058
{
1059
case CV_32F:
1060
for( j = 0; j < cols; j++ )
1061
buf[j] = ((float*)src)[j];
1062
break;
1063
case CV_64F:
1064
for( j = 0; j < cols; j++ )
1065
buf[j] = ((double*)src)[j];
1066
break;
1067
default:
1068
assert(0);
1069
}
1070
1071
switch( cn )
1072
{
1073
case 2:
1074
for( j = 0; j < cols; j += 2 )
1075
{
1076
double t0 = buf[j]*mat[0] + buf[j+1]*mat[1] + mat[2];
1077
double t1 = buf[j]*mat[3] + buf[j+1]*mat[4] + mat[5];
1078
double w = buf[j]*mat[6] + buf[j+1]*mat[7] + mat[8];
1079
w = w ? 1./w : 0;
1080
buf[j] = t0*w;
1081
buf[j+1] = t1*w;
1082
}
1083
break;
1084
case 3:
1085
for( j = 0; j < cols; j += 3 )
1086
{
1087
double t0 = buf[j]*mat[0] + buf[j+1]*mat[1] + buf[j+2]*mat[2] + mat[3];
1088
double t1 = buf[j]*mat[4] + buf[j+1]*mat[5] + buf[j+2]*mat[6] + mat[7];
1089
double t2 = buf[j]*mat[8] + buf[j+1]*mat[9] + buf[j+2]*mat[10] + mat[11];
1090
double w = buf[j]*mat[12] + buf[j+1]*mat[13] + buf[j+2]*mat[14] + mat[15];
1091
w = w ? 1./w : 0;
1092
buf[j] = t0*w;
1093
buf[j+1] = t1*w;
1094
buf[j+2] = t2*w;
1095
}
1096
break;
1097
default:
1098
assert(0);
1099
}
1100
1101
switch( depth )
1102
{
1103
case CV_32F:
1104
for( j = 0; j < cols; j++ )
1105
((float*)dst)[j] = (float)buf[j];
1106
break;
1107
case CV_64F:
1108
for( j = 0; j < cols; j++ )
1109
((double*)dst)[j] = buf[j];
1110
break;
1111
default:
1112
assert(0);
1113
}
1114
}
1115
}
1116
1117
1118
void Core_PerspectiveTransformTest::prepare_to_validation( int )
1119
{
1120
CvMat transmat = cvMat(test_mat[INPUT][1]);
1121
cvTsPerspectiveTransform( test_array[INPUT][0], test_array[REF_OUTPUT][0], &transmat );
1122
}
1123
1124
///////////////// Mahalanobis /////////////////////
1125
1126
class Core_MahalanobisTest : public Core_MatrixTest
1127
{
1128
public:
1129
typedef Core_MatrixTest Base;
1130
Core_MahalanobisTest();
1131
protected:
1132
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
1133
int prepare_test_case( int test_case_idx );
1134
void run_func();
1135
void prepare_to_validation( int test_case_idx );
1136
};
1137
1138
1139
Core_MahalanobisTest::Core_MahalanobisTest() : Core_MatrixTest( 3, 1, false, true, 1 )
1140
{
1141
test_case_count = 100;
1142
test_array[TEMP].push_back(NULL);
1143
test_array[TEMP].push_back(NULL);
1144
test_array[TEMP].push_back(NULL);
1145
}
1146
1147
1148
void Core_MahalanobisTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
1149
{
1150
RNG& rng = ts->get_rng();
1151
Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1152
1153
if( cvtest::randInt(rng) & 1 )
1154
sizes[INPUT][0].width = sizes[INPUT][1].width = 1;
1155
else
1156
sizes[INPUT][0].height = sizes[INPUT][1].height = 1;
1157
1158
sizes[TEMP][0] = sizes[TEMP][1] = sizes[INPUT][0];
1159
sizes[INPUT][2].width = sizes[INPUT][2].height = sizes[INPUT][0].width + sizes[INPUT][0].height - 1;
1160
sizes[TEMP][2] = sizes[INPUT][2];
1161
types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[INPUT][0];
1162
}
1163
1164
int Core_MahalanobisTest::prepare_test_case( int test_case_idx )
1165
{
1166
int code = Base::prepare_test_case( test_case_idx );
1167
if( code > 0 )
1168
{
1169
// make sure that the inverted "covariation" matrix is symmetrix and positively defined.
1170
cvtest::gemm( test_mat[INPUT][2], test_mat[INPUT][2], 1., Mat(), 0., test_mat[TEMP][2], GEMM_2_T );
1171
cvtest::copy( test_mat[TEMP][2], test_mat[INPUT][2] );
1172
}
1173
1174
return code;
1175
}
1176
1177
1178
void Core_MahalanobisTest::run_func()
1179
{
1180
test_mat[OUTPUT][0].at<Scalar>(0,0) =
1181
cvRealScalar(cvMahalanobis(test_array[INPUT][0], test_array[INPUT][1], test_array[INPUT][2]));
1182
}
1183
1184
void Core_MahalanobisTest::prepare_to_validation( int )
1185
{
1186
cvtest::add( test_mat[INPUT][0], 1., test_mat[INPUT][1], -1.,
1187
Scalar::all(0), test_mat[TEMP][0], test_mat[TEMP][0].type() );
1188
if( test_mat[INPUT][0].rows == 1 )
1189
cvtest::gemm( test_mat[TEMP][0], test_mat[INPUT][2], 1.,
1190
Mat(), 0., test_mat[TEMP][1], 0 );
1191
else
1192
cvtest::gemm( test_mat[INPUT][2], test_mat[TEMP][0], 1.,
1193
Mat(), 0., test_mat[TEMP][1], 0 );
1194
1195
test_mat[REF_OUTPUT][0].at<Scalar>(0,0) = cvRealScalar(sqrt(cvtest::crossCorr(test_mat[TEMP][0], test_mat[TEMP][1])));
1196
}
1197
1198
1199
///////////////// covarmatrix /////////////////////
1200
1201
class Core_CovarMatrixTest : public Core_MatrixTest
1202
{
1203
public:
1204
Core_CovarMatrixTest();
1205
protected:
1206
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
1207
int prepare_test_case( int test_case_idx );
1208
void run_func();
1209
void prepare_to_validation( int test_case_idx );
1210
vector<void*> temp_hdrs;
1211
vector<uchar> hdr_data;
1212
int flags, t_flag, len, count;
1213
bool are_images;
1214
};
1215
1216
1217
Core_CovarMatrixTest::Core_CovarMatrixTest() : Core_MatrixTest( 1, 1, true, false, 1 ),
1218
flags(0), t_flag(0), len(0), count(0), are_images(false)
1219
{
1220
test_case_count = 100;
1221
test_array[INPUT_OUTPUT].push_back(NULL);
1222
test_array[REF_INPUT_OUTPUT].push_back(NULL);
1223
test_array[TEMP].push_back(NULL);
1224
test_array[TEMP].push_back(NULL);
1225
}
1226
1227
1228
void Core_CovarMatrixTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
1229
{
1230
RNG& rng = ts->get_rng();
1231
int bits = cvtest::randInt(rng);
1232
int i, single_matrix;
1233
Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1234
1235
flags = bits & (CV_COVAR_NORMAL | CV_COVAR_USE_AVG | CV_COVAR_SCALE | CV_COVAR_ROWS );
1236
single_matrix = flags & CV_COVAR_ROWS;
1237
t_flag = (bits & 256) != 0;
1238
1239
const int min_count = 2;
1240
1241
if( !t_flag )
1242
{
1243
len = sizes[INPUT][0].width;
1244
count = sizes[INPUT][0].height;
1245
count = MAX(count, min_count);
1246
sizes[INPUT][0] = Size(len, count);
1247
}
1248
else
1249
{
1250
len = sizes[INPUT][0].height;
1251
count = sizes[INPUT][0].width;
1252
count = MAX(count, min_count);
1253
sizes[INPUT][0] = Size(count, len);
1254
}
1255
1256
if( single_matrix && t_flag )
1257
flags = (flags & ~CV_COVAR_ROWS) | CV_COVAR_COLS;
1258
1259
if( CV_MAT_DEPTH(types[INPUT][0]) == CV_32S )
1260
types[INPUT][0] = (types[INPUT][0] & ~CV_MAT_DEPTH_MASK) | CV_32F;
1261
1262
sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = flags & CV_COVAR_NORMAL ? Size(len,len) : Size(count,count);
1263
sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = !t_flag ? Size(len,1) : Size(1,len);
1264
sizes[TEMP][0] = sizes[INPUT][0];
1265
1266
types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] =
1267
types[OUTPUT][0] = types[REF_OUTPUT][0] = types[TEMP][0] =
1268
CV_MAT_DEPTH(types[INPUT][0]) == CV_64F || (bits & 512) ? CV_64F : CV_32F;
1269
1270
are_images = (bits & 1024) != 0;
1271
for( i = 0; i < (single_matrix ? 1 : count); i++ )
1272
temp_hdrs.push_back(NULL);
1273
}
1274
1275
1276
int Core_CovarMatrixTest::prepare_test_case( int test_case_idx )
1277
{
1278
int code = Core_MatrixTest::prepare_test_case( test_case_idx );
1279
if( code > 0 )
1280
{
1281
int i;
1282
int single_matrix = flags & (CV_COVAR_ROWS|CV_COVAR_COLS);
1283
int hdr_size = are_images ? sizeof(IplImage) : sizeof(CvMat);
1284
1285
hdr_data.resize(count*hdr_size);
1286
uchar* _hdr_data = &hdr_data[0];
1287
if( single_matrix )
1288
{
1289
if( !are_images )
1290
*((CvMat*)_hdr_data) = cvMat(test_mat[INPUT][0]);
1291
else
1292
*((IplImage*)_hdr_data) = cvIplImage(test_mat[INPUT][0]);
1293
temp_hdrs[0] = _hdr_data;
1294
}
1295
else
1296
for( i = 0; i < count; i++ )
1297
{
1298
Mat part;
1299
void* ptr = _hdr_data + i*hdr_size;
1300
1301
if( !t_flag )
1302
part = test_mat[INPUT][0].row(i);
1303
else
1304
part = test_mat[INPUT][0].col(i);
1305
1306
if( !are_images )
1307
*((CvMat*)ptr) = cvMat(part);
1308
else
1309
*((IplImage*)ptr) = cvIplImage(part);
1310
1311
temp_hdrs[i] = ptr;
1312
}
1313
}
1314
1315
return code;
1316
}
1317
1318
1319
void Core_CovarMatrixTest::run_func()
1320
{
1321
cvCalcCovarMatrix( (const void**)&temp_hdrs[0], count,
1322
test_array[OUTPUT][0], test_array[INPUT_OUTPUT][0], flags );
1323
}
1324
1325
1326
void Core_CovarMatrixTest::prepare_to_validation( int )
1327
{
1328
Mat& avg = test_mat[REF_INPUT_OUTPUT][0];
1329
double scale = 1.;
1330
1331
if( !(flags & CV_COVAR_USE_AVG) )
1332
{
1333
Mat hdrs0 = cvarrToMat(temp_hdrs[0]);
1334
1335
int i;
1336
avg = Scalar::all(0);
1337
1338
for( i = 0; i < count; i++ )
1339
{
1340
Mat vec;
1341
if( flags & CV_COVAR_ROWS )
1342
vec = hdrs0.row(i);
1343
else if( flags & CV_COVAR_COLS )
1344
vec = hdrs0.col(i);
1345
else
1346
vec = cvarrToMat(temp_hdrs[i]);
1347
1348
cvtest::add(avg, 1, vec, 1, Scalar::all(0), avg, avg.type());
1349
}
1350
1351
cvtest::add(avg, 1./count, avg, 0., Scalar::all(0), avg, avg.type());
1352
}
1353
1354
if( flags & CV_COVAR_SCALE )
1355
{
1356
scale = 1./count;
1357
}
1358
1359
Mat& temp0 = test_mat[TEMP][0];
1360
cv::repeat( avg, temp0.rows/avg.rows, temp0.cols/avg.cols, temp0 );
1361
cvtest::add( test_mat[INPUT][0], 1, temp0, -1, Scalar::all(0), temp0, temp0.type());
1362
1363
cvtest::gemm( temp0, temp0, scale, Mat(), 0., test_mat[REF_OUTPUT][0],
1364
t_flag ^ ((flags & CV_COVAR_NORMAL) != 0) ? CV_GEMM_A_T : CV_GEMM_B_T );
1365
temp_hdrs.clear();
1366
}
1367
1368
1369
static void cvTsFloodWithZeros( Mat& mat, RNG& rng )
1370
{
1371
int k, total = mat.rows*mat.cols, type = mat.type();
1372
int zero_total = cvtest::randInt(rng) % total;
1373
CV_Assert( type == CV_32FC1 || type == CV_64FC1 );
1374
1375
for( k = 0; k < zero_total; k++ )
1376
{
1377
int i = cvtest::randInt(rng) % mat.rows;
1378
int j = cvtest::randInt(rng) % mat.cols;
1379
1380
if( type == CV_32FC1 )
1381
mat.at<float>(i,j) = 0.f;
1382
else
1383
mat.at<double>(i,j) = 0.;
1384
}
1385
}
1386
1387
1388
///////////////// determinant /////////////////////
1389
1390
class Core_DetTest : public Core_MatrixTest
1391
{
1392
public:
1393
typedef Core_MatrixTest Base;
1394
Core_DetTest();
1395
protected:
1396
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
1397
double get_success_error_level( int test_case_idx, int i, int j );
1398
void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
1399
int prepare_test_case( int test_case_idx );
1400
void run_func();
1401
void prepare_to_validation( int test_case_idx );
1402
};
1403
1404
1405
Core_DetTest::Core_DetTest() : Core_MatrixTest( 1, 1, false, true, 1 )
1406
{
1407
test_case_count = 100;
1408
max_log_array_size = 7;
1409
test_array[TEMP].push_back(NULL);
1410
}
1411
1412
1413
void Core_DetTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
1414
{
1415
Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1416
1417
sizes[INPUT][0].width = sizes[INPUT][0].height;
1418
sizes[TEMP][0] = sizes[INPUT][0];
1419
types[TEMP][0] = CV_64FC1;
1420
}
1421
1422
1423
void Core_DetTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
1424
{
1425
low = cvScalarAll(-2.);
1426
high = cvScalarAll(2.);
1427
}
1428
1429
1430
double Core_DetTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1431
{
1432
return CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0])) == CV_32F ? 1e-2 : 1e-5;
1433
}
1434
1435
1436
int Core_DetTest::prepare_test_case( int test_case_idx )
1437
{
1438
int code = Core_MatrixTest::prepare_test_case( test_case_idx );
1439
if( code > 0 )
1440
cvTsFloodWithZeros( test_mat[INPUT][0], ts->get_rng() );
1441
1442
return code;
1443
}
1444
1445
1446
void Core_DetTest::run_func()
1447
{
1448
test_mat[OUTPUT][0].at<Scalar>(0,0) = cvRealScalar(cvDet(test_array[INPUT][0]));
1449
}
1450
1451
1452
// LU method that chooses the optimal in a column pivot element
1453
static double cvTsLU( CvMat* a, CvMat* b=NULL, CvMat* x=NULL, int* rank=0 )
1454
{
1455
int i, j, k, N = a->rows, N1 = a->cols, Nm = MIN(N, N1), step = a->step/sizeof(double);
1456
int M = b ? b->cols : 0, b_step = b ? b->step/sizeof(double) : 0;
1457
int x_step = x ? x->step/sizeof(double) : 0;
1458
double *a0 = a->data.db, *b0 = b ? b->data.db : 0;
1459
double *x0 = x ? x->data.db : 0;
1460
double t, det = 1.;
1461
assert( CV_MAT_TYPE(a->type) == CV_64FC1 &&
1462
(!b || CV_ARE_TYPES_EQ(a,b)) && (!x || CV_ARE_TYPES_EQ(a,x)));
1463
1464
for( i = 0; i < Nm; i++ )
1465
{
1466
double max_val = fabs(a0[i*step + i]);
1467
double *a1, *a2, *b1 = 0, *b2 = 0;
1468
k = i;
1469
1470
for( j = i+1; j < N; j++ )
1471
{
1472
t = fabs(a0[j*step + i]);
1473
if( max_val < t )
1474
{
1475
max_val = t;
1476
k = j;
1477
}
1478
}
1479
1480
if( k != i )
1481
{
1482
for( j = i; j < N1; j++ )
1483
CV_SWAP( a0[i*step + j], a0[k*step + j], t );
1484
1485
for( j = 0; j < M; j++ )
1486
CV_SWAP( b0[i*b_step + j], b0[k*b_step + j], t );
1487
det = -det;
1488
}
1489
1490
if( max_val == 0 )
1491
{
1492
if( rank )
1493
*rank = i;
1494
return 0.;
1495
}
1496
1497
a1 = a0 + i*step;
1498
a2 = a1 + step;
1499
b1 = b0 + i*b_step;
1500
b2 = b1 + b_step;
1501
1502
for( j = i+1; j < N; j++, a2 += step, b2 += b_step )
1503
{
1504
t = a2[i]/a1[i];
1505
for( k = i+1; k < N1; k++ )
1506
a2[k] -= t*a1[k];
1507
1508
for( k = 0; k < M; k++ )
1509
b2[k] -= t*b1[k];
1510
}
1511
1512
det *= a1[i];
1513
}
1514
1515
if( x )
1516
{
1517
assert( b );
1518
1519
for( i = N-1; i >= 0; i-- )
1520
{
1521
double* a1 = a0 + i*step;
1522
double* b1 = b0 + i*b_step;
1523
for( j = 0; j < M; j++ )
1524
{
1525
t = b1[j];
1526
for( k = i+1; k < N1; k++ )
1527
t -= a1[k]*x0[k*x_step + j];
1528
x0[i*x_step + j] = t/a1[i];
1529
}
1530
}
1531
}
1532
1533
if( rank )
1534
*rank = i;
1535
return det;
1536
}
1537
1538
1539
void Core_DetTest::prepare_to_validation( int )
1540
{
1541
test_mat[INPUT][0].convertTo(test_mat[TEMP][0], test_mat[TEMP][0].type());
1542
CvMat temp0 = cvMat(test_mat[TEMP][0]);
1543
test_mat[REF_OUTPUT][0].at<Scalar>(0,0) = cvRealScalar(cvTsLU(&temp0, 0, 0));
1544
}
1545
1546
1547
///////////////// invert /////////////////////
1548
1549
class Core_InvertTest : public Core_MatrixTest
1550
{
1551
public:
1552
typedef Core_MatrixTest Base;
1553
Core_InvertTest();
1554
protected:
1555
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
1556
void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
1557
double get_success_error_level( int test_case_idx, int i, int j );
1558
int prepare_test_case( int test_case_idx );
1559
void run_func();
1560
void prepare_to_validation( int test_case_idx );
1561
int method, rank;
1562
double result;
1563
};
1564
1565
1566
Core_InvertTest::Core_InvertTest()
1567
: Core_MatrixTest( 1, 1, false, false, 1 ), method(0), rank(0), result(0.)
1568
{
1569
test_case_count = 100;
1570
max_log_array_size = 7;
1571
test_array[TEMP].push_back(NULL);
1572
test_array[TEMP].push_back(NULL);
1573
}
1574
1575
1576
void Core_InvertTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
1577
{
1578
RNG& rng = ts->get_rng();
1579
int bits = cvtest::randInt(rng);
1580
Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1581
int min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
1582
1583
if( (bits & 3) == 0 )
1584
{
1585
method = CV_SVD;
1586
if( bits & 4 )
1587
{
1588
sizes[INPUT][0] = Size(min_size, min_size);
1589
if( bits & 16 )
1590
method = CV_CHOLESKY;
1591
}
1592
}
1593
else
1594
{
1595
method = CV_LU;
1596
sizes[INPUT][0] = Size(min_size, min_size);
1597
}
1598
1599
sizes[TEMP][0].width = sizes[INPUT][0].height;
1600
sizes[TEMP][0].height = sizes[INPUT][0].width;
1601
sizes[TEMP][1] = sizes[INPUT][0];
1602
types[TEMP][0] = types[INPUT][0];
1603
types[TEMP][1] = CV_64FC1;
1604
sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = Size(min_size, min_size);
1605
}
1606
1607
1608
double Core_InvertTest::get_success_error_level( int /*test_case_idx*/, int, int )
1609
{
1610
return CV_MAT_DEPTH(cvGetElemType(test_array[OUTPUT][0])) == CV_32F ? 1e-2 : 1e-6;
1611
}
1612
1613
int Core_InvertTest::prepare_test_case( int test_case_idx )
1614
{
1615
int code = Core_MatrixTest::prepare_test_case( test_case_idx );
1616
if( code > 0 )
1617
{
1618
cvTsFloodWithZeros( test_mat[INPUT][0], ts->get_rng() );
1619
1620
if( method == CV_CHOLESKY )
1621
{
1622
cvtest::gemm( test_mat[INPUT][0], test_mat[INPUT][0], 1.,
1623
Mat(), 0., test_mat[TEMP][0], CV_GEMM_B_T );
1624
cvtest::copy( test_mat[TEMP][0], test_mat[INPUT][0] );
1625
}
1626
}
1627
1628
return code;
1629
}
1630
1631
1632
1633
void Core_InvertTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
1634
{
1635
low = cvScalarAll(-1.);
1636
high = cvScalarAll(1.);
1637
}
1638
1639
1640
void Core_InvertTest::run_func()
1641
{
1642
result = cvInvert(test_array[INPUT][0], test_array[TEMP][0], method);
1643
}
1644
1645
1646
static double cvTsSVDet( CvMat* mat, double* ratio )
1647
{
1648
int type = CV_MAT_TYPE(mat->type);
1649
int i, nm = MIN( mat->rows, mat->cols );
1650
CvMat* w = cvCreateMat( nm, 1, type );
1651
double det = 1.;
1652
1653
cvSVD( mat, w, 0, 0, 0 );
1654
1655
if( type == CV_32FC1 )
1656
{
1657
for( i = 0; i < nm; i++ )
1658
det *= w->data.fl[i];
1659
*ratio = w->data.fl[nm-1] < FLT_EPSILON ? 0 : w->data.fl[nm-1]/w->data.fl[0];
1660
}
1661
else
1662
{
1663
for( i = 0; i < nm; i++ )
1664
det *= w->data.db[i];
1665
*ratio = w->data.db[nm-1] < FLT_EPSILON ? 0 : w->data.db[nm-1]/w->data.db[0];
1666
}
1667
1668
cvReleaseMat( &w );
1669
return det;
1670
}
1671
1672
void Core_InvertTest::prepare_to_validation( int )
1673
{
1674
Mat& input = test_mat[INPUT][0];
1675
Mat& temp0 = test_mat[TEMP][0];
1676
Mat& temp1 = test_mat[TEMP][1];
1677
Mat& dst0 = test_mat[REF_OUTPUT][0];
1678
Mat& dst = test_mat[OUTPUT][0];
1679
CvMat _input = cvMat(input);
1680
double ratio = 0, det = cvTsSVDet( &_input, &ratio );
1681
double threshold = (input.depth() == CV_32F ? FLT_EPSILON : DBL_EPSILON)*1000;
1682
1683
cvtest::convert( input, temp1, temp1.type() );
1684
1685
if( det < threshold ||
1686
((method == CV_LU || method == CV_CHOLESKY) && (result == 0 || ratio < threshold)) ||
1687
((method == CV_SVD || method == CV_SVD_SYM) && result < threshold) )
1688
{
1689
dst = Scalar::all(0);
1690
dst0 = Scalar::all(0);
1691
return;
1692
}
1693
1694
if( input.rows >= input.cols )
1695
cvtest::gemm( temp0, input, 1., Mat(), 0., dst, 0 );
1696
else
1697
cvtest::gemm( input, temp0, 1., Mat(), 0., dst, 0 );
1698
1699
cv::setIdentity( dst0, Scalar::all(1) );
1700
}
1701
1702
1703
///////////////// solve /////////////////////
1704
1705
class Core_SolveTest : public Core_MatrixTest
1706
{
1707
public:
1708
typedef Core_MatrixTest Base;
1709
Core_SolveTest();
1710
protected:
1711
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
1712
void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
1713
double get_success_error_level( int test_case_idx, int i, int j );
1714
int prepare_test_case( int test_case_idx );
1715
void run_func();
1716
void prepare_to_validation( int test_case_idx );
1717
int method, rank;
1718
double result;
1719
};
1720
1721
1722
Core_SolveTest::Core_SolveTest() : Core_MatrixTest( 2, 1, false, false, 1 ), method(0), rank(0), result(0.)
1723
{
1724
test_case_count = 100;
1725
max_log_array_size = 7;
1726
test_array[TEMP].push_back(NULL);
1727
test_array[TEMP].push_back(NULL);
1728
}
1729
1730
1731
void Core_SolveTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
1732
{
1733
RNG& rng = ts->get_rng();
1734
int bits = cvtest::randInt(rng);
1735
Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1736
CvSize in_sz = cvSize(sizes[INPUT][0]);
1737
if( in_sz.width > in_sz.height )
1738
in_sz = cvSize(in_sz.height, in_sz.width);
1739
Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1740
sizes[INPUT][0] = in_sz;
1741
int min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
1742
1743
if( (bits & 3) == 0 )
1744
{
1745
method = CV_SVD;
1746
if( bits & 4 )
1747
{
1748
sizes[INPUT][0] = Size(min_size, min_size);
1749
/*if( bits & 8 )
1750
method = CV_SVD_SYM;*/
1751
}
1752
}
1753
else
1754
{
1755
method = CV_LU;
1756
sizes[INPUT][0] = Size(min_size, min_size);
1757
}
1758
1759
sizes[INPUT][1].height = sizes[INPUT][0].height;
1760
sizes[TEMP][0].width = sizes[INPUT][1].width;
1761
sizes[TEMP][0].height = sizes[INPUT][0].width;
1762
sizes[TEMP][1] = sizes[INPUT][0];
1763
types[TEMP][0] = types[INPUT][0];
1764
types[TEMP][1] = CV_64FC1;
1765
sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = Size(sizes[INPUT][1].width, min_size);
1766
}
1767
1768
1769
int Core_SolveTest::prepare_test_case( int test_case_idx )
1770
{
1771
int code = Core_MatrixTest::prepare_test_case( test_case_idx );
1772
1773
/*if( method == CV_SVD_SYM )
1774
{
1775
cvTsGEMM( test_array[INPUT][0], test_array[INPUT][0], 1.,
1776
0, 0., test_array[TEMP][0], CV_GEMM_B_T );
1777
cvTsCopy( test_array[TEMP][0], test_array[INPUT][0] );
1778
}*/
1779
1780
return code;
1781
}
1782
1783
1784
void Core_SolveTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
1785
{
1786
low = cvScalarAll(-1.);
1787
high = cvScalarAll(1.);
1788
}
1789
1790
1791
double Core_SolveTest::get_success_error_level( int /*test_case_idx*/, int, int )
1792
{
1793
return CV_MAT_DEPTH(cvGetElemType(test_array[OUTPUT][0])) == CV_32F ? 5e-2 : 1e-8;
1794
}
1795
1796
1797
void Core_SolveTest::run_func()
1798
{
1799
result = cvSolve(test_array[INPUT][0], test_array[INPUT][1], test_array[TEMP][0], method);
1800
}
1801
1802
void Core_SolveTest::prepare_to_validation( int )
1803
{
1804
//int rank = test_mat[REF_OUTPUT][0].rows;
1805
Mat& input = test_mat[INPUT][0];
1806
Mat& dst = test_mat[OUTPUT][0];
1807
Mat& dst0 = test_mat[REF_OUTPUT][0];
1808
1809
if( method == CV_LU )
1810
{
1811
if( result == 0 )
1812
{
1813
Mat& temp1 = test_mat[TEMP][1];
1814
cvtest::convert(input, temp1, temp1.type());
1815
dst = Scalar::all(0);
1816
CvMat _temp1 = cvMat(temp1);
1817
double det = cvTsLU( &_temp1, 0, 0 );
1818
dst0 = Scalar::all(det != 0);
1819
return;
1820
}
1821
1822
double threshold = (input.type() == CV_32F ? FLT_EPSILON : DBL_EPSILON)*1000;
1823
CvMat _input = cvMat(input);
1824
double ratio = 0, det = cvTsSVDet( &_input, &ratio );
1825
if( det < threshold || ratio < threshold )
1826
{
1827
dst = Scalar::all(0);
1828
dst0 = Scalar::all(0);
1829
return;
1830
}
1831
}
1832
1833
Mat* pdst = input.rows <= input.cols ? &test_mat[OUTPUT][0] : &test_mat[INPUT][1];
1834
1835
cvtest::gemm( input, test_mat[TEMP][0], 1., test_mat[INPUT][1], -1., *pdst, 0 );
1836
if( pdst != &dst )
1837
cvtest::gemm( input, *pdst, 1., Mat(), 0., dst, CV_GEMM_A_T );
1838
dst0 = Scalar::all(0);
1839
}
1840
1841
1842
///////////////// SVD /////////////////////
1843
1844
class Core_SVDTest : public Core_MatrixTest
1845
{
1846
public:
1847
typedef Core_MatrixTest Base;
1848
Core_SVDTest();
1849
protected:
1850
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
1851
double get_success_error_level( int test_case_idx, int i, int j );
1852
void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
1853
int prepare_test_case( int test_case_idx );
1854
void run_func();
1855
void prepare_to_validation( int test_case_idx );
1856
int flags;
1857
bool have_u, have_v, symmetric, compact, vector_w;
1858
};
1859
1860
1861
Core_SVDTest::Core_SVDTest() :
1862
Core_MatrixTest( 1, 4, false, false, 1 ),
1863
flags(0), have_u(false), have_v(false), symmetric(false), compact(false), vector_w(false)
1864
{
1865
test_case_count = 100;
1866
max_log_array_size = 8;
1867
test_array[TEMP].push_back(NULL);
1868
test_array[TEMP].push_back(NULL);
1869
test_array[TEMP].push_back(NULL);
1870
test_array[TEMP].push_back(NULL);
1871
}
1872
1873
1874
void Core_SVDTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
1875
{
1876
RNG& rng = ts->get_rng();
1877
int bits = cvtest::randInt(rng);
1878
Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1879
int min_size, i, m, n;
1880
1881
min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
1882
1883
flags = bits & (CV_SVD_MODIFY_A+CV_SVD_U_T+CV_SVD_V_T);
1884
have_u = (bits & 8) != 0;
1885
have_v = (bits & 16) != 0;
1886
symmetric = (bits & 32) != 0;
1887
compact = (bits & 64) != 0;
1888
vector_w = (bits & 128) != 0;
1889
1890
if( symmetric )
1891
sizes[INPUT][0] = Size(min_size, min_size);
1892
1893
m = sizes[INPUT][0].height;
1894
n = sizes[INPUT][0].width;
1895
1896
if( compact )
1897
sizes[TEMP][0] = Size(min_size, min_size);
1898
else
1899
sizes[TEMP][0] = sizes[INPUT][0];
1900
sizes[TEMP][3] = Size(0,0);
1901
1902
if( vector_w )
1903
{
1904
sizes[TEMP][3] = sizes[TEMP][0];
1905
if( bits & 256 )
1906
sizes[TEMP][0] = Size(1, min_size);
1907
else
1908
sizes[TEMP][0] = Size(min_size, 1);
1909
}
1910
1911
if( have_u )
1912
{
1913
sizes[TEMP][1] = compact ? Size(min_size, m) : Size(m, m);
1914
1915
if( flags & CV_SVD_U_T )
1916
CV_SWAP( sizes[TEMP][1].width, sizes[TEMP][1].height, i );
1917
}
1918
else
1919
sizes[TEMP][1] = Size(0,0);
1920
1921
if( have_v )
1922
{
1923
sizes[TEMP][2] = compact ? Size(n, min_size) : Size(n, n);
1924
1925
if( !(flags & CV_SVD_V_T) )
1926
CV_SWAP( sizes[TEMP][2].width, sizes[TEMP][2].height, i );
1927
}
1928
else
1929
sizes[TEMP][2] = Size(0,0);
1930
1931
types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[TEMP][3] = types[INPUT][0];
1932
types[OUTPUT][0] = types[OUTPUT][1] = types[OUTPUT][2] = types[INPUT][0];
1933
types[OUTPUT][3] = CV_8UC1;
1934
sizes[OUTPUT][0] = !have_u || !have_v ? Size(0,0) : sizes[INPUT][0];
1935
sizes[OUTPUT][1] = !have_u ? Size(0,0) : compact ? Size(min_size,min_size) : Size(m,m);
1936
sizes[OUTPUT][2] = !have_v ? Size(0,0) : compact ? Size(min_size,min_size) : Size(n,n);
1937
sizes[OUTPUT][3] = Size(min_size,1);
1938
1939
for( i = 0; i < 4; i++ )
1940
{
1941
sizes[REF_OUTPUT][i] = sizes[OUTPUT][i];
1942
types[REF_OUTPUT][i] = types[OUTPUT][i];
1943
}
1944
}
1945
1946
1947
int Core_SVDTest::prepare_test_case( int test_case_idx )
1948
{
1949
int code = Core_MatrixTest::prepare_test_case( test_case_idx );
1950
if( code > 0 )
1951
{
1952
Mat& input = test_mat[INPUT][0];
1953
cvTsFloodWithZeros( input, ts->get_rng() );
1954
1955
if( symmetric && (have_u || have_v) )
1956
{
1957
Mat& temp = test_mat[TEMP][have_u ? 1 : 2];
1958
cvtest::gemm( input, input, 1., Mat(), 0., temp, CV_GEMM_B_T );
1959
cvtest::copy( temp, input );
1960
}
1961
1962
if( (flags & CV_SVD_MODIFY_A) && test_array[OUTPUT][0] )
1963
cvtest::copy( input, test_mat[OUTPUT][0] );
1964
}
1965
1966
return code;
1967
}
1968
1969
1970
void Core_SVDTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
1971
{
1972
low = cvScalarAll(-2.);
1973
high = cvScalarAll(2.);
1974
}
1975
1976
double Core_SVDTest::get_success_error_level( int test_case_idx, int i, int j )
1977
{
1978
int input_depth = CV_MAT_DEPTH(cvGetElemType( test_array[INPUT][0] ));
1979
double input_precision = input_depth < CV_32F ? 0 : input_depth == CV_32F ? 1e-5 : 5e-11;
1980
double output_precision = Base::get_success_error_level( test_case_idx, i, j );
1981
return MAX(input_precision, output_precision);
1982
}
1983
1984
void Core_SVDTest::run_func()
1985
{
1986
CvArr* src = test_array[!(flags & CV_SVD_MODIFY_A) ? INPUT : OUTPUT][0];
1987
if( !src )
1988
src = test_array[INPUT][0];
1989
cvSVD( src, test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2], flags );
1990
}
1991
1992
1993
void Core_SVDTest::prepare_to_validation( int /*test_case_idx*/ )
1994
{
1995
Mat& input = test_mat[INPUT][0];
1996
int depth = input.depth();
1997
int i, m = input.rows, n = input.cols, min_size = MIN(m, n);
1998
Mat *src, *dst, *w;
1999
double prev = 0, threshold = depth == CV_32F ? FLT_EPSILON : DBL_EPSILON;
2000
2001
if( have_u )
2002
{
2003
src = &test_mat[TEMP][1];
2004
dst = &test_mat[OUTPUT][1];
2005
cvtest::gemm( *src, *src, 1., Mat(), 0., *dst, src->rows == dst->rows ? CV_GEMM_B_T : CV_GEMM_A_T );
2006
cv::setIdentity( test_mat[REF_OUTPUT][1], Scalar::all(1.) );
2007
}
2008
2009
if( have_v )
2010
{
2011
src = &test_mat[TEMP][2];
2012
dst = &test_mat[OUTPUT][2];
2013
cvtest::gemm( *src, *src, 1., Mat(), 0., *dst, src->rows == dst->rows ? CV_GEMM_B_T : CV_GEMM_A_T );
2014
cv::setIdentity( test_mat[REF_OUTPUT][2], Scalar::all(1.) );
2015
}
2016
2017
w = &test_mat[TEMP][0];
2018
for( i = 0; i < min_size; i++ )
2019
{
2020
double normval = 0, aii;
2021
if( w->rows > 1 && w->cols > 1 )
2022
{
2023
normval = cvtest::norm( w->row(i), NORM_L1 );
2024
aii = depth == CV_32F ? w->at<float>(i,i) : w->at<double>(i,i);
2025
}
2026
else
2027
{
2028
normval = aii = depth == CV_32F ? w->at<float>(i) : w->at<double>(i);
2029
}
2030
2031
normval = fabs(normval - aii);
2032
test_mat[OUTPUT][3].at<uchar>(i) = aii >= 0 && normval < threshold && (i == 0 || aii <= prev);
2033
prev = aii;
2034
}
2035
2036
test_mat[REF_OUTPUT][3] = Scalar::all(1);
2037
2038
if( have_u && have_v )
2039
{
2040
if( vector_w )
2041
{
2042
test_mat[TEMP][3] = Scalar::all(0);
2043
for( i = 0; i < min_size; i++ )
2044
{
2045
double val = depth == CV_32F ? w->at<float>(i) : w->at<double>(i);
2046
cvSetReal2D( test_array[TEMP][3], i, i, val );
2047
}
2048
w = &test_mat[TEMP][3];
2049
}
2050
2051
if( m >= n )
2052
{
2053
cvtest::gemm( test_mat[TEMP][1], *w, 1., Mat(), 0., test_mat[REF_OUTPUT][0],
2054
flags & CV_SVD_U_T ? CV_GEMM_A_T : 0 );
2055
cvtest::gemm( test_mat[REF_OUTPUT][0], test_mat[TEMP][2], 1., Mat(), 0.,
2056
test_mat[OUTPUT][0], flags & CV_SVD_V_T ? 0 : CV_GEMM_B_T );
2057
}
2058
else
2059
{
2060
cvtest::gemm( *w, test_mat[TEMP][2], 1., Mat(), 0., test_mat[REF_OUTPUT][0],
2061
flags & CV_SVD_V_T ? 0 : CV_GEMM_B_T );
2062
cvtest::gemm( test_mat[TEMP][1], test_mat[REF_OUTPUT][0], 1., Mat(), 0.,
2063
test_mat[OUTPUT][0], flags & CV_SVD_U_T ? CV_GEMM_A_T : 0 );
2064
}
2065
2066
cvtest::copy( test_mat[INPUT][0], test_mat[REF_OUTPUT][0] );
2067
}
2068
}
2069
2070
2071
2072
///////////////// SVBkSb /////////////////////
2073
2074
class Core_SVBkSbTest : public Core_MatrixTest
2075
{
2076
public:
2077
typedef Core_MatrixTest Base;
2078
Core_SVBkSbTest();
2079
protected:
2080
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
2081
double get_success_error_level( int test_case_idx, int i, int j );
2082
void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
2083
int prepare_test_case( int test_case_idx );
2084
void run_func();
2085
void prepare_to_validation( int test_case_idx );
2086
int flags;
2087
bool have_b, symmetric, compact, vector_w;
2088
};
2089
2090
2091
Core_SVBkSbTest::Core_SVBkSbTest() : Core_MatrixTest( 2, 1, false, false, 1 ),
2092
flags(0), have_b(false), symmetric(false), compact(false), vector_w(false)
2093
{
2094
test_case_count = 100;
2095
test_array[TEMP].push_back(NULL);
2096
test_array[TEMP].push_back(NULL);
2097
test_array[TEMP].push_back(NULL);
2098
}
2099
2100
2101
void Core_SVBkSbTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes,
2102
vector<vector<int> >& types )
2103
{
2104
RNG& rng = ts->get_rng();
2105
int bits = cvtest::randInt(rng);
2106
Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2107
int min_size, i, m, n;
2108
cv::Size b_size;
2109
2110
min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
2111
2112
flags = bits & (CV_SVD_MODIFY_A+CV_SVD_U_T+CV_SVD_V_T);
2113
have_b = (bits & 16) != 0;
2114
symmetric = (bits & 32) != 0;
2115
compact = (bits & 64) != 0;
2116
vector_w = (bits & 128) != 0;
2117
2118
if( symmetric )
2119
sizes[INPUT][0] = Size(min_size, min_size);
2120
2121
m = sizes[INPUT][0].height;
2122
n = sizes[INPUT][0].width;
2123
2124
sizes[INPUT][1] = Size(0,0);
2125
b_size = cvSize(m, m);
2126
if( have_b )
2127
{
2128
sizes[INPUT][1].height = sizes[INPUT][0].height;
2129
sizes[INPUT][1].width = cvtest::randInt(rng) % 100 + 1;
2130
b_size = sizes[INPUT][1];
2131
}
2132
2133
if( compact )
2134
sizes[TEMP][0] = Size(min_size, min_size);
2135
else
2136
sizes[TEMP][0] = sizes[INPUT][0];
2137
2138
if( vector_w )
2139
{
2140
if( bits & 256 )
2141
sizes[TEMP][0] = Size(1, min_size);
2142
else
2143
sizes[TEMP][0] = Size(min_size, 1);
2144
}
2145
2146
sizes[TEMP][1] = compact ? Size(min_size, m) : Size(m, m);
2147
2148
if( flags & CV_SVD_U_T )
2149
CV_SWAP( sizes[TEMP][1].width, sizes[TEMP][1].height, i );
2150
2151
sizes[TEMP][2] = compact ? Size(n, min_size) : Size(n, n);
2152
2153
if( !(flags & CV_SVD_V_T) )
2154
CV_SWAP( sizes[TEMP][2].width, sizes[TEMP][2].height, i );
2155
2156
types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[INPUT][0];
2157
types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][0];
2158
sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = Size( b_size.width, n );
2159
}
2160
2161
2162
int Core_SVBkSbTest::prepare_test_case( int test_case_idx )
2163
{
2164
int code = Base::prepare_test_case( test_case_idx );
2165
if( code > 0 )
2166
{
2167
Mat& input = test_mat[INPUT][0];
2168
cvTsFloodWithZeros( input, ts->get_rng() );
2169
2170
if( symmetric )
2171
{
2172
Mat& temp = test_mat[TEMP][1];
2173
cvtest::gemm( input, input, 1., Mat(), 0., temp, CV_GEMM_B_T );
2174
cvtest::copy( temp, input );
2175
}
2176
2177
CvMat _input = cvMat(input);
2178
cvSVD( &_input, test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2], flags );
2179
}
2180
2181
return code;
2182
}
2183
2184
2185
void Core_SVBkSbTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
2186
{
2187
low = cvScalarAll(-2.);
2188
high = cvScalarAll(2.);
2189
}
2190
2191
2192
double Core_SVBkSbTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
2193
{
2194
return CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0])) == CV_32F ? 1e-3 : 1e-7;
2195
}
2196
2197
2198
void Core_SVBkSbTest::run_func()
2199
{
2200
cvSVBkSb( test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2],
2201
test_array[INPUT][1], test_array[OUTPUT][0], flags );
2202
}
2203
2204
2205
void Core_SVBkSbTest::prepare_to_validation( int )
2206
{
2207
Mat& input = test_mat[INPUT][0];
2208
int i, m = input.rows, n = input.cols, min_size = MIN(m, n);
2209
bool is_float = input.type() == CV_32F;
2210
Size w_size = compact ? Size(min_size,min_size) : Size(m,n);
2211
Mat& w = test_mat[TEMP][0];
2212
Mat wdb( w_size.height, w_size.width, CV_64FC1 );
2213
CvMat _w = cvMat(w), _wdb = cvMat(wdb);
2214
// use exactly the same threshold as in icvSVD... ,
2215
// so the changes in the library and here should be synchronized.
2216
double threshold = cv::sum(w)[0]*(DBL_EPSILON*2);//(is_float ? FLT_EPSILON*10 : DBL_EPSILON*2);
2217
2218
wdb = Scalar::all(0);
2219
for( i = 0; i < min_size; i++ )
2220
{
2221
double wii = vector_w ? cvGetReal1D(&_w,i) : cvGetReal2D(&_w,i,i);
2222
cvSetReal2D( &_wdb, i, i, wii > threshold ? 1./wii : 0. );
2223
}
2224
2225
Mat u = test_mat[TEMP][1];
2226
Mat v = test_mat[TEMP][2];
2227
Mat b = test_mat[INPUT][1];
2228
2229
if( is_float )
2230
{
2231
test_mat[TEMP][1].convertTo(u, CV_64F);
2232
test_mat[TEMP][2].convertTo(v, CV_64F);
2233
if( !b.empty() )
2234
test_mat[INPUT][1].convertTo(b, CV_64F);
2235
}
2236
2237
Mat t0, t1;
2238
2239
if( !b.empty() )
2240
cvtest::gemm( u, b, 1., Mat(), 0., t0, !(flags & CV_SVD_U_T) ? CV_GEMM_A_T : 0 );
2241
else if( flags & CV_SVD_U_T )
2242
cvtest::copy( u, t0 );
2243
else
2244
cvtest::transpose( u, t0 );
2245
2246
cvtest::gemm( wdb, t0, 1, Mat(), 0, t1, 0 );
2247
2248
cvtest::gemm( v, t1, 1, Mat(), 0, t0, flags & CV_SVD_V_T ? CV_GEMM_A_T : 0 );
2249
Mat& dst0 = test_mat[REF_OUTPUT][0];
2250
t0.convertTo(dst0, dst0.type() );
2251
}
2252
2253
2254
typedef std::complex<double> complex_type;
2255
2256
struct pred_complex
2257
{
2258
bool operator() (const complex_type& lhs, const complex_type& rhs) const
2259
{
2260
return fabs(lhs.real() - rhs.real()) > fabs(rhs.real())*FLT_EPSILON ? lhs.real() < rhs.real() : lhs.imag() < rhs.imag();
2261
}
2262
};
2263
2264
struct pred_double
2265
{
2266
bool operator() (const double& lhs, const double& rhs) const
2267
{
2268
return lhs < rhs;
2269
}
2270
};
2271
2272
class Core_SolvePolyTest : public cvtest::BaseTest
2273
{
2274
public:
2275
Core_SolvePolyTest();
2276
~Core_SolvePolyTest();
2277
protected:
2278
virtual void run( int start_from );
2279
};
2280
2281
Core_SolvePolyTest::Core_SolvePolyTest() {}
2282
2283
Core_SolvePolyTest::~Core_SolvePolyTest() {}
2284
2285
void Core_SolvePolyTest::run( int )
2286
{
2287
RNG& rng = ts->get_rng();
2288
int fig = 100;
2289
double range = 50;
2290
double err_eps = 1e-4;
2291
2292
for (int idx = 0, max_idx = 1000, progress = 0; idx < max_idx; ++idx)
2293
{
2294
progress = update_progress(progress, idx-1, max_idx, 0);
2295
int n = cvtest::randInt(rng) % 13 + 1;
2296
std::vector<complex_type> r(n), ar(n), c(n + 1, 0);
2297
std::vector<double> a(n + 1), u(n * 2), ar1(n), ar2(n);
2298
2299
int rr_odds = 3; // odds that we get a real root
2300
for (int j = 0; j < n;)
2301
{
2302
if (cvtest::randInt(rng) % rr_odds == 0 || j == n - 1)
2303
r[j++] = cvtest::randReal(rng) * range;
2304
else
2305
{
2306
r[j] = complex_type(cvtest::randReal(rng) * range,
2307
cvtest::randReal(rng) * range + 1);
2308
r[j + 1] = std::conj(r[j]);
2309
j += 2;
2310
}
2311
}
2312
2313
for (int j = 0, k = 1 << n, jj, kk; j < k; ++j)
2314
{
2315
int p = 0;
2316
complex_type v(1);
2317
for (jj = 0, kk = 1; jj < n && !(j & kk); ++jj, ++p, kk <<= 1)
2318
;
2319
for (; jj < n; ++jj, kk <<= 1)
2320
{
2321
if (j & kk)
2322
v *= -r[jj];
2323
else
2324
++p;
2325
}
2326
c[p] += v;
2327
}
2328
2329
bool pass = false;
2330
double div = 0, s = 0;
2331
int cubic_case = idx & 1;
2332
for (int maxiter = 100; !pass && maxiter < 10000; maxiter *= 2, cubic_case = (cubic_case + 1) % 2)
2333
{
2334
for (int j = 0; j < n + 1; ++j)
2335
a[j] = c[j].real();
2336
2337
CvMat amat, umat;
2338
cvInitMatHeader(&amat, n + 1, 1, CV_64FC1, &a[0]);
2339
cvInitMatHeader(&umat, n, 1, CV_64FC2, &u[0]);
2340
cvSolvePoly(&amat, &umat, maxiter, fig);
2341
2342
for (int j = 0; j < n; ++j)
2343
ar[j] = complex_type(u[j * 2], u[j * 2 + 1]);
2344
2345
std::sort(r.begin(), r.end(), pred_complex());
2346
std::sort(ar.begin(), ar.end(), pred_complex());
2347
2348
pass = true;
2349
if( n == 3 )
2350
{
2351
ar2.resize(n);
2352
cv::Mat _umat2(3, 1, CV_64F, &ar2[0]), umat2 = _umat2;
2353
cvFlip(&amat, &amat, 0);
2354
int nr2;
2355
if( cubic_case == 0 )
2356
nr2 = cv::solveCubic(cv::cvarrToMat(&amat),umat2);
2357
else
2358
nr2 = cv::solveCubic(cv::Mat_<float>(cv::cvarrToMat(&amat)), umat2);
2359
cvFlip(&amat, &amat, 0);
2360
if(nr2 > 0)
2361
std::sort(ar2.begin(), ar2.begin()+nr2, pred_double());
2362
ar2.resize(nr2);
2363
2364
int nr1 = 0;
2365
for(int j = 0; j < n; j++)
2366
if( fabs(r[j].imag()) < DBL_EPSILON )
2367
ar1[nr1++] = r[j].real();
2368
2369
pass = pass && nr1 == nr2;
2370
if( nr2 > 0 )
2371
{
2372
div = s = 0;
2373
for(int j = 0; j < nr1; j++)
2374
{
2375
s += fabs(ar1[j]);
2376
div += fabs(ar1[j] - ar2[j]);
2377
}
2378
div /= s;
2379
pass = pass && div < err_eps;
2380
}
2381
}
2382
2383
div = s = 0;
2384
for (int j = 0; j < n; ++j)
2385
{
2386
s += fabs(r[j].real()) + fabs(r[j].imag());
2387
div += sqrt(pow(r[j].real() - ar[j].real(), 2) + pow(r[j].imag() - ar[j].imag(), 2));
2388
}
2389
div /= s;
2390
pass = pass && div < err_eps;
2391
}
2392
2393
//test x^3 = 0
2394
cv::Mat coeffs_5623(4, 1, CV_64FC1);
2395
cv::Mat r_5623(3, 1, CV_64FC2);
2396
coeffs_5623.at<double>(0) = 1;
2397
coeffs_5623.at<double>(1) = 0;
2398
coeffs_5623.at<double>(2) = 0;
2399
coeffs_5623.at<double>(3) = 0;
2400
double prec_5623 = cv::solveCubic(coeffs_5623, r_5623);
2401
pass = pass && r_5623.at<double>(0) == 0 && r_5623.at<double>(1) == 0 && r_5623.at<double>(2) == 0;
2402
pass = pass && prec_5623 == 1;
2403
2404
if (!pass)
2405
{
2406
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
2407
ts->printf( cvtest::TS::LOG, "too big diff = %g\n", div );
2408
2409
for (size_t j=0;j<ar2.size();++j)
2410
ts->printf( cvtest::TS::LOG, "ar2[%d]=%g\n", j, ar2[j]);
2411
ts->printf(cvtest::TS::LOG, "\n");
2412
2413
for (size_t j=0;j<r.size();++j)
2414
ts->printf( cvtest::TS::LOG, "r[%d]=(%g, %g)\n", j, r[j].real(), r[j].imag());
2415
ts->printf( cvtest::TS::LOG, "\n" );
2416
for (size_t j=0;j<ar.size();++j)
2417
ts->printf( cvtest::TS::LOG, "ar[%d]=(%g, %g)\n", j, ar[j].real(), ar[j].imag());
2418
break;
2419
}
2420
}
2421
}
2422
2423
template<typename T>
2424
static void checkRoot(Mat& r, T re, T im)
2425
{
2426
for (int i = 0; i < r.cols*r.rows; i++)
2427
{
2428
Vec<T, 2> v = *(Vec<T, 2>*)r.ptr(i);
2429
if (fabs(re - v[0]) < 1e-6 && fabs(im - v[1]) < 1e-6)
2430
{
2431
v[0] = std::numeric_limits<T>::quiet_NaN();
2432
v[1] = std::numeric_limits<T>::quiet_NaN();
2433
return;
2434
}
2435
}
2436
GTEST_NONFATAL_FAILURE_("Can't find root") << "(" << re << ", " << im << ")";
2437
}
2438
TEST(Core_SolvePoly, regression_5599)
2439
{
2440
// x^4 - x^2 = 0, roots: 1, -1, 0, 0
2441
cv::Mat coefs = (cv::Mat_<float>(1,5) << 0, 0, -1, 0, 1 );
2442
{
2443
cv::Mat r;
2444
double prec;
2445
prec = cv::solvePoly(coefs, r);
2446
EXPECT_LE(prec, 1e-6);
2447
EXPECT_EQ(4u, r.total());
2448
//std::cout << "Preciseness = " << prec << std::endl;
2449
//std::cout << "roots:\n" << r << "\n" << std::endl;
2450
ASSERT_EQ(CV_32FC2, r.type());
2451
checkRoot<float>(r, 1, 0);
2452
checkRoot<float>(r, -1, 0);
2453
checkRoot<float>(r, 0, 0);
2454
checkRoot<float>(r, 0, 0);
2455
}
2456
// x^2 - 2x + 1 = 0, roots: 1, 1
2457
coefs = (cv::Mat_<float>(1,3) << 1, -2, 1 );
2458
{
2459
cv::Mat r;
2460
double prec;
2461
prec = cv::solvePoly(coefs, r);
2462
EXPECT_LE(prec, 1e-6);
2463
EXPECT_EQ(2u, r.total());
2464
//std::cout << "Preciseness = " << prec << std::endl;
2465
//std::cout << "roots:\n" << r << "\n" << std::endl;
2466
ASSERT_EQ(CV_32FC2, r.type());
2467
checkRoot<float>(r, 1, 0);
2468
checkRoot<float>(r, 1, 0);
2469
}
2470
}
2471
2472
class Core_PhaseTest : public cvtest::BaseTest
2473
{
2474
int t;
2475
public:
2476
Core_PhaseTest(int t_) : t(t_) {}
2477
~Core_PhaseTest() {}
2478
protected:
2479
virtual void run(int)
2480
{
2481
const float maxAngleDiff = 0.5; //in degrees
2482
const int axisCount = 8;
2483
const int dim = theRNG().uniform(1,10);
2484
const float scale = theRNG().uniform(1.f, 100.f);
2485
Mat x(axisCount + 1, dim, t),
2486
y(axisCount + 1, dim, t);
2487
Mat anglesInDegrees(axisCount + 1, dim, t);
2488
2489
// fill the data
2490
x.row(0).setTo(Scalar(0));
2491
y.row(0).setTo(Scalar(0));
2492
anglesInDegrees.row(0).setTo(Scalar(0));
2493
2494
x.row(1).setTo(Scalar(scale));
2495
y.row(1).setTo(Scalar(0));
2496
anglesInDegrees.row(1).setTo(Scalar(0));
2497
2498
x.row(2).setTo(Scalar(scale));
2499
y.row(2).setTo(Scalar(scale));
2500
anglesInDegrees.row(2).setTo(Scalar(45));
2501
2502
x.row(3).setTo(Scalar(0));
2503
y.row(3).setTo(Scalar(scale));
2504
anglesInDegrees.row(3).setTo(Scalar(90));
2505
2506
x.row(4).setTo(Scalar(-scale));
2507
y.row(4).setTo(Scalar(scale));
2508
anglesInDegrees.row(4).setTo(Scalar(135));
2509
2510
x.row(5).setTo(Scalar(-scale));
2511
y.row(5).setTo(Scalar(0));
2512
anglesInDegrees.row(5).setTo(Scalar(180));
2513
2514
x.row(6).setTo(Scalar(-scale));
2515
y.row(6).setTo(Scalar(-scale));
2516
anglesInDegrees.row(6).setTo(Scalar(225));
2517
2518
x.row(7).setTo(Scalar(0));
2519
y.row(7).setTo(Scalar(-scale));
2520
anglesInDegrees.row(7).setTo(Scalar(270));
2521
2522
x.row(8).setTo(Scalar(scale));
2523
y.row(8).setTo(Scalar(-scale));
2524
anglesInDegrees.row(8).setTo(Scalar(315));
2525
2526
Mat resInRad, resInDeg;
2527
phase(x, y, resInRad, false);
2528
phase(x, y, resInDeg, true);
2529
2530
CV_Assert(resInRad.size() == x.size());
2531
CV_Assert(resInRad.type() == x.type());
2532
2533
CV_Assert(resInDeg.size() == x.size());
2534
CV_Assert(resInDeg.type() == x.type());
2535
2536
// check the result
2537
int outOfRangeCount = countNonZero((resInDeg > 360) | (resInDeg < 0));
2538
if(outOfRangeCount > 0)
2539
{
2540
ts->printf(cvtest::TS::LOG, "There are result angles that are out of range [0, 360] (part of them is %f)\n",
2541
static_cast<float>(outOfRangeCount)/resInDeg.total());
2542
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
2543
}
2544
2545
Mat diff = abs(anglesInDegrees - resInDeg);
2546
size_t errDegCount = diff.total() - countNonZero((diff < maxAngleDiff) | ((360 - diff) < maxAngleDiff));
2547
if(errDegCount > 0)
2548
{
2549
ts->printf(cvtest::TS::LOG, "There are incorrect result angles (in degrees) (part of them is %f)\n",
2550
static_cast<float>(errDegCount)/resInDeg.total());
2551
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
2552
}
2553
2554
Mat convertedRes = resInRad * 180. / CV_PI;
2555
double normDiff = cvtest::norm(convertedRes - resInDeg, NORM_INF);
2556
if(normDiff > FLT_EPSILON * 180.)
2557
{
2558
ts->printf(cvtest::TS::LOG, "There are incorrect result angles (in radians)\n");
2559
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
2560
}
2561
2562
ts->set_failed_test_info(cvtest::TS::OK);
2563
}
2564
};
2565
2566
TEST(Core_CheckRange_Empty, accuracy)
2567
{
2568
cv::Mat m;
2569
ASSERT_TRUE( cv::checkRange(m) );
2570
}
2571
2572
TEST(Core_CheckRange_INT_MAX, accuracy)
2573
{
2574
cv::Mat m(3, 3, CV_32SC1, cv::Scalar(INT_MAX));
2575
ASSERT_FALSE( cv::checkRange(m, true, 0, 0, INT_MAX) );
2576
ASSERT_TRUE( cv::checkRange(m) );
2577
}
2578
2579
TEST(Core_CheckRange_INT_MAX1, accuracy)
2580
{
2581
cv::Mat m(3, 3, CV_32SC1, cv::Scalar(INT_MAX));
2582
ASSERT_TRUE( cv::checkRange(m, true, 0, 0, INT_MAX+1.0f) );
2583
ASSERT_TRUE( cv::checkRange(m) );
2584
}
2585
2586
template <typename T> class Core_CheckRange : public testing::Test {};
2587
2588
TYPED_TEST_CASE_P(Core_CheckRange);
2589
2590
TYPED_TEST_P(Core_CheckRange, Negative)
2591
{
2592
double min_bound = 4.5;
2593
double max_bound = 16.0;
2594
2595
TypeParam data[] = {5, 10, 15, 10, 10, 2, 8, 12, 14};
2596
cv::Mat src = cv::Mat(3,3, cv::DataDepth<TypeParam>::value, data);
2597
2598
cv::Point bad_pt(0, 0);
2599
2600
ASSERT_FALSE(checkRange(src, true, &bad_pt, min_bound, max_bound));
2601
ASSERT_EQ(bad_pt.x, 2);
2602
ASSERT_EQ(bad_pt.y, 1);
2603
}
2604
2605
TYPED_TEST_P(Core_CheckRange, Negative3CN)
2606
{
2607
double min_bound = 4.5;
2608
double max_bound = 16.0;
2609
2610
TypeParam data[] = { 5, 6, 7, 10, 11, 12, 13, 14, 15,
2611
10, 11, 12, 10, 11, 12, 2, 5, 6,
2612
8, 8, 8, 12, 12, 12, 14, 14, 14};
2613
cv::Mat src = cv::Mat(3,3, CV_MAKETYPE(cv::DataDepth<TypeParam>::value, 3), data);
2614
2615
cv::Point bad_pt(0, 0);
2616
2617
ASSERT_FALSE(checkRange(src, true, &bad_pt, min_bound, max_bound));
2618
ASSERT_EQ(bad_pt.x, 2);
2619
ASSERT_EQ(bad_pt.y, 1);
2620
}
2621
2622
TYPED_TEST_P(Core_CheckRange, Positive)
2623
{
2624
double min_bound = -1;
2625
double max_bound = 16.0;
2626
2627
TypeParam data[] = {5, 10, 15, 4, 10, 2, 8, 12, 14};
2628
cv::Mat src = cv::Mat(3,3, cv::DataDepth<TypeParam>::value, data);
2629
2630
cv::Point bad_pt(0, 0);
2631
2632
ASSERT_TRUE(checkRange(src, true, &bad_pt, min_bound, max_bound));
2633
ASSERT_EQ(bad_pt.x, 0);
2634
ASSERT_EQ(bad_pt.y, 0);
2635
}
2636
2637
TYPED_TEST_P(Core_CheckRange, Bounds)
2638
{
2639
double min_bound = 24.5;
2640
double max_bound = 1.0;
2641
2642
TypeParam data[] = {5, 10, 15, 4, 10, 2, 8, 12, 14};
2643
cv::Mat src = cv::Mat(3,3, cv::DataDepth<TypeParam>::value, data);
2644
2645
cv::Point bad_pt(0, 0);
2646
2647
ASSERT_FALSE(checkRange(src, true, &bad_pt, min_bound, max_bound));
2648
ASSERT_EQ(bad_pt.x, 0);
2649
ASSERT_EQ(bad_pt.y, 0);
2650
}
2651
2652
TYPED_TEST_P(Core_CheckRange, Zero)
2653
{
2654
double min_bound = 0.0;
2655
double max_bound = 0.1;
2656
2657
cv::Mat src1 = cv::Mat::zeros(3, 3, cv::DataDepth<TypeParam>::value);
2658
2659
int sizes[] = {5, 6, 7};
2660
cv::Mat src2 = cv::Mat::zeros(3, sizes, cv::DataDepth<TypeParam>::value);
2661
2662
ASSERT_TRUE( checkRange(src1, true, NULL, min_bound, max_bound) );
2663
ASSERT_TRUE( checkRange(src2, true, NULL, min_bound, max_bound) );
2664
}
2665
2666
TYPED_TEST_P(Core_CheckRange, One)
2667
{
2668
double min_bound = 1.0;
2669
double max_bound = 1.1;
2670
2671
cv::Mat src1 = cv::Mat::ones(3, 3, cv::DataDepth<TypeParam>::value);
2672
2673
int sizes[] = {5, 6, 7};
2674
cv::Mat src2 = cv::Mat::ones(3, sizes, cv::DataDepth<TypeParam>::value);
2675
2676
ASSERT_TRUE( checkRange(src1, true, NULL, min_bound, max_bound) );
2677
ASSERT_TRUE( checkRange(src2, true, NULL, min_bound, max_bound) );
2678
}
2679
2680
TEST(Core_CheckRange, NaN)
2681
{
2682
float data[] = { 5, 6, 7, 10, 11, 12, 13, 14, 15,
2683
10, 11, 12, 10, 11, 12, 5, 5, std::numeric_limits<float>::quiet_NaN(),
2684
8, 8, 8, 12, 12, 12, 14, 14, 14};
2685
cv::Mat src = cv::Mat(3,3, CV_32FC3, data);
2686
2687
cv::Point bad_pt(0, 0);
2688
2689
ASSERT_FALSE(checkRange(src, true, &bad_pt));
2690
ASSERT_EQ(bad_pt.x, 2);
2691
ASSERT_EQ(bad_pt.y, 1);
2692
}
2693
2694
TEST(Core_CheckRange, Inf)
2695
{
2696
float data[] = { 5, 6, 7, 10, 11, 12, 13, 14, 15,
2697
10, 11, 12, 10, 11, 12, 5, 5, std::numeric_limits<float>::infinity(),
2698
8, 8, 8, 12, 12, 12, 14, 14, 14};
2699
cv::Mat src = cv::Mat(3,3, CV_32FC3, data);
2700
2701
cv::Point bad_pt(0, 0);
2702
2703
ASSERT_FALSE(checkRange(src, true, &bad_pt));
2704
ASSERT_EQ(bad_pt.x, 2);
2705
ASSERT_EQ(bad_pt.y, 1);
2706
}
2707
2708
TEST(Core_CheckRange, Inf_Minus)
2709
{
2710
float data[] = { 5, 6, 7, 10, 11, 12, 13, 14, 15,
2711
10, 11, 12, 10, 11, 12, 5, 5, -std::numeric_limits<float>::infinity(),
2712
8, 8, 8, 12, 12, 12, 14, 14, 14};
2713
cv::Mat src = cv::Mat(3,3, CV_32FC3, data);
2714
2715
cv::Point bad_pt(0, 0);
2716
2717
ASSERT_FALSE(checkRange(src, true, &bad_pt));
2718
ASSERT_EQ(bad_pt.x, 2);
2719
ASSERT_EQ(bad_pt.y, 1);
2720
}
2721
2722
REGISTER_TYPED_TEST_CASE_P(Core_CheckRange, Negative, Negative3CN, Positive, Bounds, Zero, One);
2723
2724
typedef ::testing::Types<signed char,unsigned char, signed short, unsigned short, signed int> mat_data_types;
2725
INSTANTIATE_TYPED_TEST_CASE_P(Negative_Test, Core_CheckRange, mat_data_types);
2726
2727
TEST(Core_Invert, small)
2728
{
2729
cv::Mat a = (cv::Mat_<float>(3,3) << 2.42104644730331, 1.81444796521479, -3.98072565304758, 0, 7.08389214348967e-3, 5.55326770986007e-3, 0,0, 7.44556154284261e-3);
2730
//cv::randu(a, -1, 1);
2731
2732
cv::Mat b = a.t()*a;
2733
cv::Mat c, i = Mat_<float>::eye(3, 3);
2734
cv::invert(b, c, cv::DECOMP_LU); //std::cout << b*c << std::endl;
2735
ASSERT_LT( cvtest::norm(b*c, i, CV_C), 0.1 );
2736
cv::invert(b, c, cv::DECOMP_SVD); //std::cout << b*c << std::endl;
2737
ASSERT_LT( cvtest::norm(b*c, i, CV_C), 0.1 );
2738
cv::invert(b, c, cv::DECOMP_CHOLESKY); //std::cout << b*c << std::endl;
2739
ASSERT_LT( cvtest::norm(b*c, i, CV_C), 0.1 );
2740
}
2741
2742
/////////////////////////////////////////////////////////////////////////////////////////////////////
2743
2744
TEST(Core_CovarMatrix, accuracy) { Core_CovarMatrixTest test; test.safe_run(); }
2745
TEST(Core_CrossProduct, accuracy) { Core_CrossProductTest test; test.safe_run(); }
2746
TEST(Core_Determinant, accuracy) { Core_DetTest test; test.safe_run(); }
2747
TEST(Core_DotProduct, accuracy) { Core_DotProductTest test; test.safe_run(); }
2748
TEST(Core_GEMM, accuracy) { Core_GEMMTest test; test.safe_run(); }
2749
TEST(Core_Invert, accuracy) { Core_InvertTest test; test.safe_run(); }
2750
TEST(Core_Mahalanobis, accuracy) { Core_MahalanobisTest test; test.safe_run(); }
2751
TEST(Core_MulTransposed, accuracy) { Core_MulTransposedTest test; test.safe_run(); }
2752
TEST(Core_Transform, accuracy) { Core_TransformTest test; test.safe_run(); }
2753
TEST(Core_TransformLarge, accuracy) { Core_TransformLargeTest test; test.safe_run(); }
2754
TEST(Core_PerspectiveTransform, accuracy) { Core_PerspectiveTransformTest test; test.safe_run(); }
2755
TEST(Core_Pow, accuracy) { Core_PowTest test; test.safe_run(); }
2756
TEST(Core_SolveLinearSystem, accuracy) { Core_SolveTest test; test.safe_run(); }
2757
TEST(Core_SVD, accuracy) { Core_SVDTest test; test.safe_run(); }
2758
TEST(Core_SVBkSb, accuracy) { Core_SVBkSbTest test; test.safe_run(); }
2759
TEST(Core_Trace, accuracy) { Core_TraceTest test; test.safe_run(); }
2760
TEST(Core_SolvePoly, accuracy) { Core_SolvePolyTest test; test.safe_run(); }
2761
TEST(Core_Phase, accuracy32f) { Core_PhaseTest test(CV_32FC1); test.safe_run(); }
2762
TEST(Core_Phase, accuracy64f) { Core_PhaseTest test(CV_64FC1); test.safe_run(); }
2763
2764
TEST(Core_SVD, flt)
2765
{
2766
float a[] = {
2767
1.23377746e+011f, -7.05490125e+010f, -4.18380882e+010f, -11693456.f,
2768
-39091328.f, 77492224.f, -7.05490125e+010f, 2.36211143e+011f,
2769
-3.51093473e+010f, 70773408.f, -4.83386156e+005f, -129560368.f,
2770
-4.18380882e+010f, -3.51093473e+010f, 9.25311222e+010f, -49052424.f,
2771
43922752.f, 12176842.f, -11693456.f, 70773408.f, -49052424.f, 8.40836094e+004f,
2772
5.17475293e+003f, -1.16122949e+004f, -39091328.f, -4.83386156e+005f,
2773
43922752.f, 5.17475293e+003f, 5.16047969e+004f, 5.68887842e+003f, 77492224.f,
2774
-129560368.f, 12176842.f, -1.16122949e+004f, 5.68887842e+003f,
2775
1.28060578e+005f
2776
};
2777
2778
float b[] = {
2779
283751232.f, 2.61604198e+009f, -745033216.f, 2.31125625e+005f,
2780
-4.52429188e+005f, -1.37596525e+006f
2781
};
2782
2783
Mat A(6, 6, CV_32F, a);
2784
Mat B(6, 1, CV_32F, b);
2785
Mat X, B1;
2786
solve(A, B, X, DECOMP_SVD);
2787
B1 = A*X;
2788
EXPECT_LE(cvtest::norm(B1, B, NORM_L2 + NORM_RELATIVE), FLT_EPSILON*10);
2789
}
2790
2791
2792
// TODO: eigenvv, invsqrt, cbrt, fastarctan, (round, floor, ceil(?)),
2793
2794
enum
2795
{
2796
MAT_N_DIM_C1,
2797
MAT_N_1_CDIM,
2798
MAT_1_N_CDIM,
2799
MAT_N_DIM_C1_NONCONT,
2800
MAT_N_1_CDIM_NONCONT,
2801
VECTOR
2802
};
2803
2804
class CV_KMeansSingularTest : public cvtest::BaseTest
2805
{
2806
public:
2807
CV_KMeansSingularTest() {}
2808
~CV_KMeansSingularTest() {}
2809
protected:
2810
void run(int inVariant)
2811
{
2812
RNG& rng = ts->get_rng();
2813
int i, iter = 0, N = 0, N0 = 0, K = 0, dims = 0;
2814
Mat labels;
2815
2816
{
2817
const int MAX_DIM=5;
2818
int MAX_POINTS = 100, maxIter = 100;
2819
for( iter = 0; iter < maxIter; iter++ )
2820
{
2821
ts->update_context(this, iter, true);
2822
dims = rng.uniform(inVariant == MAT_1_N_CDIM ? 2 : 1, MAX_DIM+1);
2823
N = rng.uniform(2, MAX_POINTS+1);
2824
N0 = rng.uniform(1, MAX(N/10, 2));
2825
K = rng.uniform(1, N+1);
2826
2827
Mat centers;
2828
2829
if (inVariant == VECTOR)
2830
{
2831
dims = 2;
2832
2833
std::vector<cv::Point2f> data0(N0);
2834
rng.fill(data0, RNG::UNIFORM, -1, 1);
2835
2836
std::vector<cv::Point2f> data(N);
2837
for( i = 0; i < N; i++ )
2838
data[i] = data0[rng.uniform(0, N0)];
2839
2840
kmeans(data, K, labels, TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 0),
2841
5, KMEANS_PP_CENTERS, centers);
2842
}
2843
else
2844
{
2845
Mat data0(N0, dims, CV_32F);
2846
rng.fill(data0, RNG::UNIFORM, -1, 1);
2847
2848
Mat data;
2849
2850
switch (inVariant)
2851
{
2852
case MAT_N_DIM_C1:
2853
data.create(N, dims, CV_32F);
2854
for( i = 0; i < N; i++ )
2855
data0.row(rng.uniform(0, N0)).copyTo(data.row(i));
2856
break;
2857
2858
case MAT_N_1_CDIM:
2859
data.create(N, 1, CV_32FC(dims));
2860
for( i = 0; i < N; i++ )
2861
memcpy(data.ptr(i), data0.ptr(rng.uniform(0, N0)), dims * sizeof(float));
2862
break;
2863
2864
case MAT_1_N_CDIM:
2865
data.create(1, N, CV_32FC(dims));
2866
for( i = 0; i < N; i++ )
2867
memcpy(data.ptr() + i * dims * sizeof(float), data0.ptr(rng.uniform(0, N0)), dims * sizeof(float));
2868
break;
2869
2870
case MAT_N_DIM_C1_NONCONT:
2871
data.create(N, dims + 5, CV_32F);
2872
data = data(Range(0, N), Range(0, dims));
2873
for( i = 0; i < N; i++ )
2874
data0.row(rng.uniform(0, N0)).copyTo(data.row(i));
2875
break;
2876
2877
case MAT_N_1_CDIM_NONCONT:
2878
data.create(N, 3, CV_32FC(dims));
2879
data = data.colRange(0, 1);
2880
for( i = 0; i < N; i++ )
2881
memcpy(data.ptr(i), data0.ptr(rng.uniform(0, N0)), dims * sizeof(float));
2882
break;
2883
}
2884
2885
kmeans(data, K, labels, TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 0),
2886
5, KMEANS_PP_CENTERS, centers);
2887
}
2888
2889
ASSERT_EQ(centers.rows, K);
2890
ASSERT_EQ(labels.rows, N);
2891
2892
Mat hist(K, 1, CV_32S, Scalar(0));
2893
for( i = 0; i < N; i++ )
2894
{
2895
int l = labels.at<int>(i);
2896
ASSERT_GE(l, 0);
2897
ASSERT_LT(l, K);
2898
hist.at<int>(l)++;
2899
}
2900
for( i = 0; i < K; i++ )
2901
ASSERT_GT(hist.at<int>(i), 0);
2902
}
2903
}
2904
}
2905
};
2906
2907
TEST(Core_KMeans, singular) { CV_KMeansSingularTest test; test.safe_run(MAT_N_DIM_C1); }
2908
2909
CV_ENUM(KMeansInputVariant, MAT_N_DIM_C1, MAT_N_1_CDIM, MAT_1_N_CDIM, MAT_N_DIM_C1_NONCONT, MAT_N_1_CDIM_NONCONT, VECTOR)
2910
2911
typedef testing::TestWithParam<KMeansInputVariant> Core_KMeans_InputVariants;
2912
2913
TEST_P(Core_KMeans_InputVariants, singular)
2914
{
2915
CV_KMeansSingularTest test;
2916
test.safe_run(GetParam());
2917
}
2918
2919
INSTANTIATE_TEST_CASE_P(AllVariants, Core_KMeans_InputVariants, KMeansInputVariant::all());
2920
2921
TEST(Core_KMeans, compactness)
2922
{
2923
const int N = 1024;
2924
const int attempts = 4;
2925
const TermCriteria crit = TermCriteria(TermCriteria::COUNT, 5, 0); // low number of iterations
2926
cvtest::TS& ts = *cvtest::TS::ptr();
2927
for (int K = 1; K <= N; K *= 2)
2928
{
2929
Mat data(N, 1, CV_32FC2);
2930
cvtest::randUni(ts.get_rng(), data, Scalar(-200, -200), Scalar(200, 200));
2931
Mat labels, centers;
2932
double compactness = kmeans(data, K, labels, crit, attempts, KMEANS_PP_CENTERS, centers);
2933
centers = centers.reshape(2);
2934
EXPECT_EQ(labels.rows, N);
2935
EXPECT_EQ(centers.rows, K);
2936
EXPECT_GE(compactness, 0.0);
2937
double expected = 0.0;
2938
for (int i = 0; i < N; ++i)
2939
{
2940
int l = labels.at<int>(i);
2941
Point2f d = data.at<Point2f>(i) - centers.at<Point2f>(l);
2942
expected += d.x * d.x + d.y * d.y;
2943
}
2944
EXPECT_NEAR(expected, compactness, expected * 1e-8);
2945
if (K == N)
2946
{
2947
EXPECT_DOUBLE_EQ(compactness, 0.0);
2948
}
2949
}
2950
}
2951
2952
TEST(CovariationMatrixVectorOfMat, accuracy)
2953
{
2954
unsigned int col_problem_size = 8, row_problem_size = 8, vector_size = 16;
2955
cv::Mat src(vector_size, col_problem_size * row_problem_size, CV_32F);
2956
int singleMatFlags = CV_COVAR_ROWS;
2957
2958
cv::Mat gold;
2959
cv::Mat goldMean;
2960
cv::randu(src,cv::Scalar(-128), cv::Scalar(128));
2961
cv::calcCovarMatrix(src,gold,goldMean,singleMatFlags,CV_32F);
2962
std::vector<cv::Mat> srcVec;
2963
for(size_t i = 0; i < vector_size; i++)
2964
{
2965
srcVec.push_back(src.row(static_cast<int>(i)).reshape(0,col_problem_size));
2966
}
2967
2968
cv::Mat actual;
2969
cv::Mat actualMean;
2970
cv::calcCovarMatrix(srcVec, actual, actualMean,singleMatFlags,CV_32F);
2971
2972
cv::Mat diff;
2973
cv::absdiff(gold, actual, diff);
2974
cv::Scalar s = cv::sum(diff);
2975
ASSERT_EQ(s.dot(s), 0.0);
2976
2977
cv::Mat meanDiff;
2978
cv::absdiff(goldMean, actualMean.reshape(0,1), meanDiff);
2979
cv::Scalar sDiff = cv::sum(meanDiff);
2980
ASSERT_EQ(sDiff.dot(sDiff), 0.0);
2981
}
2982
2983
TEST(CovariationMatrixVectorOfMatWithMean, accuracy)
2984
{
2985
unsigned int col_problem_size = 8, row_problem_size = 8, vector_size = 16;
2986
cv::Mat src(vector_size, col_problem_size * row_problem_size, CV_32F);
2987
int singleMatFlags = CV_COVAR_ROWS | CV_COVAR_USE_AVG;
2988
2989
cv::Mat gold;
2990
cv::randu(src,cv::Scalar(-128), cv::Scalar(128));
2991
cv::Mat goldMean;
2992
2993
cv::reduce(src,goldMean,0 ,CV_REDUCE_AVG, CV_32F);
2994
2995
cv::calcCovarMatrix(src,gold,goldMean,singleMatFlags,CV_32F);
2996
2997
std::vector<cv::Mat> srcVec;
2998
for(size_t i = 0; i < vector_size; i++)
2999
{
3000
srcVec.push_back(src.row(static_cast<int>(i)).reshape(0,col_problem_size));
3001
}
3002
3003
cv::Mat actual;
3004
cv::Mat actualMean = goldMean.reshape(0, row_problem_size);
3005
cv::calcCovarMatrix(srcVec, actual, actualMean,singleMatFlags,CV_32F);
3006
3007
cv::Mat diff;
3008
cv::absdiff(gold, actual, diff);
3009
cv::Scalar s = cv::sum(diff);
3010
ASSERT_EQ(s.dot(s), 0.0);
3011
3012
cv::Mat meanDiff;
3013
cv::absdiff(goldMean, actualMean.reshape(0,1), meanDiff);
3014
cv::Scalar sDiff = cv::sum(meanDiff);
3015
ASSERT_EQ(sDiff.dot(sDiff), 0.0);
3016
}
3017
3018
TEST(Core_Pow, special)
3019
{
3020
for( int i = 0; i < 100; i++ )
3021
{
3022
int n = theRNG().uniform(1, 30);
3023
Mat mtx0(1, n, CV_8S), mtx, result;
3024
randu(mtx0, -5, 5);
3025
3026
int type = theRNG().uniform(0, 2) ? CV_64F : CV_32F;
3027
double eps = type == CV_32F ? 1e-3 : 1e-10;
3028
mtx0.convertTo(mtx, type);
3029
// generate power from [-n, n] interval with 1/8 step - enough to check various cases.
3030
const int max_pf = 3;
3031
int pf = theRNG().uniform(0, max_pf*2+1);
3032
double power = ((1 << pf) - (1 << (max_pf*2-1)))/16.;
3033
int ipower = cvRound(power);
3034
bool is_ipower = ipower == power;
3035
cv::pow(mtx, power, result);
3036
for( int j = 0; j < n; j++ )
3037
{
3038
double val = type == CV_32F ? (double)mtx.at<float>(j) : mtx.at<double>(j);
3039
double r = type == CV_32F ? (double)result.at<float>(j) : result.at<double>(j);
3040
double r0;
3041
if( power == 0. )
3042
r0 = 1;
3043
else if( is_ipower )
3044
{
3045
r0 = 1;
3046
for( int k = 0; k < std::abs(ipower); k++ )
3047
r0 *= val;
3048
if( ipower < 0 )
3049
r0 = 1./r0;
3050
}
3051
else
3052
r0 = std::pow(val, power);
3053
if( cvIsInf(r0) )
3054
{
3055
ASSERT_TRUE(cvIsInf(r) != 0);
3056
}
3057
else if( cvIsNaN(r0) )
3058
{
3059
ASSERT_TRUE(cvIsNaN(r) != 0);
3060
}
3061
else
3062
{
3063
ASSERT_TRUE(cvIsInf(r) == 0 && cvIsNaN(r) == 0);
3064
ASSERT_LT(fabs(r - r0), eps);
3065
}
3066
}
3067
}
3068
}
3069
3070
TEST(Core_Cholesky, accuracy64f)
3071
{
3072
const int n = 5;
3073
Mat A(n, n, CV_64F), refA;
3074
Mat mean(1, 1, CV_64F);
3075
*mean.ptr<double>() = 10.0;
3076
Mat dev(1, 1, CV_64F);
3077
*dev.ptr<double>() = 10.0;
3078
RNG rng(10);
3079
rng.fill(A, RNG::NORMAL, mean, dev);
3080
A = A*A.t();
3081
A.copyTo(refA);
3082
Cholesky(A.ptr<double>(), A.step, n, NULL, 0, 0);
3083
3084
for (int i = 0; i < A.rows; i++)
3085
for (int j = i + 1; j < A.cols; j++)
3086
A.at<double>(i, j) = 0.0;
3087
EXPECT_LE(cvtest::norm(refA, A*A.t(), CV_RELATIVE_L2), FLT_EPSILON);
3088
}
3089
3090
TEST(Core_QR_Solver, accuracy64f)
3091
{
3092
int m = 20, n = 18;
3093
Mat A(m, m, CV_64F);
3094
Mat B(m, n, CV_64F);
3095
Mat mean(1, 1, CV_64F);
3096
*mean.ptr<double>() = 10.0;
3097
Mat dev(1, 1, CV_64F);
3098
*dev.ptr<double>() = 10.0;
3099
RNG rng(10);
3100
rng.fill(A, RNG::NORMAL, mean, dev);
3101
rng.fill(B, RNG::NORMAL, mean, dev);
3102
A = A*A.t();
3103
Mat solutionQR;
3104
3105
//solve system with square matrix
3106
solve(A, B, solutionQR, DECOMP_QR);
3107
EXPECT_LE(cvtest::norm(A*solutionQR, B, CV_RELATIVE_L2), FLT_EPSILON);
3108
3109
A = Mat(m, n, CV_64F);
3110
B = Mat(m, n, CV_64F);
3111
rng.fill(A, RNG::NORMAL, mean, dev);
3112
rng.fill(B, RNG::NORMAL, mean, dev);
3113
3114
//solve normal system
3115
solve(A, B, solutionQR, DECOMP_QR | DECOMP_NORMAL);
3116
EXPECT_LE(cvtest::norm(A.t()*(A*solutionQR), A.t()*B, CV_RELATIVE_L2), FLT_EPSILON);
3117
3118
//solve overdeterminated system as a least squares problem
3119
Mat solutionSVD;
3120
solve(A, B, solutionQR, DECOMP_QR);
3121
solve(A, B, solutionSVD, DECOMP_SVD);
3122
EXPECT_LE(cvtest::norm(solutionQR, solutionSVD, CV_RELATIVE_L2), FLT_EPSILON);
3123
3124
//solve system with singular matrix
3125
A = Mat(10, 10, CV_64F);
3126
B = Mat(10, 1, CV_64F);
3127
rng.fill(A, RNG::NORMAL, mean, dev);
3128
rng.fill(B, RNG::NORMAL, mean, dev);
3129
for (int i = 0; i < A.cols; i++)
3130
A.at<double>(0, i) = A.at<double>(1, i);
3131
ASSERT_FALSE(solve(A, B, solutionQR, DECOMP_QR));
3132
}
3133
3134
TEST(Core_Solve, regression_11888)
3135
{
3136
cv::Matx<float, 3, 2> A(
3137
2, 1,
3138
3, 1,
3139
6, 1
3140
);
3141
cv::Vec<float, 3> b(4, 5, 7);
3142
cv::Matx<float, 2, 1> xQR = A.solve(b, DECOMP_QR);
3143
cv::Matx<float, 2, 1> xSVD = A.solve(b, DECOMP_SVD);
3144
EXPECT_LE(cvtest::norm(xQR, xSVD, NORM_L2 | NORM_RELATIVE), 0.001);
3145
cv::Matx<float, 2, 3> iA = A.inv(DECOMP_SVD);
3146
EXPECT_LE(cvtest::norm(iA*A, Matx<float, 2, 2>::eye(), NORM_L2), 1e-3);
3147
EXPECT_ANY_THROW({
3148
/*cv::Matx<float, 2, 1> xLU =*/ A.solve(b, DECOMP_LU);
3149
std::cout << "FATAL ERROR" << std::endl;
3150
});
3151
}
3152
3153
TEST(Core_Solve, Matx_2_2)
3154
{
3155
cv::Matx<float, 2, 2> A(
3156
2, 1,
3157
1, 1
3158
);
3159
cv::Vec<float, 2> b(4, 5);
3160
cv::Matx<float, 2, 1> xLU = A.solve(b, DECOMP_LU);
3161
cv::Matx<float, 2, 1> xQR = A.solve(b, DECOMP_QR);
3162
cv::Matx<float, 2, 1> xSVD = A.solve(b, DECOMP_SVD);
3163
EXPECT_LE(cvtest::norm(xQR, xSVD, NORM_L2 | NORM_RELATIVE), 1e-3);
3164
EXPECT_LE(cvtest::norm(xQR, xLU, NORM_L2 | NORM_RELATIVE), 1e-3);
3165
cv::Matx<float, 2, 2> iA = A.inv(DECOMP_SVD);
3166
EXPECT_LE(cvtest::norm(iA*A, Matx<float, 2, 2>::eye(), NORM_L2), 1e-3);
3167
}
3168
TEST(Core_Solve, Matx_3_3)
3169
{
3170
cv::Matx<float, 3, 3> A(
3171
2, 1, 0,
3172
0, 1, 1,
3173
1, 0, 1
3174
);
3175
cv::Vec<float, 3> b(4, 5, 6);
3176
cv::Matx<float, 3, 1> xLU = A.solve(b, DECOMP_LU);
3177
cv::Matx<float, 3, 1> xQR = A.solve(b, DECOMP_QR);
3178
cv::Matx<float, 3, 1> xSVD = A.solve(b, DECOMP_SVD);
3179
EXPECT_LE(cvtest::norm(xQR, xSVD, NORM_L2 | NORM_RELATIVE), 1e-3);
3180
EXPECT_LE(cvtest::norm(xQR, xLU, NORM_L2 | NORM_RELATIVE), 1e-3);
3181
cv::Matx<float, 3, 3> iA = A.inv(DECOMP_SVD);
3182
EXPECT_LE(cvtest::norm(iA*A, Matx<float, 3, 3>::eye(), NORM_L2), 1e-3);
3183
}
3184
3185
TEST(Core_Solve, Matx_4_4)
3186
{
3187
cv::Matx<float, 4, 4> A(
3188
2, 1, 0, 4,
3189
0, 1, 1, 3,
3190
1, 0, 1, 2,
3191
2, 2, 0, 1
3192
);
3193
cv::Vec<float, 4> b(4, 5, 6, 7);
3194
cv::Matx<float, 4, 1> xLU = A.solve(b, DECOMP_LU);
3195
cv::Matx<float, 4, 1> xQR = A.solve(b, DECOMP_QR);
3196
cv::Matx<float, 4, 1> xSVD = A.solve(b, DECOMP_SVD);
3197
EXPECT_LE(cvtest::norm(xQR, xSVD, NORM_L2 | NORM_RELATIVE), 1e-3);
3198
EXPECT_LE(cvtest::norm(xQR, xLU, NORM_L2 | NORM_RELATIVE), 1e-3);
3199
cv::Matx<float, 4, 4> iA = A.inv(DECOMP_SVD);
3200
EXPECT_LE(cvtest::norm(iA*A, Matx<float, 4, 4>::eye(), NORM_L2), 1e-3);
3201
}
3202
3203
softdouble naiveExp(softdouble x)
3204
{
3205
int exponent = x.getExp();
3206
int sign = x.getSign() ? -1 : 1;
3207
if(sign < 0 && exponent >= 10) return softdouble::inf();
3208
softdouble mantissa = x.getFrac();
3209
//Taylor series for mantissa
3210
uint64 fac[20] = {1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800,
3211
39916800, 479001600, 6227020800, 87178291200, 1307674368000,
3212
20922789888000, 355687428096000, 6402373705728000, 121645100408832000,
3213
2432902008176640000};
3214
softdouble sum = softdouble::one();
3215
// 21! > (2 ** 64)
3216
for(int i = 20; i > 0; i--)
3217
sum += pow(mantissa, softdouble(i))/softdouble(fac[i-1]);
3218
if(exponent >= 0)
3219
{
3220
exponent = (1 << exponent);
3221
return pow(sum, softdouble(exponent*sign));
3222
}
3223
else
3224
{
3225
if(sign < 0) sum = softdouble::one()/sum;
3226
exponent = -exponent;
3227
for(int j = 0; j < exponent; j++)
3228
sum = sqrt(sum);
3229
return sum;
3230
}
3231
}
3232
3233
static float makeFP32(int sign, int exponent, int significand)
3234
{
3235
Cv32suf x;
3236
x.u = (unsigned)(((sign & 1) << 31) | ((exponent&255) << 23) | (significand & 0x7fffff));
3237
return x.f;
3238
}
3239
3240
static float makeRandomFP32(RNG& rng, int sign, int exprange)
3241
{
3242
if( sign == -1 )
3243
sign = rng() % 2;
3244
int exponent = rng() % exprange;
3245
int significand = rng() % (1 << 23);
3246
return makeFP32(sign, exponent, significand);
3247
}
3248
3249
TEST(Core_SoftFloat, exp32)
3250
{
3251
//special cases
3252
EXPECT_TRUE(exp( softfloat::nan()).isNaN());
3253
EXPECT_TRUE(exp( softfloat::inf()).isInf());
3254
EXPECT_EQ (exp(-softfloat::inf()), softfloat::zero());
3255
3256
//ln(FLT_MAX) ~ 88.722
3257
const softfloat ln_max(88.722f);
3258
vector<softfloat> inputs;
3259
RNG rng(0);
3260
inputs.push_back(softfloat::zero());
3261
inputs.push_back(softfloat::one());
3262
inputs.push_back(softfloat::min());
3263
for(int i = 0; i < 50000; i++)
3264
{
3265
float x = makeRandomFP32(rng, -1, 10+127 //bigger exponent will produce inf
3266
);
3267
if(softfloat(x) > ln_max)
3268
x = rng.uniform(0.0f, (float)ln_max);
3269
inputs.push_back(softfloat(x));
3270
}
3271
3272
for(size_t i = 0; i < inputs.size(); i++)
3273
{
3274
softfloat x(inputs[i]);
3275
softfloat y = exp(x);
3276
ASSERT_TRUE(!y.isNaN());
3277
ASSERT_TRUE(!y.isInf());
3278
ASSERT_GE(y, softfloat::zero());
3279
softfloat ygood = naiveExp(x);
3280
softfloat diff = abs(ygood - y);
3281
const softfloat eps = softfloat::eps();
3282
if(diff > eps)
3283
{
3284
ASSERT_LE(diff/max(abs(y), abs(ygood)), eps);
3285
}
3286
}
3287
}
3288
3289
TEST(Core_SoftFloat, exp64)
3290
{
3291
//special cases
3292
EXPECT_TRUE(exp( softdouble::nan()).isNaN());
3293
EXPECT_TRUE(exp( softdouble::inf()).isInf());
3294
EXPECT_EQ (exp(-softdouble::inf()), softdouble::zero());
3295
3296
//ln(DBL_MAX) ~ 709.7827
3297
const softdouble ln_max(709.7827);
3298
vector<softdouble> inputs;
3299
RNG rng(0);
3300
inputs.push_back(softdouble::zero());
3301
inputs.push_back(softdouble::one());
3302
inputs.push_back(softdouble::min());
3303
for(int i = 0; i < 50000; i++)
3304
{
3305
Cv64suf x;
3306
uint64 sign = rng() % 2;
3307
uint64 exponent = rng() % (10 + 1023); //bigger exponent will produce inf
3308
uint64 mantissa = (((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng)) & ((1LL << 52) - 1);
3309
x.u = (sign << 63) | (exponent << 52) | mantissa;
3310
if(softdouble(x.f) > ln_max)
3311
x.f = rng.uniform(0.0, (double)ln_max);
3312
inputs.push_back(softdouble(x.f));
3313
}
3314
3315
for(size_t i = 0; i < inputs.size(); i++)
3316
{
3317
softdouble x(inputs[i]);
3318
softdouble y = exp(x);
3319
ASSERT_TRUE(!y.isNaN());
3320
ASSERT_TRUE(!y.isInf());
3321
ASSERT_GE(y, softdouble::zero());
3322
softdouble ygood = naiveExp(x);
3323
softdouble diff = abs(ygood - y);
3324
const softdouble eps = softdouble::eps();
3325
if(diff > eps)
3326
{
3327
ASSERT_LE(diff/max(abs(y), abs(ygood)), softdouble(8192)*eps);
3328
}
3329
}
3330
}
3331
3332
TEST(Core_SoftFloat, log32)
3333
{
3334
const int nValues = 50000;
3335
RNG rng(0);
3336
//special cases
3337
EXPECT_TRUE(log(softfloat::nan()).isNaN());
3338
for(int i = 0; i < nValues; i++)
3339
{
3340
softfloat x32(makeRandomFP32(rng, 1, 255));
3341
ASSERT_TRUE(log(x32).isNaN());
3342
}
3343
EXPECT_TRUE(log(softfloat::zero()).isInf());
3344
3345
vector<softfloat> inputs;
3346
3347
inputs.push_back(softfloat::one());
3348
inputs.push_back(softfloat(exp(softfloat::one())));
3349
inputs.push_back(softfloat::min());
3350
inputs.push_back(softfloat::max());
3351
for(int i = 0; i < nValues; i++)
3352
{
3353
inputs.push_back(softfloat(makeRandomFP32(rng, 0, 255)));
3354
}
3355
3356
for(size_t i = 0; i < inputs.size(); i++)
3357
{
3358
softfloat x(inputs[i]);
3359
softfloat y = log(x);
3360
ASSERT_TRUE(!y.isNaN());
3361
ASSERT_TRUE(!y.isInf());
3362
softfloat ex = exp(y);
3363
softfloat diff = abs(ex - x);
3364
// 88 is approx estimate of max exp() argument
3365
ASSERT_TRUE(!ex.isInf() || (y > softfloat(88)));
3366
const softfloat eps2 = softfloat().setExp(-17);
3367
if(!ex.isInf() && diff > softfloat::eps())
3368
{
3369
ASSERT_LT(diff/max(abs(ex), x), eps2);
3370
}
3371
}
3372
}
3373
3374
TEST(Core_SoftFloat, log64)
3375
{
3376
const int nValues = 50000;
3377
RNG rng(0);
3378
//special cases
3379
EXPECT_TRUE(log(softdouble::nan()).isNaN());
3380
for(int i = 0; i < nValues; i++)
3381
{
3382
Cv64suf x;
3383
uint64 sign = 1;
3384
uint64 exponent = rng() % 2047;
3385
uint64 mantissa = (((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng)) & ((1LL << 52) - 1);
3386
x.u = (sign << 63) | (exponent << 52) | mantissa;
3387
softdouble x64(x.f);
3388
ASSERT_TRUE(log(x64).isNaN());
3389
}
3390
EXPECT_TRUE(log(softdouble::zero()).isInf());
3391
3392
vector<softdouble> inputs;
3393
inputs.push_back(softdouble::one());
3394
inputs.push_back(exp(softdouble::one()));
3395
inputs.push_back(softdouble::min());
3396
inputs.push_back(softdouble::max());
3397
for(int i = 0; i < nValues; i++)
3398
{
3399
Cv64suf x;
3400
uint64 sign = 0;
3401
uint64 exponent = rng() % 2047;
3402
uint64 mantissa = (((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng)) & ((1LL << 52) - 1);
3403
x.u = (sign << 63) | (exponent << 52) | mantissa;
3404
inputs.push_back(softdouble(x.f));
3405
}
3406
3407
for(size_t i = 0; i < inputs.size(); i++)
3408
{
3409
softdouble x(inputs[i]);
3410
softdouble y = log(x);
3411
ASSERT_TRUE(!y.isNaN());
3412
ASSERT_TRUE(!y.isInf());
3413
softdouble ex = exp(y);
3414
softdouble diff = abs(ex - x);
3415
// 700 is approx estimate of max exp() argument
3416
ASSERT_TRUE(!ex.isInf() || (y > softdouble(700)));
3417
const softdouble eps2 = softdouble().setExp(-41);
3418
if(!ex.isInf() && diff > softdouble::eps())
3419
{
3420
ASSERT_LT(diff/max(abs(ex), x), eps2);
3421
}
3422
}
3423
}
3424
3425
TEST(Core_SoftFloat, cbrt32)
3426
{
3427
vector<softfloat> inputs;
3428
RNG rng(0);
3429
inputs.push_back(softfloat::zero());
3430
inputs.push_back(softfloat::one());
3431
inputs.push_back(softfloat::max());
3432
inputs.push_back(softfloat::min());
3433
for(int i = 0; i < 50000; i++)
3434
{
3435
inputs.push_back(softfloat(makeRandomFP32(rng, -1, 255)));
3436
}
3437
3438
for(size_t i = 0; i < inputs.size(); i++)
3439
{
3440
softfloat x(inputs[i]);
3441
softfloat y = cbrt(x);
3442
ASSERT_TRUE(!y.isNaN());
3443
ASSERT_TRUE(!y.isInf());
3444
softfloat cube = y*y*y;
3445
softfloat diff = abs(x - cube);
3446
const softfloat eps = softfloat::eps();
3447
if(diff > eps)
3448
{
3449
ASSERT_LT(diff/max(abs(x), abs(cube)), softfloat(4)*eps);
3450
}
3451
}
3452
}
3453
3454
TEST(Core_SoftFloat, pow32)
3455
{
3456
const softfloat zero = softfloat::zero(), one = softfloat::one();
3457
const softfloat inf = softfloat::inf(), nan = softfloat::nan();
3458
const size_t nValues = 5000;
3459
RNG rng(0);
3460
//x ** nan == nan
3461
for(size_t i = 0; i < nValues; i++)
3462
{
3463
Cv32suf x;
3464
x.u = rng();
3465
ASSERT_TRUE(pow(softfloat(x.f), nan).isNaN());
3466
}
3467
//x ** inf check
3468
for(size_t i = 0; i < nValues; i++)
3469
{
3470
Cv32suf x;
3471
x.u = rng();
3472
softfloat x32(x.f);
3473
softfloat ax = abs(x32);
3474
if(x32.isNaN())
3475
{
3476
ASSERT_TRUE(pow(x32, inf).isNaN());
3477
}
3478
if(ax > one)
3479
{
3480
ASSERT_TRUE(pow(x32, inf).isInf());
3481
ASSERT_EQ (pow(x32, -inf), zero);
3482
}
3483
if(ax < one && ax > zero)
3484
{
3485
ASSERT_TRUE(pow(x32, -inf).isInf());
3486
ASSERT_EQ (pow(x32, inf), zero);
3487
}
3488
}
3489
//+-1 ** inf
3490
EXPECT_TRUE(pow( one, inf).isNaN());
3491
EXPECT_TRUE(pow(-one, inf).isNaN());
3492
3493
// x ** 0 == 1
3494
for(size_t i = 0; i < nValues; i++)
3495
{
3496
Cv32suf x;
3497
x.u = rng();
3498
ASSERT_EQ(pow(softfloat(x.f), zero), one);
3499
}
3500
3501
// x ** 1 == x
3502
for(size_t i = 0; i < nValues; i++)
3503
{
3504
Cv32suf x;
3505
x.u = rng();
3506
softfloat x32(x.f);
3507
softfloat val = pow(x32, one);
3508
// don't compare val and x32 directly because x != x if x is nan
3509
ASSERT_EQ(val.v, x32.v);
3510
}
3511
3512
// nan ** y == nan, if y != 0
3513
for(size_t i = 0; i < nValues; i++)
3514
{
3515
unsigned u = rng();
3516
softfloat x32 = softfloat::fromRaw(u);
3517
x32 = (x32 != softfloat::zero()) ? x32 : softfloat::min();
3518
ASSERT_TRUE(pow(nan, x32).isNaN());
3519
}
3520
// nan ** 0 == 1
3521
EXPECT_EQ(pow(nan, zero), one);
3522
3523
// inf ** y == 0, if y < 0
3524
// inf ** y == inf, if y > 0
3525
for(size_t i = 0; i < nValues; i++)
3526
{
3527
float x = makeRandomFP32(rng, 0, 255);
3528
softfloat x32 = softfloat(x);
3529
ASSERT_TRUE(pow( inf, x32).isInf());
3530
ASSERT_TRUE(pow(-inf, x32).isInf());
3531
ASSERT_EQ(pow( inf, -x32), zero);
3532
ASSERT_EQ(pow(-inf, -x32), zero);
3533
}
3534
3535
// x ** y == (-x) ** y, if y % 2 == 0
3536
// x ** y == - (-x) ** y, if y % 2 == 1
3537
// x ** y == nan, if x < 0 and y is not integer
3538
for(size_t i = 0; i < nValues; i++)
3539
{
3540
softfloat x32(makeRandomFP32(rng, 1, 255));
3541
softfloat y32(makeRandomFP32(rng, -1, 23+127 //bigger exponent produces integer numbers only
3542
));
3543
int yi = cvRound(y32);
3544
if(y32 != softfloat(yi))
3545
ASSERT_TRUE(pow(x32, y32).isNaN());
3546
else if(yi % 2)
3547
ASSERT_EQ(pow(-x32, y32), -pow(x32, y32));
3548
else
3549
ASSERT_EQ(pow(-x32, y32), pow(x32, y32));
3550
}
3551
3552
// (0 ** 0) == 1
3553
EXPECT_EQ(pow(zero, zero), one);
3554
3555
// 0 ** y == inf, if y < 0
3556
// 0 ** y == 0, if y > 0
3557
for(size_t i = 0; i < nValues; i++)
3558
{
3559
softfloat x32(makeRandomFP32(rng, 0, 255));
3560
ASSERT_TRUE(pow(zero, -x32).isInf());
3561
if(x32 != one)
3562
{
3563
ASSERT_EQ(pow(zero, x32), zero);
3564
}
3565
}
3566
}
3567
3568
TEST(Core_SoftFloat, pow64)
3569
{
3570
const softdouble zero = softdouble::zero(), one = softdouble::one();
3571
const softdouble inf = softdouble::inf(), nan = softdouble::nan();
3572
3573
const size_t nValues = 5000;
3574
RNG rng(0);
3575
3576
//x ** nan == nan
3577
for(size_t i = 0; i < nValues; i++)
3578
{
3579
Cv64suf x;
3580
x.u = ((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng);
3581
ASSERT_TRUE(pow(softdouble(x.f), nan).isNaN());
3582
}
3583
//x ** inf check
3584
for(size_t i = 0; i < nValues; i++)
3585
{
3586
Cv64suf x;
3587
x.u = ((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng);
3588
softdouble x64(x.f);
3589
softdouble ax = abs(x64);
3590
if(x64.isNaN())
3591
{
3592
ASSERT_TRUE(pow(x64, inf).isNaN());
3593
}
3594
if(ax > one)
3595
{
3596
ASSERT_TRUE(pow(x64, inf).isInf());
3597
ASSERT_EQ(pow(x64, -inf), zero);
3598
}
3599
if(ax < one && ax > zero)
3600
{
3601
ASSERT_TRUE(pow(x64, -inf).isInf());
3602
ASSERT_EQ(pow(x64, inf), zero);
3603
}
3604
}
3605
//+-1 ** inf
3606
EXPECT_TRUE(pow( one, inf).isNaN());
3607
EXPECT_TRUE(pow(-one, inf).isNaN());
3608
3609
// x ** 0 == 1
3610
for(size_t i = 0; i < nValues; i++)
3611
{
3612
Cv64suf x;
3613
x.u = ((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng);
3614
ASSERT_EQ(pow(softdouble(x.f), zero), one);
3615
}
3616
3617
// x ** 1 == x
3618
for(size_t i = 0; i < nValues; i++)
3619
{
3620
Cv64suf x;
3621
x.u = ((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng);
3622
softdouble x64(x.f);
3623
softdouble val = pow(x64, one);
3624
// don't compare val and x64 directly because x != x if x is nan
3625
ASSERT_EQ(val.v, x64.v);
3626
}
3627
3628
// nan ** y == nan, if y != 0
3629
for(size_t i = 0; i < nValues; i++)
3630
{
3631
uint64 u = ((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng);
3632
softdouble x64 = softdouble::fromRaw(u);
3633
x64 = (x64 != softdouble::zero()) ? x64 : softdouble::min();
3634
ASSERT_TRUE(pow(nan, x64).isNaN());
3635
}
3636
// nan ** 0 == 1
3637
EXPECT_EQ(pow(nan, zero), one);
3638
3639
// inf ** y == 0, if y < 0
3640
// inf ** y == inf, if y > 0
3641
for(size_t i = 0; i < nValues; i++)
3642
{
3643
Cv64suf x;
3644
uint64 sign = 0;
3645
uint64 exponent = rng() % 2047;
3646
uint64 mantissa = (((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng)) & ((1LL << 52) - 1);
3647
x.u = (sign << 63) | (exponent << 52) | mantissa;
3648
softdouble x64(x.f);
3649
ASSERT_TRUE(pow( inf, x64).isInf());
3650
ASSERT_TRUE(pow(-inf, x64).isInf());
3651
ASSERT_EQ(pow( inf, -x64), zero);
3652
ASSERT_EQ(pow(-inf, -x64), zero);
3653
}
3654
3655
// x ** y == (-x) ** y, if y % 2 == 0
3656
// x ** y == - (-x) ** y, if y % 2 == 1
3657
// x ** y == nan, if x < 0 and y is not integer
3658
for(size_t i = 0; i < nValues; i++)
3659
{
3660
Cv64suf x;
3661
uint64 sign = 1;
3662
uint64 exponent = rng() % 2047;
3663
uint64 mantissa = (((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng)) & ((1LL << 52) - 1);
3664
x.u = (sign << 63) | (exponent << 52) | mantissa;
3665
softdouble x64(x.f);
3666
Cv64suf y;
3667
sign = rng() % 2;
3668
//bigger exponent produces integer numbers only
3669
//exponent = rng() % (52 + 1023);
3670
//bigger exponent is too big
3671
exponent = rng() % (23 + 1023);
3672
mantissa = (((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng)) & ((1LL << 52) - 1);
3673
y.u = (sign << 63) | (exponent << 52) | mantissa;
3674
softdouble y64(y.f);
3675
uint64 yi = cvRound(y64);
3676
if(y64 != softdouble(yi))
3677
ASSERT_TRUE(pow(x64, y64).isNaN());
3678
else if(yi % 2)
3679
ASSERT_EQ(pow(-x64, y64), -pow(x64, y64));
3680
else
3681
ASSERT_EQ(pow(-x64, y64), pow(x64, y64));
3682
}
3683
3684
// (0 ** 0) == 1
3685
EXPECT_EQ(pow(zero, zero), one);
3686
3687
// 0 ** y == inf, if y < 0
3688
// 0 ** y == 0, if y > 0
3689
for(size_t i = 0; i < nValues; i++)
3690
{
3691
Cv64suf x;
3692
uint64 sign = 0;
3693
uint64 exponent = rng() % 2047;
3694
uint64 mantissa = (((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng)) & ((1LL << 52) - 1);
3695
x.u = (sign << 63) | (exponent << 52) | mantissa;
3696
softdouble x64(x.f);
3697
3698
ASSERT_TRUE(pow(zero, -x64).isInf());
3699
if(x64 != one)
3700
{
3701
ASSERT_EQ(pow(zero, x64), zero);
3702
}
3703
}
3704
}
3705
3706
TEST(Core_SoftFloat, sincos64)
3707
{
3708
static const softdouble
3709
two = softdouble(2), three = softdouble(3),
3710
half = softdouble::one()/two,
3711
zero = softdouble::zero(), one = softdouble::one(),
3712
pi = softdouble::pi(), piby2 = pi/two, eps = softdouble::eps(),
3713
sin45 = sqrt(two)/two, sin60 = sqrt(three)/two;
3714
3715
softdouble vstdAngles[] =
3716
//x, sin(x), cos(x)
3717
{
3718
zero, zero, one,
3719
pi/softdouble(6), half, sin60,
3720
pi/softdouble(4), sin45, sin45,
3721
pi/three, sin60, half,
3722
};
3723
vector<softdouble> stdAngles;
3724
stdAngles.assign(vstdAngles, vstdAngles + 3*4);
3725
3726
static const softdouble stdEps = eps.setExp(-39);
3727
const size_t nStdValues = 5000;
3728
for(size_t i = 0; i < nStdValues; i++)
3729
{
3730
for(size_t k = 0; k < stdAngles.size()/3; k++)
3731
{
3732
softdouble x = stdAngles[k*3] + pi*softdouble(2*((int)i-(int)nStdValues/2));
3733
softdouble s = stdAngles[k*3+1];
3734
softdouble c = stdAngles[k*3+2];
3735
ASSERT_LE(abs(sin(x) - s), stdEps);
3736
ASSERT_LE(abs(cos(x) - c), stdEps);
3737
//sin(x+pi/2) = cos(x)
3738
ASSERT_LE(abs(sin(x + piby2) - c), stdEps);
3739
//sin(x+pi) = -sin(x)
3740
ASSERT_LE(abs(sin(x + pi) + s), stdEps);
3741
//cos(x+pi/2) = -sin(x)
3742
ASSERT_LE(abs(cos(x+piby2) + s), stdEps);
3743
//cos(x+pi) = -cos(x)
3744
ASSERT_LE(abs(cos(x+pi) + c), stdEps);
3745
}
3746
}
3747
3748
// sin(x) is NaN iff x ix NaN or Inf
3749
EXPECT_TRUE(sin(softdouble::inf()).isNaN());
3750
EXPECT_TRUE(sin(softdouble::nan()).isNaN());
3751
3752
vector<int> exponents;
3753
exponents.push_back(0);
3754
for(int i = 1; i < 52; i++)
3755
{
3756
exponents.push_back( i);
3757
exponents.push_back(-i);
3758
}
3759
exponents.push_back(256); exponents.push_back(-256);
3760
exponents.push_back(512); exponents.push_back(-512);
3761
exponents.push_back(1022); exponents.push_back(-1022);
3762
3763
vector<softdouble> inputs;
3764
RNG rng(0);
3765
3766
static const size_t nValues = 1 << 18;
3767
for(size_t i = 0; i < nValues; i++)
3768
{
3769
softdouble x;
3770
uint64 mantissa = (((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng)) & ((1LL << 52) - 1);
3771
x.v = mantissa;
3772
x = x.setSign((rng() % 2) != 0);
3773
x = x.setExp(exponents[rng() % exponents.size()]);
3774
inputs.push_back(x);
3775
}
3776
3777
for(size_t i = 0; i < inputs.size(); i++)
3778
{
3779
softdouble x = inputs[i];
3780
3781
int xexp = x.getExp();
3782
softdouble randEps = eps.setExp(std::max(xexp-52, -46));
3783
softdouble sx = sin(x);
3784
softdouble cx = cos(x);
3785
ASSERT_FALSE(sx.isInf()); ASSERT_FALSE(cx.isInf());
3786
ASSERT_FALSE(sx.isNaN()); ASSERT_FALSE(cx.isNaN());
3787
ASSERT_LE(abs(sx), one); ASSERT_LE(abs(cx), one);
3788
ASSERT_LE(abs((sx*sx + cx*cx) - one), eps);
3789
ASSERT_LE(abs(sin(x*two) - two*sx*cx), randEps);
3790
ASSERT_LE(abs(cos(x*two) - (cx*cx - sx*sx)), randEps);
3791
ASSERT_LE(abs(sin(-x) + sx), eps);
3792
ASSERT_LE(abs(cos(-x) - cx), eps);
3793
ASSERT_LE(abs(sin(x + piby2) - cx), randEps);
3794
ASSERT_LE(abs(sin(x + pi) + sx), randEps);
3795
ASSERT_LE(abs(cos(x+piby2) + sx), randEps);
3796
ASSERT_LE(abs(cos(x+pi) + cx), randEps);
3797
}
3798
}
3799
3800
TEST(Core_SoftFloat, CvRound)
3801
{
3802
struct
3803
{
3804
uint64_t inVal;
3805
int64_t out64;
3806
int32_t out32;
3807
} _values[] =
3808
{
3809
{ 0x0123456789abcdefU, 0, 0 }, // 3.51270056408850369812238561681E-303
3810
{ 0x0000000000000000U, 0, 0 }, // 0
3811
{ 0x8000000000000000U, 0, 0 }, // -0
3812
{ 0x000123456789abcdU, 0, 0 }, // 1.5822747438273385725152200433E-309
3813
{ 0x800123456789abcdU, 0, 0 }, // -1.5822747438273385725152200433E-309
3814
{ 0x7ff0000000000000U, INT64_MAX, INT32_MAX }, // +inf
3815
{ 0xfff0000000000000U, INT64_MIN, INT32_MIN }, // -inf
3816
{ 0x7ff0000000000001U, INT64_MAX, INT32_MAX }, // nan(casts to maximum value)
3817
{ 0xfff0000000000001U, INT64_MAX, INT32_MAX }, // nan(casts to maximum value)
3818
{ 0x7ffa5a5a5a5a5a5aU, INT64_MAX, INT32_MAX }, // nan(casts to maximum value)
3819
{ 0xfffa5a5a5a5a5a5aU, INT64_MAX, INT32_MAX }, // nan(casts to maximum value)
3820
{ 0x7fe123456789abcdU, INT64_MAX, INT32_MAX }, // 9.627645455595956656406699747E307
3821
{ 0xffe123456789abcdU, INT64_MIN, INT32_MIN }, // -9.627645455595956656406699747E307
3822
{ 0x43ffffffffffffffU, INT64_MAX, INT32_MAX }, // (2^53-1)*2^12
3823
{ 0xc3ffffffffffffffU, INT64_MIN, INT32_MIN }, // -(2^53-1)*2^12
3824
{ 0x43f0000000000000U, INT64_MAX, INT32_MAX }, // 2^64
3825
{ 0xc3f0000000000000U, INT64_MIN, INT32_MIN }, // -2^64
3826
{ 0x43efffffffffffffU, INT64_MAX, INT32_MAX }, // (2^53-1)*2^11
3827
{ 0xc3efffffffffffffU, INT64_MIN, INT32_MIN }, // -(2^53-1)*2^11
3828
{ 0x43e0000000000000U, INT64_MAX, INT32_MAX }, // 2^63
3829
{ 0xc3e0000000000000U, -0x7fffffffffffffff-1, INT32_MIN }, // -2^63
3830
{ 0x43dfffffffffffffU, 0x7ffffffffffffc00, INT32_MAX }, // (2^53-1)*2^10
3831
{ 0xc3dfffffffffffffU, -0x7ffffffffffffc00, INT32_MIN }, // -(2^53-1)*2^10
3832
{ 0x433fffffffffffffU, 0x1fffffffffffff, INT32_MAX }, // (2^53-1)
3833
{ 0xc33fffffffffffffU, -0x1fffffffffffff, INT32_MIN }, // -(2^53-1)
3834
{ 0x432fffffffffffffU, 0x10000000000000, INT32_MAX }, // (2^52-1) + 0.5
3835
{ 0xc32fffffffffffffU, -0x10000000000000, INT32_MIN }, // -(2^52-1) - 0.5
3836
{ 0x431fffffffffffffU, 0x8000000000000, INT32_MAX }, // (2^51-1) + 0.75
3837
{ 0xc31fffffffffffffU, -0x8000000000000, INT32_MIN }, // -(2^51-1) - 0.75
3838
{ 0x431ffffffffffffeU, 0x8000000000000, INT32_MAX }, // (2^51-1) + 0.5
3839
{ 0xc31ffffffffffffeU, -0x8000000000000, INT32_MIN }, // -(2^51-1) - 0.5
3840
{ 0x431ffffffffffffdU, 0x7ffffffffffff, INT32_MAX }, // (2^51-1) + 0.25
3841
{ 0xc31ffffffffffffdU, -0x7ffffffffffff, INT32_MIN }, // -(2^51-1) - 0.25
3842
3843
{ 0x41f0000000000000U, 0x100000000, INT32_MAX }, // 2^32 = 4294967296
3844
{ 0xc1f0000000000000U, -0x100000000, INT32_MIN }, // -2^32 = -4294967296
3845
{ 0x41efffffffffffffU, 0x100000000, INT32_MAX }, // 4294967295.99999952316284179688
3846
{ 0xc1efffffffffffffU, -0x100000000, INT32_MIN }, // -4294967295.99999952316284179688
3847
{ 0x41effffffff00000U, 0x100000000, INT32_MAX }, // (2^32-1) + 0.5 = 4294967295.5
3848
{ 0xc1effffffff00000U, -0x100000000, INT32_MIN }, // -(2^32-1) - 0.5 = -4294967295.5
3849
{ 0x41efffffffe00000U, 0xffffffffll, INT32_MAX }, // (2^32-1)
3850
{ 0xc1efffffffe00000U, -0xffffffffll, INT32_MIN }, // -(2^32-1)
3851
{ 0x41e0000000000000U, 0x80000000ll, INT32_MAX }, // 2^31 = 2147483648
3852
{ 0xc1e0000000000000U, -0x80000000ll, -0x7fffffff-1 }, // -2^31 = -2147483648
3853
{ 0x41dfffffffffffffU, 0x80000000ll, INT32_MAX }, // 2147483647.99999976158142089844
3854
{ 0xc1dfffffffffffffU, -0x80000000ll, -0x7fffffff-1 }, // -2147483647.99999976158142089844
3855
3856
{ 0x41dffffffff00000U, 0x80000000ll, INT32_MAX }, // (2^31-1) + 0.75
3857
{ 0xc1dffffffff00000U, -0x80000000ll, -0x7fffffff-1 }, // -(2^31-1) - 0.75
3858
{ 0x41dfffffffe00001U, 0x80000000ll, INT32_MAX }, // (2^31-1) + 0.5 + 2^-22
3859
{ 0xc1dfffffffe00001U, -0x80000000ll, -0x7fffffff-1 }, // -(2^31-1) - 0.5 - 2^-22
3860
{ 0x41dfffffffe00000U, 0x80000000ll, INT32_MAX }, // (2^31-1) + 0.5
3861
{ 0xc1dfffffffe00000U, -0x80000000ll, -0x7fffffff-1 }, // -(2^31-1) - 0.5
3862
{ 0x41dfffffffdfffffU, 0x7fffffff, 0x7fffffff }, // (2^31-1) + 0.5 - 2^-22
3863
{ 0xc1dfffffffdfffffU, -0x7fffffff, -0x7fffffff }, // -(2^31-1) - 0.5 + 2^-22
3864
{ 0x41dfffffffd00000U, 0x7fffffff, 0x7fffffff }, // (2^31-1) + 0.25
3865
{ 0xc1dfffffffd00000U, -0x7fffffff, -0x7fffffff }, // -(2^31-1) - 0.25
3866
{ 0x41dfffffffc00000U, 0x7fffffff, 0x7fffffff }, // (2^31-1)
3867
{ 0xc1dfffffffc00000U, -0x7fffffff, -0x7fffffff }, // -(2^31-1)
3868
{ 0x41d0000000000000U, 0x40000000, 0x40000000 }, // 2^30 = 2147483648
3869
{ 0xc1d0000000000000U, -0x40000000, -0x40000000 }, // -2^30 = -2147483648
3870
3871
{ 0x4006000000000000U, 3, 3 }, // 2.75
3872
{ 0xc006000000000000U, -3, -3 }, // -2.75
3873
{ 0x4004000000000001U, 3, 3 }, // 2.5 + 2^-51
3874
{ 0xc004000000000001U, -3, -3 }, // -2.5 - 2^-51
3875
{ 0x4004000000000000U, 2, 2 }, // 2.5
3876
{ 0xc004000000000000U, -2, -2 }, // -2.5
3877
{ 0x4003ffffffffffffU, 2, 2 }, // 2.5 - 2^-51
3878
{ 0xc003ffffffffffffU, -2, -2 }, // -2.5 + 2^-51
3879
{ 0x4002000000000000U, 2, 2 }, // 2.25
3880
{ 0xc002000000000000U, -2, -2 }, // -2.25
3881
3882
{ 0x3ffc000000000000U, 2, 2 }, // 1.75
3883
{ 0xbffc000000000000U, -2, -2 }, // -1.75
3884
{ 0x3ff8000000000001U, 2, 2 }, // 1.5 + 2^-52
3885
{ 0xbff8000000000001U, -2, -2 }, // -1.5 - 2^-52
3886
{ 0x3ff8000000000000U, 2, 2 }, // 1.5
3887
{ 0xbff8000000000000U, -2, -2 }, // -1.5
3888
{ 0x3ff7ffffffffffffU, 1, 1 }, // 1.5 - 2^-52
3889
{ 0xbff7ffffffffffffU, -1, -1 }, // -1.5 + 2^-52
3890
{ 0x3ff4000000000000U, 1, 1 }, // 1.25
3891
{ 0xbff4000000000000U, -1, -1 }, // -1.25
3892
3893
{ 0x3fe8000000000000U, 1, 1 }, // 0.75
3894
{ 0xbfe8000000000000U, -1, -1 }, // -0.75
3895
{ 0x3fe0000000000001U, 1, 1 }, // 0.5 + 2^-53
3896
{ 0xbfe0000000000001U, -1, -1 }, // -0.5 - 2^-53
3897
{ 0x3fe0000000000000U, 0, 0 }, // 0.5
3898
{ 0xbfe0000000000000U, 0, 0 }, // -0.5
3899
3900
{ 0x3fd8000000000000U, 0, 0 }, // 0.375
3901
{ 0xbfd8000000000000U, 0, 0 }, // -0.375
3902
{ 0x3fd0000000000000U, 0, 0 }, // 0.25
3903
{ 0xbfd0000000000000U, 0, 0 }, // -0.25
3904
3905
{ 0x0ff123456789abcdU, 0, 0 }, // 6.89918601543515033558134828315E-232
3906
{ 0x8ff123456789abcdU, 0, 0 } // -6.89918601543515033558134828315E-232
3907
};
3908
struct testvalues
3909
{
3910
softdouble inVal;
3911
int64_t out64;
3912
int32_t out32;
3913
} *values = (testvalues*)_values;
3914
3915
for (int i = 0, maxi = sizeof(_values) / sizeof(_values[0]); i < maxi; i++)
3916
{
3917
EXPECT_EQ(values[i].out64, cvRound64(values[i].inVal));
3918
EXPECT_EQ(values[i].out64, saturate_cast<int64_t>(values[i].inVal));
3919
EXPECT_EQ((uint64_t)(values[i].out64), saturate_cast<uint64_t>(values[i].inVal));
3920
EXPECT_EQ(values[i].out32, cvRound(values[i].inVal));
3921
EXPECT_EQ(values[i].out32, saturate_cast<int32_t>(values[i].inVal));
3922
EXPECT_EQ((uint32_t)(values[i].out32), saturate_cast<uint32_t>(values[i].inVal));
3923
}
3924
}
3925
3926
}} // namespace
3927
/* End of file. */
3928
3929