OpenCV相机标定与3D重建(43)用于计算矫正和重映射的变换函数initUndistortRectifyMap()的使用

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

算法描述

计算畸变矫正和校正变换映射。

该函数计算联合的畸变矫正和校正变换,并以 remap 所需的地图形式表示结果。矫正后的图像看起来像是原始图像,仿佛它是使用 cameraMatrix = newCameraMatrix 和零畸变的相机捕获的一样。对于单目相机,newCameraMatrix 通常等于 cameraMatrix,或者可以通过 getOptimalNewCameraMatrix 计算以更好地控制缩放。对于立体相机,newCameraMatrix 通常设置为由 stereoRectify 计算得到的 P1 或 P2。

此外,这个新的相机在坐标空间中的方向根据 R 不同。例如,这有助于对齐立体相机的两个头,使得两幅图像上的极线变得水平并且具有相同的 y 坐标(对于水平对齐的立体相机而言)。

该函数实际上构建了用于 remap 的逆映射算法的地图。也就是说,对于目标图像(即矫正和校正后的图像)中的每个像素 (u, v),该函数计算源图像(即来自相机的原始图像)中对应的坐标。应用以下过程:
x ← ( u − c ′ x ) / f ′ x y ← ( v − c ′ y ) / f ′ y [ X   Y   W ] T ← R − 1 ⋅ [ x   y   1 ] T x ′ ← X / W y ′ ← Y / W r 2 ← x ′ 2 + y ′ 2 x ′ ′ ← x ′ 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 1 + k 4 r 2 + k 5 r 4 + k 6 r 6 + 2 p 1 x ′ y ′ + p 2 ( r 2 + 2 x ′ 2 ) + s 1 r 2 + s 2 r 4 y ′ ′ ← y ′ 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 1 + k 4 r 2 + k 5 r 4 + k 6 r 6 + p 1 ( r 2 + 2 y ′ 2 ) + 2 p 2 x ′ y ′ + s 3 r 2 + s 4 r 4 s [ x ′ ′ ′ y ′ ′ ′ 1 ] = [ R 33 ( τ x , τ y ) 0 − R 13 ( τ x , τ y ) 0 R 33 ( τ x , τ y ) − R 23 ( τ x , τ y ) 0 0 1 ] ⋅ R ( τ x , τ y ) ⋅ [ x ′ ′ y ′ ′ 1 ] m a p x ( u , v ) ← x ′ ′ ′ f x + c x m a p y ( u , v ) ← y ′ ′ ′ f y + c y \begin{array}{l} x \leftarrow (u - {c'}x) / {f'}x \\ y \leftarrow (v - {c'}y) / {f'}y \\ [X\,Y\,W]^T \leftarrow R^{-1} \cdot [x \, y \, 1]^T \\ x' \leftarrow X/W \\ y' \leftarrow Y/W \\ r^2 \leftarrow x'^2 + y'^2 \\ x'' \leftarrow x' \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} + 2p_1 x' y' + p_2(r^2 + 2 x'^2) + s_1 r^2 + s_2 r^4 \\ y'' \leftarrow y' \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} + p_1 (r^2 + 2 y'^2) + 2 p_2 x' y' + s_3 r^2 + s_4 r^4 \\ s \begin{bmatrix} x''' \\ y''' \\ 1 \end{bmatrix} = \begin{bmatrix} R{33}(\tau_x, \tau_y) & 0 & -R{13}(\tau_x, \tau_y) \\ 0 & R{33}(\tau_x, \tau_y) & -R{23}(\tau_x, \tau_y) \\ 0 & 0 & 1 \end{bmatrix} \cdot R(\tau_x, \tau_y) \cdot \begin{bmatrix} x'' \\ y'' \\ 1 \end{bmatrix} \\ map_x(u,v) \leftarrow x''' f_x + c_x \\ map_y(u,v) \leftarrow y''' f_y + c_y \end{array} x←(u−c′x)/f′xy←(v−c′y)/f′y[XYW]T←R−1⋅[xy1]Tx′←X/Wy′←Y/Wr2←x′2+y′2x′′←x′1+k4r2+k5r4+k6r61+k1r2+k2r4+k3r6+2p1x′y′+p2(r2+2x′2)+s1r2+s2r4y′′←y′1+k4r2+k5r4+k6r61+k1r2+k2r4+k3r6+p1(r2+2y′2)+2p2x′y′+s3r2+s4r4s x′′′y′′′1 = R33(τx,τy)000R33(τx,τy)0−R13(τx,τy)−R23(τx,τy)1 ⋅R(τx,τy)⋅ x′′y′′1 mapx(u,v)←x′′′fx+cxmapy(u,v)←y′′′fy+cy

其中 (k1, k2, p1, p2[, k3[, k4, k5, k6[, s1, s2, s3, s4[, τx, τy]]]]) 是畸变系数。

对于立体相机,此函数会被调用两次:每次针对一个相机头,在 stereoRectify 之后调用,而 stereoRectify 又是在 stereoCalibrate 之后调用的。但如果立体相机未经过校准,仍然可以直接从基本矩阵使用 stereoRectifyUncalibrated 计算校正变换。对于每个相机,该函数以像素域中的单应性矩阵 H 而不是三维空间中的旋转矩阵 R 来计算校正变换。R 可以通过 H 按照以下方式计算:
R = cameraMatrix − 1 ⋅ H ⋅ cameraMatrix \texttt{R} = \texttt{cameraMatrix} ^{-1} \cdot \texttt{H} \cdot \texttt{cameraMatrix} R=cameraMatrix−1⋅H⋅cameraMatrix

