OpenCV相机标定与3D重建(3)校正鱼眼镜头畸变的函数calibrate()的使用

  • 操作系统:ubuntu22.04
  • OpenCV版本:OpenCV4.9
  • IDE:Visual Studio Code
  • 编程语言:C++11

算法描述

cv::fisheye::calibrate 函数是 OpenCV 中用于校正鱼眼镜头畸变的一个重要函数。该函数通过一系列棋盘格标定板的图像来计算相机的内参矩阵和畸变系数。

函数原型

cpp 复制代码
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:迭代优化算法的终止条件。

代码示例

cpp 复制代码
#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;
}

运行结果

终端输出:

bash 复制代码
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]
相关推荐
谷谷地图下载器6 小时前
【全网首发】台湾省模型数据“去水印“说明(3Dtiles和osgb格式),全台湾省的模型数据,全域无水印AI处理,支持所有模型格式
3d
9分钟带帽7 小时前
opencv存图速度测试
opencv·halcon
西猫雷婶9 小时前
python学opencv|读取图像(二十二)使用cv2.polylines()绘制多边形
开发语言·python·opencv
伊一大数据&人工智能学习日志9 小时前
OpenCV计算机视觉 02 图片修改 图像运算 边缘填充 阈值处理
人工智能·opencv·计算机视觉
伊一大数据&人工智能学习日志14 小时前
OpenCV计算机视觉 01 图像与视频的读取操作&颜色通道
人工智能·opencv·计算机视觉
前端Hardy14 小时前
HTML&CSS:惊!3D 折叠按钮
css·3d·html
18号房客15 小时前
计算机视觉-人工智能(AI)入门教程一
人工智能·深度学习·opencv·机器学习·计算机视觉·数据挖掘·语音识别
工业3D_大熊16 小时前
【CAE开发SDK】CEETRON Envision:适用于桌面端、Web端的数据可视化与分析
3d·数据分析·虚拟仿真·cae·cae系统开发·cae可视化·cae数据分析
天天进步201516 小时前
使用 Three.js 创建一个 3D 人形机器人仿真系统
3d
是十一月末17 小时前
Opencv实现图像的腐蚀、膨胀及开、闭运算
人工智能·python·opencv·计算机视觉