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]
相关推荐
恬静的小魔龙31 分钟前
【SKFramework框架核心模块】3-2、音频管理模块
3d·unity·编辑器·游戏引擎·音视频
前端Hardy4 小时前
HTML&CSS:比赛记分卡
前端·javascript·css·3d·html
只怕自己不够好7 小时前
《全面解析图像平滑处理:多种滤波方法及应用实例》
图像处理·python·opencv
SEVEN-YEARS8 小时前
使用OpenCV实现图像拼接
人工智能·opencv·计算机视觉
魔珐科技11 小时前
当产业经济插上“数字羽翼”,魔珐有言AIGC“3D视频创作大赛”成功举办
3d·aigc·音视频
Mr.鱼12 小时前
opencv undefined reference to `cv::noarray()‘ 。window系统配置opencv,找到opencv库,但连接不了
人工智能·opencv·计算机视觉
SEVEN-YEARS13 小时前
使用OpenCV实现视频背景减除与目标检测
opencv·目标检测·音视频
tealcwu15 小时前
【Unity踩坑】出现d3d11问题导致编辑器崩溃
3d
前端Hardy1 天前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html