Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/calib3d/test/test_fundam.cpp
16337 views
1
/*M///////////////////////////////////////////////////////////////////////////////////////
2
//
3
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4
//
5
// By downloading, copying, installing or using the software you agree to this license.
6
// If you do not agree to this license, do not download, install,
7
// copy or use the software.
8
//
9
//
10
// Intel License Agreement
11
// For Open Source Computer Vision Library
12
//
13
// Copyright (C) 2000, Intel Corporation, all rights reserved.
14
// Third party copyrights are property of their respective owners.
15
//
16
// Redistribution and use in source and binary forms, with or without modification,
17
// are permitted provided that the following conditions are met:
18
//
19
// * Redistribution's of source code must retain the above copyright notice,
20
// this list of conditions and the following disclaimer.
21
//
22
// * Redistribution's in binary form must reproduce the above copyright notice,
23
// this list of conditions and the following disclaimer in the documentation
24
// and/or other materials provided with the distribution.
25
//
26
// * The name of Intel Corporation may not be used to endorse or promote products
27
// derived from this software without specific prior written permission.
28
//
29
// This software is provided by the copyright holders and contributors "as is" and
30
// any express or implied warranties, including, but not limited to, the implied
31
// warranties of merchantability and fitness for a particular purpose are disclaimed.
32
// In no event shall the Intel Corporation or contributors be liable for any direct,
33
// indirect, incidental, special, exemplary, or consequential damages
34
// (including, but not limited to, procurement of substitute goods or services;
35
// loss of use, data, or profits; or business interruption) however caused
36
// and on any theory of liability, whether in contract, strict liability,
37
// or tort (including negligence or otherwise) arising in any way out of
38
// the use of this software, even if advised of the possibility of such damage.
39
//
40
//M*/
41
42
#include "test_precomp.hpp"
43
#include "opencv2/calib3d/calib3d_c.h"
44
45
namespace cvtest {
46
47
static int cvTsRodrigues( const CvMat* src, CvMat* dst, CvMat* jacobian )
48
{
49
int depth;
50
int i;
51
float Jf[27];
52
double J[27];
53
CvMat _Jf, matJ = cvMat( 3, 9, CV_64F, J );
54
55
depth = CV_MAT_DEPTH(src->type);
56
57
if( jacobian )
58
{
59
assert( (jacobian->rows == 9 && jacobian->cols == 3) ||
60
(jacobian->rows == 3 && jacobian->cols == 9) );
61
}
62
63
if( src->cols == 1 || src->rows == 1 )
64
{
65
double r[3], theta;
66
CvMat _r = cvMat( src->rows, src->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(src->type)), r);
67
68
assert( dst->rows == 3 && dst->cols == 3 );
69
70
cvConvert( src, &_r );
71
72
theta = sqrt(r[0]*r[0] + r[1]*r[1] + r[2]*r[2]);
73
if( theta < DBL_EPSILON )
74
{
75
cvSetIdentity( dst );
76
77
if( jacobian )
78
{
79
memset( J, 0, sizeof(J) );
80
J[5] = J[15] = J[19] = 1;
81
J[7] = J[11] = J[21] = -1;
82
}
83
}
84
else
85
{
86
// omega = r/theta (~[w1, w2, w3])
87
double itheta = 1./theta;
88
double w1 = r[0]*itheta, w2 = r[1]*itheta, w3 = r[2]*itheta;
89
double alpha = cos(theta);
90
double beta = sin(theta);
91
double gamma = 1 - alpha;
92
double omegav[] =
93
{
94
0, -w3, w2,
95
w3, 0, -w1,
96
-w2, w1, 0
97
};
98
double A[] =
99
{
100
w1*w1, w1*w2, w1*w3,
101
w2*w1, w2*w2, w2*w3,
102
w3*w1, w3*w2, w3*w3
103
};
104
double R[9];
105
CvMat _omegav = cvMat(3, 3, CV_64F, omegav);
106
CvMat matA = cvMat(3, 3, CV_64F, A);
107
CvMat matR = cvMat(3, 3, CV_64F, R);
108
109
cvSetIdentity( &matR, cvRealScalar(alpha) );
110
cvScaleAdd( &_omegav, cvRealScalar(beta), &matR, &matR );
111
cvScaleAdd( &matA, cvRealScalar(gamma), &matR, &matR );
112
cvConvert( &matR, dst );
113
114
if( jacobian )
115
{
116
// m3 = [r, theta]
117
double dm3din[] =
118
{
119
1, 0, 0,
120
0, 1, 0,
121
0, 0, 1,
122
w1, w2, w3
123
};
124
// m2 = [omega, theta]
125
double dm2dm3[] =
126
{
127
itheta, 0, 0, -w1*itheta,
128
0, itheta, 0, -w2*itheta,
129
0, 0, itheta, -w3*itheta,
130
0, 0, 0, 1
131
};
132
double t0[9*4];
133
double dm1dm2[21*4];
134
double dRdm1[9*21];
135
CvMat _dm3din = cvMat( 4, 3, CV_64FC1, dm3din );
136
CvMat _dm2dm3 = cvMat( 4, 4, CV_64FC1, dm2dm3 );
137
CvMat _dm1dm2 = cvMat( 21, 4, CV_64FC1, dm1dm2 );
138
CvMat _dRdm1 = cvMat( 9, 21, CV_64FC1, dRdm1 );
139
CvMat _dRdm1_part;
140
CvMat _t0 = cvMat( 9, 4, CV_64FC1, t0 );
141
CvMat _t1 = cvMat( 9, 4, CV_64FC1, dRdm1 );
142
143
// m1 = [alpha, beta, gamma, omegav; A]
144
memset( dm1dm2, 0, sizeof(dm1dm2) );
145
dm1dm2[3] = -beta;
146
dm1dm2[7] = alpha;
147
dm1dm2[11] = beta;
148
149
// dm1dm2(4:12,1:3) = [0 0 0 0 0 1 0 -1 0;
150
// 0 0 -1 0 0 0 1 0 0;
151
// 0 1 0 -1 0 0 0 0 0]'
152
// -------------------
153
// 0 0 0 0 0 0 0 0 0
154
dm1dm2[12 + 6] = dm1dm2[12 + 20] = dm1dm2[12 + 25] = 1;
155
dm1dm2[12 + 9] = dm1dm2[12 + 14] = dm1dm2[12 + 28] = -1;
156
157
double dm1dw[] =
158
{
159
2*w1, w2, w3, w2, 0, 0, w3, 0, 0,
160
0, w1, 0, w1, 2*w2, w3, 0, w3, 0,
161
0, 0, w1, 0, 0, w2, w1, w2, 2*w3
162
};
163
164
CvMat _dm1dw = cvMat( 3, 9, CV_64FC1, dm1dw );
165
CvMat _dm1dm2_part;
166
167
cvGetSubRect( &_dm1dm2, &_dm1dm2_part, cvRect(0,12,3,9) );
168
cvTranspose( &_dm1dw, &_dm1dm2_part );
169
170
memset( dRdm1, 0, sizeof(dRdm1) );
171
dRdm1[0*21] = dRdm1[4*21] = dRdm1[8*21] = 1;
172
173
cvGetCol( &_dRdm1, &_dRdm1_part, 1 );
174
cvTranspose( &_omegav, &_omegav );
175
cvReshape( &_omegav, &_omegav, 1, 1 );
176
cvTranspose( &_omegav, &_dRdm1_part );
177
178
cvGetCol( &_dRdm1, &_dRdm1_part, 2 );
179
cvReshape( &matA, &matA, 1, 1 );
180
cvTranspose( &matA, &_dRdm1_part );
181
182
cvGetSubRect( &_dRdm1, &_dRdm1_part, cvRect(3,0,9,9) );
183
cvSetIdentity( &_dRdm1_part, cvScalarAll(beta) );
184
185
cvGetSubRect( &_dRdm1, &_dRdm1_part, cvRect(12,0,9,9) );
186
cvSetIdentity( &_dRdm1_part, cvScalarAll(gamma) );
187
188
matJ = cvMat( 9, 3, CV_64FC1, J );
189
190
cvMatMul( &_dRdm1, &_dm1dm2, &_t0 );
191
cvMatMul( &_t0, &_dm2dm3, &_t1 );
192
cvMatMul( &_t1, &_dm3din, &matJ );
193
194
_t0 = cvMat( 3, 9, CV_64FC1, t0 );
195
cvTranspose( &matJ, &_t0 );
196
197
for( i = 0; i < 3; i++ )
198
{
199
_t1 = cvMat( 3, 3, CV_64FC1, t0 + i*9 );
200
cvTranspose( &_t1, &_t1 );
201
}
202
203
cvTranspose( &_t0, &matJ );
204
}
205
}
206
}
207
else if( src->cols == 3 && src->rows == 3 )
208
{
209
double R[9], A[9], I[9], r[3], W[3], U[9], V[9];
210
double tr, alpha, beta, theta;
211
CvMat matR = cvMat( 3, 3, CV_64F, R );
212
CvMat matA = cvMat( 3, 3, CV_64F, A );
213
CvMat matI = cvMat( 3, 3, CV_64F, I );
214
CvMat _r = cvMat( dst->rows, dst->cols, CV_MAKETYPE(CV_64F, CV_MAT_CN(dst->type)), r );
215
CvMat matW = cvMat( 1, 3, CV_64F, W );
216
CvMat matU = cvMat( 3, 3, CV_64F, U );
217
CvMat matV = cvMat( 3, 3, CV_64F, V );
218
219
cvConvert( src, &matR );
220
cvSVD( &matR, &matW, &matU, &matV, CV_SVD_MODIFY_A + CV_SVD_U_T + CV_SVD_V_T );
221
cvGEMM( &matU, &matV, 1, 0, 0, &matR, CV_GEMM_A_T );
222
223
cvMulTransposed( &matR, &matA, 0 );
224
cvSetIdentity( &matI );
225
226
if( cvNorm( &matA, &matI, CV_C ) > 1e-3 ||
227
fabs( cvDet(&matR) - 1 ) > 1e-3 )
228
return 0;
229
230
tr = (cvTrace(&matR).val[0] - 1.)*0.5;
231
tr = tr > 1. ? 1. : tr < -1. ? -1. : tr;
232
theta = acos(tr);
233
alpha = cos(theta);
234
beta = sin(theta);
235
236
if( beta >= 1e-5 )
237
{
238
double dtheta_dtr = -1./sqrt(1 - tr*tr);
239
double vth = 1/(2*beta);
240
241
// om1 = [R(3,2) - R(2,3), R(1,3) - R(3,1), R(2,1) - R(1,2)]'
242
double om1[] = { R[7] - R[5], R[2] - R[6], R[3] - R[1] };
243
// om = om1*vth
244
// r = om*theta
245
double d3 = vth*theta;
246
247
r[0] = om1[0]*d3; r[1] = om1[1]*d3; r[2] = om1[2]*d3;
248
cvConvert( &_r, dst );
249
250
if( jacobian )
251
{
252
// var1 = [vth;theta]
253
// var = [om1;var1] = [om1;vth;theta]
254
double dvth_dtheta = -vth*alpha/beta;
255
double d1 = 0.5*dvth_dtheta*dtheta_dtr;
256
double d2 = 0.5*dtheta_dtr;
257
// dvar1/dR = dvar1/dtheta*dtheta/dR = [dvth/dtheta; 1] * dtheta/dtr * dtr/dR
258
double dvardR[5*9] =
259
{
260
0, 0, 0, 0, 0, 1, 0, -1, 0,
261
0, 0, -1, 0, 0, 0, 1, 0, 0,
262
0, 1, 0, -1, 0, 0, 0, 0, 0,
263
d1, 0, 0, 0, d1, 0, 0, 0, d1,
264
d2, 0, 0, 0, d2, 0, 0, 0, d2
265
};
266
// var2 = [om;theta]
267
double dvar2dvar[] =
268
{
269
vth, 0, 0, om1[0], 0,
270
0, vth, 0, om1[1], 0,
271
0, 0, vth, om1[2], 0,
272
0, 0, 0, 0, 1
273
};
274
double domegadvar2[] =
275
{
276
theta, 0, 0, om1[0]*vth,
277
0, theta, 0, om1[1]*vth,
278
0, 0, theta, om1[2]*vth
279
};
280
281
CvMat _dvardR = cvMat( 5, 9, CV_64FC1, dvardR );
282
CvMat _dvar2dvar = cvMat( 4, 5, CV_64FC1, dvar2dvar );
283
CvMat _domegadvar2 = cvMat( 3, 4, CV_64FC1, domegadvar2 );
284
double t0[3*5];
285
CvMat _t0 = cvMat( 3, 5, CV_64FC1, t0 );
286
287
cvMatMul( &_domegadvar2, &_dvar2dvar, &_t0 );
288
cvMatMul( &_t0, &_dvardR, &matJ );
289
}
290
}
291
else if( tr > 0 )
292
{
293
cvZero( dst );
294
if( jacobian )
295
{
296
memset( J, 0, sizeof(J) );
297
J[5] = J[15] = J[19] = 0.5;
298
J[7] = J[11] = J[21] = -0.5;
299
}
300
}
301
else
302
{
303
r[0] = theta*sqrt((R[0] + 1)*0.5);
304
r[1] = theta*sqrt((R[4] + 1)*0.5)*(R[1] >= 0 ? 1 : -1);
305
r[2] = theta*sqrt((R[8] + 1)*0.5)*(R[2] >= 0 ? 1 : -1);
306
cvConvert( &_r, dst );
307
308
if( jacobian )
309
memset( J, 0, sizeof(J) );
310
}
311
312
if( jacobian )
313
{
314
for( i = 0; i < 3; i++ )
315
{
316
CvMat t = cvMat( 3, 3, CV_64F, J + i*9 );
317
cvTranspose( &t, &t );
318
}
319
}
320
}
321
else
322
{
323
assert(0);
324
return 0;
325
}
326
327
if( jacobian )
328
{
329
if( depth == CV_32F )
330
{
331
if( jacobian->rows == matJ.rows )
332
cvConvert( &matJ, jacobian );
333
else
334
{
335
_Jf = cvMat( matJ.rows, matJ.cols, CV_32FC1, Jf );
336
cvConvert( &matJ, &_Jf );
337
cvTranspose( &_Jf, jacobian );
338
}
339
}
340
else if( jacobian->rows == matJ.rows )
341
cvCopy( &matJ, jacobian );
342
else
343
cvTranspose( &matJ, jacobian );
344
}
345
346
return 1;
347
}
348
349
350
/*extern*/ void Rodrigues(const Mat& src, Mat& dst, Mat* jac)
351
{
352
CV_Assert(src.data != dst.data && "Inplace is not supported");
353
CV_Assert(!dst.empty() && "'dst' must be allocated");
354
CvMat _src = cvMat(src), _dst = cvMat(dst), _jac;
355
if( jac )
356
_jac = cvMat(*jac);
357
cvTsRodrigues(&_src, &_dst, jac ? &_jac : 0);
358
}
359
360
} // namespace
361
namespace opencv_test {
362
363
static void test_convertHomogeneous( const Mat& _src, Mat& _dst )
364
{
365
Mat src = _src, dst = _dst;
366
int i, count, sdims, ddims;
367
int sstep1, sstep2, dstep1, dstep2;
368
369
if( src.depth() != CV_64F )
370
_src.convertTo(src, CV_64F);
371
372
if( dst.depth() != CV_64F )
373
dst.create(dst.size(), CV_MAKETYPE(CV_64F, _dst.channels()));
374
375
if( src.rows > src.cols )
376
{
377
count = src.rows;
378
sdims = src.channels()*src.cols;
379
sstep1 = (int)(src.step/sizeof(double));
380
sstep2 = 1;
381
}
382
else
383
{
384
count = src.cols;
385
sdims = src.channels()*src.rows;
386
if( src.rows == 1 )
387
{
388
sstep1 = sdims;
389
sstep2 = 1;
390
}
391
else
392
{
393
sstep1 = 1;
394
sstep2 = (int)(src.step/sizeof(double));
395
}
396
}
397
398
if( dst.rows > dst.cols )
399
{
400
CV_Assert( count == dst.rows );
401
ddims = dst.channels()*dst.cols;
402
dstep1 = (int)(dst.step/sizeof(double));
403
dstep2 = 1;
404
}
405
else
406
{
407
assert( count == dst.cols );
408
ddims = dst.channels()*dst.rows;
409
if( dst.rows == 1 )
410
{
411
dstep1 = ddims;
412
dstep2 = 1;
413
}
414
else
415
{
416
dstep1 = 1;
417
dstep2 = (int)(dst.step/sizeof(double));
418
}
419
}
420
421
double* s = src.ptr<double>();
422
double* d = dst.ptr<double>();
423
424
if( sdims <= ddims )
425
{
426
int wstep = dstep2*(ddims - 1);
427
428
for( i = 0; i < count; i++, s += sstep1, d += dstep1 )
429
{
430
double x = s[0];
431
double y = s[sstep2];
432
433
d[wstep] = 1;
434
d[0] = x;
435
d[dstep2] = y;
436
437
if( sdims >= 3 )
438
{
439
d[dstep2*2] = s[sstep2*2];
440
if( sdims == 4 )
441
d[dstep2*3] = s[sstep2*3];
442
}
443
}
444
}
445
else
446
{
447
int wstep = sstep2*(sdims - 1);
448
449
for( i = 0; i < count; i++, s += sstep1, d += dstep1 )
450
{
451
double w = s[wstep];
452
double x = s[0];
453
double y = s[sstep2];
454
455
w = w ? 1./w : 1;
456
457
d[0] = x*w;
458
d[dstep2] = y*w;
459
460
if( ddims == 3 )
461
d[dstep2*2] = s[sstep2*2]*w;
462
}
463
}
464
465
if( dst.data != _dst.data )
466
dst.convertTo(_dst, _dst.depth());
467
}
468
469
namespace {
470
471
void
472
test_projectPoints( const Mat& _3d, const Mat& Rt, const Mat& A, Mat& _2d, RNG* rng, double sigma )
473
{
474
CV_Assert( _3d.isContinuous() );
475
476
double p[12];
477
Mat P( 3, 4, CV_64F, p );
478
gemm(A, Rt, 1, Mat(), 0, P);
479
480
int i, count = _3d.cols;
481
482
Mat noise;
483
if( rng )
484
{
485
if( sigma == 0 )
486
rng = 0;
487
else
488
{
489
noise.create( 1, _3d.cols, CV_64FC2 );
490
rng->fill(noise, RNG::NORMAL, Scalar::all(0), Scalar::all(sigma) );
491
}
492
}
493
494
Mat temp( 1, count, CV_64FC3 );
495
496
for( i = 0; i < count; i++ )
497
{
498
const double* M = _3d.ptr<double>() + i*3;
499
double* m = temp.ptr<double>() + i*3;
500
double X = M[0], Y = M[1], Z = M[2];
501
double u = p[0]*X + p[1]*Y + p[2]*Z + p[3];
502
double v = p[4]*X + p[5]*Y + p[6]*Z + p[7];
503
double s = p[8]*X + p[9]*Y + p[10]*Z + p[11];
504
505
if( !noise.empty() )
506
{
507
u += noise.at<Point2d>(i).x*s;
508
v += noise.at<Point2d>(i).y*s;
509
}
510
511
m[0] = u;
512
m[1] = v;
513
m[2] = s;
514
}
515
516
test_convertHomogeneous( temp, _2d );
517
}
518
519
520
/********************************** Rodrigues transform ********************************/
521
522
class CV_RodriguesTest : public cvtest::ArrayTest
523
{
524
public:
525
CV_RodriguesTest();
526
527
protected:
528
int read_params( CvFileStorage* fs );
529
void fill_array( int test_case_idx, int i, int j, Mat& arr );
530
int prepare_test_case( int test_case_idx );
531
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
532
double get_success_error_level( int test_case_idx, int i, int j );
533
void run_func();
534
void prepare_to_validation( int );
535
536
bool calc_jacobians;
537
bool test_cpp;
538
};
539
540
541
CV_RodriguesTest::CV_RodriguesTest()
542
{
543
test_array[INPUT].push_back(NULL); // rotation vector
544
test_array[OUTPUT].push_back(NULL); // rotation matrix
545
test_array[OUTPUT].push_back(NULL); // jacobian (J)
546
test_array[OUTPUT].push_back(NULL); // rotation vector (backward transform result)
547
test_array[OUTPUT].push_back(NULL); // inverse transform jacobian (J1)
548
test_array[OUTPUT].push_back(NULL); // J*J1 (or J1*J) == I(3x3)
549
test_array[REF_OUTPUT].push_back(NULL);
550
test_array[REF_OUTPUT].push_back(NULL);
551
test_array[REF_OUTPUT].push_back(NULL);
552
test_array[REF_OUTPUT].push_back(NULL);
553
test_array[REF_OUTPUT].push_back(NULL);
554
555
element_wise_relative_error = false;
556
calc_jacobians = false;
557
558
test_cpp = false;
559
}
560
561
562
int CV_RodriguesTest::read_params( CvFileStorage* fs )
563
{
564
int code = cvtest::ArrayTest::read_params( fs );
565
return code;
566
}
567
568
569
void CV_RodriguesTest::get_test_array_types_and_sizes(
570
int /*test_case_idx*/, vector<vector<Size> >& sizes, vector<vector<int> >& types )
571
{
572
RNG& rng = ts->get_rng();
573
int depth = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
574
int i, code;
575
576
code = cvtest::randInt(rng) % 3;
577
types[INPUT][0] = CV_MAKETYPE(depth, 1);
578
579
if( code == 0 )
580
{
581
sizes[INPUT][0] = cvSize(1,1);
582
types[INPUT][0] = CV_MAKETYPE(depth, 3);
583
}
584
else if( code == 1 )
585
sizes[INPUT][0] = cvSize(3,1);
586
else
587
sizes[INPUT][0] = cvSize(1,3);
588
589
sizes[OUTPUT][0] = cvSize(3, 3);
590
types[OUTPUT][0] = CV_MAKETYPE(depth, 1);
591
592
types[OUTPUT][1] = CV_MAKETYPE(depth, 1);
593
594
if( cvtest::randInt(rng) % 2 )
595
sizes[OUTPUT][1] = cvSize(3,9);
596
else
597
sizes[OUTPUT][1] = cvSize(9,3);
598
599
types[OUTPUT][2] = types[INPUT][0];
600
sizes[OUTPUT][2] = sizes[INPUT][0];
601
602
types[OUTPUT][3] = types[OUTPUT][1];
603
sizes[OUTPUT][3] = cvSize(sizes[OUTPUT][1].height, sizes[OUTPUT][1].width);
604
605
types[OUTPUT][4] = types[OUTPUT][1];
606
sizes[OUTPUT][4] = cvSize(3,3);
607
608
calc_jacobians = cvtest::randInt(rng) % 3 != 0;
609
if( !calc_jacobians )
610
sizes[OUTPUT][1] = sizes[OUTPUT][3] = sizes[OUTPUT][4] = cvSize(0,0);
611
612
for( i = 0; i < 5; i++ )
613
{
614
types[REF_OUTPUT][i] = types[OUTPUT][i];
615
sizes[REF_OUTPUT][i] = sizes[OUTPUT][i];
616
}
617
test_cpp = (cvtest::randInt(rng) & 256) == 0;
618
}
619
620
621
double CV_RodriguesTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int j )
622
{
623
return j == 4 ? 1e-2 : 1e-2;
624
}
625
626
627
void CV_RodriguesTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
628
{
629
if( i == INPUT && j == 0 )
630
{
631
double r[3], theta0, theta1, f;
632
Mat _r( arr.rows, arr.cols, CV_MAKETYPE(CV_64F,arr.channels()), r );
633
RNG& rng = ts->get_rng();
634
635
r[0] = cvtest::randReal(rng)*CV_PI*2;
636
r[1] = cvtest::randReal(rng)*CV_PI*2;
637
r[2] = cvtest::randReal(rng)*CV_PI*2;
638
639
theta0 = sqrt(r[0]*r[0] + r[1]*r[1] + r[2]*r[2]);
640
theta1 = fmod(theta0, CV_PI*2);
641
642
if( theta1 > CV_PI )
643
theta1 = -(CV_PI*2 - theta1);
644
645
f = theta1/(theta0 ? theta0 : 1);
646
r[0] *= f;
647
r[1] *= f;
648
r[2] *= f;
649
650
cvtest::convert( _r, arr, arr.type() );
651
}
652
else
653
cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr );
654
}
655
656
657
int CV_RodriguesTest::prepare_test_case( int test_case_idx )
658
{
659
int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
660
return code;
661
}
662
663
664
void CV_RodriguesTest::run_func()
665
{
666
CvMat v2m_jac, m2v_jac;
667
668
if( calc_jacobians )
669
{
670
v2m_jac = cvMat(test_mat[OUTPUT][1]);
671
m2v_jac = cvMat(test_mat[OUTPUT][3]);
672
}
673
674
if( !test_cpp )
675
{
676
CvMat _input = cvMat(test_mat[INPUT][0]), _output = cvMat(test_mat[OUTPUT][0]), _output2 = cvMat(test_mat[OUTPUT][2]);
677
cvRodrigues2( &_input, &_output, calc_jacobians ? &v2m_jac : 0 );
678
cvRodrigues2( &_output, &_output2, calc_jacobians ? &m2v_jac : 0 );
679
}
680
else
681
{
682
cv::Mat v = test_mat[INPUT][0], M = test_mat[OUTPUT][0], v2 = test_mat[OUTPUT][2];
683
cv::Mat M0 = M, v2_0 = v2;
684
if( !calc_jacobians )
685
{
686
cv::Rodrigues(v, M);
687
cv::Rodrigues(M, v2);
688
}
689
else
690
{
691
cv::Mat J1 = test_mat[OUTPUT][1], J2 = test_mat[OUTPUT][3];
692
cv::Mat J1_0 = J1, J2_0 = J2;
693
cv::Rodrigues(v, M, J1);
694
cv::Rodrigues(M, v2, J2);
695
if( J1.data != J1_0.data )
696
{
697
if( J1.size() != J1_0.size() )
698
J1 = J1.t();
699
J1.convertTo(J1_0, J1_0.type());
700
}
701
if( J2.data != J2_0.data )
702
{
703
if( J2.size() != J2_0.size() )
704
J2 = J2.t();
705
J2.convertTo(J2_0, J2_0.type());
706
}
707
}
708
if( M.data != M0.data )
709
M.reshape(M0.channels(), M0.rows).convertTo(M0, M0.type());
710
if( v2.data != v2_0.data )
711
v2.reshape(v2_0.channels(), v2_0.rows).convertTo(v2_0, v2_0.type());
712
}
713
}
714
715
716
void CV_RodriguesTest::prepare_to_validation( int /*test_case_idx*/ )
717
{
718
const Mat& vec = test_mat[INPUT][0];
719
Mat& m = test_mat[REF_OUTPUT][0];
720
Mat& vec2 = test_mat[REF_OUTPUT][2];
721
Mat* v2m_jac = 0, *m2v_jac = 0;
722
double theta0, theta1;
723
724
if( calc_jacobians )
725
{
726
v2m_jac = &test_mat[REF_OUTPUT][1];
727
m2v_jac = &test_mat[REF_OUTPUT][3];
728
}
729
730
731
cvtest::Rodrigues( vec, m, v2m_jac );
732
cvtest::Rodrigues( m, vec2, m2v_jac );
733
cvtest::copy( vec, vec2 );
734
735
theta0 = cvtest::norm( vec2, CV_L2 );
736
theta1 = fmod( theta0, CV_PI*2 );
737
738
if( theta1 > CV_PI )
739
theta1 = -(CV_PI*2 - theta1);
740
vec2 *= theta1/(theta0 ? theta0 : 1);
741
742
if( calc_jacobians )
743
{
744
//cvInvert( v2m_jac, m2v_jac, CV_SVD );
745
double nrm = cvtest::norm(test_mat[REF_OUTPUT][3], CV_C);
746
if( FLT_EPSILON < nrm && nrm < 1000 )
747
{
748
gemm( test_mat[OUTPUT][1], test_mat[OUTPUT][3],
749
1, Mat(), 0, test_mat[OUTPUT][4],
750
v2m_jac->rows == 3 ? 0 : CV_GEMM_A_T + CV_GEMM_B_T );
751
}
752
else
753
{
754
setIdentity(test_mat[OUTPUT][4], Scalar::all(1.));
755
cvtest::copy( test_mat[REF_OUTPUT][2], test_mat[OUTPUT][2] );
756
}
757
setIdentity(test_mat[REF_OUTPUT][4], Scalar::all(1.));
758
}
759
}
760
761
762
/********************************** fundamental matrix *********************************/
763
764
class CV_FundamentalMatTest : public cvtest::ArrayTest
765
{
766
public:
767
CV_FundamentalMatTest();
768
769
protected:
770
int read_params( CvFileStorage* fs );
771
void fill_array( int test_case_idx, int i, int j, Mat& arr );
772
int prepare_test_case( int test_case_idx );
773
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
774
double get_success_error_level( int test_case_idx, int i, int j );
775
void run_func();
776
void prepare_to_validation( int );
777
778
int method;
779
int img_size;
780
int cube_size;
781
int dims;
782
int f_result;
783
double min_f, max_f;
784
double sigma;
785
bool test_cpp;
786
};
787
788
789
CV_FundamentalMatTest::CV_FundamentalMatTest()
790
{
791
// input arrays:
792
// 0, 1 - arrays of 2d points that are passed to %func%.
793
// Can have different data type, layout, be stored in homogeneous coordinates or not.
794
// 2 - array of 3d points that are projected to both view planes
795
// 3 - [R|t] matrix for the second view plane (for the first one it is [I|0]
796
// 4, 5 - intrinsic matrices
797
test_array[INPUT].push_back(NULL);
798
test_array[INPUT].push_back(NULL);
799
test_array[INPUT].push_back(NULL);
800
test_array[INPUT].push_back(NULL);
801
test_array[INPUT].push_back(NULL);
802
test_array[INPUT].push_back(NULL);
803
test_array[TEMP].push_back(NULL);
804
test_array[TEMP].push_back(NULL);
805
test_array[OUTPUT].push_back(NULL);
806
test_array[OUTPUT].push_back(NULL);
807
test_array[REF_OUTPUT].push_back(NULL);
808
test_array[REF_OUTPUT].push_back(NULL);
809
810
element_wise_relative_error = false;
811
812
method = 0;
813
img_size = 10;
814
cube_size = 10;
815
dims = 0;
816
min_f = 1;
817
max_f = 3;
818
sigma = 0;//0.1;
819
f_result = 0;
820
821
test_cpp = false;
822
}
823
824
825
int CV_FundamentalMatTest::read_params( CvFileStorage* fs )
826
{
827
int code = cvtest::ArrayTest::read_params( fs );
828
return code;
829
}
830
831
832
void CV_FundamentalMatTest::get_test_array_types_and_sizes( int /*test_case_idx*/,
833
vector<vector<Size> >& sizes, vector<vector<int> >& types )
834
{
835
RNG& rng = ts->get_rng();
836
int pt_depth = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
837
double pt_count_exp = cvtest::randReal(rng)*6 + 1;
838
int pt_count = cvRound(exp(pt_count_exp));
839
840
dims = cvtest::randInt(rng) % 2 + 2;
841
method = 1 << (cvtest::randInt(rng) % 4);
842
843
if( method == CV_FM_7POINT )
844
pt_count = 7;
845
else
846
{
847
pt_count = MAX( pt_count, 8 + (method == CV_FM_8POINT) );
848
if( pt_count >= 8 && cvtest::randInt(rng) % 2 )
849
method |= CV_FM_8POINT;
850
}
851
852
types[INPUT][0] = CV_MAKETYPE(pt_depth, 1);
853
854
if( cvtest::randInt(rng) % 2 )
855
sizes[INPUT][0] = cvSize(pt_count, dims);
856
else
857
{
858
sizes[INPUT][0] = cvSize(dims, pt_count);
859
if( cvtest::randInt(rng) % 2 )
860
{
861
types[INPUT][0] = CV_MAKETYPE(pt_depth, dims);
862
if( cvtest::randInt(rng) % 2 )
863
sizes[INPUT][0] = cvSize(pt_count, 1);
864
else
865
sizes[INPUT][0] = cvSize(1, pt_count);
866
}
867
}
868
869
sizes[INPUT][1] = sizes[INPUT][0];
870
types[INPUT][1] = types[INPUT][0];
871
872
sizes[INPUT][2] = cvSize(pt_count, 1 );
873
types[INPUT][2] = CV_64FC3;
874
875
sizes[INPUT][3] = cvSize(4,3);
876
types[INPUT][3] = CV_64FC1;
877
878
sizes[INPUT][4] = sizes[INPUT][5] = cvSize(3,3);
879
types[INPUT][4] = types[INPUT][5] = CV_MAKETYPE(CV_64F, 1);
880
881
sizes[TEMP][0] = cvSize(3,3);
882
types[TEMP][0] = CV_64FC1;
883
sizes[TEMP][1] = cvSize(pt_count,1);
884
types[TEMP][1] = CV_8UC1;
885
886
sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(3,1);
887
types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;
888
sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] = cvSize(pt_count,1);
889
types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_8UC1;
890
891
test_cpp = (cvtest::randInt(rng) & 256) == 0;
892
}
893
894
895
double CV_FundamentalMatTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
896
{
897
return 1e-2;
898
}
899
900
901
void CV_FundamentalMatTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
902
{
903
double t[12]={0};
904
RNG& rng = ts->get_rng();
905
906
if( i != INPUT )
907
{
908
cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr );
909
return;
910
}
911
912
switch( j )
913
{
914
case 0:
915
case 1:
916
return; // fill them later in prepare_test_case
917
case 2:
918
{
919
double* p = arr.ptr<double>();
920
for( i = 0; i < arr.cols*3; i += 3 )
921
{
922
p[i] = cvtest::randReal(rng)*cube_size;
923
p[i+1] = cvtest::randReal(rng)*cube_size;
924
p[i+2] = cvtest::randReal(rng)*cube_size + cube_size;
925
}
926
}
927
break;
928
case 3:
929
{
930
double r[3];
931
Mat rot_vec( 3, 1, CV_64F, r );
932
Mat rot_mat( 3, 3, CV_64F, t, 4*sizeof(t[0]) );
933
r[0] = cvtest::randReal(rng)*CV_PI*2;
934
r[1] = cvtest::randReal(rng)*CV_PI*2;
935
r[2] = cvtest::randReal(rng)*CV_PI*2;
936
937
cvtest::Rodrigues( rot_vec, rot_mat );
938
t[3] = cvtest::randReal(rng)*cube_size;
939
t[7] = cvtest::randReal(rng)*cube_size;
940
t[11] = cvtest::randReal(rng)*cube_size;
941
Mat( 3, 4, CV_64F, t ).convertTo(arr, arr.type());
942
}
943
break;
944
case 4:
945
case 5:
946
t[0] = t[4] = cvtest::randReal(rng)*(max_f - min_f) + min_f;
947
t[2] = (img_size*0.5 + cvtest::randReal(rng)*4. - 2.)*t[0];
948
t[5] = (img_size*0.5 + cvtest::randReal(rng)*4. - 2.)*t[4];
949
t[8] = 1.;
950
Mat( 3, 3, CV_64F, t ).convertTo( arr, arr.type() );
951
break;
952
}
953
}
954
955
956
int CV_FundamentalMatTest::prepare_test_case( int test_case_idx )
957
{
958
int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
959
if( code > 0 )
960
{
961
const Mat& _3d = test_mat[INPUT][2];
962
RNG& rng = ts->get_rng();
963
double Idata[] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 };
964
Mat I( 3, 4, CV_64F, Idata );
965
int k;
966
967
for( k = 0; k < 2; k++ )
968
{
969
const Mat& Rt = k == 0 ? I : test_mat[INPUT][3];
970
const Mat& A = test_mat[INPUT][k == 0 ? 4 : 5];
971
Mat& _2d = test_mat[INPUT][k];
972
973
test_projectPoints( _3d, Rt, A, _2d, &rng, sigma );
974
}
975
}
976
977
return code;
978
}
979
980
void CV_FundamentalMatTest::run_func()
981
{
982
// cvFindFundamentalMat calls cv::findFundamentalMat
983
CvMat _input0 = cvMat(test_mat[INPUT][0]), _input1 = cvMat(test_mat[INPUT][1]);
984
CvMat F = cvMat(test_mat[TEMP][0]), mask = cvMat(test_mat[TEMP][1]);
985
f_result = cvFindFundamentalMat( &_input0, &_input1, &F, method, MAX(sigma*3, 0.01), 0, &mask );
986
}
987
988
989
void CV_FundamentalMatTest::prepare_to_validation( int test_case_idx )
990
{
991
const Mat& Rt = test_mat[INPUT][3];
992
const Mat& A1 = test_mat[INPUT][4];
993
const Mat& A2 = test_mat[INPUT][5];
994
double f0[9], f[9];
995
Mat F0(3, 3, CV_64FC1, f0), F(3, 3, CV_64F, f);
996
997
Mat invA1, invA2, R=Rt.colRange(0, 3), T;
998
999
cv::invert(A1, invA1, CV_SVD);
1000
cv::invert(A2, invA2, CV_SVD);
1001
1002
double tx = Rt.at<double>(0, 3);
1003
double ty = Rt.at<double>(1, 3);
1004
double tz = Rt.at<double>(2, 3);
1005
1006
double _t_x[] = { 0, -tz, ty, tz, 0, -tx, -ty, tx, 0 };
1007
1008
// F = (A2^-T)*[t]_x*R*(A1^-1)
1009
cv::gemm( invA2, Mat( 3, 3, CV_64F, _t_x ), 1, Mat(), 0, T, CV_GEMM_A_T );
1010
cv::gemm( R, invA1, 1, Mat(), 0, invA2 );
1011
cv::gemm( T, invA2, 1, Mat(), 0, F0 );
1012
F0 *= 1./f0[8];
1013
1014
uchar* status = test_mat[TEMP][1].ptr();
1015
double err_level = get_success_error_level( test_case_idx, OUTPUT, 1 );
1016
uchar* mtfm1 = test_mat[REF_OUTPUT][1].ptr();
1017
uchar* mtfm2 = test_mat[OUTPUT][1].ptr();
1018
double* f_prop1 = test_mat[REF_OUTPUT][0].ptr<double>();
1019
double* f_prop2 = test_mat[OUTPUT][0].ptr<double>();
1020
1021
int i, pt_count = test_mat[INPUT][2].cols;
1022
Mat p1( 1, pt_count, CV_64FC2 );
1023
Mat p2( 1, pt_count, CV_64FC2 );
1024
1025
test_convertHomogeneous( test_mat[INPUT][0], p1 );
1026
test_convertHomogeneous( test_mat[INPUT][1], p2 );
1027
1028
cvtest::convert(test_mat[TEMP][0], F, F.type());
1029
1030
if( method <= CV_FM_8POINT )
1031
memset( status, 1, pt_count );
1032
1033
for( i = 0; i < pt_count; i++ )
1034
{
1035
double x1 = p1.at<Point2d>(i).x;
1036
double y1 = p1.at<Point2d>(i).y;
1037
double x2 = p2.at<Point2d>(i).x;
1038
double y2 = p2.at<Point2d>(i).y;
1039
double n1 = 1./sqrt(x1*x1 + y1*y1 + 1);
1040
double n2 = 1./sqrt(x2*x2 + y2*y2 + 1);
1041
double t0 = fabs(f0[0]*x2*x1 + f0[1]*x2*y1 + f0[2]*x2 +
1042
f0[3]*y2*x1 + f0[4]*y2*y1 + f0[5]*y2 +
1043
f0[6]*x1 + f0[7]*y1 + f0[8])*n1*n2;
1044
double t = fabs(f[0]*x2*x1 + f[1]*x2*y1 + f[2]*x2 +
1045
f[3]*y2*x1 + f[4]*y2*y1 + f[5]*y2 +
1046
f[6]*x1 + f[7]*y1 + f[8])*n1*n2;
1047
mtfm1[i] = 1;
1048
mtfm2[i] = !status[i] || t0 > err_level || t < err_level;
1049
}
1050
1051
f_prop1[0] = 1;
1052
f_prop1[1] = 1;
1053
f_prop1[2] = 0;
1054
1055
f_prop2[0] = f_result != 0;
1056
f_prop2[1] = f[8];
1057
f_prop2[2] = cv::determinant( F );
1058
}
1059
/******************************* find essential matrix ***********************************/
1060
class CV_EssentialMatTest : public cvtest::ArrayTest
1061
{
1062
public:
1063
CV_EssentialMatTest();
1064
1065
protected:
1066
int read_params( CvFileStorage* fs );
1067
void fill_array( int test_case_idx, int i, int j, Mat& arr );
1068
int prepare_test_case( int test_case_idx );
1069
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
1070
double get_success_error_level( int test_case_idx, int i, int j );
1071
void run_func();
1072
void prepare_to_validation( int );
1073
1074
#if 0
1075
double sampson_error(const double* f, double x1, double y1, double x2, double y2);
1076
#endif
1077
1078
int method;
1079
int img_size;
1080
int cube_size;
1081
int dims;
1082
double min_f, max_f;
1083
double sigma;
1084
};
1085
1086
1087
CV_EssentialMatTest::CV_EssentialMatTest()
1088
{
1089
// input arrays:
1090
// 0, 1 - arrays of 2d points that are passed to %func%.
1091
// Can have different data type, layout, be stored in homogeneous coordinates or not.
1092
// 2 - array of 3d points that are projected to both view planes
1093
// 3 - [R|t] matrix for the second view plane (for the first one it is [I|0]
1094
// 4 - intrinsic matrix for both camera
1095
test_array[INPUT].push_back(NULL);
1096
test_array[INPUT].push_back(NULL);
1097
test_array[INPUT].push_back(NULL);
1098
test_array[INPUT].push_back(NULL);
1099
test_array[INPUT].push_back(NULL);
1100
test_array[TEMP].push_back(NULL);
1101
test_array[TEMP].push_back(NULL);
1102
test_array[TEMP].push_back(NULL);
1103
test_array[TEMP].push_back(NULL);
1104
test_array[TEMP].push_back(NULL);
1105
test_array[OUTPUT].push_back(NULL); // Essential Matrix singularity
1106
test_array[OUTPUT].push_back(NULL); // Inliers mask
1107
test_array[OUTPUT].push_back(NULL); // Translation error
1108
test_array[OUTPUT].push_back(NULL); // Positive depth count
1109
test_array[REF_OUTPUT].push_back(NULL);
1110
test_array[REF_OUTPUT].push_back(NULL);
1111
test_array[REF_OUTPUT].push_back(NULL);
1112
test_array[REF_OUTPUT].push_back(NULL);
1113
1114
element_wise_relative_error = false;
1115
1116
method = 0;
1117
img_size = 10;
1118
cube_size = 10;
1119
dims = 0;
1120
min_f = 1;
1121
max_f = 3;
1122
sigma = 0;
1123
}
1124
1125
1126
int CV_EssentialMatTest::read_params( CvFileStorage* fs )
1127
{
1128
int code = cvtest::ArrayTest::read_params( fs );
1129
return code;
1130
}
1131
1132
1133
void CV_EssentialMatTest::get_test_array_types_and_sizes( int /*test_case_idx*/,
1134
vector<vector<Size> >& sizes, vector<vector<int> >& types )
1135
{
1136
RNG& rng = ts->get_rng();
1137
int pt_depth = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
1138
double pt_count_exp = cvtest::randReal(rng)*6 + 1;
1139
int pt_count = MAX(5, cvRound(exp(pt_count_exp)));
1140
1141
dims = cvtest::randInt(rng) % 2 + 2;
1142
dims = 2;
1143
method = CV_LMEDS << (cvtest::randInt(rng) % 2);
1144
1145
types[INPUT][0] = CV_MAKETYPE(pt_depth, 1);
1146
1147
if( 0 && cvtest::randInt(rng) % 2 )
1148
sizes[INPUT][0] = cvSize(pt_count, dims);
1149
else
1150
{
1151
sizes[INPUT][0] = cvSize(dims, pt_count);
1152
if( cvtest::randInt(rng) % 2 )
1153
{
1154
types[INPUT][0] = CV_MAKETYPE(pt_depth, dims);
1155
if( cvtest::randInt(rng) % 2 )
1156
sizes[INPUT][0] = cvSize(pt_count, 1);
1157
else
1158
sizes[INPUT][0] = cvSize(1, pt_count);
1159
}
1160
}
1161
1162
sizes[INPUT][1] = sizes[INPUT][0];
1163
types[INPUT][1] = types[INPUT][0];
1164
1165
sizes[INPUT][2] = cvSize(pt_count, 1 );
1166
types[INPUT][2] = CV_64FC3;
1167
1168
sizes[INPUT][3] = cvSize(4,3);
1169
types[INPUT][3] = CV_64FC1;
1170
1171
sizes[INPUT][4] = cvSize(3,3);
1172
types[INPUT][4] = CV_MAKETYPE(CV_64F, 1);
1173
1174
sizes[TEMP][0] = cvSize(3,3);
1175
types[TEMP][0] = CV_64FC1;
1176
sizes[TEMP][1] = cvSize(pt_count,1);
1177
types[TEMP][1] = CV_8UC1;
1178
sizes[TEMP][2] = cvSize(3,3);
1179
types[TEMP][2] = CV_64FC1;
1180
sizes[TEMP][3] = cvSize(3, 1);
1181
types[TEMP][3] = CV_64FC1;
1182
sizes[TEMP][4] = cvSize(pt_count,1);
1183
types[TEMP][4] = CV_8UC1;
1184
1185
sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(3,1);
1186
types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;
1187
sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] = cvSize(pt_count,1);
1188
types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_8UC1;
1189
sizes[OUTPUT][2] = sizes[REF_OUTPUT][2] = cvSize(1,1);
1190
types[OUTPUT][2] = types[REF_OUTPUT][2] = CV_64FC1;
1191
sizes[OUTPUT][3] = sizes[REF_OUTPUT][3] = cvSize(1,1);
1192
types[OUTPUT][3] = types[REF_OUTPUT][3] = CV_8UC1;
1193
1194
}
1195
1196
1197
double CV_EssentialMatTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1198
{
1199
return 1e-2;
1200
}
1201
1202
1203
void CV_EssentialMatTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
1204
{
1205
double t[12]={0};
1206
RNG& rng = ts->get_rng();
1207
1208
if( i != INPUT )
1209
{
1210
cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr );
1211
return;
1212
}
1213
1214
switch( j )
1215
{
1216
case 0:
1217
case 1:
1218
return; // fill them later in prepare_test_case
1219
case 2:
1220
{
1221
double* p = arr.ptr<double>();
1222
for( i = 0; i < arr.cols*3; i += 3 )
1223
{
1224
p[i] = cvtest::randReal(rng)*cube_size;
1225
p[i+1] = cvtest::randReal(rng)*cube_size;
1226
p[i+2] = cvtest::randReal(rng)*cube_size + cube_size;
1227
}
1228
}
1229
break;
1230
case 3:
1231
{
1232
double r[3];
1233
Mat rot_vec( 3, 1, CV_64F, r );
1234
Mat rot_mat( 3, 3, CV_64F, t, 4*sizeof(t[0]) );
1235
r[0] = cvtest::randReal(rng)*CV_PI*2;
1236
r[1] = cvtest::randReal(rng)*CV_PI*2;
1237
r[2] = cvtest::randReal(rng)*CV_PI*2;
1238
1239
cvtest::Rodrigues( rot_vec, rot_mat );
1240
t[3] = cvtest::randReal(rng)*cube_size;
1241
t[7] = cvtest::randReal(rng)*cube_size;
1242
t[11] = cvtest::randReal(rng)*cube_size;
1243
Mat( 3, 4, CV_64F, t ).convertTo(arr, arr.type());
1244
}
1245
break;
1246
case 4:
1247
t[0] = t[4] = cvtest::randReal(rng)*(max_f - min_f) + min_f;
1248
t[2] = (img_size*0.5 + cvtest::randReal(rng)*4. - 2.)*t[0];
1249
t[5] = (img_size*0.5 + cvtest::randReal(rng)*4. - 2.)*t[4];
1250
t[8] = 1.;
1251
Mat( 3, 3, CV_64F, t ).convertTo( arr, arr.type() );
1252
break;
1253
}
1254
}
1255
1256
1257
int CV_EssentialMatTest::prepare_test_case( int test_case_idx )
1258
{
1259
int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
1260
if( code > 0 )
1261
{
1262
const Mat& _3d = test_mat[INPUT][2];
1263
RNG& rng = ts->get_rng();
1264
double Idata[] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 };
1265
Mat I( 3, 4, CV_64F, Idata );
1266
int k;
1267
1268
for( k = 0; k < 2; k++ )
1269
{
1270
const Mat& Rt = k == 0 ? I : test_mat[INPUT][3];
1271
const Mat& A = test_mat[INPUT][4];
1272
Mat& _2d = test_mat[INPUT][k];
1273
1274
test_projectPoints( _3d, Rt, A, _2d, &rng, sigma );
1275
}
1276
}
1277
1278
return code;
1279
}
1280
1281
1282
void CV_EssentialMatTest::run_func()
1283
{
1284
Mat _input0(test_mat[INPUT][0]), _input1(test_mat[INPUT][1]);
1285
Mat K(test_mat[INPUT][4]);
1286
double focal(K.at<double>(0, 0));
1287
cv::Point2d pp(K.at<double>(0, 2), K.at<double>(1, 2));
1288
1289
RNG& rng = ts->get_rng();
1290
Mat E, mask1(test_mat[TEMP][1]);
1291
E = cv::findEssentialMat( _input0, _input1, focal, pp, method, 0.99, MAX(sigma*3, 0.0001), mask1 );
1292
if (E.rows > 3)
1293
{
1294
int count = E.rows / 3;
1295
int row = (cvtest::randInt(rng) % count) * 3;
1296
E = E.rowRange(row, row + 3) * 1.0;
1297
}
1298
1299
E.copyTo(test_mat[TEMP][0]);
1300
1301
Mat R, t, mask2;
1302
recoverPose( E, _input0, _input1, R, t, focal, pp, mask2 );
1303
R.copyTo(test_mat[TEMP][2]);
1304
t.copyTo(test_mat[TEMP][3]);
1305
mask2.copyTo(test_mat[TEMP][4]);
1306
}
1307
1308
#if 0
1309
double CV_EssentialMatTest::sampson_error(const double * f, double x1, double y1, double x2, double y2)
1310
{
1311
double Fx1[3] = {
1312
f[0] * x1 + f[1] * y1 + f[2],
1313
f[3] * x1 + f[4] * y1 + f[5],
1314
f[6] * x1 + f[7] * y1 + f[8]
1315
};
1316
double Ftx2[3] = {
1317
f[0] * x2 + f[3] * y2 + f[6],
1318
f[1] * x2 + f[4] * y2 + f[7],
1319
f[2] * x2 + f[5] * y2 + f[8]
1320
};
1321
double x2tFx1 = Fx1[0] * x2 + Fx1[1] * y2 + Fx1[2];
1322
1323
double error = x2tFx1 * x2tFx1 / (Fx1[0] * Fx1[0] + Fx1[1] * Fx1[1] + Ftx2[0] * Ftx2[0] + Ftx2[1] * Ftx2[1]);
1324
error = sqrt(error);
1325
return error;
1326
}
1327
#endif
1328
1329
void CV_EssentialMatTest::prepare_to_validation( int test_case_idx )
1330
{
1331
const Mat& Rt0 = test_mat[INPUT][3];
1332
const Mat& A = test_mat[INPUT][4];
1333
double f0[9], f[9], e[9];
1334
Mat F0(3, 3, CV_64FC1, f0), F(3, 3, CV_64F, f);
1335
Mat E(3, 3, CV_64F, e);
1336
1337
Mat invA, R=Rt0.colRange(0, 3), T1, T2;
1338
1339
cv::invert(A, invA, CV_SVD);
1340
1341
double tx = Rt0.at<double>(0, 3);
1342
double ty = Rt0.at<double>(1, 3);
1343
double tz = Rt0.at<double>(2, 3);
1344
1345
double _t_x[] = { 0, -tz, ty, tz, 0, -tx, -ty, tx, 0 };
1346
1347
// F = (A2^-T)*[t]_x*R*(A1^-1)
1348
cv::gemm( invA, Mat( 3, 3, CV_64F, _t_x ), 1, Mat(), 0, T1, CV_GEMM_A_T );
1349
cv::gemm( R, invA, 1, Mat(), 0, T2 );
1350
cv::gemm( T1, T2, 1, Mat(), 0, F0 );
1351
F0 *= 1./f0[8];
1352
1353
uchar* status = test_mat[TEMP][1].ptr();
1354
double err_level = get_success_error_level( test_case_idx, OUTPUT, 1 );
1355
uchar* mtfm1 = test_mat[REF_OUTPUT][1].ptr();
1356
uchar* mtfm2 = test_mat[OUTPUT][1].ptr();
1357
double* e_prop1 = test_mat[REF_OUTPUT][0].ptr<double>();
1358
double* e_prop2 = test_mat[OUTPUT][0].ptr<double>();
1359
Mat E_prop2 = Mat(3, 1, CV_64F, e_prop2);
1360
1361
int i, pt_count = test_mat[INPUT][2].cols;
1362
Mat p1( 1, pt_count, CV_64FC2 );
1363
Mat p2( 1, pt_count, CV_64FC2 );
1364
1365
test_convertHomogeneous( test_mat[INPUT][0], p1 );
1366
test_convertHomogeneous( test_mat[INPUT][1], p2 );
1367
1368
cvtest::convert(test_mat[TEMP][0], E, E.type());
1369
cv::gemm( invA, E, 1, Mat(), 0, T1, CV_GEMM_A_T );
1370
cv::gemm( T1, invA, 1, Mat(), 0, F );
1371
1372
for( i = 0; i < pt_count; i++ )
1373
{
1374
double x1 = p1.at<Point2d>(i).x;
1375
double y1 = p1.at<Point2d>(i).y;
1376
double x2 = p2.at<Point2d>(i).x;
1377
double y2 = p2.at<Point2d>(i).y;
1378
// double t0 = sampson_error(f0, x1, y1, x2, y2);
1379
// double t = sampson_error(f, x1, y1, x2, y2);
1380
double n1 = 1./sqrt(x1*x1 + y1*y1 + 1);
1381
double n2 = 1./sqrt(x2*x2 + y2*y2 + 1);
1382
double t0 = fabs(f0[0]*x2*x1 + f0[1]*x2*y1 + f0[2]*x2 +
1383
f0[3]*y2*x1 + f0[4]*y2*y1 + f0[5]*y2 +
1384
f0[6]*x1 + f0[7]*y1 + f0[8])*n1*n2;
1385
double t = fabs(f[0]*x2*x1 + f[1]*x2*y1 + f[2]*x2 +
1386
f[3]*y2*x1 + f[4]*y2*y1 + f[5]*y2 +
1387
f[6]*x1 + f[7]*y1 + f[8])*n1*n2;
1388
mtfm1[i] = 1;
1389
mtfm2[i] = !status[i] || t0 > err_level || t < err_level;
1390
}
1391
1392
e_prop1[0] = sqrt(0.5);
1393
e_prop1[1] = sqrt(0.5);
1394
e_prop1[2] = 0;
1395
1396
e_prop2[0] = 0;
1397
e_prop2[1] = 0;
1398
e_prop2[2] = 0;
1399
SVD::compute(E, E_prop2);
1400
1401
1402
1403
double* pose_prop1 = test_mat[REF_OUTPUT][2].ptr<double>();
1404
double* pose_prop2 = test_mat[OUTPUT][2].ptr<double>();
1405
double terr1 = cvtest::norm(Rt0.col(3) / cvtest::norm(Rt0.col(3), NORM_L2) + test_mat[TEMP][3], NORM_L2);
1406
double terr2 = cvtest::norm(Rt0.col(3) / cvtest::norm(Rt0.col(3), NORM_L2) - test_mat[TEMP][3], NORM_L2);
1407
Mat rvec(3, 1, CV_32F);
1408
cvtest::Rodrigues(Rt0.colRange(0, 3), rvec);
1409
pose_prop1[0] = 0;
1410
// No check for CV_LMeDS on translation. Since it
1411
// involves with some degraded problem, when data is exact inliers.
1412
pose_prop2[0] = method == CV_LMEDS || pt_count == 5 ? 0 : MIN(terr1, terr2);
1413
1414
1415
// int inliers_count = countNonZero(test_mat[TEMP][1]);
1416
// int good_count = countNonZero(test_mat[TEMP][4]);
1417
test_mat[OUTPUT][3] = true; //good_count >= inliers_count / 2;
1418
test_mat[REF_OUTPUT][3] = true;
1419
1420
1421
}
1422
1423
1424
/********************************** convert homogeneous *********************************/
1425
1426
class CV_ConvertHomogeneousTest : public cvtest::ArrayTest
1427
{
1428
public:
1429
CV_ConvertHomogeneousTest();
1430
1431
protected:
1432
int read_params( CvFileStorage* fs );
1433
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
1434
void fill_array( int test_case_idx, int i, int j, Mat& arr );
1435
double get_success_error_level( int test_case_idx, int i, int j );
1436
void run_func();
1437
void prepare_to_validation( int );
1438
1439
int dims1, dims2;
1440
int pt_count;
1441
};
1442
1443
1444
CV_ConvertHomogeneousTest::CV_ConvertHomogeneousTest()
1445
{
1446
test_array[INPUT].push_back(NULL);
1447
test_array[OUTPUT].push_back(NULL);
1448
test_array[REF_OUTPUT].push_back(NULL);
1449
element_wise_relative_error = false;
1450
1451
pt_count = dims1 = dims2 = 0;
1452
}
1453
1454
1455
int CV_ConvertHomogeneousTest::read_params( CvFileStorage* fs )
1456
{
1457
int code = cvtest::ArrayTest::read_params( fs );
1458
return code;
1459
}
1460
1461
1462
void CV_ConvertHomogeneousTest::get_test_array_types_and_sizes( int /*test_case_idx*/,
1463
vector<vector<Size> >& sizes, vector<vector<int> >& types )
1464
{
1465
RNG& rng = ts->get_rng();
1466
int pt_depth1 = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
1467
int pt_depth2 = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
1468
double pt_count_exp = cvtest::randReal(rng)*6 + 1;
1469
int t;
1470
1471
pt_count = cvRound(exp(pt_count_exp));
1472
pt_count = MAX( pt_count, 5 );
1473
1474
dims1 = 2 + (cvtest::randInt(rng) % 3);
1475
dims2 = 2 + (cvtest::randInt(rng) % 3);
1476
1477
if( dims1 == dims2 + 2 )
1478
dims1--;
1479
else if( dims1 == dims2 - 2 )
1480
dims1++;
1481
1482
if( cvtest::randInt(rng) % 2 )
1483
CV_SWAP( dims1, dims2, t );
1484
1485
types[INPUT][0] = CV_MAKETYPE(pt_depth1, 1);
1486
1487
if( cvtest::randInt(rng) % 2 )
1488
sizes[INPUT][0] = cvSize(pt_count, dims1);
1489
else
1490
{
1491
sizes[INPUT][0] = cvSize(dims1, pt_count);
1492
if( cvtest::randInt(rng) % 2 )
1493
{
1494
types[INPUT][0] = CV_MAKETYPE(pt_depth1, dims1);
1495
if( cvtest::randInt(rng) % 2 )
1496
sizes[INPUT][0] = cvSize(pt_count, 1);
1497
else
1498
sizes[INPUT][0] = cvSize(1, pt_count);
1499
}
1500
}
1501
1502
types[OUTPUT][0] = CV_MAKETYPE(pt_depth2, 1);
1503
1504
if( cvtest::randInt(rng) % 2 )
1505
sizes[OUTPUT][0] = cvSize(pt_count, dims2);
1506
else
1507
{
1508
sizes[OUTPUT][0] = cvSize(dims2, pt_count);
1509
if( cvtest::randInt(rng) % 2 )
1510
{
1511
types[OUTPUT][0] = CV_MAKETYPE(pt_depth2, dims2);
1512
if( cvtest::randInt(rng) % 2 )
1513
sizes[OUTPUT][0] = cvSize(pt_count, 1);
1514
else
1515
sizes[OUTPUT][0] = cvSize(1, pt_count);
1516
}
1517
}
1518
1519
types[REF_OUTPUT][0] = types[OUTPUT][0];
1520
sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
1521
}
1522
1523
1524
double CV_ConvertHomogeneousTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1525
{
1526
return 1e-5;
1527
}
1528
1529
1530
void CV_ConvertHomogeneousTest::fill_array( int /*test_case_idx*/, int /*i*/, int /*j*/, Mat& arr )
1531
{
1532
Mat temp( 1, pt_count, CV_MAKETYPE(CV_64FC1,dims1) );
1533
RNG& rng = ts->get_rng();
1534
CvScalar low = cvScalarAll(0), high = cvScalarAll(10);
1535
1536
if( dims1 > dims2 )
1537
low.val[dims1-1] = 1.;
1538
1539
cvtest::randUni( rng, temp, low, high );
1540
test_convertHomogeneous( temp, arr );
1541
}
1542
1543
1544
void CV_ConvertHomogeneousTest::run_func()
1545
{
1546
CvMat _input = cvMat(test_mat[INPUT][0]), _output = cvMat(test_mat[OUTPUT][0]);
1547
cvConvertPointsHomogeneous( &_input, &_output );
1548
}
1549
1550
1551
void CV_ConvertHomogeneousTest::prepare_to_validation( int /*test_case_idx*/ )
1552
{
1553
test_convertHomogeneous( test_mat[INPUT][0], test_mat[REF_OUTPUT][0] );
1554
}
1555
1556
1557
/************************** compute corresponding epipolar lines ************************/
1558
1559
class CV_ComputeEpilinesTest : public cvtest::ArrayTest
1560
{
1561
public:
1562
CV_ComputeEpilinesTest();
1563
1564
protected:
1565
int read_params( CvFileStorage* fs );
1566
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
1567
void fill_array( int test_case_idx, int i, int j, Mat& arr );
1568
double get_success_error_level( int test_case_idx, int i, int j );
1569
void run_func();
1570
void prepare_to_validation( int );
1571
1572
int which_image;
1573
int dims;
1574
int pt_count;
1575
};
1576
1577
1578
CV_ComputeEpilinesTest::CV_ComputeEpilinesTest()
1579
{
1580
test_array[INPUT].push_back(NULL);
1581
test_array[INPUT].push_back(NULL);
1582
test_array[OUTPUT].push_back(NULL);
1583
test_array[REF_OUTPUT].push_back(NULL);
1584
element_wise_relative_error = false;
1585
1586
pt_count = dims = which_image = 0;
1587
}
1588
1589
1590
int CV_ComputeEpilinesTest::read_params( CvFileStorage* fs )
1591
{
1592
int code = cvtest::ArrayTest::read_params( fs );
1593
return code;
1594
}
1595
1596
1597
void CV_ComputeEpilinesTest::get_test_array_types_and_sizes( int /*test_case_idx*/,
1598
vector<vector<Size> >& sizes, vector<vector<int> >& types )
1599
{
1600
RNG& rng = ts->get_rng();
1601
int fm_depth = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
1602
int pt_depth = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
1603
int ln_depth = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
1604
double pt_count_exp = cvtest::randReal(rng)*6;
1605
1606
which_image = 1 + (cvtest::randInt(rng) % 2);
1607
1608
pt_count = cvRound(exp(pt_count_exp));
1609
pt_count = MAX( pt_count, 1 );
1610
bool few_points = pt_count < 5;
1611
1612
dims = 2 + (cvtest::randInt(rng) % 2);
1613
1614
types[INPUT][0] = CV_MAKETYPE(pt_depth, 1);
1615
1616
if( cvtest::randInt(rng) % 2 && !few_points )
1617
sizes[INPUT][0] = cvSize(pt_count, dims);
1618
else
1619
{
1620
sizes[INPUT][0] = cvSize(dims, pt_count);
1621
if( cvtest::randInt(rng) % 2 || few_points )
1622
{
1623
types[INPUT][0] = CV_MAKETYPE(pt_depth, dims);
1624
if( cvtest::randInt(rng) % 2 )
1625
sizes[INPUT][0] = cvSize(pt_count, 1);
1626
else
1627
sizes[INPUT][0] = cvSize(1, pt_count);
1628
}
1629
}
1630
1631
types[INPUT][1] = CV_MAKETYPE(fm_depth, 1);
1632
sizes[INPUT][1] = cvSize(3, 3);
1633
1634
types[OUTPUT][0] = CV_MAKETYPE(ln_depth, 1);
1635
1636
if( cvtest::randInt(rng) % 2 && !few_points )
1637
sizes[OUTPUT][0] = cvSize(pt_count, 3);
1638
else
1639
{
1640
sizes[OUTPUT][0] = cvSize(3, pt_count);
1641
if( cvtest::randInt(rng) % 2 || few_points )
1642
{
1643
types[OUTPUT][0] = CV_MAKETYPE(ln_depth, 3);
1644
if( cvtest::randInt(rng) % 2 )
1645
sizes[OUTPUT][0] = cvSize(pt_count, 1);
1646
else
1647
sizes[OUTPUT][0] = cvSize(1, pt_count);
1648
}
1649
}
1650
1651
types[REF_OUTPUT][0] = types[OUTPUT][0];
1652
sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
1653
}
1654
1655
1656
double CV_ComputeEpilinesTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1657
{
1658
return 1e-5;
1659
}
1660
1661
1662
void CV_ComputeEpilinesTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
1663
{
1664
RNG& rng = ts->get_rng();
1665
1666
if( i == INPUT && j == 0 )
1667
{
1668
Mat temp( 1, pt_count, CV_MAKETYPE(CV_64FC1,dims) );
1669
cvtest::randUni( rng, temp, cvScalar(0,0,1), cvScalarAll(10) );
1670
test_convertHomogeneous( temp, arr );
1671
}
1672
else if( i == INPUT && j == 1 )
1673
cvtest::randUni( rng, arr, cvScalarAll(0), cvScalarAll(10) );
1674
else
1675
cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr );
1676
}
1677
1678
1679
void CV_ComputeEpilinesTest::run_func()
1680
{
1681
CvMat _points = cvMat(test_mat[INPUT][0]), _F = cvMat(test_mat[INPUT][1]), _lines = cvMat(test_mat[OUTPUT][0]);
1682
cvComputeCorrespondEpilines( &_points, which_image, &_F, &_lines );
1683
}
1684
1685
1686
void CV_ComputeEpilinesTest::prepare_to_validation( int /*test_case_idx*/ )
1687
{
1688
Mat pt( 1, pt_count, CV_MAKETYPE(CV_64F, 3) );
1689
Mat lines( 1, pt_count, CV_MAKETYPE(CV_64F, 3) );
1690
double f[9];
1691
Mat F( 3, 3, CV_64F, f );
1692
1693
test_convertHomogeneous( test_mat[INPUT][0], pt );
1694
test_mat[INPUT][1].convertTo(F, CV_64F);
1695
if( which_image == 2 )
1696
cv::transpose( F, F );
1697
1698
for( int i = 0; i < pt_count; i++ )
1699
{
1700
double* p = pt.ptr<double>() + i*3;
1701
double* l = lines.ptr<double>() + i*3;
1702
double t0 = f[0]*p[0] + f[1]*p[1] + f[2]*p[2];
1703
double t1 = f[3]*p[0] + f[4]*p[1] + f[5]*p[2];
1704
double t2 = f[6]*p[0] + f[7]*p[1] + f[8]*p[2];
1705
double d = sqrt(t0*t0 + t1*t1);
1706
d = d ? 1./d : 1.;
1707
l[0] = t0*d; l[1] = t1*d; l[2] = t2*d;
1708
}
1709
1710
test_convertHomogeneous( lines, test_mat[REF_OUTPUT][0] );
1711
}
1712
1713
TEST(Calib3d_Rodrigues, accuracy) { CV_RodriguesTest test; test.safe_run(); }
1714
TEST(Calib3d_FindFundamentalMat, accuracy) { CV_FundamentalMatTest test; test.safe_run(); }
1715
TEST(Calib3d_ConvertHomogeneoous, accuracy) { CV_ConvertHomogeneousTest test; test.safe_run(); }
1716
TEST(Calib3d_ComputeEpilines, accuracy) { CV_ComputeEpilinesTest test; test.safe_run(); }
1717
TEST(Calib3d_FindEssentialMat, accuracy) { CV_EssentialMatTest test; test.safe_run(); }
1718
1719
TEST(Calib3d_FindFundamentalMat, correctMatches)
1720
{
1721
double fdata[] = {0, 0, 0, 0, 0, -1, 0, 1, 0};
1722
double p1data[] = {200, 0, 1};
1723
double p2data[] = {170, 0, 1};
1724
1725
Mat F(3, 3, CV_64F, fdata);
1726
Mat p1(1, 1, CV_64FC2, p1data);
1727
Mat p2(1, 1, CV_64FC2, p2data);
1728
Mat np1, np2;
1729
1730
correctMatches(F, p1, p2, np1, np2);
1731
1732
cout << np1 << endl;
1733
cout << np2 << endl;
1734
}
1735
1736
}} // namespace
1737
/* End of file. */
1738
1739