Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/calib3d/test/test_cameracalibration.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 opencv_test { namespace {
46
47
#if 0
48
class CV_ProjectPointsTest : public cvtest::ArrayTest
49
{
50
public:
51
CV_ProjectPointsTest();
52
53
protected:
54
int read_params( CvFileStorage* fs );
55
void fill_array( int test_case_idx, int i, int j, Mat& arr );
56
int prepare_test_case( int test_case_idx );
57
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
58
double get_success_error_level( int test_case_idx, int i, int j );
59
void run_func();
60
void prepare_to_validation( int );
61
62
bool calc_jacobians;
63
};
64
65
66
CV_ProjectPointsTest::CV_ProjectPointsTest()
67
: cvtest::ArrayTest( "3d-ProjectPoints", "cvProjectPoints2", "" )
68
{
69
test_array[INPUT].push_back(NULL); // rotation vector
70
test_array[OUTPUT].push_back(NULL); // rotation matrix
71
test_array[OUTPUT].push_back(NULL); // jacobian (J)
72
test_array[OUTPUT].push_back(NULL); // rotation vector (backward transform result)
73
test_array[OUTPUT].push_back(NULL); // inverse transform jacobian (J1)
74
test_array[OUTPUT].push_back(NULL); // J*J1 (or J1*J) == I(3x3)
75
test_array[REF_OUTPUT].push_back(NULL);
76
test_array[REF_OUTPUT].push_back(NULL);
77
test_array[REF_OUTPUT].push_back(NULL);
78
test_array[REF_OUTPUT].push_back(NULL);
79
test_array[REF_OUTPUT].push_back(NULL);
80
81
element_wise_relative_error = false;
82
calc_jacobians = false;
83
}
84
85
86
int CV_ProjectPointsTest::read_params( CvFileStorage* fs )
87
{
88
int code = cvtest::ArrayTest::read_params( fs );
89
return code;
90
}
91
92
93
void CV_ProjectPointsTest::get_test_array_types_and_sizes(
94
int /*test_case_idx*/, vector<vector<Size> >& sizes, vector<vector<int> >& types )
95
{
96
RNG& rng = ts->get_rng();
97
int depth = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
98
int i, code;
99
100
code = cvtest::randInt(rng) % 3;
101
types[INPUT][0] = CV_MAKETYPE(depth, 1);
102
103
if( code == 0 )
104
{
105
sizes[INPUT][0] = cvSize(1,1);
106
types[INPUT][0] = CV_MAKETYPE(depth, 3);
107
}
108
else if( code == 1 )
109
sizes[INPUT][0] = cvSize(3,1);
110
else
111
sizes[INPUT][0] = cvSize(1,3);
112
113
sizes[OUTPUT][0] = cvSize(3, 3);
114
types[OUTPUT][0] = CV_MAKETYPE(depth, 1);
115
116
types[OUTPUT][1] = CV_MAKETYPE(depth, 1);
117
118
if( cvtest::randInt(rng) % 2 )
119
sizes[OUTPUT][1] = cvSize(3,9);
120
else
121
sizes[OUTPUT][1] = cvSize(9,3);
122
123
types[OUTPUT][2] = types[INPUT][0];
124
sizes[OUTPUT][2] = sizes[INPUT][0];
125
126
types[OUTPUT][3] = types[OUTPUT][1];
127
sizes[OUTPUT][3] = cvSize(sizes[OUTPUT][1].height, sizes[OUTPUT][1].width);
128
129
types[OUTPUT][4] = types[OUTPUT][1];
130
sizes[OUTPUT][4] = cvSize(3,3);
131
132
calc_jacobians = 1;//cvtest::randInt(rng) % 3 != 0;
133
if( !calc_jacobians )
134
sizes[OUTPUT][1] = sizes[OUTPUT][3] = sizes[OUTPUT][4] = cvSize(0,0);
135
136
for( i = 0; i < 5; i++ )
137
{
138
types[REF_OUTPUT][i] = types[OUTPUT][i];
139
sizes[REF_OUTPUT][i] = sizes[OUTPUT][i];
140
}
141
}
142
143
144
double CV_ProjectPointsTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int j )
145
{
146
return j == 4 ? 1e-2 : 1e-2;
147
}
148
149
150
void CV_ProjectPointsTest::fill_array( int /*test_case_idx*/, int /*i*/, int /*j*/, CvMat* arr )
151
{
152
double r[3], theta0, theta1, f;
153
CvMat _r = cvMat( arr->rows, arr->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(arr->type)), r );
154
RNG& rng = ts->get_rng();
155
156
r[0] = cvtest::randReal(rng)*CV_PI*2;
157
r[1] = cvtest::randReal(rng)*CV_PI*2;
158
r[2] = cvtest::randReal(rng)*CV_PI*2;
159
160
theta0 = sqrt(r[0]*r[0] + r[1]*r[1] + r[2]*r[2]);
161
theta1 = fmod(theta0, CV_PI*2);
162
163
if( theta1 > CV_PI )
164
theta1 = -(CV_PI*2 - theta1);
165
166
f = theta1/(theta0 ? theta0 : 1);
167
r[0] *= f;
168
r[1] *= f;
169
r[2] *= f;
170
171
cvTsConvert( &_r, arr );
172
}
173
174
175
int CV_ProjectPointsTest::prepare_test_case( int test_case_idx )
176
{
177
int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
178
return code;
179
}
180
181
182
void CV_ProjectPointsTest::run_func()
183
{
184
CvMat *v2m_jac = 0, *m2v_jac = 0;
185
if( calc_jacobians )
186
{
187
v2m_jac = &test_mat[OUTPUT][1];
188
m2v_jac = &test_mat[OUTPUT][3];
189
}
190
191
cvProjectPoints2( &test_mat[INPUT][0], &test_mat[OUTPUT][0], v2m_jac );
192
cvProjectPoints2( &test_mat[OUTPUT][0], &test_mat[OUTPUT][2], m2v_jac );
193
}
194
195
196
void CV_ProjectPointsTest::prepare_to_validation( int /*test_case_idx*/ )
197
{
198
const CvMat* vec = &test_mat[INPUT][0];
199
CvMat* m = &test_mat[REF_OUTPUT][0];
200
CvMat* vec2 = &test_mat[REF_OUTPUT][2];
201
CvMat* v2m_jac = 0, *m2v_jac = 0;
202
double theta0, theta1;
203
204
if( calc_jacobians )
205
{
206
v2m_jac = &test_mat[REF_OUTPUT][1];
207
m2v_jac = &test_mat[REF_OUTPUT][3];
208
}
209
210
211
cvTsProjectPoints( vec, m, v2m_jac );
212
cvTsProjectPoints( m, vec2, m2v_jac );
213
cvTsCopy( vec, vec2 );
214
215
theta0 = cvtest::norm( cvarrtomat(vec2), 0, CV_L2 );
216
theta1 = fmod( theta0, CV_PI*2 );
217
218
if( theta1 > CV_PI )
219
theta1 = -(CV_PI*2 - theta1);
220
cvScale( vec2, vec2, theta1/(theta0 ? theta0 : 1) );
221
222
if( calc_jacobians )
223
{
224
//cvInvert( v2m_jac, m2v_jac, CV_SVD );
225
if( cvtest::norm(cvarrtomat(&test_mat[OUTPUT][3]), 0, CV_C) < 1000 )
226
{
227
cvTsGEMM( &test_mat[OUTPUT][1], &test_mat[OUTPUT][3],
228
1, 0, 0, &test_mat[OUTPUT][4],
229
v2m_jac->rows == 3 ? 0 : CV_GEMM_A_T + CV_GEMM_B_T );
230
}
231
else
232
{
233
cvTsSetIdentity( &test_mat[OUTPUT][4], cvScalarAll(1.) );
234
cvTsCopy( &test_mat[REF_OUTPUT][2], &test_mat[OUTPUT][2] );
235
}
236
cvTsSetIdentity( &test_mat[REF_OUTPUT][4], cvScalarAll(1.) );
237
}
238
}
239
240
241
CV_ProjectPointsTest ProjectPoints_test;
242
243
#endif
244
245
// --------------------------------- CV_CameraCalibrationTest --------------------------------------------
246
247
class CV_CameraCalibrationTest : public cvtest::BaseTest
248
{
249
public:
250
CV_CameraCalibrationTest();
251
~CV_CameraCalibrationTest();
252
void clear();
253
protected:
254
int compare(double* val, double* refVal, int len,
255
double eps, const char* paramName);
256
virtual void calibrate( int imageCount, int* pointCounts,
257
CvSize imageSize, CvPoint2D64f* imagePoints, CvPoint3D64f* objectPoints,
258
int iFixedPoint, double* distortionCoeffs, double* cameraMatrix, double* translationVectors,
259
double* rotationMatrices, double* newObjPoints, double *stdDevs, double* perViewErrors,
260
int flags ) = 0;
261
virtual void project( int pointCount, CvPoint3D64f* objectPoints,
262
double* rotationMatrix, double* translationVector,
263
double* cameraMatrix, double* distortion, CvPoint2D64f* imagePoints ) = 0;
264
265
void run(int);
266
};
267
268
CV_CameraCalibrationTest::CV_CameraCalibrationTest()
269
{
270
}
271
272
CV_CameraCalibrationTest::~CV_CameraCalibrationTest()
273
{
274
clear();
275
}
276
277
void CV_CameraCalibrationTest::clear()
278
{
279
cvtest::BaseTest::clear();
280
}
281
282
int CV_CameraCalibrationTest::compare(double* val, double* ref_val, int len,
283
double eps, const char* param_name )
284
{
285
return cvtest::cmpEps2_64f( ts, val, ref_val, len, eps, param_name );
286
}
287
288
void CV_CameraCalibrationTest::run( int start_from )
289
{
290
int code = cvtest::TS::OK;
291
cv::String filepath;
292
cv::String filename;
293
294
Size imageSize;
295
Size etalonSize;
296
int numImages;
297
298
CvPoint2D64f* imagePoints;
299
CvPoint3D64f* objectPoints;
300
CvPoint2D64f* reprojectPoints;
301
302
double* transVects;
303
double* rotMatrs;
304
double* newObjPoints;
305
double* stdDevs;
306
double* perViewErrors;
307
308
double* goodTransVects;
309
double* goodRotMatrs;
310
double* goodObjPoints;
311
double* goodPerViewErrors;
312
double* goodStdDevs;
313
314
double cameraMatrix[3*3];
315
double distortion[5]={0,0,0,0,0};
316
317
double goodDistortion[4];
318
319
int* numbers;
320
FILE* file = 0;
321
FILE* datafile = 0;
322
int i,j;
323
int currImage;
324
int currPoint;
325
326
int calibFlags;
327
char i_dat_file[100];
328
int numPoints;
329
int numTests;
330
int currTest;
331
332
imagePoints = 0;
333
objectPoints = 0;
334
reprojectPoints = 0;
335
numbers = 0;
336
337
transVects = 0;
338
rotMatrs = 0;
339
goodTransVects = 0;
340
goodRotMatrs = 0;
341
int progress = 0;
342
int values_read = -1;
343
344
filepath = cv::format("%scv/cameracalibration/", ts->get_data_path().c_str() );
345
filename = cv::format("%sdatafiles.txt", filepath.c_str() );
346
datafile = fopen( filename.c_str(), "r" );
347
if( datafile == 0 )
348
{
349
ts->printf( cvtest::TS::LOG, "Could not open file with list of test files: %s\n", filename.c_str() );
350
code = cvtest::TS::FAIL_MISSING_TEST_DATA;
351
goto _exit_;
352
}
353
354
values_read = fscanf(datafile,"%d",&numTests);
355
CV_Assert(values_read == 1);
356
357
for( currTest = start_from; currTest < numTests; currTest++ )
358
{
359
values_read = fscanf(datafile,"%s",i_dat_file);
360
CV_Assert(values_read == 1);
361
filename = cv::format("%s%s", filepath.c_str(), i_dat_file);
362
file = fopen(filename.c_str(),"r");
363
364
ts->update_context( this, currTest, true );
365
366
if( file == 0 )
367
{
368
ts->printf( cvtest::TS::LOG,
369
"Can't open current test file: %s\n",filename.c_str());
370
if( numTests == 1 )
371
{
372
code = cvtest::TS::FAIL_MISSING_TEST_DATA;
373
goto _exit_;
374
}
375
continue; // if there is more than one test, just skip the test
376
}
377
378
values_read = fscanf(file,"%d %d\n",&(imageSize.width),&(imageSize.height));
379
CV_Assert(values_read == 2);
380
if( imageSize.width <= 0 || imageSize.height <= 0 )
381
{
382
ts->printf( cvtest::TS::LOG, "Image size in test file is incorrect\n" );
383
code = cvtest::TS::FAIL_INVALID_TEST_DATA;
384
goto _exit_;
385
}
386
387
/* Read etalon size */
388
values_read = fscanf(file,"%d %d\n",&(etalonSize.width),&(etalonSize.height));
389
CV_Assert(values_read == 2);
390
if( etalonSize.width <= 0 || etalonSize.height <= 0 )
391
{
392
ts->printf( cvtest::TS::LOG, "Pattern size in test file is incorrect\n" );
393
code = cvtest::TS::FAIL_INVALID_TEST_DATA;
394
goto _exit_;
395
}
396
397
numPoints = etalonSize.width * etalonSize.height;
398
399
/* Read number of images */
400
values_read = fscanf(file,"%d\n",&numImages);
401
CV_Assert(values_read == 1);
402
if( numImages <=0 )
403
{
404
ts->printf( cvtest::TS::LOG, "Number of images in test file is incorrect\n");
405
code = cvtest::TS::FAIL_INVALID_TEST_DATA;
406
goto _exit_;
407
}
408
409
/* Read calibration flags */
410
values_read = fscanf(file,"%d\n",&calibFlags);
411
CV_Assert(values_read == 1);
412
413
/* Read index of the fixed point */
414
int iFixedPoint;
415
values_read = fscanf(file,"%d\n",&iFixedPoint);
416
CV_Assert(values_read == 1);
417
418
/* Need to allocate memory */
419
imagePoints = (CvPoint2D64f*)cvAlloc( numPoints *
420
numImages * sizeof(CvPoint2D64f));
421
422
objectPoints = (CvPoint3D64f*)cvAlloc( numPoints *
423
numImages * sizeof(CvPoint3D64f));
424
425
reprojectPoints = (CvPoint2D64f*)cvAlloc( numPoints *
426
numImages * sizeof(CvPoint2D64f));
427
428
/* Alloc memory for numbers */
429
numbers = (int*)cvAlloc( numImages * sizeof(int));
430
431
/* Fill it by numbers of points of each image*/
432
for( currImage = 0; currImage < numImages; currImage++ )
433
{
434
numbers[currImage] = etalonSize.width * etalonSize.height;
435
}
436
437
/* Allocate memory for translate vectors and rotmatrixs*/
438
transVects = (double*)cvAlloc(3 * 1 * numImages * sizeof(double));
439
rotMatrs = (double*)cvAlloc(3 * 3 * numImages * sizeof(double));
440
newObjPoints = (double*)cvAlloc(3 * numbers[0] * sizeof(double));
441
stdDevs = (double*)cvAlloc((CV_CALIB_NINTRINSIC + 6*numImages + 3*numbers[0])
442
* sizeof(double));
443
perViewErrors = (double*)cvAlloc(numImages * sizeof(double));
444
445
goodTransVects = (double*)cvAlloc(3 * 1 * numImages * sizeof(double));
446
goodRotMatrs = (double*)cvAlloc(3 * 3 * numImages * sizeof(double));
447
goodObjPoints = (double*)cvAlloc(3 * numbers[0] * sizeof(double));
448
goodPerViewErrors = (double*)cvAlloc(numImages * sizeof(double));
449
goodStdDevs = (double*)cvAlloc((CV_CALIB_NINTRINSIC + 6*numImages + 3*numbers[0])
450
* sizeof(double));
451
452
/* Read object points */
453
i = 0;/* shift for current point */
454
for( currImage = 0; currImage < numImages; currImage++ )
455
{
456
for( currPoint = 0; currPoint < numPoints; currPoint++ )
457
{
458
double x,y,z;
459
values_read = fscanf(file,"%lf %lf %lf\n",&x,&y,&z);
460
CV_Assert(values_read == 3);
461
462
(objectPoints+i)->x = x;
463
(objectPoints+i)->y = y;
464
(objectPoints+i)->z = z;
465
i++;
466
}
467
}
468
469
/* Read image points */
470
i = 0;/* shift for current point */
471
for( currImage = 0; currImage < numImages; currImage++ )
472
{
473
for( currPoint = 0; currPoint < numPoints; currPoint++ )
474
{
475
double x,y;
476
values_read = fscanf(file,"%lf %lf\n",&x,&y);
477
CV_Assert(values_read == 2);
478
479
(imagePoints+i)->x = x;
480
(imagePoints+i)->y = y;
481
i++;
482
}
483
}
484
485
/* Read good data computed before */
486
487
/* Focal lengths */
488
double goodFcx,goodFcy;
489
values_read = fscanf(file,"%lf %lf",&goodFcx,&goodFcy);
490
CV_Assert(values_read == 2);
491
492
/* Principal points */
493
double goodCx,goodCy;
494
values_read = fscanf(file,"%lf %lf",&goodCx,&goodCy);
495
CV_Assert(values_read == 2);
496
497
/* Read distortion */
498
499
values_read = fscanf(file,"%lf",goodDistortion+0); CV_Assert(values_read == 1);
500
values_read = fscanf(file,"%lf",goodDistortion+1); CV_Assert(values_read == 1);
501
values_read = fscanf(file,"%lf",goodDistortion+2); CV_Assert(values_read == 1);
502
values_read = fscanf(file,"%lf",goodDistortion+3); CV_Assert(values_read == 1);
503
504
/* Read good Rot matrices */
505
for( currImage = 0; currImage < numImages; currImage++ )
506
{
507
for( i = 0; i < 3; i++ )
508
for( j = 0; j < 3; j++ )
509
{
510
values_read = fscanf(file, "%lf", goodRotMatrs + currImage * 9 + j * 3 + i);
511
CV_Assert(values_read == 1);
512
}
513
}
514
515
/* Read good Trans vectors */
516
for( currImage = 0; currImage < numImages; currImage++ )
517
{
518
for( i = 0; i < 3; i++ )
519
{
520
values_read = fscanf(file, "%lf", goodTransVects + currImage * 3 + i);
521
CV_Assert(values_read == 1);
522
}
523
}
524
525
bool releaseObject = iFixedPoint > 0 && iFixedPoint < numPoints - 1;
526
/* Read good refined 3D object points */
527
if( releaseObject )
528
{
529
for( i = 0; i < numbers[0]; i++ )
530
{
531
for( j = 0; j < 3; j++ )
532
{
533
values_read = fscanf(file, "%lf", goodObjPoints + i * 3 + j);
534
CV_Assert(values_read == 1);
535
}
536
}
537
}
538
539
/* Read good stdDeviations */
540
for (i = 0; i < CV_CALIB_NINTRINSIC + numImages*6; i++)
541
{
542
values_read = fscanf(file, "%lf", goodStdDevs + i);
543
CV_Assert(values_read == 1);
544
}
545
if( releaseObject )
546
{
547
for( i = CV_CALIB_NINTRINSIC + numImages*6; i < CV_CALIB_NINTRINSIC + numImages*6
548
+ numbers[0]*3; i++ )
549
{
550
values_read = fscanf(file, "%lf", goodStdDevs + i);
551
CV_Assert(values_read == 1);
552
}
553
}
554
555
memset( cameraMatrix, 0, 9*sizeof(cameraMatrix[0]) );
556
cameraMatrix[0] = cameraMatrix[4] = 807.;
557
cameraMatrix[2] = (imageSize.width - 1)*0.5;
558
cameraMatrix[5] = (imageSize.height - 1)*0.5;
559
cameraMatrix[8] = 1.;
560
561
/* Now we can calibrate camera */
562
calibrate( numImages,
563
numbers,
564
cvSize(imageSize),
565
imagePoints,
566
objectPoints,
567
iFixedPoint,
568
distortion,
569
cameraMatrix,
570
transVects,
571
rotMatrs,
572
newObjPoints,
573
stdDevs,
574
perViewErrors,
575
calibFlags );
576
577
/* ---- Reproject points to the image ---- */
578
for( currImage = 0; currImage < numImages; currImage++ )
579
{
580
int nPoints = etalonSize.width * etalonSize.height;
581
if( releaseObject )
582
{
583
memcpy( objectPoints + currImage * nPoints, newObjPoints,
584
nPoints * 3 * sizeof(double) );
585
}
586
project( nPoints,
587
objectPoints + currImage * nPoints,
588
rotMatrs + currImage * 9,
589
transVects + currImage * 3,
590
cameraMatrix,
591
distortion,
592
reprojectPoints + currImage * nPoints);
593
}
594
595
/* ----- Compute reprojection error ----- */
596
i = 0;
597
double dx,dy;
598
double rx,ry;
599
double meanDx,meanDy;
600
double maxDx = 0.0;
601
double maxDy = 0.0;
602
603
meanDx = 0;
604
meanDy = 0;
605
for( currImage = 0; currImage < numImages; currImage++ )
606
{
607
double imageMeanDx = 0;
608
double imageMeanDy = 0;
609
for( currPoint = 0; currPoint < etalonSize.width * etalonSize.height; currPoint++ )
610
{
611
rx = reprojectPoints[i].x;
612
ry = reprojectPoints[i].y;
613
dx = rx - imagePoints[i].x;
614
dy = ry - imagePoints[i].y;
615
616
meanDx += dx;
617
meanDy += dy;
618
619
imageMeanDx += dx*dx;
620
imageMeanDy += dy*dy;
621
622
dx = fabs(dx);
623
dy = fabs(dy);
624
625
if( dx > maxDx )
626
maxDx = dx;
627
628
if( dy > maxDy )
629
maxDy = dy;
630
i++;
631
}
632
goodPerViewErrors[currImage] = sqrt( (imageMeanDx + imageMeanDy) /
633
(etalonSize.width * etalonSize.height));
634
635
//only for c-version of test (it does not provides evaluation of perViewErrors
636
//and returns zeros)
637
if(perViewErrors[currImage] == 0.0)
638
perViewErrors[currImage] = goodPerViewErrors[currImage];
639
}
640
641
meanDx /= numImages * etalonSize.width * etalonSize.height;
642
meanDy /= numImages * etalonSize.width * etalonSize.height;
643
644
/* ========= Compare parameters ========= */
645
646
/* ----- Compare focal lengths ----- */
647
code = compare(cameraMatrix+0,&goodFcx,1,0.1,"fx");
648
if( code < 0 )
649
goto _exit_;
650
651
code = compare(cameraMatrix+4,&goodFcy,1,0.1,"fy");
652
if( code < 0 )
653
goto _exit_;
654
655
/* ----- Compare principal points ----- */
656
code = compare(cameraMatrix+2,&goodCx,1,0.1,"cx");
657
if( code < 0 )
658
goto _exit_;
659
660
code = compare(cameraMatrix+5,&goodCy,1,0.1,"cy");
661
if( code < 0 )
662
goto _exit_;
663
664
/* ----- Compare distortion ----- */
665
code = compare(distortion,goodDistortion,4,0.1,"[k1,k2,p1,p2]");
666
if( code < 0 )
667
goto _exit_;
668
669
/* ----- Compare rot matrixs ----- */
670
code = compare(rotMatrs,goodRotMatrs, 9*numImages,0.05,"rotation matrices");
671
if( code < 0 )
672
goto _exit_;
673
674
/* ----- Compare rot matrixs ----- */
675
code = compare(transVects,goodTransVects, 3*numImages,0.1,"translation vectors");
676
if( code < 0 )
677
goto _exit_;
678
679
/* ----- Compare refined 3D object points ----- */
680
if( releaseObject )
681
{
682
code = compare(newObjPoints,goodObjPoints, 3*numbers[0],0.1,"refined 3D object points");
683
if( code < 0 )
684
goto _exit_;
685
}
686
687
/* ----- Compare per view re-projection errors ----- */
688
code = compare(perViewErrors,goodPerViewErrors, numImages,0.1,"per view errors vector");
689
if( code < 0 )
690
goto _exit_;
691
692
/* ----- Compare standard deviations of parameters ----- */
693
//only for c-version of test (it does not provides evaluation of stdDevs
694
//and returns zeros)
695
for ( i = 0; i < CV_CALIB_NINTRINSIC + 6*numImages + 3*numbers[0]; i++)
696
{
697
if(stdDevs[i] == 0.0)
698
stdDevs[i] = goodStdDevs[i];
699
}
700
code = compare(stdDevs,goodStdDevs, CV_CALIB_NINTRINSIC + 6*numImages + 3*numbers[0],.5,
701
"stdDevs vector");
702
if( code < 0 )
703
goto _exit_;
704
705
if( maxDx > 1.0 )
706
{
707
ts->printf( cvtest::TS::LOG,
708
"Error in reprojection maxDx=%f > 1.0\n",maxDx);
709
code = cvtest::TS::FAIL_BAD_ACCURACY; goto _exit_;
710
}
711
712
if( maxDy > 1.0 )
713
{
714
ts->printf( cvtest::TS::LOG,
715
"Error in reprojection maxDy=%f > 1.0\n",maxDy);
716
code = cvtest::TS::FAIL_BAD_ACCURACY; goto _exit_;
717
}
718
719
progress = update_progress( progress, currTest, numTests, 0 );
720
721
cvFree(&imagePoints);
722
cvFree(&objectPoints);
723
cvFree(&reprojectPoints);
724
cvFree(&numbers);
725
726
cvFree(&transVects);
727
cvFree(&rotMatrs);
728
cvFree(&newObjPoints);
729
cvFree(&stdDevs);
730
cvFree(&perViewErrors);
731
cvFree(&goodTransVects);
732
cvFree(&goodRotMatrs);
733
cvFree(&goodObjPoints);
734
cvFree(&goodPerViewErrors);
735
cvFree(&goodStdDevs);
736
737
fclose(file);
738
file = 0;
739
}
740
741
_exit_:
742
743
if( file )
744
fclose(file);
745
746
if( datafile )
747
fclose(datafile);
748
749
/* Free all allocated memory */
750
cvFree(&imagePoints);
751
cvFree(&objectPoints);
752
cvFree(&reprojectPoints);
753
cvFree(&numbers);
754
755
cvFree(&transVects);
756
cvFree(&rotMatrs);
757
cvFree(&goodTransVects);
758
cvFree(&goodRotMatrs);
759
760
if( code < 0 )
761
ts->set_failed_test_info( code );
762
}
763
764
// --------------------------------- CV_CameraCalibrationTest_C --------------------------------------------
765
766
class CV_CameraCalibrationTest_C : public CV_CameraCalibrationTest
767
{
768
public:
769
CV_CameraCalibrationTest_C(){}
770
protected:
771
virtual void calibrate( int imageCount, int* pointCounts,
772
CvSize imageSize, CvPoint2D64f* imagePoints, CvPoint3D64f* objectPoints, int iFixedPoint,
773
double* distortionCoeffs, double* cameraMatrix, double* translationVectors,
774
double* rotationMatrices, double* newObjPoints, double *stdDevs, double* perViewErrors,
775
int flags );
776
virtual void project( int pointCount, CvPoint3D64f* objectPoints,
777
double* rotationMatrix, double* translationVector,
778
double* cameraMatrix, double* distortion, CvPoint2D64f* imagePoints );
779
};
780
781
void CV_CameraCalibrationTest_C::calibrate(int imageCount, int* pointCounts,
782
CvSize imageSize, CvPoint2D64f* imagePoints, CvPoint3D64f* objectPoints, int iFixedPoint,
783
double* distortionCoeffs, double* cameraMatrix, double* translationVectors,
784
double* rotationMatrices, double* newObjPoints, double *stdDevs, double *perViewErrors,
785
int flags )
786
{
787
int i, total = 0;
788
for( i = 0; i < imageCount; i++ )
789
{
790
perViewErrors[i] = 0.0;
791
total += pointCounts[i];
792
}
793
794
for( i = 0; i < CV_CALIB_NINTRINSIC + imageCount*6 + pointCounts[0]*3; i++)
795
{
796
stdDevs[i] = 0.0;
797
}
798
799
CvMat _objectPoints = cvMat(1, total, CV_64FC3, objectPoints);
800
CvMat _imagePoints = cvMat(1, total, CV_64FC2, imagePoints);
801
CvMat _pointCounts = cvMat(1, imageCount, CV_32S, pointCounts);
802
CvMat _cameraMatrix = cvMat(3, 3, CV_64F, cameraMatrix);
803
CvMat _distCoeffs = cvMat(4, 1, CV_64F, distortionCoeffs);
804
CvMat _rotationMatrices = cvMat(imageCount, 9, CV_64F, rotationMatrices);
805
CvMat _translationVectors = cvMat(imageCount, 3, CV_64F, translationVectors);
806
CvMat _newObjPoints = cvMat(1, pointCounts[0], CV_64FC3, newObjPoints);
807
808
cvCalibrateCamera4(&_objectPoints, &_imagePoints, &_pointCounts, imageSize, iFixedPoint,
809
&_cameraMatrix, &_distCoeffs, &_rotationMatrices, &_translationVectors,
810
&_newObjPoints, flags);
811
}
812
813
void CV_CameraCalibrationTest_C::project( int pointCount, CvPoint3D64f* objectPoints,
814
double* rotationMatrix, double* translationVector,
815
double* cameraMatrix, double* distortion, CvPoint2D64f* imagePoints )
816
{
817
CvMat _objectPoints = cvMat(1, pointCount, CV_64FC3, objectPoints);
818
CvMat _imagePoints = cvMat(1, pointCount, CV_64FC2, imagePoints);
819
CvMat _cameraMatrix = cvMat(3, 3, CV_64F, cameraMatrix);
820
CvMat _distCoeffs = cvMat(4, 1, CV_64F, distortion);
821
CvMat _rotationMatrix = cvMat(3, 3, CV_64F, rotationMatrix);
822
CvMat _translationVector = cvMat(1, 3, CV_64F, translationVector);
823
824
cvProjectPoints2(&_objectPoints, &_rotationMatrix, &_translationVector, &_cameraMatrix, &_distCoeffs, &_imagePoints);
825
}
826
827
// --------------------------------- CV_CameraCalibrationTest_CPP --------------------------------------------
828
829
class CV_CameraCalibrationTest_CPP : public CV_CameraCalibrationTest
830
{
831
public:
832
CV_CameraCalibrationTest_CPP(){}
833
protected:
834
virtual void calibrate( int imageCount, int* pointCounts,
835
CvSize imageSize, CvPoint2D64f* imagePoints, CvPoint3D64f* objectPoints, int iFixedPoint,
836
double* distortionCoeffs, double* cameraMatrix, double* translationVectors,
837
double* rotationMatrices, double* newObjPoints, double *stdDevs, double* perViewErrors,
838
int flags );
839
virtual void project( int pointCount, CvPoint3D64f* objectPoints,
840
double* rotationMatrix, double* translationVector,
841
double* cameraMatrix, double* distortion, CvPoint2D64f* imagePoints );
842
};
843
844
void CV_CameraCalibrationTest_CPP::calibrate(int imageCount, int* pointCounts,
845
CvSize _imageSize, CvPoint2D64f* _imagePoints, CvPoint3D64f* _objectPoints, int iFixedPoint,
846
double* _distortionCoeffs, double* _cameraMatrix, double* translationVectors,
847
double* rotationMatrices, double* newObjPoints, double *stdDevs, double *perViewErrors,
848
int flags )
849
{
850
vector<vector<Point3f> > objectPoints( imageCount );
851
vector<vector<Point2f> > imagePoints( imageCount );
852
Size imageSize = _imageSize;
853
Mat cameraMatrix, distCoeffs(1,4,CV_64F,Scalar::all(0));
854
vector<Mat> rvecs, tvecs;
855
Mat newObjMat;
856
Mat stdDevsMatInt, stdDevsMatExt;
857
Mat stdDevsMatObj;
858
Mat perViewErrorsMat;
859
860
CvPoint3D64f* op = _objectPoints;
861
CvPoint2D64f* ip = _imagePoints;
862
vector<vector<Point3f> >::iterator objectPointsIt = objectPoints.begin();
863
vector<vector<Point2f> >::iterator imagePointsIt = imagePoints.begin();
864
for( int i = 0; i < imageCount; ++objectPointsIt, ++imagePointsIt, i++ )
865
{
866
int num = pointCounts[i];
867
objectPointsIt->resize( num );
868
imagePointsIt->resize( num );
869
vector<Point3f>::iterator oIt = objectPointsIt->begin();
870
vector<Point2f>::iterator iIt = imagePointsIt->begin();
871
for( int j = 0; j < num; ++oIt, ++iIt, j++, op++, ip++)
872
{
873
oIt->x = (float)op->x, oIt->y = (float)op->y, oIt->z = (float)op->z;
874
iIt->x = (float)ip->x, iIt->y = (float)ip->y;
875
}
876
}
877
878
for( int i = CV_CALIB_NINTRINSIC + imageCount*6; i < CV_CALIB_NINTRINSIC + imageCount*6
879
+ pointCounts[0]*3; i++)
880
{
881
stdDevs[i] = 0.0;
882
}
883
884
calibrateCameraRO( objectPoints,
885
imagePoints,
886
imageSize,
887
iFixedPoint,
888
cameraMatrix,
889
distCoeffs,
890
rvecs,
891
tvecs,
892
newObjMat,
893
stdDevsMatInt,
894
stdDevsMatExt,
895
stdDevsMatObj,
896
perViewErrorsMat,
897
flags );
898
899
bool releaseObject = iFixedPoint > 0 && iFixedPoint < pointCounts[0] - 1;
900
if( releaseObject )
901
{
902
newObjMat.convertTo( newObjMat, CV_64F );
903
assert( newObjMat.total() * newObjMat.channels() == static_cast<size_t>(3*pointCounts[0]) );
904
memcpy( newObjPoints, newObjMat.ptr(), 3*pointCounts[0]*sizeof(double) );
905
}
906
907
assert( stdDevsMatInt.type() == CV_64F );
908
assert( stdDevsMatInt.total() == static_cast<size_t>(CV_CALIB_NINTRINSIC) );
909
memcpy( stdDevs, stdDevsMatInt.ptr(), CV_CALIB_NINTRINSIC*sizeof(double) );
910
911
assert( stdDevsMatExt.type() == CV_64F );
912
assert( stdDevsMatExt.total() == static_cast<size_t>(6*imageCount) );
913
memcpy( stdDevs + CV_CALIB_NINTRINSIC, stdDevsMatExt.ptr(), 6*imageCount*sizeof(double) );
914
915
if( releaseObject )
916
{
917
assert( stdDevsMatObj.type() == CV_64F );
918
assert( stdDevsMatObj.total() == static_cast<size_t>(3*pointCounts[0]) );
919
memcpy( stdDevs + CV_CALIB_NINTRINSIC + 6*imageCount, stdDevsMatObj.ptr(),
920
3*pointCounts[0]*sizeof(double) );
921
}
922
923
assert( perViewErrorsMat.type() == CV_64F);
924
assert( perViewErrorsMat.total() == static_cast<size_t>(imageCount) );
925
memcpy( perViewErrors, perViewErrorsMat.ptr(), imageCount*sizeof(double) );
926
927
assert( cameraMatrix.type() == CV_64FC1 );
928
memcpy( _cameraMatrix, cameraMatrix.ptr(), 9*sizeof(double) );
929
930
assert( cameraMatrix.type() == CV_64FC1 );
931
memcpy( _distortionCoeffs, distCoeffs.ptr(), 4*sizeof(double) );
932
933
vector<Mat>::iterator rvecsIt = rvecs.begin();
934
vector<Mat>::iterator tvecsIt = tvecs.begin();
935
double *rm = rotationMatrices,
936
*tm = translationVectors;
937
assert( rvecsIt->type() == CV_64FC1 );
938
assert( tvecsIt->type() == CV_64FC1 );
939
for( int i = 0; i < imageCount; ++rvecsIt, ++tvecsIt, i++, rm+=9, tm+=3 )
940
{
941
Mat r9( 3, 3, CV_64FC1 );
942
cvtest::Rodrigues( *rvecsIt, r9 );
943
memcpy( rm, r9.ptr(), 9*sizeof(double) );
944
memcpy( tm, tvecsIt->ptr(), 3*sizeof(double) );
945
}
946
}
947
948
void CV_CameraCalibrationTest_CPP::project( int pointCount, CvPoint3D64f* _objectPoints,
949
double* rotationMatrix, double* translationVector,
950
double* _cameraMatrix, double* distortion, CvPoint2D64f* _imagePoints )
951
{
952
Mat objectPoints( pointCount, 3, CV_64FC1, _objectPoints );
953
Mat rmat( 3, 3, CV_64FC1, rotationMatrix ),
954
rvec( 1, 3, CV_64FC1 ),
955
tvec( 1, 3, CV_64FC1, translationVector );
956
Mat cameraMatrix( 3, 3, CV_64FC1, _cameraMatrix );
957
Mat distCoeffs( 1, 4, CV_64FC1, distortion );
958
vector<Point2f> imagePoints;
959
cvtest::Rodrigues( rmat, rvec );
960
961
objectPoints.convertTo( objectPoints, CV_32FC1 );
962
projectPoints( objectPoints, rvec, tvec,
963
cameraMatrix, distCoeffs, imagePoints );
964
vector<Point2f>::const_iterator it = imagePoints.begin();
965
for( int i = 0; it != imagePoints.end(); ++it, i++ )
966
{
967
_imagePoints[i] = cvPoint2D64f( it->x, it->y );
968
}
969
}
970
971
972
//----------------------------------------- CV_CalibrationMatrixValuesTest --------------------------------
973
974
class CV_CalibrationMatrixValuesTest : public cvtest::BaseTest
975
{
976
public:
977
CV_CalibrationMatrixValuesTest() {}
978
protected:
979
void run(int);
980
virtual void calibMatrixValues( const Mat& cameraMatrix, Size imageSize,
981
double apertureWidth, double apertureHeight, double& fovx, double& fovy, double& focalLength,
982
Point2d& principalPoint, double& aspectRatio ) = 0;
983
};
984
985
void CV_CalibrationMatrixValuesTest::run(int)
986
{
987
int code = cvtest::TS::OK;
988
const double fcMinVal = 1e-5;
989
const double fcMaxVal = 1000;
990
const double apertureMaxVal = 0.01;
991
992
RNG rng = ts->get_rng();
993
994
double fx, fy, cx, cy, nx, ny;
995
Mat cameraMatrix( 3, 3, CV_64FC1 );
996
cameraMatrix.setTo( Scalar(0) );
997
fx = cameraMatrix.at<double>(0,0) = rng.uniform( fcMinVal, fcMaxVal );
998
fy = cameraMatrix.at<double>(1,1) = rng.uniform( fcMinVal, fcMaxVal );
999
cx = cameraMatrix.at<double>(0,2) = rng.uniform( fcMinVal, fcMaxVal );
1000
cy = cameraMatrix.at<double>(1,2) = rng.uniform( fcMinVal, fcMaxVal );
1001
cameraMatrix.at<double>(2,2) = 1;
1002
1003
Size imageSize( 600, 400 );
1004
1005
double apertureWidth = (double)rng * apertureMaxVal,
1006
apertureHeight = (double)rng * apertureMaxVal;
1007
1008
double fovx, fovy, focalLength, aspectRatio,
1009
goodFovx, goodFovy, goodFocalLength, goodAspectRatio;
1010
Point2d principalPoint, goodPrincipalPoint;
1011
1012
1013
calibMatrixValues( cameraMatrix, imageSize, apertureWidth, apertureHeight,
1014
fovx, fovy, focalLength, principalPoint, aspectRatio );
1015
1016
// calculate calibration matrix values
1017
goodAspectRatio = fy / fx;
1018
1019
if( apertureWidth != 0.0 && apertureHeight != 0.0 )
1020
{
1021
nx = imageSize.width / apertureWidth;
1022
ny = imageSize.height / apertureHeight;
1023
}
1024
else
1025
{
1026
nx = 1.0;
1027
ny = goodAspectRatio;
1028
}
1029
1030
goodFovx = (atan2(cx, fx) + atan2(imageSize.width - cx, fx)) * 180.0 / CV_PI;
1031
goodFovy = (atan2(cy, fy) + atan2(imageSize.height - cy, fy)) * 180.0 / CV_PI;
1032
1033
goodFocalLength = fx / nx;
1034
1035
goodPrincipalPoint.x = cx / nx;
1036
goodPrincipalPoint.y = cy / ny;
1037
1038
// check results
1039
if( fabs(fovx - goodFovx) > FLT_EPSILON )
1040
{
1041
ts->printf( cvtest::TS::LOG, "bad fovx (real=%f, good = %f\n", fovx, goodFovx );
1042
code = cvtest::TS::FAIL_BAD_ACCURACY;
1043
goto _exit_;
1044
}
1045
if( fabs(fovy - goodFovy) > FLT_EPSILON )
1046
{
1047
ts->printf( cvtest::TS::LOG, "bad fovy (real=%f, good = %f\n", fovy, goodFovy );
1048
code = cvtest::TS::FAIL_BAD_ACCURACY;
1049
goto _exit_;
1050
}
1051
if( fabs(focalLength - goodFocalLength) > FLT_EPSILON )
1052
{
1053
ts->printf( cvtest::TS::LOG, "bad focalLength (real=%f, good = %f\n", focalLength, goodFocalLength );
1054
code = cvtest::TS::FAIL_BAD_ACCURACY;
1055
goto _exit_;
1056
}
1057
if( fabs(aspectRatio - goodAspectRatio) > FLT_EPSILON )
1058
{
1059
ts->printf( cvtest::TS::LOG, "bad aspectRatio (real=%f, good = %f\n", aspectRatio, goodAspectRatio );
1060
code = cvtest::TS::FAIL_BAD_ACCURACY;
1061
goto _exit_;
1062
}
1063
if( cv::norm(principalPoint - goodPrincipalPoint) > FLT_EPSILON ) // Point2d
1064
{
1065
ts->printf( cvtest::TS::LOG, "bad principalPoint\n" );
1066
code = cvtest::TS::FAIL_BAD_ACCURACY;
1067
goto _exit_;
1068
}
1069
1070
_exit_:
1071
RNG& _rng = ts->get_rng();
1072
_rng = rng;
1073
ts->set_failed_test_info( code );
1074
}
1075
1076
//----------------------------------------- CV_CalibrationMatrixValuesTest_C --------------------------------
1077
1078
class CV_CalibrationMatrixValuesTest_C : public CV_CalibrationMatrixValuesTest
1079
{
1080
public:
1081
CV_CalibrationMatrixValuesTest_C(){}
1082
protected:
1083
virtual void calibMatrixValues( const Mat& cameraMatrix, Size imageSize,
1084
double apertureWidth, double apertureHeight, double& fovx, double& fovy, double& focalLength,
1085
Point2d& principalPoint, double& aspectRatio );
1086
};
1087
1088
void CV_CalibrationMatrixValuesTest_C::calibMatrixValues( const Mat& _cameraMatrix, Size imageSize,
1089
double apertureWidth, double apertureHeight,
1090
double& fovx, double& fovy, double& focalLength,
1091
Point2d& principalPoint, double& aspectRatio )
1092
{
1093
CvMat cameraMatrix = cvMat(_cameraMatrix);
1094
CvPoint2D64f pp = {0, 0};
1095
cvCalibrationMatrixValues( &cameraMatrix, cvSize(imageSize), apertureWidth, apertureHeight,
1096
&fovx, &fovy, &focalLength, &pp, &aspectRatio );
1097
principalPoint.x = pp.x;
1098
principalPoint.y = pp.y;
1099
}
1100
1101
1102
//----------------------------------------- CV_CalibrationMatrixValuesTest_CPP --------------------------------
1103
1104
class CV_CalibrationMatrixValuesTest_CPP : public CV_CalibrationMatrixValuesTest
1105
{
1106
public:
1107
CV_CalibrationMatrixValuesTest_CPP() {}
1108
protected:
1109
virtual void calibMatrixValues( const Mat& cameraMatrix, Size imageSize,
1110
double apertureWidth, double apertureHeight, double& fovx, double& fovy, double& focalLength,
1111
Point2d& principalPoint, double& aspectRatio );
1112
};
1113
1114
void CV_CalibrationMatrixValuesTest_CPP::calibMatrixValues( const Mat& cameraMatrix, Size imageSize,
1115
double apertureWidth, double apertureHeight,
1116
double& fovx, double& fovy, double& focalLength,
1117
Point2d& principalPoint, double& aspectRatio )
1118
{
1119
calibrationMatrixValues( cameraMatrix, imageSize, apertureWidth, apertureHeight,
1120
fovx, fovy, focalLength, principalPoint, aspectRatio );
1121
}
1122
1123
1124
//----------------------------------------- CV_ProjectPointsTest --------------------------------
1125
void calcdfdx( const vector<vector<Point2f> >& leftF, const vector<vector<Point2f> >& rightF, double eps, Mat& dfdx )
1126
{
1127
const int fdim = 2;
1128
CV_Assert( !leftF.empty() && !rightF.empty() && !leftF[0].empty() && !rightF[0].empty() );
1129
CV_Assert( leftF[0].size() == rightF[0].size() );
1130
CV_Assert( fabs(eps) > std::numeric_limits<double>::epsilon() );
1131
int fcount = (int)leftF[0].size(), xdim = (int)leftF.size();
1132
1133
dfdx.create( fcount*fdim, xdim, CV_64FC1 );
1134
1135
vector<vector<Point2f> >::const_iterator arrLeftIt = leftF.begin();
1136
vector<vector<Point2f> >::const_iterator arrRightIt = rightF.begin();
1137
for( int xi = 0; xi < xdim; xi++, ++arrLeftIt, ++arrRightIt )
1138
{
1139
CV_Assert( (int)arrLeftIt->size() == fcount );
1140
CV_Assert( (int)arrRightIt->size() == fcount );
1141
vector<Point2f>::const_iterator lIt = arrLeftIt->begin();
1142
vector<Point2f>::const_iterator rIt = arrRightIt->begin();
1143
for( int fi = 0; fi < dfdx.rows; fi+=fdim, ++lIt, ++rIt )
1144
{
1145
dfdx.at<double>(fi, xi ) = 0.5 * ((double)(rIt->x - lIt->x)) / eps;
1146
dfdx.at<double>(fi+1, xi ) = 0.5 * ((double)(rIt->y - lIt->y)) / eps;
1147
}
1148
}
1149
}
1150
1151
class CV_ProjectPointsTest : public cvtest::BaseTest
1152
{
1153
public:
1154
CV_ProjectPointsTest() {}
1155
protected:
1156
void run(int);
1157
virtual void project( const Mat& objectPoints,
1158
const Mat& rvec, const Mat& tvec,
1159
const Mat& cameraMatrix,
1160
const Mat& distCoeffs,
1161
vector<Point2f>& imagePoints,
1162
Mat& dpdrot, Mat& dpdt, Mat& dpdf,
1163
Mat& dpdc, Mat& dpddist,
1164
double aspectRatio=0 ) = 0;
1165
};
1166
1167
void CV_ProjectPointsTest::run(int)
1168
{
1169
//typedef float matType;
1170
1171
int code = cvtest::TS::OK;
1172
const int pointCount = 100;
1173
1174
const float zMinVal = 10.0f, zMaxVal = 100.0f,
1175
rMinVal = -0.3f, rMaxVal = 0.3f,
1176
tMinVal = -2.0f, tMaxVal = 2.0f;
1177
1178
const float imgPointErr = 1e-3f,
1179
dEps = 1e-3f;
1180
1181
double err;
1182
1183
Size imgSize( 600, 800 );
1184
Mat_<float> objPoints( pointCount, 3), rvec( 1, 3), rmat, tvec( 1, 3 ), cameraMatrix( 3, 3 ), distCoeffs( 1, 4 ),
1185
leftRvec, rightRvec, leftTvec, rightTvec, leftCameraMatrix, rightCameraMatrix, leftDistCoeffs, rightDistCoeffs;
1186
1187
RNG rng = ts->get_rng();
1188
1189
// generate data
1190
cameraMatrix << 300.f, 0.f, imgSize.width/2.f,
1191
0.f, 300.f, imgSize.height/2.f,
1192
0.f, 0.f, 1.f;
1193
distCoeffs << 0.1, 0.01, 0.001, 0.001;
1194
1195
rvec(0,0) = rng.uniform( rMinVal, rMaxVal );
1196
rvec(0,1) = rng.uniform( rMinVal, rMaxVal );
1197
rvec(0,2) = rng.uniform( rMinVal, rMaxVal );
1198
rmat = cv::Mat_<float>::zeros(3, 3);
1199
cvtest::Rodrigues( rvec, rmat );
1200
1201
tvec(0,0) = rng.uniform( tMinVal, tMaxVal );
1202
tvec(0,1) = rng.uniform( tMinVal, tMaxVal );
1203
tvec(0,2) = rng.uniform( tMinVal, tMaxVal );
1204
1205
for( int y = 0; y < objPoints.rows; y++ )
1206
{
1207
Mat point(1, 3, CV_32FC1, objPoints.ptr(y) );
1208
float z = rng.uniform( zMinVal, zMaxVal );
1209
point.at<float>(0,2) = z;
1210
point.at<float>(0,0) = (rng.uniform(2.f,(float)(imgSize.width-2)) - cameraMatrix(0,2)) / cameraMatrix(0,0) * z;
1211
point.at<float>(0,1) = (rng.uniform(2.f,(float)(imgSize.height-2)) - cameraMatrix(1,2)) / cameraMatrix(1,1) * z;
1212
point = (point - tvec) * rmat;
1213
}
1214
1215
vector<Point2f> imgPoints;
1216
vector<vector<Point2f> > leftImgPoints;
1217
vector<vector<Point2f> > rightImgPoints;
1218
Mat dpdrot, dpdt, dpdf, dpdc, dpddist,
1219
valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist;
1220
1221
project( objPoints, rvec, tvec, cameraMatrix, distCoeffs,
1222
imgPoints, dpdrot, dpdt, dpdf, dpdc, dpddist, 0 );
1223
1224
// calculate and check image points
1225
assert( (int)imgPoints.size() == pointCount );
1226
vector<Point2f>::const_iterator it = imgPoints.begin();
1227
for( int i = 0; i < pointCount; i++, ++it )
1228
{
1229
Point3d p( objPoints(i,0), objPoints(i,1), objPoints(i,2) );
1230
double z = p.x*rmat(2,0) + p.y*rmat(2,1) + p.z*rmat(2,2) + tvec(0,2),
1231
x = (p.x*rmat(0,0) + p.y*rmat(0,1) + p.z*rmat(0,2) + tvec(0,0)) / z,
1232
y = (p.x*rmat(1,0) + p.y*rmat(1,1) + p.z*rmat(1,2) + tvec(0,1)) / z,
1233
r2 = x*x + y*y,
1234
r4 = r2*r2;
1235
Point2f validImgPoint;
1236
double a1 = 2*x*y,
1237
a2 = r2 + 2*x*x,
1238
a3 = r2 + 2*y*y,
1239
cdist = 1+distCoeffs(0,0)*r2+distCoeffs(0,1)*r4;
1240
validImgPoint.x = static_cast<float>((double)cameraMatrix(0,0)*(x*cdist + (double)distCoeffs(0,2)*a1 + (double)distCoeffs(0,3)*a2)
1241
+ (double)cameraMatrix(0,2));
1242
validImgPoint.y = static_cast<float>((double)cameraMatrix(1,1)*(y*cdist + (double)distCoeffs(0,2)*a3 + distCoeffs(0,3)*a1)
1243
+ (double)cameraMatrix(1,2));
1244
1245
if( fabs(it->x - validImgPoint.x) > imgPointErr ||
1246
fabs(it->y - validImgPoint.y) > imgPointErr )
1247
{
1248
ts->printf( cvtest::TS::LOG, "bad image point\n" );
1249
code = cvtest::TS::FAIL_BAD_ACCURACY;
1250
goto _exit_;
1251
}
1252
}
1253
1254
// check derivatives
1255
// 1. rotation
1256
leftImgPoints.resize(3);
1257
rightImgPoints.resize(3);
1258
for( int i = 0; i < 3; i++ )
1259
{
1260
rvec.copyTo( leftRvec ); leftRvec(0,i) -= dEps;
1261
project( objPoints, leftRvec, tvec, cameraMatrix, distCoeffs,
1262
leftImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
1263
rvec.copyTo( rightRvec ); rightRvec(0,i) += dEps;
1264
project( objPoints, rightRvec, tvec, cameraMatrix, distCoeffs,
1265
rightImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
1266
}
1267
calcdfdx( leftImgPoints, rightImgPoints, dEps, valDpdrot );
1268
err = cvtest::norm( dpdrot, valDpdrot, NORM_INF );
1269
if( err > 3 )
1270
{
1271
ts->printf( cvtest::TS::LOG, "bad dpdrot: too big difference = %g\n", err );
1272
code = cvtest::TS::FAIL_BAD_ACCURACY;
1273
}
1274
1275
// 2. translation
1276
for( int i = 0; i < 3; i++ )
1277
{
1278
tvec.copyTo( leftTvec ); leftTvec(0,i) -= dEps;
1279
project( objPoints, rvec, leftTvec, cameraMatrix, distCoeffs,
1280
leftImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
1281
tvec.copyTo( rightTvec ); rightTvec(0,i) += dEps;
1282
project( objPoints, rvec, rightTvec, cameraMatrix, distCoeffs,
1283
rightImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
1284
}
1285
calcdfdx( leftImgPoints, rightImgPoints, dEps, valDpdt );
1286
if( cvtest::norm( dpdt, valDpdt, NORM_INF ) > 0.2 )
1287
{
1288
ts->printf( cvtest::TS::LOG, "bad dpdtvec\n" );
1289
code = cvtest::TS::FAIL_BAD_ACCURACY;
1290
}
1291
1292
// 3. camera matrix
1293
// 3.1. focus
1294
leftImgPoints.resize(2);
1295
rightImgPoints.resize(2);
1296
cameraMatrix.copyTo( leftCameraMatrix ); leftCameraMatrix(0,0) -= dEps;
1297
project( objPoints, rvec, tvec, leftCameraMatrix, distCoeffs,
1298
leftImgPoints[0], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
1299
cameraMatrix.copyTo( leftCameraMatrix ); leftCameraMatrix(1,1) -= dEps;
1300
project( objPoints, rvec, tvec, leftCameraMatrix, distCoeffs,
1301
leftImgPoints[1], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
1302
cameraMatrix.copyTo( rightCameraMatrix ); rightCameraMatrix(0,0) += dEps;
1303
project( objPoints, rvec, tvec, rightCameraMatrix, distCoeffs,
1304
rightImgPoints[0], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
1305
cameraMatrix.copyTo( rightCameraMatrix ); rightCameraMatrix(1,1) += dEps;
1306
project( objPoints, rvec, tvec, rightCameraMatrix, distCoeffs,
1307
rightImgPoints[1], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
1308
calcdfdx( leftImgPoints, rightImgPoints, dEps, valDpdf );
1309
if ( cvtest::norm( dpdf, valDpdf, NORM_L2 ) > 0.2 )
1310
{
1311
ts->printf( cvtest::TS::LOG, "bad dpdf\n" );
1312
code = cvtest::TS::FAIL_BAD_ACCURACY;
1313
}
1314
// 3.2. principal point
1315
leftImgPoints.resize(2);
1316
rightImgPoints.resize(2);
1317
cameraMatrix.copyTo( leftCameraMatrix ); leftCameraMatrix(0,2) -= dEps;
1318
project( objPoints, rvec, tvec, leftCameraMatrix, distCoeffs,
1319
leftImgPoints[0], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
1320
cameraMatrix.copyTo( leftCameraMatrix ); leftCameraMatrix(1,2) -= dEps;
1321
project( objPoints, rvec, tvec, leftCameraMatrix, distCoeffs,
1322
leftImgPoints[1], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
1323
cameraMatrix.copyTo( rightCameraMatrix ); rightCameraMatrix(0,2) += dEps;
1324
project( objPoints, rvec, tvec, rightCameraMatrix, distCoeffs,
1325
rightImgPoints[0], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
1326
cameraMatrix.copyTo( rightCameraMatrix ); rightCameraMatrix(1,2) += dEps;
1327
project( objPoints, rvec, tvec, rightCameraMatrix, distCoeffs,
1328
rightImgPoints[1], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
1329
calcdfdx( leftImgPoints, rightImgPoints, dEps, valDpdc );
1330
if ( cvtest::norm( dpdc, valDpdc, NORM_L2 ) > 0.2 )
1331
{
1332
ts->printf( cvtest::TS::LOG, "bad dpdc\n" );
1333
code = cvtest::TS::FAIL_BAD_ACCURACY;
1334
}
1335
1336
// 4. distortion
1337
leftImgPoints.resize(distCoeffs.cols);
1338
rightImgPoints.resize(distCoeffs.cols);
1339
for( int i = 0; i < distCoeffs.cols; i++ )
1340
{
1341
distCoeffs.copyTo( leftDistCoeffs ); leftDistCoeffs(0,i) -= dEps;
1342
project( objPoints, rvec, tvec, cameraMatrix, leftDistCoeffs,
1343
leftImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
1344
distCoeffs.copyTo( rightDistCoeffs ); rightDistCoeffs(0,i) += dEps;
1345
project( objPoints, rvec, tvec, cameraMatrix, rightDistCoeffs,
1346
rightImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
1347
}
1348
calcdfdx( leftImgPoints, rightImgPoints, dEps, valDpddist );
1349
if( cvtest::norm( dpddist, valDpddist, NORM_L2 ) > 0.3 )
1350
{
1351
ts->printf( cvtest::TS::LOG, "bad dpddist\n" );
1352
code = cvtest::TS::FAIL_BAD_ACCURACY;
1353
}
1354
1355
_exit_:
1356
RNG& _rng = ts->get_rng();
1357
_rng = rng;
1358
ts->set_failed_test_info( code );
1359
}
1360
1361
//----------------------------------------- CV_ProjectPointsTest_C --------------------------------
1362
class CV_ProjectPointsTest_C : public CV_ProjectPointsTest
1363
{
1364
public:
1365
CV_ProjectPointsTest_C() {}
1366
protected:
1367
virtual void project( const Mat& objectPoints,
1368
const Mat& rvec, const Mat& tvec,
1369
const Mat& cameraMatrix,
1370
const Mat& distCoeffs,
1371
vector<Point2f>& imagePoints,
1372
Mat& dpdrot, Mat& dpdt, Mat& dpdf,
1373
Mat& dpdc, Mat& dpddist,
1374
double aspectRatio=0 );
1375
};
1376
1377
void CV_ProjectPointsTest_C::project( const Mat& opoints, const Mat& rvec, const Mat& tvec,
1378
const Mat& cameraMatrix, const Mat& distCoeffs, vector<Point2f>& ipoints,
1379
Mat& dpdrot, Mat& dpdt, Mat& dpdf, Mat& dpdc, Mat& dpddist, double aspectRatio)
1380
{
1381
int npoints = opoints.cols*opoints.rows*opoints.channels()/3;
1382
ipoints.resize(npoints);
1383
dpdrot.create(npoints*2, 3, CV_64F);
1384
dpdt.create(npoints*2, 3, CV_64F);
1385
dpdf.create(npoints*2, 2, CV_64F);
1386
dpdc.create(npoints*2, 2, CV_64F);
1387
dpddist.create(npoints*2, distCoeffs.rows + distCoeffs.cols - 1, CV_64F);
1388
Mat imagePoints(ipoints);
1389
CvMat _objectPoints = cvMat(opoints), _imagePoints = cvMat(imagePoints);
1390
CvMat _rvec = cvMat(rvec), _tvec = cvMat(tvec), _cameraMatrix = cvMat(cameraMatrix), _distCoeffs = cvMat(distCoeffs);
1391
CvMat _dpdrot = cvMat(dpdrot), _dpdt = cvMat(dpdt), _dpdf = cvMat(dpdf), _dpdc = cvMat(dpdc), _dpddist = cvMat(dpddist);
1392
1393
cvProjectPoints2( &_objectPoints, &_rvec, &_tvec, &_cameraMatrix, &_distCoeffs,
1394
&_imagePoints, &_dpdrot, &_dpdt, &_dpdf, &_dpdc, &_dpddist, aspectRatio );
1395
}
1396
1397
1398
//----------------------------------------- CV_ProjectPointsTest_CPP --------------------------------
1399
class CV_ProjectPointsTest_CPP : public CV_ProjectPointsTest
1400
{
1401
public:
1402
CV_ProjectPointsTest_CPP() {}
1403
protected:
1404
virtual void project( const Mat& objectPoints,
1405
const Mat& rvec, const Mat& tvec,
1406
const Mat& cameraMatrix,
1407
const Mat& distCoeffs,
1408
vector<Point2f>& imagePoints,
1409
Mat& dpdrot, Mat& dpdt, Mat& dpdf,
1410
Mat& dpdc, Mat& dpddist,
1411
double aspectRatio=0 );
1412
};
1413
1414
void CV_ProjectPointsTest_CPP::project( const Mat& objectPoints, const Mat& rvec, const Mat& tvec,
1415
const Mat& cameraMatrix, const Mat& distCoeffs, vector<Point2f>& imagePoints,
1416
Mat& dpdrot, Mat& dpdt, Mat& dpdf, Mat& dpdc, Mat& dpddist, double aspectRatio)
1417
{
1418
Mat J;
1419
projectPoints( objectPoints, rvec, tvec, cameraMatrix, distCoeffs, imagePoints, J, aspectRatio);
1420
J.colRange(0, 3).copyTo(dpdrot);
1421
J.colRange(3, 6).copyTo(dpdt);
1422
J.colRange(6, 8).copyTo(dpdf);
1423
J.colRange(8, 10).copyTo(dpdc);
1424
J.colRange(10, J.cols).copyTo(dpddist);
1425
}
1426
1427
///////////////////////////////// Stereo Calibration /////////////////////////////////////
1428
1429
class CV_StereoCalibrationCornerTest : public cvtest::BaseTest
1430
{
1431
public:
1432
CV_StereoCalibrationCornerTest();
1433
~CV_StereoCalibrationCornerTest();
1434
void clear();
1435
protected:
1436
void run(int);
1437
};
1438
1439
CV_StereoCalibrationCornerTest::CV_StereoCalibrationCornerTest()
1440
{
1441
}
1442
1443
1444
CV_StereoCalibrationCornerTest::~CV_StereoCalibrationCornerTest()
1445
{
1446
clear();
1447
}
1448
1449
void CV_StereoCalibrationCornerTest::clear()
1450
{
1451
cvtest::BaseTest::clear();
1452
}
1453
1454
static bool resizeCameraMatrix(const Mat &in_cm, Mat &dst_cm, double scale)
1455
{
1456
if (in_cm.empty() || in_cm.cols != 3 || in_cm.rows != 3 || in_cm.type() != CV_64FC1)
1457
return false;
1458
dst_cm = in_cm * scale;
1459
dst_cm.at<double>(2, 2) = 1.0;
1460
return true;
1461
}
1462
1463
// see https://github.com/opencv/opencv/pull/6836 for details
1464
void CV_StereoCalibrationCornerTest::run(int)
1465
{
1466
const Matx33d M1(906.7857732303256, 0.0, 1026.456125870669,
1467
0.0, 906.7857732303256, 540.0531577669913,
1468
0.0, 0.0, 1.0);
1469
const Matx33d M2(906.782205162265, 0.0, 1014.619997352785,
1470
0.0, 906.782205162265, 561.9990018887295,
1471
0.0, 0.0, 1.0);
1472
const Matx<double, 5, 1> D1(0.0064836857220181504, 0.033880363848984636, 0.0, 0.0, -0.042996356352306114);
1473
const Matx<double, 5, 1> D2(0.023754068600491646, -0.02364619610835259, 0.0, 0.0, 0.0015014971456262652);
1474
1475
const Size imageSize(2048, 1088);
1476
const double scale = 0.25;
1477
1478
const Matx33d Rot(0.999788461750194, -0.015696495349844446, -0.013291041528534329,
1479
0.015233019205877604, 0.999296086451901, -0.034282455101525826,
1480
0.01381980018141639, 0.03407274036010432, 0.9993238021218641);
1481
const Matx31d T(-1.552005597952028, 0.0019508251875105093, -0.023335501616116062);
1482
1483
// generate camera matrices for resized image rectification.
1484
Mat srcM1(M1), srcM2(M2);
1485
Mat rszM1, rszM2;
1486
resizeCameraMatrix(srcM1, rszM1, scale);
1487
resizeCameraMatrix(srcM2, rszM2, scale);
1488
Size rszImageSize(cvRound(scale * imageSize.width), cvRound(scale * imageSize.height));
1489
Size srcImageSize = imageSize;
1490
// apply stereoRectify
1491
Mat srcR[2], srcP[2], srcQ;
1492
Mat rszR[2], rszP[2], rszQ;
1493
stereoRectify(srcM1, D1, srcM2, D2, srcImageSize, Rot, T,
1494
srcR[0], srcR[1], srcP[0], srcP[1], srcQ,
1495
CALIB_ZERO_DISPARITY, 0);
1496
stereoRectify(rszM1, D1, rszM2, D2, rszImageSize, Rot, T,
1497
rszR[0], rszR[1], rszP[0], rszP[1], rszQ,
1498
CALIB_ZERO_DISPARITY, 0);
1499
// generate remap maps
1500
Mat srcRmap[2], rszRmap[2];
1501
initUndistortRectifyMap(srcM1, D1, srcR[0], srcP[0], srcImageSize, CV_32FC2, srcRmap[0], srcRmap[1]);
1502
initUndistortRectifyMap(rszM1, D1, rszR[0], rszP[0], rszImageSize, CV_32FC2, rszRmap[0], rszRmap[1]);
1503
1504
// generate source image
1505
// it's an artificial pattern with white rect in the center
1506
Mat image(imageSize, CV_8UC3);
1507
image.setTo(0);
1508
image(cv::Rect(imageSize.width / 3, imageSize.height / 3, imageSize.width / 3, imageSize.height / 3)).setTo(255);
1509
1510
// perform remap-resize
1511
Mat src_result;
1512
remap(image, src_result, srcRmap[0], srcRmap[1], INTER_LINEAR);
1513
resize(src_result, src_result, Size(), scale, scale, INTER_LINEAR_EXACT);
1514
// perform resize-remap
1515
Mat rsz_result;
1516
resize(image, rsz_result, Size(), scale, scale, INTER_LINEAR_EXACT);
1517
remap(rsz_result, rsz_result, rszRmap[0], rszRmap[1], INTER_LINEAR);
1518
1519
// modifying the camera matrix with resizeCameraMatrix must yield the same
1520
// result as calibrating the downscaled images
1521
int cnz = countNonZero((cv::Mat(src_result - rsz_result) != 0)(
1522
cv::Rect(src_result.cols / 3, src_result.rows / 3,
1523
(int)(src_result.cols / 3.1), int(src_result.rows / 3.1))));
1524
if (cnz)
1525
{
1526
ts->printf( cvtest::TS::LOG, "The camera matrix is wrong for downscaled image\n");
1527
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
1528
}
1529
}
1530
1531
class CV_StereoCalibrationTest : public cvtest::BaseTest
1532
{
1533
public:
1534
CV_StereoCalibrationTest();
1535
~CV_StereoCalibrationTest();
1536
void clear();
1537
protected:
1538
bool checkPandROI( int test_case_idx,
1539
const Mat& M, const Mat& D, const Mat& R,
1540
const Mat& P, Size imgsize, Rect roi );
1541
1542
// covers of tested functions
1543
virtual double calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
1544
const vector<vector<Point2f> >& imagePoints1,
1545
const vector<vector<Point2f> >& imagePoints2,
1546
Mat& cameraMatrix1, Mat& distCoeffs1,
1547
Mat& cameraMatrix2, Mat& distCoeffs2,
1548
Size imageSize, Mat& R, Mat& T,
1549
Mat& E, Mat& F, TermCriteria criteria, int flags ) = 0;
1550
virtual void rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1,
1551
const Mat& cameraMatrix2, const Mat& distCoeffs2,
1552
Size imageSize, const Mat& R, const Mat& T,
1553
Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q,
1554
double alpha, Size newImageSize,
1555
Rect* validPixROI1, Rect* validPixROI2, int flags ) = 0;
1556
virtual bool rectifyUncalibrated( const Mat& points1,
1557
const Mat& points2, const Mat& F, Size imgSize,
1558
Mat& H1, Mat& H2, double threshold=5 ) = 0;
1559
virtual void triangulate( const Mat& P1, const Mat& P2,
1560
const Mat &points1, const Mat &points2,
1561
Mat &points4D ) = 0;
1562
virtual void correct( const Mat& F,
1563
const Mat &points1, const Mat &points2,
1564
Mat &newPoints1, Mat &newPoints2 ) = 0;
1565
1566
void run(int);
1567
};
1568
1569
1570
CV_StereoCalibrationTest::CV_StereoCalibrationTest()
1571
{
1572
}
1573
1574
1575
CV_StereoCalibrationTest::~CV_StereoCalibrationTest()
1576
{
1577
clear();
1578
}
1579
1580
void CV_StereoCalibrationTest::clear()
1581
{
1582
cvtest::BaseTest::clear();
1583
}
1584
1585
bool CV_StereoCalibrationTest::checkPandROI( int test_case_idx, const Mat& M, const Mat& D, const Mat& R,
1586
const Mat& P, Size imgsize, Rect roi )
1587
{
1588
const double eps = 0.05;
1589
const int N = 21;
1590
int x, y, k;
1591
vector<Point2f> pts, upts;
1592
1593
// step 1. check that all the original points belong to the destination image
1594
for( y = 0; y < N; y++ )
1595
for( x = 0; x < N; x++ )
1596
pts.push_back(Point2f((float)x*imgsize.width/(N-1), (float)y*imgsize.height/(N-1)));
1597
1598
undistortPoints(Mat(pts), upts, M, D, R, P );
1599
for( k = 0; k < N*N; k++ )
1600
if( upts[k].x < -imgsize.width*eps || upts[k].x > imgsize.width*(1+eps) ||
1601
upts[k].y < -imgsize.height*eps || upts[k].y > imgsize.height*(1+eps) )
1602
{
1603
ts->printf(cvtest::TS::LOG, "Test #%d. The point (%g, %g) was mapped to (%g, %g) which is out of image\n",
1604
test_case_idx, pts[k].x, pts[k].y, upts[k].x, upts[k].y);
1605
return false;
1606
}
1607
1608
// step 2. check that all the points inside ROI belong to the original source image
1609
Mat temp(imgsize, CV_8U), utemp, map1, map2;
1610
temp = Scalar::all(1);
1611
initUndistortRectifyMap(M, D, R, P, imgsize, CV_16SC2, map1, map2);
1612
remap(temp, utemp, map1, map2, INTER_LINEAR);
1613
1614
if(roi.x < 0 || roi.y < 0 || roi.x + roi.width > imgsize.width || roi.y + roi.height > imgsize.height)
1615
{
1616
ts->printf(cvtest::TS::LOG, "Test #%d. The ROI=(%d, %d, %d, %d) is outside of the imge rectangle\n",
1617
test_case_idx, roi.x, roi.y, roi.width, roi.height);
1618
return false;
1619
}
1620
double s = sum(utemp(roi))[0];
1621
if( s > roi.area() || roi.area() - s > roi.area()*(1-eps) )
1622
{
1623
ts->printf(cvtest::TS::LOG, "Test #%d. The ratio of black pixels inside the valid ROI (~%g%%) is too large\n",
1624
test_case_idx, s*100./roi.area());
1625
return false;
1626
}
1627
1628
return true;
1629
}
1630
1631
void CV_StereoCalibrationTest::run( int )
1632
{
1633
const int ntests = 1;
1634
const double maxReprojErr = 2;
1635
const double maxScanlineDistErr_c = 3;
1636
const double maxScanlineDistErr_uc = 4;
1637
FILE* f = 0;
1638
1639
for(int testcase = 1; testcase <= ntests; testcase++)
1640
{
1641
cv::String filepath;
1642
char buf[1000];
1643
filepath = cv::format("%scv/stereo/case%d/stereo_calib.txt", ts->get_data_path().c_str(), testcase );
1644
f = fopen(filepath.c_str(), "rt");
1645
Size patternSize;
1646
vector<string> imglist;
1647
1648
if( !f || !fgets(buf, sizeof(buf)-3, f) || sscanf(buf, "%d%d", &patternSize.width, &patternSize.height) != 2 )
1649
{
1650
ts->printf( cvtest::TS::LOG, "The file %s can not be opened or has invalid content\n", filepath.c_str() );
1651
ts->set_failed_test_info( f ? cvtest::TS::FAIL_INVALID_TEST_DATA : cvtest::TS::FAIL_MISSING_TEST_DATA );
1652
if (f)
1653
fclose(f);
1654
return;
1655
}
1656
1657
for(;;)
1658
{
1659
if( !fgets( buf, sizeof(buf)-3, f ))
1660
break;
1661
size_t len = strlen(buf);
1662
while( len > 0 && isspace(buf[len-1]))
1663
buf[--len] = '\0';
1664
if( buf[0] == '#')
1665
continue;
1666
filepath = cv::format("%scv/stereo/case%d/%s", ts->get_data_path().c_str(), testcase, buf );
1667
imglist.push_back(string(filepath));
1668
}
1669
fclose(f);
1670
1671
if( imglist.size() == 0 || imglist.size() % 2 != 0 )
1672
{
1673
ts->printf( cvtest::TS::LOG, "The number of images is 0 or an odd number in the case #%d\n", testcase );
1674
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
1675
return;
1676
}
1677
1678
int nframes = (int)(imglist.size()/2);
1679
int npoints = patternSize.width*patternSize.height;
1680
vector<vector<Point3f> > objpt(nframes);
1681
vector<vector<Point2f> > imgpt1(nframes);
1682
vector<vector<Point2f> > imgpt2(nframes);
1683
Size imgsize;
1684
int total = 0;
1685
1686
for( int i = 0; i < nframes; i++ )
1687
{
1688
Mat left = imread(imglist[i*2]);
1689
Mat right = imread(imglist[i*2+1]);
1690
if(left.empty() || right.empty())
1691
{
1692
ts->printf( cvtest::TS::LOG, "Can not load images %s and %s, testcase %d\n",
1693
imglist[i*2].c_str(), imglist[i*2+1].c_str(), testcase );
1694
ts->set_failed_test_info( cvtest::TS::FAIL_MISSING_TEST_DATA );
1695
return;
1696
}
1697
imgsize = left.size();
1698
bool found1 = findChessboardCorners(left, patternSize, imgpt1[i]);
1699
bool found2 = findChessboardCorners(right, patternSize, imgpt2[i]);
1700
if(!found1 || !found2)
1701
{
1702
ts->printf( cvtest::TS::LOG, "The function could not detect boards (%d x %d) on the images %s and %s, testcase %d\n",
1703
patternSize.width, patternSize.height,
1704
imglist[i*2].c_str(), imglist[i*2+1].c_str(), testcase );
1705
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
1706
return;
1707
}
1708
total += (int)imgpt1[i].size();
1709
for( int j = 0; j < npoints; j++ )
1710
objpt[i].push_back(Point3f((float)(j%patternSize.width), (float)(j/patternSize.width), 0.f));
1711
}
1712
1713
// rectify (calibrated)
1714
Mat M1 = Mat::eye(3,3,CV_64F), M2 = Mat::eye(3,3,CV_64F), D1(5,1,CV_64F), D2(5,1,CV_64F), R, T, E, F;
1715
M1.at<double>(0,2) = M2.at<double>(0,2)=(imgsize.width-1)*0.5;
1716
M1.at<double>(1,2) = M2.at<double>(1,2)=(imgsize.height-1)*0.5;
1717
D1 = Scalar::all(0);
1718
D2 = Scalar::all(0);
1719
double err = calibrateStereoCamera(objpt, imgpt1, imgpt2, M1, D1, M2, D2, imgsize, R, T, E, F,
1720
TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 1e-6),
1721
CV_CALIB_SAME_FOCAL_LENGTH
1722
//+ CV_CALIB_FIX_ASPECT_RATIO
1723
+ CV_CALIB_FIX_PRINCIPAL_POINT
1724
+ CV_CALIB_ZERO_TANGENT_DIST
1725
+ CV_CALIB_FIX_K3
1726
+ CV_CALIB_FIX_K4 + CV_CALIB_FIX_K5 //+ CV_CALIB_FIX_K6
1727
);
1728
err /= nframes*npoints;
1729
if( err > maxReprojErr )
1730
{
1731
ts->printf( cvtest::TS::LOG, "The average reprojection error is too big (=%g), testcase %d\n", err, testcase);
1732
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
1733
return;
1734
}
1735
1736
Mat R1, R2, P1, P2, Q;
1737
Rect roi1, roi2;
1738
rectify(M1, D1, M2, D2, imgsize, R, T, R1, R2, P1, P2, Q, 1, imgsize, &roi1, &roi2, 0);
1739
Mat eye33 = Mat::eye(3,3,CV_64F);
1740
Mat R1t = R1.t(), R2t = R2.t();
1741
1742
if( cvtest::norm(R1t*R1 - eye33, NORM_L2) > 0.01 ||
1743
cvtest::norm(R2t*R2 - eye33, NORM_L2) > 0.01 ||
1744
abs(determinant(F)) > 0.01)
1745
{
1746
ts->printf( cvtest::TS::LOG, "The computed (by rectify) R1 and R2 are not orthogonal,"
1747
"or the computed (by calibrate) F is not singular, testcase %d\n", testcase);
1748
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
1749
return;
1750
}
1751
1752
if(!checkPandROI(testcase, M1, D1, R1, P1, imgsize, roi1))
1753
{
1754
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
1755
return;
1756
}
1757
1758
if(!checkPandROI(testcase, M2, D2, R2, P2, imgsize, roi2))
1759
{
1760
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
1761
return;
1762
}
1763
1764
//check that Tx after rectification is equal to distance between cameras
1765
double tx = fabs(P2.at<double>(0, 3) / P2.at<double>(0, 0));
1766
if (fabs(tx - cvtest::norm(T, NORM_L2)) > 1e-5)
1767
{
1768
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
1769
return;
1770
}
1771
1772
//check that Q reprojects points before the camera
1773
double testPoint[4] = {0.0, 0.0, 100.0, 1.0};
1774
Mat reprojectedTestPoint = Q * Mat_<double>(4, 1, testPoint);
1775
CV_Assert(reprojectedTestPoint.type() == CV_64FC1);
1776
if( reprojectedTestPoint.at<double>(2) / reprojectedTestPoint.at<double>(3) < 0 )
1777
{
1778
ts->printf( cvtest::TS::LOG, "A point after rectification is reprojected behind the camera, testcase %d\n", testcase);
1779
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
1780
}
1781
1782
//check that Q reprojects the same points as reconstructed by triangulation
1783
const float minCoord = -300.0f;
1784
const float maxCoord = 300.0f;
1785
const float minDisparity = 0.1f;
1786
const float maxDisparity = 60.0f;
1787
const int pointsCount = 500;
1788
const float requiredAccuracy = 1e-3f;
1789
const float allowToFail = 0.2f; // 20%
1790
RNG& rng = ts->get_rng();
1791
1792
Mat projectedPoints_1(2, pointsCount, CV_32FC1);
1793
Mat projectedPoints_2(2, pointsCount, CV_32FC1);
1794
Mat disparities(1, pointsCount, CV_32FC1);
1795
1796
rng.fill(projectedPoints_1, RNG::UNIFORM, minCoord, maxCoord);
1797
rng.fill(disparities, RNG::UNIFORM, minDisparity, maxDisparity);
1798
projectedPoints_2.row(0) = projectedPoints_1.row(0) - disparities;
1799
Mat ys_2 = projectedPoints_2.row(1);
1800
projectedPoints_1.row(1).copyTo(ys_2);
1801
1802
Mat points4d;
1803
triangulate(P1, P2, projectedPoints_1, projectedPoints_2, points4d);
1804
Mat homogeneousPoints4d = points4d.t();
1805
const int dimension = 4;
1806
homogeneousPoints4d = homogeneousPoints4d.reshape(dimension);
1807
Mat triangulatedPoints;
1808
convertPointsFromHomogeneous(homogeneousPoints4d, triangulatedPoints);
1809
1810
Mat sparsePoints;
1811
sparsePoints.push_back(projectedPoints_1);
1812
sparsePoints.push_back(disparities);
1813
sparsePoints = sparsePoints.t();
1814
sparsePoints = sparsePoints.reshape(3);
1815
Mat reprojectedPoints;
1816
perspectiveTransform(sparsePoints, reprojectedPoints, Q);
1817
1818
Mat diff;
1819
absdiff(triangulatedPoints, reprojectedPoints, diff);
1820
Mat mask = diff > requiredAccuracy;
1821
mask = mask.reshape(1);
1822
mask = mask.col(0) | mask.col(1) | mask.col(2);
1823
int numFailed = countNonZero(mask);
1824
#if 0
1825
std::cout << "numFailed=" << numFailed << std::endl;
1826
for (int i = 0; i < triangulatedPoints.rows; i++)
1827
{
1828
if (mask.at<uchar>(i))
1829
{
1830
// failed points usually have 'w'~0 (points4d[3])
1831
std::cout << "i=" << i << " triangulatePoints=" << triangulatedPoints.row(i) << " reprojectedPoints=" << reprojectedPoints.row(i) << std::endl <<
1832
" points4d=" << points4d.col(i).t() << " projectedPoints_1=" << projectedPoints_1.col(i).t() << " disparities=" << disparities.col(i).t() << std::endl;
1833
}
1834
}
1835
#endif
1836
1837
if (numFailed >= allowToFail * pointsCount)
1838
{
1839
ts->printf( cvtest::TS::LOG, "Points reprojected with a matrix Q and points reconstructed by triangulation are different (tolerance=%g, failed=%d), testcase %d\n",
1840
requiredAccuracy, numFailed, testcase);
1841
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
1842
}
1843
1844
//check correctMatches
1845
const float constraintAccuracy = 1e-5f;
1846
Mat newPoints1, newPoints2;
1847
Mat points1 = projectedPoints_1.t();
1848
points1 = points1.reshape(2, 1);
1849
Mat points2 = projectedPoints_2.t();
1850
points2 = points2.reshape(2, 1);
1851
correctMatches(F, points1, points2, newPoints1, newPoints2);
1852
Mat newHomogeneousPoints1, newHomogeneousPoints2;
1853
convertPointsToHomogeneous(newPoints1, newHomogeneousPoints1);
1854
convertPointsToHomogeneous(newPoints2, newHomogeneousPoints2);
1855
newHomogeneousPoints1 = newHomogeneousPoints1.reshape(1);
1856
newHomogeneousPoints2 = newHomogeneousPoints2.reshape(1);
1857
Mat typedF;
1858
F.convertTo(typedF, newHomogeneousPoints1.type());
1859
for (int i = 0; i < newHomogeneousPoints1.rows; ++i)
1860
{
1861
Mat error = newHomogeneousPoints2.row(i) * typedF * newHomogeneousPoints1.row(i).t();
1862
CV_Assert(error.rows == 1 && error.cols == 1);
1863
if (cvtest::norm(error, NORM_L2) > constraintAccuracy)
1864
{
1865
ts->printf( cvtest::TS::LOG, "Epipolar constraint is violated after correctMatches, testcase %d\n", testcase);
1866
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
1867
}
1868
}
1869
1870
// rectifyUncalibrated
1871
CV_Assert( imgpt1.size() == imgpt2.size() );
1872
Mat _imgpt1( total, 1, CV_32FC2 ), _imgpt2( total, 1, CV_32FC2 );
1873
vector<vector<Point2f> >::const_iterator iit1 = imgpt1.begin();
1874
vector<vector<Point2f> >::const_iterator iit2 = imgpt2.begin();
1875
for( int pi = 0; iit1 != imgpt1.end(); ++iit1, ++iit2 )
1876
{
1877
vector<Point2f>::const_iterator pit1 = iit1->begin();
1878
vector<Point2f>::const_iterator pit2 = iit2->begin();
1879
CV_Assert( iit1->size() == iit2->size() );
1880
for( ; pit1 != iit1->end(); ++pit1, ++pit2, pi++ )
1881
{
1882
_imgpt1.at<Point2f>(pi,0) = Point2f( pit1->x, pit1->y );
1883
_imgpt2.at<Point2f>(pi,0) = Point2f( pit2->x, pit2->y );
1884
}
1885
}
1886
1887
Mat _M1, _M2, _D1, _D2;
1888
vector<Mat> _R1, _R2, _T1, _T2;
1889
calibrateCamera( objpt, imgpt1, imgsize, _M1, _D1, _R1, _T1, 0 );
1890
calibrateCamera( objpt, imgpt2, imgsize, _M2, _D2, _R2, _T2, 0 );
1891
undistortPoints( _imgpt1, _imgpt1, _M1, _D1, Mat(), _M1 );
1892
undistortPoints( _imgpt2, _imgpt2, _M2, _D2, Mat(), _M2 );
1893
1894
Mat matF, _H1, _H2;
1895
matF = findFundamentalMat( _imgpt1, _imgpt2 );
1896
rectifyUncalibrated( _imgpt1, _imgpt2, matF, imgsize, _H1, _H2 );
1897
1898
Mat rectifPoints1, rectifPoints2;
1899
perspectiveTransform( _imgpt1, rectifPoints1, _H1 );
1900
perspectiveTransform( _imgpt2, rectifPoints2, _H2 );
1901
1902
bool verticalStereo = abs(P2.at<double>(0,3)) < abs(P2.at<double>(1,3));
1903
double maxDiff_c = 0, maxDiff_uc = 0;
1904
for( int i = 0, k = 0; i < nframes; i++ )
1905
{
1906
vector<Point2f> temp[2];
1907
undistortPoints(Mat(imgpt1[i]), temp[0], M1, D1, R1, P1);
1908
undistortPoints(Mat(imgpt2[i]), temp[1], M2, D2, R2, P2);
1909
1910
for( int j = 0; j < npoints; j++, k++ )
1911
{
1912
double diff_c = verticalStereo ? abs(temp[0][j].x - temp[1][j].x) : abs(temp[0][j].y - temp[1][j].y);
1913
Point2f d = rectifPoints1.at<Point2f>(k,0) - rectifPoints2.at<Point2f>(k,0);
1914
double diff_uc = verticalStereo ? abs(d.x) : abs(d.y);
1915
maxDiff_c = max(maxDiff_c, diff_c);
1916
maxDiff_uc = max(maxDiff_uc, diff_uc);
1917
if( maxDiff_c > maxScanlineDistErr_c )
1918
{
1919
ts->printf( cvtest::TS::LOG, "The distance between %s coordinates is too big(=%g) (used calibrated stereo), testcase %d\n",
1920
verticalStereo ? "x" : "y", diff_c, testcase);
1921
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
1922
return;
1923
}
1924
if( maxDiff_uc > maxScanlineDistErr_uc )
1925
{
1926
ts->printf( cvtest::TS::LOG, "The distance between %s coordinates is too big(=%g) (used uncalibrated stereo), testcase %d\n",
1927
verticalStereo ? "x" : "y", diff_uc, testcase);
1928
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
1929
return;
1930
}
1931
}
1932
}
1933
1934
ts->printf( cvtest::TS::LOG, "Testcase %d. Max distance (calibrated) =%g\n"
1935
"Max distance (uncalibrated) =%g\n", testcase, maxDiff_c, maxDiff_uc );
1936
}
1937
}
1938
1939
//-------------------------------- CV_StereoCalibrationTest_C ------------------------------
1940
1941
class CV_StereoCalibrationTest_C : public CV_StereoCalibrationTest
1942
{
1943
public:
1944
CV_StereoCalibrationTest_C() {}
1945
protected:
1946
virtual double calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
1947
const vector<vector<Point2f> >& imagePoints1,
1948
const vector<vector<Point2f> >& imagePoints2,
1949
Mat& cameraMatrix1, Mat& distCoeffs1,
1950
Mat& cameraMatrix2, Mat& distCoeffs2,
1951
Size imageSize, Mat& R, Mat& T,
1952
Mat& E, Mat& F, TermCriteria criteria, int flags );
1953
virtual void rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1,
1954
const Mat& cameraMatrix2, const Mat& distCoeffs2,
1955
Size imageSize, const Mat& R, const Mat& T,
1956
Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q,
1957
double alpha, Size newImageSize,
1958
Rect* validPixROI1, Rect* validPixROI2, int flags );
1959
virtual bool rectifyUncalibrated( const Mat& points1,
1960
const Mat& points2, const Mat& F, Size imgSize,
1961
Mat& H1, Mat& H2, double threshold=5 );
1962
virtual void triangulate( const Mat& P1, const Mat& P2,
1963
const Mat &points1, const Mat &points2,
1964
Mat &points4D );
1965
virtual void correct( const Mat& F,
1966
const Mat &points1, const Mat &points2,
1967
Mat &newPoints1, Mat &newPoints2 );
1968
};
1969
1970
double CV_StereoCalibrationTest_C::calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
1971
const vector<vector<Point2f> >& imagePoints1,
1972
const vector<vector<Point2f> >& imagePoints2,
1973
Mat& cameraMatrix1, Mat& distCoeffs1,
1974
Mat& cameraMatrix2, Mat& distCoeffs2,
1975
Size imageSize, Mat& R, Mat& T,
1976
Mat& E, Mat& F, TermCriteria criteria, int flags )
1977
{
1978
cameraMatrix1.create( 3, 3, CV_64F );
1979
cameraMatrix2.create( 3, 3, CV_64F);
1980
distCoeffs1.create( 1, 5, CV_64F);
1981
distCoeffs2.create( 1, 5, CV_64F);
1982
R.create(3, 3, CV_64F);
1983
T.create(3, 1, CV_64F);
1984
E.create(3, 3, CV_64F);
1985
F.create(3, 3, CV_64F);
1986
1987
int nimages = (int)objectPoints.size(), total = 0;
1988
for( int i = 0; i < nimages; i++ )
1989
{
1990
total += (int)objectPoints[i].size();
1991
}
1992
1993
Mat npoints( 1, nimages, CV_32S ),
1994
objPt( 1, total, traits::Type<Point3f>::value ),
1995
imgPt( 1, total, traits::Type<Point2f>::value ),
1996
imgPt2( 1, total, traits::Type<Point2f>::value );
1997
1998
Point2f* imgPtData2 = imgPt2.ptr<Point2f>();
1999
Point3f* objPtData = objPt.ptr<Point3f>();
2000
Point2f* imgPtData = imgPt.ptr<Point2f>();
2001
for( int i = 0, ni = 0, j = 0; i < nimages; i++, j += ni )
2002
{
2003
ni = (int)objectPoints[i].size();
2004
npoints.ptr<int>()[i] = ni;
2005
std::copy(objectPoints[i].begin(), objectPoints[i].end(), objPtData + j);
2006
std::copy(imagePoints1[i].begin(), imagePoints1[i].end(), imgPtData + j);
2007
std::copy(imagePoints2[i].begin(), imagePoints2[i].end(), imgPtData2 + j);
2008
}
2009
CvMat _objPt = cvMat(objPt), _imgPt = cvMat(imgPt), _imgPt2 = cvMat(imgPt2), _npoints = cvMat(npoints);
2010
CvMat _cameraMatrix1 = cvMat(cameraMatrix1), _distCoeffs1 = cvMat(distCoeffs1);
2011
CvMat _cameraMatrix2 = cvMat(cameraMatrix2), _distCoeffs2 = cvMat(distCoeffs2);
2012
CvMat matR = cvMat(R), matT = cvMat(T), matE = cvMat(E), matF = cvMat(F);
2013
2014
return cvStereoCalibrate(&_objPt, &_imgPt, &_imgPt2, &_npoints, &_cameraMatrix1,
2015
&_distCoeffs1, &_cameraMatrix2, &_distCoeffs2, cvSize(imageSize),
2016
&matR, &matT, &matE, &matF, flags, cvTermCriteria(criteria));
2017
}
2018
2019
void CV_StereoCalibrationTest_C::rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1,
2020
const Mat& cameraMatrix2, const Mat& distCoeffs2,
2021
Size imageSize, const Mat& R, const Mat& T,
2022
Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q,
2023
double alpha, Size newImageSize,
2024
Rect* validPixROI1, Rect* validPixROI2, int flags )
2025
{
2026
int rtype = CV_64F;
2027
R1.create(3, 3, rtype);
2028
R2.create(3, 3, rtype);
2029
P1.create(3, 4, rtype);
2030
P2.create(3, 4, rtype);
2031
Q.create(4, 4, rtype);
2032
CvMat _cameraMatrix1 = cvMat(cameraMatrix1), _distCoeffs1 = cvMat(distCoeffs1);
2033
CvMat _cameraMatrix2 = cvMat(cameraMatrix2), _distCoeffs2 = cvMat(distCoeffs2);
2034
CvMat matR = cvMat(R), matT = cvMat(T), _R1 = cvMat(R1), _R2 = cvMat(R2), _P1 = cvMat(P1), _P2 = cvMat(P2), matQ = cvMat(Q);
2035
cvStereoRectify( &_cameraMatrix1, &_cameraMatrix2, &_distCoeffs1, &_distCoeffs2,
2036
cvSize(imageSize), &matR, &matT, &_R1, &_R2, &_P1, &_P2, &matQ, flags,
2037
alpha, cvSize(newImageSize), (CvRect*)validPixROI1, (CvRect*)validPixROI2);
2038
}
2039
2040
bool CV_StereoCalibrationTest_C::rectifyUncalibrated( const Mat& points1,
2041
const Mat& points2, const Mat& F, Size imgSize, Mat& H1, Mat& H2, double threshold )
2042
{
2043
H1.create(3, 3, CV_64F);
2044
H2.create(3, 3, CV_64F);
2045
CvMat _pt1 = cvMat(points1), _pt2 = cvMat(points2), matF, *pF=0, _H1 = cvMat(H1), _H2 = cvMat(H2);
2046
if( F.size() == Size(3, 3) )
2047
pF = &(matF = cvMat(F));
2048
return cvStereoRectifyUncalibrated(&_pt1, &_pt2, pF, cvSize(imgSize), &_H1, &_H2, threshold) > 0;
2049
}
2050
2051
void CV_StereoCalibrationTest_C::triangulate( const Mat& P1, const Mat& P2,
2052
const Mat &points1, const Mat &points2,
2053
Mat &points4D )
2054
{
2055
CvMat _P1 = cvMat(P1), _P2 = cvMat(P2), _points1 = cvMat(points1), _points2 = cvMat(points2);
2056
points4D.create(4, points1.cols, points1.type());
2057
CvMat _points4D = cvMat(points4D);
2058
cvTriangulatePoints(&_P1, &_P2, &_points1, &_points2, &_points4D);
2059
}
2060
2061
void CV_StereoCalibrationTest_C::correct( const Mat& F,
2062
const Mat &points1, const Mat &points2,
2063
Mat &newPoints1, Mat &newPoints2 )
2064
{
2065
CvMat _F = cvMat(F), _points1 = cvMat(points1), _points2 = cvMat(points2);
2066
newPoints1.create(1, points1.cols, points1.type());
2067
newPoints2.create(1, points2.cols, points2.type());
2068
CvMat _newPoints1 = cvMat(newPoints1), _newPoints2 = cvMat(newPoints2);
2069
cvCorrectMatches(&_F, &_points1, &_points2, &_newPoints1, &_newPoints2);
2070
}
2071
2072
//-------------------------------- CV_StereoCalibrationTest_CPP ------------------------------
2073
2074
class CV_StereoCalibrationTest_CPP : public CV_StereoCalibrationTest
2075
{
2076
public:
2077
CV_StereoCalibrationTest_CPP() {}
2078
protected:
2079
virtual double calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
2080
const vector<vector<Point2f> >& imagePoints1,
2081
const vector<vector<Point2f> >& imagePoints2,
2082
Mat& cameraMatrix1, Mat& distCoeffs1,
2083
Mat& cameraMatrix2, Mat& distCoeffs2,
2084
Size imageSize, Mat& R, Mat& T,
2085
Mat& E, Mat& F, TermCriteria criteria, int flags );
2086
virtual void rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1,
2087
const Mat& cameraMatrix2, const Mat& distCoeffs2,
2088
Size imageSize, const Mat& R, const Mat& T,
2089
Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q,
2090
double alpha, Size newImageSize,
2091
Rect* validPixROI1, Rect* validPixROI2, int flags );
2092
virtual bool rectifyUncalibrated( const Mat& points1,
2093
const Mat& points2, const Mat& F, Size imgSize,
2094
Mat& H1, Mat& H2, double threshold=5 );
2095
virtual void triangulate( const Mat& P1, const Mat& P2,
2096
const Mat &points1, const Mat &points2,
2097
Mat &points4D );
2098
virtual void correct( const Mat& F,
2099
const Mat &points1, const Mat &points2,
2100
Mat &newPoints1, Mat &newPoints2 );
2101
};
2102
2103
double CV_StereoCalibrationTest_CPP::calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
2104
const vector<vector<Point2f> >& imagePoints1,
2105
const vector<vector<Point2f> >& imagePoints2,
2106
Mat& cameraMatrix1, Mat& distCoeffs1,
2107
Mat& cameraMatrix2, Mat& distCoeffs2,
2108
Size imageSize, Mat& R, Mat& T,
2109
Mat& E, Mat& F, TermCriteria criteria, int flags )
2110
{
2111
return stereoCalibrate( objectPoints, imagePoints1, imagePoints2,
2112
cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2,
2113
imageSize, R, T, E, F, flags, criteria );
2114
}
2115
2116
void CV_StereoCalibrationTest_CPP::rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1,
2117
const Mat& cameraMatrix2, const Mat& distCoeffs2,
2118
Size imageSize, const Mat& R, const Mat& T,
2119
Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q,
2120
double alpha, Size newImageSize,
2121
Rect* validPixROI1, Rect* validPixROI2, int flags )
2122
{
2123
stereoRectify( cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2,
2124
imageSize, R, T, R1, R2, P1, P2, Q, flags, alpha, newImageSize,validPixROI1, validPixROI2 );
2125
}
2126
2127
bool CV_StereoCalibrationTest_CPP::rectifyUncalibrated( const Mat& points1,
2128
const Mat& points2, const Mat& F, Size imgSize, Mat& H1, Mat& H2, double threshold )
2129
{
2130
return stereoRectifyUncalibrated( points1, points2, F, imgSize, H1, H2, threshold );
2131
}
2132
2133
void CV_StereoCalibrationTest_CPP::triangulate( const Mat& P1, const Mat& P2,
2134
const Mat &points1, const Mat &points2,
2135
Mat &points4D )
2136
{
2137
triangulatePoints(P1, P2, points1, points2, points4D);
2138
}
2139
2140
void CV_StereoCalibrationTest_CPP::correct( const Mat& F,
2141
const Mat &points1, const Mat &points2,
2142
Mat &newPoints1, Mat &newPoints2 )
2143
{
2144
correctMatches(F, points1, points2, newPoints1, newPoints2);
2145
}
2146
2147
///////////////////////////////////////////////////////////////////////////////////////////////////
2148
2149
TEST(Calib3d_CalibrateCamera_C, regression) { CV_CameraCalibrationTest_C test; test.safe_run(); }
2150
TEST(Calib3d_CalibrateCamera_CPP, regression) { CV_CameraCalibrationTest_CPP test; test.safe_run(); }
2151
TEST(Calib3d_CalibrationMatrixValues_C, accuracy) { CV_CalibrationMatrixValuesTest_C test; test.safe_run(); }
2152
TEST(Calib3d_CalibrationMatrixValues_CPP, accuracy) { CV_CalibrationMatrixValuesTest_CPP test; test.safe_run(); }
2153
TEST(Calib3d_ProjectPoints_C, accuracy) { CV_ProjectPointsTest_C test; test.safe_run(); }
2154
TEST(Calib3d_ProjectPoints_CPP, regression) { CV_ProjectPointsTest_CPP test; test.safe_run(); }
2155
TEST(Calib3d_StereoCalibrate_C, regression) { CV_StereoCalibrationTest_C test; test.safe_run(); }
2156
TEST(Calib3d_StereoCalibrate_CPP, regression) { CV_StereoCalibrationTest_CPP test; test.safe_run(); }
2157
TEST(Calib3d_StereoCalibrateCorner, regression) { CV_StereoCalibrationCornerTest test; test.safe_run(); }
2158
2159
TEST(Calib3d_StereoCalibrate_CPP, extended)
2160
{
2161
cvtest::TS* ts = cvtest::TS::ptr();
2162
String filepath = cv::format("%scv/stereo/case%d/", ts->get_data_path().c_str(), 1 );
2163
2164
Mat left = imread(filepath+"left01.png");
2165
Mat right = imread(filepath+"right01.png");
2166
if(left.empty() || right.empty())
2167
{
2168
ts->set_failed_test_info( cvtest::TS::FAIL_MISSING_TEST_DATA );
2169
return;
2170
}
2171
2172
vector<vector<Point2f> > imgpt1(1), imgpt2(1);
2173
vector<vector<Point3f> > objpt(1);
2174
Size patternSize(9, 6), imageSize(640, 480);
2175
bool found1 = findChessboardCorners(left, patternSize, imgpt1[0]);
2176
bool found2 = findChessboardCorners(right, patternSize, imgpt2[0]);
2177
2178
if(!found1 || !found2)
2179
{
2180
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
2181
return;
2182
}
2183
2184
for( int j = 0; j < patternSize.width*patternSize.height; j++ )
2185
objpt[0].push_back(Point3f((float)(j%patternSize.width), (float)(j/patternSize.width), 0.f));
2186
2187
Mat K1, K2, c1, c2, R, T, E, F, err;
2188
int flags = 0;
2189
double res0 = stereoCalibrate( objpt, imgpt1, imgpt2,
2190
K1, c1, K2, c2,
2191
imageSize, R, T, E, F, err, flags);
2192
2193
flags = CALIB_USE_EXTRINSIC_GUESS;
2194
double res1 = stereoCalibrate( objpt, imgpt1, imgpt2,
2195
K1, c1, K2, c2,
2196
imageSize, R, T, E, F, err, flags);
2197
EXPECT_LE(res1, res0);
2198
EXPECT_TRUE(err.total() == 2);
2199
}
2200
2201
TEST(Calib3d_StereoCalibrate, regression_10791)
2202
{
2203
const Matx33d M1(
2204
853.1387981631528, 0, 704.154907802121,
2205
0, 853.6445089162528, 520.3600712930319,
2206
0, 0, 1
2207
);
2208
const Matx33d M2(
2209
848.6090216909176, 0, 701.6162856852185,
2210
0, 849.7040162357157, 509.1864036137,
2211
0, 0, 1
2212
);
2213
const Matx<double, 14, 1> D1(-6.463598629567206, 79.00104930508179, -0.0001006144444464403, -0.0005437499822299972,
2214
12.56900616588467, -6.056719942752855, 76.3842481414836, 45.57460250612659,
2215
0, 0, 0, 0, 0, 0);
2216
const Matx<double, 14, 1> D2(0.6123436439798265, -0.4671756923224087, -0.0001261947899033442, -0.000597334584036978,
2217
-0.05660119809538371, 1.037075740629769, -0.3076042835831711, -0.2502169324283623,
2218
0, 0, 0, 0, 0, 0);
2219
2220
const Matx33d R(
2221
0.9999926627018476, -0.0001095586963765905, 0.003829169539302921,
2222
0.0001021735876758584, 0.9999981346680941, 0.0019287874145156,
2223
-0.003829373712065528, -0.001928382022437616, 0.9999908085776333
2224
);
2225
const Matx31d T(-58.9161771697128, -0.01581306249996402, -0.8492960216760961);
2226
2227
const Size imageSize(1280, 960);
2228
2229
Mat R1, R2, P1, P2, Q;
2230
Rect roi1, roi2;
2231
stereoRectify(M1, D1, M2, D2, imageSize, R, T,
2232
R1, R2, P1, P2, Q,
2233
CALIB_ZERO_DISPARITY, 1, imageSize, &roi1, &roi2);
2234
2235
EXPECT_GE(roi1.area(), 400*300) << roi1;
2236
EXPECT_GE(roi2.area(), 400*300) << roi2;
2237
}
2238
2239
TEST(Calib3d_Triangulate, accuracy)
2240
{
2241
// the testcase from http://code.opencv.org/issues/4334
2242
{
2243
double P1data[] = { 250, 0, 200, 0, 0, 250, 150, 0, 0, 0, 1, 0 };
2244
double P2data[] = { 250, 0, 200, -250, 0, 250, 150, 0, 0, 0, 1, 0 };
2245
Mat P1(3, 4, CV_64F, P1data), P2(3, 4, CV_64F, P2data);
2246
2247
float x1data[] = { 200.f, 0.f };
2248
float x2data[] = { 170.f, 1.f };
2249
float Xdata[] = { 0.f, -5.f, 25/3.f };
2250
Mat x1(2, 1, CV_32F, x1data);
2251
Mat x2(2, 1, CV_32F, x2data);
2252
Mat res0(1, 3, CV_32F, Xdata);
2253
Mat res_, res;
2254
2255
triangulatePoints(P1, P2, x1, x2, res_);
2256
cv::transpose(res_, res_); // TODO cvtest (transpose doesn't support inplace)
2257
convertPointsFromHomogeneous(res_, res);
2258
res = res.reshape(1, 1);
2259
2260
cout << "[1]:" << endl;
2261
cout << "\tres0: " << res0 << endl;
2262
cout << "\tres: " << res << endl;
2263
2264
ASSERT_LE(cvtest::norm(res, res0, NORM_INF), 1e-1);
2265
}
2266
2267
// another testcase http://code.opencv.org/issues/3461
2268
{
2269
Matx33d K1(6137.147949, 0.000000, 644.974609,
2270
0.000000, 6137.147949, 573.442749,
2271
0.000000, 0.000000, 1.000000);
2272
Matx33d K2(6137.147949, 0.000000, 644.674438,
2273
0.000000, 6137.147949, 573.079834,
2274
0.000000, 0.000000, 1.000000);
2275
2276
Matx34d RT1(1, 0, 0, 0,
2277
0, 1, 0, 0,
2278
0, 0, 1, 0);
2279
2280
Matx34d RT2(0.998297, 0.0064108, -0.0579766, 143.614334,
2281
-0.0065818, 0.999975, -0.00275888, -5.160085,
2282
0.0579574, 0.00313577, 0.998314, 96.066109);
2283
2284
Matx34d P1 = K1*RT1;
2285
Matx34d P2 = K2*RT2;
2286
2287
float x1data[] = { 438.f, 19.f };
2288
float x2data[] = { 452.363600f, 16.452225f };
2289
float Xdata[] = { -81.049530f, -215.702804f, 2401.645449f };
2290
Mat x1(2, 1, CV_32F, x1data);
2291
Mat x2(2, 1, CV_32F, x2data);
2292
Mat res0(1, 3, CV_32F, Xdata);
2293
Mat res_, res;
2294
2295
triangulatePoints(P1, P2, x1, x2, res_);
2296
cv::transpose(res_, res_); // TODO cvtest (transpose doesn't support inplace)
2297
convertPointsFromHomogeneous(res_, res);
2298
res = res.reshape(1, 1);
2299
2300
cout << "[2]:" << endl;
2301
cout << "\tres0: " << res0 << endl;
2302
cout << "\tres: " << res << endl;
2303
2304
ASSERT_LE(cvtest::norm(res, res0, NORM_INF), 2);
2305
}
2306
}
2307
2308
}} // namespace
2309
2310