@@ -1181,7 +1181,6 @@ CV_IMPL void cvFindExtrinsicCameraParams2( const CvMat* objectPoints,
1181
1181
cvConvert ( &_t, tvec );
1182
1182
}
1183
1183
1184
-
1185
1184
CV_IMPL void cvInitIntrinsicParams2D ( const CvMat* objectPoints,
1186
1185
const CvMat* imagePoints, const CvMat* npoints,
1187
1186
CvSize imageSize, CvMat* cameraMatrix,
@@ -1270,15 +1269,37 @@ CV_IMPL void cvInitIntrinsicParams2D( const CvMat* objectPoints,
1270
1269
cvConvert ( &_a, cameraMatrix );
1271
1270
}
1272
1271
1272
+ static void subMatrix (const cv::Mat& src, cv::Mat& dst, const std::vector<uchar>& cols,
1273
+ const std::vector<uchar>& rows) {
1274
+ int nonzeros_cols = cv::countNonZero (cols);
1275
+ cv::Mat tmp (src.rows , nonzeros_cols, CV_64FC1);
1273
1276
1274
- /* finds intrinsic and extrinsic camera parameters
1275
- from a few views of known calibration pattern */
1276
- CV_IMPL double cvCalibrateCamera2 ( const CvMat* objectPoints,
1277
+ for (int i = 0 , j = 0 ; i < (int )cols.size (); i++)
1278
+ {
1279
+ if (cols[i])
1280
+ {
1281
+ src.col (i).copyTo (tmp.col (j++));
1282
+ }
1283
+ }
1284
+
1285
+ int nonzeros_rows = cv::countNonZero (rows);
1286
+ dst.create (nonzeros_rows, nonzeros_cols, CV_64FC1);
1287
+ for (int i = 0 , j = 0 ; i < (int )rows.size (); i++)
1288
+ {
1289
+ if (rows[i])
1290
+ {
1291
+ tmp.row (i).copyTo (dst.row (j++));
1292
+ }
1293
+ }
1294
+ }
1295
+
1296
+ static double cvCalibrateCamera2Internal ( const CvMat* objectPoints,
1277
1297
const CvMat* imagePoints, const CvMat* npoints,
1278
1298
CvSize imageSize, CvMat* cameraMatrix, CvMat* distCoeffs,
1279
- CvMat* rvecs, CvMat* tvecs, int flags, CvTermCriteria termCrit )
1299
+ CvMat* rvecs, CvMat* tvecs, CvMat* stdDevs,
1300
+ CvMat* perViewErrors, int flags, CvTermCriteria termCrit )
1280
1301
{
1281
- const int NINTRINSIC = 18 ;
1302
+ const int NINTRINSIC = CV_CALIB_NINTRINSIC ;
1282
1303
double reprojErr = 0 ;
1283
1304
1284
1305
Matx33d A;
@@ -1338,6 +1359,20 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
1338
1359
" 1xn or nx1 array or 1-channel nx3 array, where n is the number of views" );
1339
1360
}
1340
1361
1362
+ if ( stdDevs )
1363
+ {
1364
+ cn = CV_MAT_CN (stdDevs->type );
1365
+ if ( !CV_IS_MAT (stdDevs) ||
1366
+ (CV_MAT_DEPTH (stdDevs->type ) != CV_32F && CV_MAT_DEPTH (stdDevs->type ) != CV_64F) ||
1367
+ ((stdDevs->rows != (nimages*6 + NINTRINSIC) || stdDevs->cols *cn != 1 ) &&
1368
+ (stdDevs->rows != 1 || stdDevs->cols != (nimages*6 + NINTRINSIC) || cn != 1 )) )
1369
+ #define STR__ (x ) #x
1370
+ #define STR_ (x ) STR__(x)
1371
+ CV_Error ( CV_StsBadArg, " the output array of standard deviations vectors must be 1-channel "
1372
+ " 1x(n*6 + NINTRINSIC) or (n*6 + NINTRINSIC)x1 array, where n is the number of views,"
1373
+ " NINTRINSIC = " STR_ (CV_CALIB_NINTRINSIC));
1374
+ }
1375
+
1341
1376
if ( (CV_MAT_TYPE (cameraMatrix->type ) != CV_32FC1 &&
1342
1377
CV_MAT_TYPE (cameraMatrix->type ) != CV_64FC1) ||
1343
1378
cameraMatrix->rows != 3 || cameraMatrix->cols != 3 )
@@ -1367,6 +1402,7 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
1367
1402
1368
1403
Mat matM ( 1 , total, CV_64FC3 );
1369
1404
Mat _m ( 1 , total, CV_64FC2 );
1405
+ Mat allErrors (1 , total, CV_64FC2);
1370
1406
1371
1407
if (CV_MAT_CN (objectPoints->type ) == 3 ) {
1372
1408
cvarrToMat (objectPoints).convertTo (matM, CV_64F);
@@ -1518,6 +1554,7 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
1518
1554
double * _errNorm = 0 ;
1519
1555
bool proceed = solver.updateAlt ( _param, _JtJ, _JtErr, _errNorm );
1520
1556
double *param = solver.param ->data .db , *pparam = solver.prevParam ->data .db ;
1557
+ bool calcJ = solver.state == CvLevMarq::CALC_J || (!proceed && stdDevs);
1521
1558
1522
1559
if ( flags & CALIB_FIX_ASPECT_RATIO )
1523
1560
{
@@ -1528,8 +1565,10 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
1528
1565
A (0 , 0 ) = param[0 ]; A (1 , 1 ) = param[1 ]; A (0 , 2 ) = param[2 ]; A (1 , 2 ) = param[3 ];
1529
1566
std::copy (param + 4 , param + 4 + 14 , k);
1530
1567
1531
- if ( !proceed )
1568
+ if ( !proceed && !stdDevs && !perViewErrors )
1532
1569
break ;
1570
+ else if ( !proceed && stdDevs )
1571
+ cvZero (_JtJ);
1533
1572
1534
1573
reprojErr = 0 ;
1535
1574
@@ -1543,6 +1582,7 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
1543
1582
1544
1583
CvMat _Mi (matM.colRange (pos, pos + ni));
1545
1584
CvMat _mi (_m.colRange (pos, pos + ni));
1585
+ CvMat _me (allErrors.colRange (pos, pos + ni));
1546
1586
1547
1587
_Je.resize (ni*2 ); _Ji.resize (ni*2 ); _err.resize (ni*2 );
1548
1588
CvMat _dpdr (_Je.colRange (0 , 3 ));
@@ -1552,7 +1592,7 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
1552
1592
CvMat _dpdk (_Ji.colRange (4 , NINTRINSIC));
1553
1593
CvMat _mp (_err.reshape (2 , 1 ));
1554
1594
1555
- if ( solver. state == CvLevMarq::CALC_J )
1595
+ if ( calcJ )
1556
1596
{
1557
1597
cvProjectPoints2 ( &_Mi, &_ri, &_ti, &matA, &_k, &_mp, &_dpdr, &_dpdt,
1558
1598
(flags & CALIB_FIX_FOCAL_LENGTH) ? 0 : &_dpdf,
@@ -1563,8 +1603,10 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
1563
1603
cvProjectPoints2 ( &_Mi, &_ri, &_ti, &matA, &_k, &_mp );
1564
1604
1565
1605
cvSub ( &_mp, &_mi, &_mp );
1606
+ if (perViewErrors || stdDevs)
1607
+ cvCopy (&_mp, &_me);
1566
1608
1567
- if ( solver. state == CvLevMarq::CALC_J )
1609
+ if ( calcJ )
1568
1610
{
1569
1611
Mat JtJ (cvarrToMat (_JtJ)), JtErr (cvarrToMat (_JtErr));
1570
1612
@@ -1581,15 +1623,52 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
1581
1623
}
1582
1624
if ( _errNorm )
1583
1625
*_errNorm = reprojErr;
1626
+
1627
+ if ( !proceed )
1628
+ {
1629
+ if ( stdDevs )
1630
+ {
1631
+ Mat mask = cvarrToMat (solver.mask );
1632
+ int nparams_nz = countNonZero (mask);
1633
+ Mat JtJinv, JtJN;
1634
+ JtJN.create (nparams_nz, nparams_nz, CV_64F);
1635
+ subMatrix (cvarrToMat (_JtJ), JtJN, mask, mask);
1636
+ completeSymm (JtJN, false );
1637
+ cv::invert (JtJN, JtJinv, DECOMP_SVD);
1638
+ // sigma2 is deviation of the noise
1639
+ // see any papers about variance of the least squares estimator for
1640
+ // detailed description of the variance estimation methods
1641
+ double sigma2 = norm (allErrors, NORM_L2SQR) / (total - nparams_nz);
1642
+ Mat stdDevsM = cvarrToMat (stdDevs);
1643
+ int j = 0 ;
1644
+ for ( int s = 0 ; s < nparams; s++ )
1645
+ if ( mask.data [s] )
1646
+ {
1647
+ stdDevsM.at <double >(s) = std::sqrt (JtJinv.at <double >(j,j) * sigma2);
1648
+ j++;
1649
+ }
1650
+ else
1651
+ stdDevsM.at <double >(s) = 0 .;
1652
+ }
1653
+ break ;
1654
+ }
1584
1655
}
1585
1656
1586
1657
// 4. store the results
1587
1658
cvConvert ( &matA, cameraMatrix );
1588
1659
cvConvert ( &_k, distCoeffs );
1589
1660
1590
- for ( i = 0 ; i < nimages; i++ )
1661
+ for ( i = 0 , pos = 0 ; i < nimages; i++ )
1591
1662
{
1592
1663
CvMat src, dst;
1664
+ if ( perViewErrors )
1665
+ {
1666
+ ni = npoints->data .i [i*npstep];
1667
+ perViewErrors->data .db [i] = std::sqrt (cv::norm (allErrors.colRange (pos, pos + ni),
1668
+ NORM_L2SQR) / ni);
1669
+ pos+=ni;
1670
+ }
1671
+
1593
1672
if ( rvecs )
1594
1673
{
1595
1674
src = cvMat ( 3 , 1 , CV_64F, solver.param ->data .db + NINTRINSIC + i*6 );
@@ -1622,6 +1701,17 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
1622
1701
}
1623
1702
1624
1703
1704
+ /* finds intrinsic and extrinsic camera parameters
1705
+ from a few views of known calibration pattern */
1706
+ CV_IMPL double cvCalibrateCamera2 ( const CvMat* objectPoints,
1707
+ const CvMat* imagePoints, const CvMat* npoints,
1708
+ CvSize imageSize, CvMat* cameraMatrix, CvMat* distCoeffs,
1709
+ CvMat* rvecs, CvMat* tvecs, int flags, CvTermCriteria termCrit )
1710
+ {
1711
+ return cvCalibrateCamera2Internal (objectPoints, imagePoints, npoints, imageSize, cameraMatrix,
1712
+ distCoeffs, rvecs, tvecs, NULL , NULL , flags, termCrit);
1713
+ }
1714
+
1625
1715
void cvCalibrationMatrixValues ( const CvMat *calibMatr, CvSize imgSize,
1626
1716
double apertureWidth, double apertureHeight, double *fovx, double *fovy,
1627
1717
double *focalLength, CvPoint2D64f *principalPoint, double *pasp )
@@ -1772,7 +1862,7 @@ double cvStereoCalibrate( const CvMat* _objectPoints, const CvMat* _imagePoints1
1772
1862
if ( !(flags & (CV_CALIB_FIX_INTRINSIC|CV_CALIB_USE_INTRINSIC_GUESS)))
1773
1863
{
1774
1864
cvCalibrateCamera2 ( objectPoints, imagePoints[k],
1775
- npoints, imageSize, &K[k], &Dist[k], 0 , 0 , flags );
1865
+ npoints, imageSize, &K[k], &Dist[k], NULL , NULL , flags );
1776
1866
}
1777
1867
}
1778
1868
@@ -3091,7 +3181,6 @@ static void collectCalibrationData( InputArrayOfArrays objectPoints,
3091
3181
}
3092
3182
}
3093
3183
3094
-
3095
3184
static Mat prepareCameraMatrix (Mat& cameraMatrix0, int rtype)
3096
3185
{
3097
3186
Mat cameraMatrix = Mat::eye (3 , 3 , rtype);
@@ -3287,10 +3376,23 @@ cv::Mat cv::initCameraMatrix2D( InputArrayOfArrays objectPoints,
3287
3376
}
3288
3377
3289
3378
3379
+
3290
3380
double cv::calibrateCamera ( InputArrayOfArrays _objectPoints,
3291
3381
InputArrayOfArrays _imagePoints,
3292
3382
Size imageSize, InputOutputArray _cameraMatrix, InputOutputArray _distCoeffs,
3293
3383
OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, int flags, TermCriteria criteria )
3384
+ {
3385
+ return calibrateCamera (_objectPoints, _imagePoints, imageSize, _cameraMatrix, _distCoeffs,
3386
+ _rvecs, _tvecs, noArray (), noArray (), noArray (), flags, criteria);
3387
+ }
3388
+
3389
+ double cv::calibrateCamera (InputArrayOfArrays _objectPoints,
3390
+ InputArrayOfArrays _imagePoints,
3391
+ Size imageSize, InputOutputArray _cameraMatrix, InputOutputArray _distCoeffs,
3392
+ OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs,
3393
+ OutputArray stdDeviationsIntrinsics,
3394
+ OutputArray stdDeviationsExtrinsics,
3395
+ OutputArray _perViewErrors, int flags, TermCriteria criteria )
3294
3396
{
3295
3397
int rtype = CV_64F;
3296
3398
Mat cameraMatrix = _cameraMatrix.getMat ();
@@ -3304,14 +3406,17 @@ double cv::calibrateCamera( InputArrayOfArrays _objectPoints,
3304
3406
3305
3407
int nimages = int (_objectPoints.total ());
3306
3408
CV_Assert ( nimages > 0 );
3307
- Mat objPt, imgPt, npoints, rvecM, tvecM;
3409
+ Mat objPt, imgPt, npoints, rvecM, tvecM, stdDeviationsM, errorsM ;
3308
3410
3309
- bool rvecs_needed = _rvecs.needed (), tvecs_needed = _tvecs.needed ();
3411
+ bool rvecs_needed = _rvecs.needed (), tvecs_needed = _tvecs.needed (),
3412
+ stddev_needed = stdDeviationsIntrinsics.needed (), errors_needed = _perViewErrors.needed (),
3413
+ stddev_ext_needed = stdDeviationsExtrinsics.needed ();
3310
3414
3311
3415
bool rvecs_mat_vec = _rvecs.isMatVector ();
3312
3416
bool tvecs_mat_vec = _tvecs.isMatVector ();
3313
3417
3314
- if ( rvecs_needed ) {
3418
+ if ( rvecs_needed )
3419
+ {
3315
3420
_rvecs.create (nimages, 1 , CV_64FC3);
3316
3421
3317
3422
if (rvecs_mat_vec)
@@ -3320,7 +3425,8 @@ double cv::calibrateCamera( InputArrayOfArrays _objectPoints,
3320
3425
rvecM = _rvecs.getMat ();
3321
3426
}
3322
3427
3323
- if ( tvecs_needed ) {
3428
+ if ( tvecs_needed )
3429
+ {
3324
3430
_tvecs.create (nimages, 1 , CV_64FC3);
3325
3431
3326
3432
if (tvecs_mat_vec)
@@ -3329,16 +3435,46 @@ double cv::calibrateCamera( InputArrayOfArrays _objectPoints,
3329
3435
tvecM = _tvecs.getMat ();
3330
3436
}
3331
3437
3438
+ if ( stddev_needed || stddev_ext_needed )
3439
+ {
3440
+ stdDeviationsM.create (nimages*6 + CV_CALIB_NINTRINSIC, 1 , CV_64F);
3441
+ }
3442
+
3443
+ if ( errors_needed )
3444
+ {
3445
+ _perViewErrors.create (nimages, 1 , CV_64F);
3446
+ errorsM = _perViewErrors.getMat ();
3447
+ }
3448
+
3332
3449
collectCalibrationData ( _objectPoints, _imagePoints, noArray (),
3333
3450
objPt, imgPt, 0 , npoints );
3334
3451
CvMat c_objPt = objPt, c_imgPt = imgPt, c_npoints = npoints;
3335
3452
CvMat c_cameraMatrix = cameraMatrix, c_distCoeffs = distCoeffs;
3336
- CvMat c_rvecM = rvecM, c_tvecM = tvecM;
3453
+ CvMat c_rvecM = rvecM, c_tvecM = tvecM, c_stdDev = stdDeviationsM, c_errors = errorsM ;
3337
3454
3338
- double reprojErr = cvCalibrateCamera2 (&c_objPt, &c_imgPt, &c_npoints, imageSize,
3455
+ double reprojErr = cvCalibrateCamera2Internal (&c_objPt, &c_imgPt, &c_npoints, imageSize,
3339
3456
&c_cameraMatrix, &c_distCoeffs,
3340
3457
rvecs_needed ? &c_rvecM : NULL ,
3341
- tvecs_needed ? &c_tvecM : NULL , flags, criteria );
3458
+ tvecs_needed ? &c_tvecM : NULL ,
3459
+ stddev_needed ? &c_stdDev : NULL ,
3460
+ errors_needed ? &c_errors : NULL , flags, criteria );
3461
+
3462
+ if ( stddev_needed )
3463
+ {
3464
+ stdDeviationsIntrinsics.create (CV_CALIB_NINTRINSIC, 1 , CV_64F);
3465
+ Mat stdDeviationsIntrinsicsMat = stdDeviationsIntrinsics.getMat ();
3466
+ std::memcpy (stdDeviationsIntrinsicsMat.ptr (), stdDeviationsM.ptr (),
3467
+ CV_CALIB_NINTRINSIC*sizeof (double ));
3468
+ }
3469
+
3470
+ if ( stddev_ext_needed )
3471
+ {
3472
+ stdDeviationsExtrinsics.create (nimages*6 , 1 , CV_64F);
3473
+ Mat stdDeviationsExtrinsicsMat = stdDeviationsExtrinsics.getMat ();
3474
+ std::memcpy (stdDeviationsExtrinsicsMat.ptr (),
3475
+ stdDeviationsM.ptr () + CV_CALIB_NINTRINSIC*sizeof (double ),
3476
+ nimages*6 *sizeof (double ));
3477
+ }
3342
3478
3343
3479
// overly complicated and inefficient rvec/ tvec handling to support vector<Mat>
3344
3480
for (int i = 0 ; i < nimages; i++ )
0 commit comments