OpenCV相机标定与3D重建(3)校正鱼眼镜头畸变的函数calibrate()的使用
- 操作系统:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 编程语言:C++11
算法描述
cv::fisheye::calibrate 函数是 OpenCV 中用于校正鱼眼镜头畸变的一个重要函数。该函数通过一系列棋盘格标定板的图像来计算相机的内参矩阵和畸变系数。
函数原型
double cv::fisheye::calibrate
(
InputArrayOfArrays objectPoints,
InputArrayOfArrays imagePoints,
const Size & image_size,
InputOutputArray K,
InputOutputArray D,
OutputArrayOfArrays rvecs,
OutputArrayOfArrays tvecs,
int flags = 0,
TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 100, DBL_EPSILON)
)
参数
- 参数objectPoints:标定图案坐标空间中标定图案点的向量的向量。
- 参数imagePoints:标定图案点投影的向量的向量。对于每个 i,imagePoints.size() 和 objectPoints.size() 以及 imagePoints[i].size() 必须等于 objectPoints[i].size()。
- 参数image_size:仅用于初始化相机内参矩阵的图像尺寸。
- 参数K:输出 3x3 浮点型相机内参矩阵 K = [ f x 0 c x 0 f y c y 0 0 1 ] K = \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} K= fx000fy0cxcy1 。如果指定了 fisheye::CALIB_USE_INTRINSIC_GUESS,则 fx, fy, cx, cy 中的一些或全部必须在调用函数前初始化。
- 参数D:输出的畸变系数向量 D = [ k 1 k 2 k 3 k 4 ] D = \begin{bmatrix} k_1 & k_2 & k_3 & k_4 \end{bmatrix} D=[k1k2k3k4]
- 参数rvecs:输出的旋转向量向量(见 Rodrigues),每个元素是一个 3x1 向量,表示每个图案视图的旋转。每个第 k 个旋转向量与对应的第 k 个平移向量(见下一个输出参数描述)一起,将标定板从模型坐标空间(在其中指定物体点)带到世界坐标空间,即标定板在第 k 个图案视图中的真实位置(k=0…M-1)。
- 参数tvecs:输出的平移向量向量,每个元素是一个 3x1 向量,表示每个图案视图的平移。
- 参数flags:不同的标志,可以是零或以下值的组合:
- fisheye::CALIB_USE_INTRINSIC_GUESS:cameraMatrix 包含有效的初始值 fx, fy, cx, cy,这些值将进一步优化。否则,(cx, cy) 最初设置为图像中心(使用 imageSize),焦距以最小二乘法计算。
- fisheye::CALIB_RECOMPUTE_EXTRINSIC:每次内在参数优化迭代后,外在参数将重新计算。
- fisheye::CALIB_CHECK_COND:函数将检查条件数的有效性。
- fisheye::CALIB_FIX_SKEW:斜率系数(alpha)设置为零并保持不变。
- fisheye::CALIB_FIX_K1 到 fisheye::CALIB_FIX_K4:选定的畸变系数设置为零并保持不变。
- fisheye::CALIB_FIX_PRINCIPAL_POINT:主点在全局优化过程中不改变。它保持在中心或在 fisheye::CALIB_USE_INTRINSIC_GUESS 设置时指定的不同位置。
- fisheye::CALIB_FIX_FOCAL_LENGTH:焦距在全局优化过程中不改变。它是 max(width, height)/π 或者当
- fisheye::CALIB_USE_INTRINSIC_GUESS 设置时提供的 fx, fy。
- criteria:迭代优化算法的终止条件。
代码示例
#include <iostream>
#include <opencv2/calib3d.hpp>
#include <opencv2/opencv.hpp>
#include <string>
#include <vector>
using namespace cv;
using namespace std;
int main( int argc, char** argv )
{
// 棋盘格尺寸(内部角点数)
Size boardSize( 5, 8 );
// 存储棋盘格角点的世界坐标
vector< Point3f > objp;
for ( int i = 0; i < boardSize.height; ++i )
{
for ( int j = 0; j < boardSize.width; ++j )
{
objp.push_back( Point3f( j, i, 0 ) );
}
}
// 存储所有图像中的棋盘格角点的像素坐标
vector< vector< Point2f > > imgPoints;
// 存储所有图像中棋盘格角点的世界坐标
vector< vector< Point3f > > objPoints;
// 读取图像文件列表
vector< String > imageNames;
glob( "/media/dingxin/data/study/OpenCV/sources/images/chessboard.png", imageNames, false );
if ( imageNames.empty() )
{
std::cout << "No images found at the specified path." << std::endl;
return -1;
}
Mat img, gray;
for ( const auto& imageName : imageNames )
{
img = imread( imageName, IMREAD_COLOR );
if ( img.empty() )
{
std::cout << "Could not open or find the image: " << imageName << std::endl;
continue;
}
cvtColor( img, gray, COLOR_BGR2GRAY );
// 查找棋盘格角点
vector< Point2f > corners;
bool found = findChessboardCorners( gray, boardSize, corners, CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE + CALIB_CB_FAST_CHECK );
if ( found )
{
// 亚像素精确定位
cornerSubPix( gray, corners, Size( 11, 11 ), Size( -1, -1 ), TermCriteria( TermCriteria::EPS + TermCriteria::MAX_ITER, 30, 0.1 ) );
// 添加角点到 imgPoints 和 objPoints
imgPoints.push_back( corners );
objPoints.push_back( objp );
// 绘制角点
drawChessboardCorners( img, boardSize, corners, found );
imshow( "Found Corners", img );
waitKey( 500 );
}
else
{
std::cout << "Could not find chessboard corners in image: " << imageName << std::endl;
}
}
// 检查是否有足够的图像用于校准
if ( imgPoints.empty() )
{
std::cout << "No valid images found for calibration." << std::endl;
return -1;
}
// 相机内参矩阵
Mat K = Mat::eye( 3, 3, CV_64F );
// 畸变系数
Mat D = Mat::zeros( 4, 1, CV_64F );
// 终止条件
TermCriteria criteria( TermCriteria::COUNT + TermCriteria::EPS, 100, DBL_EPSILON );
// 校准
int flags = cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC + cv::fisheye::CALIB_FIX_SKEW + cv::fisheye::CALIB_CHECK_COND;
double rms = cv::fisheye::calibrate( objPoints, imgPoints, gray.size(), K, D, noArray(), noArray(), flags, criteria );
cout << "RMS re-projection error: " << rms << endl;
cout << "Camera matrix:\n" << K << endl;
cout << "Distortion coefficients:\n" << D << endl;
// 保存结果
FileStorage fs( "calibration_result.yml", FileStorage::WRITE );
fs << "camera_matrix" << K;
fs << "dist_coeffs" << D;
fs.release();
cv::waitKey( 0 );
return 0;
}
运行结果
终端输出:
RMS re-projection error: 0.0538752
Camera matrix:
[125280.3440762279, 0, 224.5000000010562;
0, 125280.3438483639, 149.4999999998818;
0, 0, 1]
Distortion coefficients:
[-582.4113543586071;
116.5218245736505;
-11.04383019115448;
0.5796488453961863]