From 57f328a27c5f48e40c7a2ba3e8e9c3c222097fb7 Mon Sep 17 00:00:00 2001 From: Vincent Rabaud Date: Wed, 9 Sep 2026 16:58:58 +0200 Subject: [PATCH] Only optimize upon 4 distortion parameters when the input has dim==4 --- modules/calib/src/calibration.cpp | 17 +++++-- modules/calib/test/test_cameracalibration.cpp | 47 +++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/modules/calib/src/calibration.cpp b/modules/calib/src/calibration.cpp index 034581ce6f..9e57a0af2d 100644 --- a/modules/calib/src/calibration.cpp +++ b/modules/calib/src/calibration.cpp @@ -2861,9 +2861,10 @@ static Mat prepareDistCoeffs(Mat& distCoeffs0, int rtype, int outputSize) int n = sz.area(); if (n > 0) CV_Assert(sz.width == 1 || sz.height == 1); + CV_Assert(n == 0 || n == 4 || n == 5 || n == 8 || n == 12 || n == 14); CV_Assert((int)distCoeffs0.total() <= outputSize); Mat distCoeffs = Mat::zeros(sz.width == 1 ? Size(1, outputSize) : Size(outputSize, 1), rtype); - if( n == 4 || n == 5 || n == 8 || n == 12 || n == 14 ) + if( n > 0 ) { distCoeffs0.convertTo(distCoeffs(Rect(Point(), sz)), rtype); } @@ -2932,6 +2933,7 @@ double calibrateCameraRO(InputArrayOfArrays _objectPoints, Mat cameraMatrix = _cameraMatrix.getMat(); cameraMatrix = prepareCameraMatrix(cameraMatrix, rtype, flags); Mat distCoeffs = _distCoeffs.getMat(); + int dist_total = distCoeffs.total(); distCoeffs = (flags & CALIB_THIN_PRISM_MODEL) && !(flags & CALIB_TILTED_MODEL) ? @@ -2940,7 +2942,10 @@ double calibrateCameraRO(InputArrayOfArrays _objectPoints, if( !(flags & CALIB_RATIONAL_MODEL) && (!(flags & CALIB_THIN_PRISM_MODEL)) && (!(flags & CALIB_TILTED_MODEL))) - distCoeffs = distCoeffs.rows == 1 ? distCoeffs.colRange(0, 5) : distCoeffs.rowRange(0, 5); + { + int out_size = (dist_total == 0) ? 5 : std::min(5, dist_total); + distCoeffs = distCoeffs.rows == 1 ? distCoeffs.colRange(0, out_size) : distCoeffs.rowRange(0, out_size); + } int nimages = int(_objectPoints.total()); CV_Assert( nimages > 0 ); @@ -3115,6 +3120,8 @@ double stereoCalibrate( InputArrayOfArrays _objectPoints, Mat cameraMatrix2 = _cameraMatrix2.getMat(); Mat distCoeffs1 = _distCoeffs1.getMat(); Mat distCoeffs2 = _distCoeffs2.getMat(); + int dist1_total = distCoeffs1.total(); + int dist2_total = distCoeffs2.total(); cameraMatrix1 = prepareCameraMatrix(cameraMatrix1, rtype, flags); cameraMatrix2 = prepareCameraMatrix(cameraMatrix2, rtype, flags); distCoeffs1 = prepareDistCoeffs(distCoeffs1, rtype, 14); @@ -3124,8 +3131,10 @@ double stereoCalibrate( InputArrayOfArrays _objectPoints, (!(flags & CALIB_THIN_PRISM_MODEL)) && (!(flags & CALIB_TILTED_MODEL))) { - distCoeffs1 = distCoeffs1.rows == 1 ? distCoeffs1.colRange(0, 5) : distCoeffs1.rowRange(0, 5); - distCoeffs2 = distCoeffs2.rows == 1 ? distCoeffs2.colRange(0, 5) : distCoeffs2.rowRange(0, 5); + int out_size1 = (dist1_total == 0) ? 5 : std::min(5, dist1_total); + int out_size2 = (dist2_total == 0) ? 5 : std::min(5, dist2_total); + distCoeffs1 = distCoeffs1.rows == 1 ? distCoeffs1.colRange(0, out_size1) : distCoeffs1.rowRange(0, out_size1); + distCoeffs2 = distCoeffs2.rows == 1 ? distCoeffs2.colRange(0, out_size2) : distCoeffs2.rowRange(0, out_size2); } if((flags & CALIB_USE_EXTRINSIC_GUESS) == 0) diff --git a/modules/calib/test/test_cameracalibration.cpp b/modules/calib/test/test_cameracalibration.cpp index 7fcc41f991..0093b40b63 100644 --- a/modules/calib/test/test_cameracalibration.cpp +++ b/modules/calib/test/test_cameracalibration.cpp @@ -1898,4 +1898,51 @@ TEST(Calib_StereoCalibrate, regression_22421) EXPECT_LE(terr, 0.0000001); } +TEST(Calib_CalibrateCamera, size4DistortionCoeffs) +{ + std::vector> objectPoints(3); + std::vector> imagePoints(3); + cv::Size boardSize(9, 6); + for (int i = 0; i < 3; i++) { + for (int y = 0; y < boardSize.height; y++) { + for (int x = 0; x < boardSize.width; x++) { + objectPoints[i].push_back(cv::Point3f(x * 0.1f, y * 0.1f, 0.f)); + } + } + } + + cv::Matx33d cameraMatrix(800, 0, 320, 0, 800, 240, 0, 0, 1); + cv::Vec4d distCoeffs(0.1, -0.05, 0.001, -0.002); + for (int i = 0; i < 3; i++) { + cv::Vec3d rvec(0.1 * i, -0.2 * i, 0.05 * i); + cv::Vec3d tvec(-0.1 * i, 0.05 * i, 1.0 + 0.1 * i); + cv::projectPoints(objectPoints[i], rvec, tvec, cameraMatrix, distCoeffs, imagePoints[i]); + } + + // 1. Test calibrateCamera + cv::Matx33d cameraMatrix_est = cameraMatrix; + cv::Mat1d distCoeffs_est = cv::Mat1d::zeros(1, 4); + std::vector rvecs, tvecs; + double rms = cv::calibrateCamera(objectPoints, imagePoints, cv::Size(640, 480), + cameraMatrix_est, distCoeffs_est, rvecs, tvecs, + cv::CALIB_USE_INTRINSIC_GUESS); + + EXPECT_LT(rms, 1e-4); + EXPECT_LE(cv::norm(cv::Vec4d(distCoeffs_est), distCoeffs, NORM_INF), 1e-4); + + // 2. Test stereoCalibrate + cv::Matx33d K1 = cameraMatrix; + cv::Matx33d K2 = cameraMatrix; + cv::Mat1d D1 = cv::Mat1d::zeros(1, 4); + cv::Mat1d D2 = cv::Mat1d::zeros(1, 4); + cv::Mat R, T, E, F; + double stereo_rms = cv::stereoCalibrate(objectPoints, imagePoints, imagePoints, + K1, D1, K2, D2, cv::Size(640, 480), + R, T, E, F, cv::CALIB_USE_INTRINSIC_GUESS); + + EXPECT_LT(stereo_rms, 1e-4); + EXPECT_LE(cv::norm(cv::Vec4d(D1), distCoeffs, NORM_INF), 1e-4); + EXPECT_LE(cv::norm(cv::Vec4d(D2), distCoeffs, NORM_INF), 1e-4); +} + }} // namespace