1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-31 08:13:04 +04:00

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2026-04-07 12:02:55 +03:00
28 changed files with 2027 additions and 118 deletions
+11 -3
View File
@@ -534,6 +534,7 @@ enum { CALIB_USE_INTRINSIC_GUESS = 0x00001, //!< Use user provided intrinsics as
// for stereo rectification
CALIB_ZERO_DISPARITY = 0x00400, //!< Deprecated synonim of @ref STEREO_ZERO_DISPARITY. See @ref stereoRectify.
CALIB_USE_LU = (1 << 17), //!< use LU instead of SVD decomposition for solving. much faster but potentially less precise
CALIB_DISABLE_SCHUR_COMPLEMENT = (1 << 18), //!< disable Schur complement (use Bouguet calibration engine)
CALIB_USE_EXTRINSIC_GUESS = (1 << 22), //!< For stereo and multi-view calibration. Use user provided extrinsics (R, T) as initial point for optimization
// fisheye only flags
CALIB_RECOMPUTE_EXTRINSIC = (1 << 23), //!< For fisheye model only. Recompute board position on each calibration iteration
@@ -875,6 +876,7 @@ fx, fy, cx, cy that are optimized further. Otherwise, (cx, cy) is initially set
center ( imageSize is used), and focal distances are computed in a least-squares fashion.
Note, that if intrinsic parameters are known, there is no need to use this function just to
estimate extrinsic parameters. Use @ref solvePnP instead.
- @ref CALIB_DISABLE_SCHUR_COMPLEMENT Disable Schur complement and use the Bouguet calibration engine (@cite Zhang2000, @cite BouguetMCT).
- @ref CALIB_FIX_PRINCIPAL_POINT The principal point is not changed during the global
optimization. It stays at the center or at a different location specified when
@ref CALIB_USE_INTRINSIC_GUESS is set too.
@@ -909,7 +911,9 @@ supplied distCoeffs matrix is used. Otherwise, it is set to 0.
@return the overall RMS re-projection error.
The function estimates the intrinsic camera parameters and extrinsic parameters for each of the
views. The algorithm is based on @cite Zhang2000 and @cite BouguetMCT . The coordinates of 3D object
views. By default, the optimization follows a sparse bundle adjustment formulation with Schur
complement; see @cite Triggs2000_bundle_adjustment and @cite Lourakis2009_sba for background. Use
@ref CALIB_DISABLE_SCHUR_COMPLEMENT to switch to the Bouguet calibration engine. The coordinates of 3D object
points and their corresponding 2D projections in each view must be specified. That may be achieved
by using an object with known geometry and easily detectable feature points. Such an object is
called a calibration rig or calibration pattern, and OpenCV has built-in support for a chessboard as
@@ -932,6 +936,10 @@ The algorithm performs the following steps:
the projected (using the current estimates for camera parameters and the poses) object points
objectPoints. See @ref projectPoints for details.
- In practice, robust acquisition is essential for stable results: use multiple board poses with
significant tilt, avoid collecting all views at a single working distance, span the expected
working-distance range (a larger board with larger squares can help for longer distances).
@note
If you use a non-square (i.e. non-N-by-N) grid and @ref findChessboardCorners for calibration,
and @ref calibrateCamera returns bad values (zero distortion coefficients, \f$c_x\f$ and
@@ -1017,8 +1025,8 @@ less precise and less stable in some rare cases.
@return the overall RMS re-projection error.
The function estimates the intrinsic camera parameters and extrinsic parameters for each of the
views. The algorithm is based on @cite Zhang2000, @cite BouguetMCT and @cite strobl2011iccv. See
#calibrateCamera for other detailed explanations.
views. The object-releasing extension follows @cite strobl2011iccv and uses the same optimization
core as #calibrateCamera. See #calibrateCamera for other detailed explanations.
@sa
calibrateCamera, findChessboardCorners, solvePnP, initCameraMatrix2D, stereoCalibrate, undistort
*/
+164
View File
@@ -0,0 +1,164 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
#include "perf_precomp.hpp"
#include "opencv2/core/utils/filesystem.hpp"
//#define SAVE_IMAGE_POINTS
namespace opencv_test {
#ifdef SAVE_IMAGE_POINTS
static std::vector<std::string> loadBulkImages(size_t max_images)
{
const std::string data_dir = findDataDirectory("perf/calib3d/bulk_n500", false);
std::vector<std::string> image_paths;
cv::utils::fs::glob(data_dir, "*.png", image_paths, false, false);
if (image_paths.empty())
cv::utils::fs::glob(data_dir, "*.jpg", image_paths, false, false);
if (image_paths.empty())
throw SkipTestException("No images found in perf/calib3d/bulk_n500");
std::sort(image_paths.begin(), image_paths.end());
if (image_paths.size() > max_images)
image_paths.resize(max_images);
return image_paths;
}
static std::vector<std::vector<Point2f>> buildImagePoints(const std::vector<std::string>& image_paths, const cv::Size pattern_size)
{
std::vector<std::vector<Point2f>> image_points;
image_points.reserve(image_paths.size());
for (const auto& path : image_paths)
{
Mat gray = imread(path, IMREAD_GRAYSCALE);
if (gray.empty())
{
printf("Can't read image: %s\n", path.c_str());
return std::vector<std::vector<Point2f>>();
}
std::vector<Point2f> corners;
bool found = findChessboardCorners(
gray, pattern_size, corners,
CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE);
if (found)
{
cornerSubPix(gray, corners, Size(11, 11), Size(-1, -1),
TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.1));
image_points.push_back(corners);
}
}
return image_points;
}
static void saveImagePoints(const std::vector<std::vector<Point2f>>& image_points)
{
const std::string points_file = "bulk_n500.yaml";
cv::FileStorage fs(points_file, cv::FileStorage::WRITE | cv::FileStorage::FORMAT_YAML);
if (!fs.isOpened())
{
printf("Cannot open yaml config \"%s\" for output\n", points_file.c_str());
}
fs << "count" << (int)image_points.size();
for (int i = 0; i < (int)image_points.size(); i++)
{
fs << cv::format("frame_%d", i) << image_points[i];
}
fs.release();
}
#else
static std::vector<std::vector<Point2f>> loadImagePoints()
{
const std::string points_file = findDataFile("perf/calib3d/bulk_n500.yaml");
cv::FileStorage fs(points_file, cv::FileStorage::READ);
if (!fs.isOpened())
{
printf("Cannot open yaml config \"%s\" for output\n", points_file.c_str());
return std::vector<std::vector<Point2f>>();
}
int count = fs["count"];
std::vector<std::vector<Point2f>> image_points(count);
for (int i = 0; i < (int)image_points.size(); i++)
{
fs[cv::format("frame_%d", i)] >> image_points[i];
}
fs.release();
return image_points;
}
#endif
static std::vector<std::vector<Point3f>> buildObjectPoints(const Size& pattern_size, float square_size, size_t count)
{
std::vector<Point3f> board;
board.reserve(pattern_size.area());
for (int y = 0; y < pattern_size.height; ++y)
for (int x = 0; x < pattern_size.width; ++x)
board.push_back(Point3f(x * square_size, y * square_size, 0.f));
std::vector<std::vector<Point3f> > object_points;
object_points.reserve(count);
for (size_t i = 0; i < count; i++)
object_points.push_back(board);
return object_points;
}
PERF_TEST(CalibrateCamera, BulkImages_N500)
{
// NOTE: The images archive is published at https://dl.opencv.org/data/bulk_n500.zip
applyTestTag(CV_TEST_TAG_LONG);
const cv::Size pattern_size(6, 8);
const cv::Size image_size(1280, 720);
#ifdef SAVE_IMAGE_POINTS
std::vector<std::string> image_paths = loadBulkImages(500);
std::vector<std::vector<Point2f>> image_points = buildImagePoints(image_paths, pattern_size);
ASSERT_FALSE(image_points.empty());
saveImagePoints(image_points);
#else
std::vector<std::vector<Point2f>> image_points = loadImagePoints();
ASSERT_FALSE(image_points.empty());
#endif
std::vector<std::vector<Point3f> > object_points = buildObjectPoints(pattern_size, 1.0f, image_points.size());
Mat camera_matrix = Mat::eye(3, 3, CV_64F);
Mat dist_coeffs = Mat::zeros(8, 1, CV_64F);
std::vector<Mat> rvecs;
std::vector<Mat> tvecs;
double rms = 0.0;
declare.in(image_points, object_points);
declare.out(camera_matrix, dist_coeffs);
declare.iterations(1);
TEST_CYCLE()
{
camera_matrix = Mat::eye(3, 3, CV_64F);
dist_coeffs = Mat::zeros(8, 1, CV_64F);
rvecs.clear();
tvecs.clear();
rms = calibrateCamera(object_points, image_points, image_size,
camera_matrix, dist_coeffs, rvecs, tvecs, 0);
}
EXPECT_NEAR(rms, 1.768263, 1e-4);
SANITY_CHECK_NOTHING();
}
} // namespace opencv_test
File diff suppressed because it is too large Load Diff
+2 -5
View File
@@ -312,7 +312,7 @@ TEST_F(MultiViewTest, OneLine)
std::vector<cv::Vec3f> board_pattern = genAsymmetricObjectPoints();
std::vector<std::vector<cv::Vec3f>> objPoints(num_frames, board_pattern);
std::vector<int> flagsForIntrinsics(3, CALIB_RATIONAL_MODEL);
std::vector<int> flagsForIntrinsics(3, CALIB_RATIONAL_MODEL | CALIB_DISABLE_SCHUR_COMPLEMENT);
std::vector<cv::Mat> Ks, distortions, Rs, Rs_rvec, Ts;
double rms = calibrateMultiview(objPoints, image_points_all, image_sizes, visibility, models,
@@ -334,7 +334,6 @@ TEST_F(MultiViewTest, OneLine)
TEST_F(MultiViewTest, OneLineInitialGuess)
{
applyTestTag(CV_TEST_TAG_VERYLONG);
const string root = cvtest::TS::ptr()->get_data_path() + "cv/cameracalibration/multiview/3cams-one-line/";
const std::vector<std::string> cam_names = {"cam_0", "cam_1", "cam_3"};
const std::vector<cv::Size> image_sizes = {{1920, 1080}, {1920, 1080}, {1920, 1080} };
@@ -389,7 +388,7 @@ TEST_F(MultiViewTest, OneLineInitialGuess)
{
Mat K, dist;
double mono_rms = calibrateMono(board_pattern, image_points_all[c], image_sizes[c],
cv::CALIB_MODEL_PINHOLE, cv::CALIB_RATIONAL_MODEL,
cv::CALIB_MODEL_PINHOLE, cv::CALIB_RATIONAL_MODEL | CALIB_DISABLE_SCHUR_COMPLEMENT,
K, dist);
CV_LOG_INFO(NULL, "K:" << K);
@@ -440,7 +439,6 @@ TEST_F(MultiViewTest, OneLineInitialGuess)
TEST_F(MultiViewTest, CamsToFloor)
{
applyTestTag(CV_TEST_TAG_VERYLONG);
const string root = cvtest::TS::ptr()->get_data_path() + "cv/cameracalibration/multiview/3cams-to-floor/";
const std::vector<std::string> cam_names = {"cam_0", "cam_1", "cam_2"};
std::vector<cv::Size> image_sizes = {{1920, 1080}, {1920, 1080}, {1280, 720}};
@@ -508,7 +506,6 @@ TEST_F(MultiViewTest, CamsToFloor)
TEST_F(MultiViewTest, Hetero)
{
applyTestTag(CV_TEST_TAG_VERYLONG);
const string root = cvtest::TS::ptr()->get_data_path() + "cv/cameracalibration/multiview/3cams-hetero/";
const std::vector<std::string> cam_names = {"cam_7", "cam_4", "cam_8"};
std::vector<cv::Size> image_sizes = {{1920, 1080}, {1920, 1080}, {2048, 2048}};