其中 cameraMatrix 可以任意选择。

函数原型

cpp 复制代码
void cv::initUndistortRectifyMap	
(
	InputArray 	cameraMatrix,
	InputArray 	distCoeffs,
	InputArray 	R,
	InputArray 	newCameraMatrix,
	Size 	size,
	int 	m1type,
	OutputArray 	map1,
	OutputArray 	map2 
)		

参数

  • 参数cameraMatrix 输入相机矩阵 cameraMatrix = A = [ f x 0 c x 0 f y c y 0 0 1 ] \text{cameraMatrix} = A = \begin{bmatrix}f_x & 0 & c_x \\0 & f_y & c_y \\0 & 0 & 1\end{bmatrix} cameraMatrix=A= fx000fy0cxcy1 。
  • 参数distCoeffs 输入畸变系数向量 (k1, k2, p1, p2[, k3[, k4, k5, k6[, s1, s2, s3, s4[, τx, τy]]]]),包含 4、5、8、12 或 14 个元素。如果该向量为 NULL/空,则假设畸变系数为零。
  • 参数R 可选的对象空间中的校正变换(3x3 矩阵)。可以传递由 stereoRectify 计算得到的 R1 或 R2。如果该矩阵为空,则假定为单位变换。在 initUndistortRectifyMap 中,R 假设为单位矩阵。
  • 参数newCameraMatrix 新的相机矩阵 $ newCameraMatrix = A ′ = [ f x ′ 0 c x ′ 0 f y ′ c y ′ 0 0 1 ] \text{newCameraMatrix} = A' = \begin{bmatrix} f'_x & 0 & c'_x \\ 0 & f'_y & c'_y \\ 0 & 0 & 1 \end{bmatrix} newCameraMatrix=A′= fx′000fy′0cx′cy′1 。
  • 参数size 矫正后图像的尺寸。
  • 参数m1type 第一个输出映射的类型,可以是 CV_32FC1, CV_32FC2 或 CV_16SC2,参见 convertMaps。
  • 参数map1 第一个输出映射。
  • 参数map2 第二个输出映射。

代码示例

cpp 复制代码
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
    // 假设的相机矩阵和畸变系数
    Mat cameraMatrix = ( Mat_< double >( 3, 3 ) << 500, 0, 320, 0, 500, 240, 0, 0, 1 );
    Mat distCoeffs   = ( Mat_< double >( 5, 1 ) << 0.1, 0.05, -0.01, 0.005, 0 );

    // 假设的旋转矩阵 R 和新的相机矩阵 newCameraMatrix
    Mat R               = Mat::eye( 3, 3, CV_64F );  // 单位矩阵作为示例
    Mat newCameraMatrix = cameraMatrix.clone();

    // 图像尺寸
    Size imageSize( 640, 480 );

    // 定义输出映射类型
    int m1type = CV_32FC1;

    // 初始化矫正映射
    Mat map1, map2;
    initUndistortRectifyMap( cameraMatrix, distCoeffs, R, newCameraMatrix, imageSize, m1type, map1, map2 );

    cout << "Undistortion and rectification maps created." << endl;

    // 使用 remap 对图像进行矫正
    Mat originalImage = imread( "/media/dingxin/data/study/OpenCV/sources/images/remap.png" );  // 加载原始图像
    if ( originalImage.empty() )
    {
        cerr << "Error: Could not open or find the image!" << endl;
        return -1;
    }

    Mat undistortedImage;
    remap( originalImage, undistortedImage, map1, map2, INTER_LINEAR );

    // 显示结果
    imshow( "Original Image", originalImage );
    imshow( "Undistorted Image", undistortedImage );
    waitKey( 0 );

    return 0;
}
相关推荐
你好!蒋韦杰-(烟雨平生)14 小时前
Opengl模拟水面
c++·游戏·3d
a11177614 小时前
3D赛车躲避游戏(html threeJS开源)
前端·游戏·3d·开源·html·threejs
清风与日月15 小时前
OpenCV 读取和显示图像功能详解
人工智能·opencv·计算机视觉
该怎么办呢17 小时前
基于 Cesium 3D Tiles 的局部压平方案解析
3d
清风与日月17 小时前
OpenCV 图像显示高级技巧和常见问题
人工智能·opencv·计算机视觉
视觉人机器视觉2 天前
海康机器人3D 机器人引导 —— 空间基础篇一
3d·机器人
程序员林北北2 天前
【前端进阶之旅】Vue3 + Three.js 实战:从零构建交互式 3D 立方体场景
前端·javascript·vue.js·react.js·3d·typescript
deep_drink2 天前
【论文精读(三)】PointMLP:大道至简,无需卷积与注意力的纯MLP点云网络 (ICLR 2022)
人工智能·pytorch·python·深度学习·3d·point cloud
咚咚王者2 天前
人工智能之视觉领域 计算机视觉 第十章 图像直方图
人工智能·opencv·计算机视觉
新缸中之脑3 天前
Tripo AI:构建游戏就绪的3D资产
人工智能·游戏·3d