【cv::triangulatePoints】其中的投射矩阵P(3x4)是怎么得到的?(内外参数K[R|t]到最终矩阵的变换过程)

1. cv::triangulatePoints

cv::triangulatePoints 是 OpenCV 中用于三角测量的函数,用于从两个视角的图像点计算出对应的三维空间点。这在立体视觉和计算机视觉中非常有用,尤其是在从多视角图像中恢复三维结构时。

函数声明

cpp 复制代码
void cv::triangulatePoints(
    const cv::Mat& projMatrix1,
    const cv::Mat& projMatrix2,
    const cv::Mat& projPoints1,
    const cv::Mat& projPoints2,
    cv::Mat& points4D
);

参数解释

  • projMatrix1: 第一个视角的投影矩阵(3x4),描述了从三维空间到第一视角图像的映射关系。可以通过相机内参和外参来构造。
  • projMatrix2: 第二个视角的投影矩阵(3x4),描述了从三维空间到第二视角图像的映射关系。
  • projPoints1 : 第一个视角图像中的点坐标集合,类型通常为 cv::Mat,每个点为一个 2D 坐标。大小为 2xN,N 为点的数量。
  • projPoints2 : 第二个视角图像中的点坐标集合,类型与 projPoints1 相同,大小也为 2xN
  • points4D : 输出的四维点集合,类型为 cv::Mat。每个点表示为四维齐次坐标 (X, Y, Z, W),其中 W 通常是 1。大小为 4xN,N 为点的数量。

使用示例

以下是一个使用 cv::triangulatePoints 的示例:

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

int main() {
    // 第一个视角的投影矩阵(示例值)
    cv::Mat projMatrix1 = (cv::Mat_<double>(3, 4) << 
        1000, 0, 320, 0,
        0, 1000, 240, 0,
        0, 0, 1, 0);

    // 第二个视角的投影矩阵(示例值)
    cv::Mat projMatrix2 = (cv::Mat_<double>(3, 4) << 
        1000, 0, 320, -100,
        0, 1000, 240, 0,
        0, 0, 1, 0);

    // 第一个视角中的点
    cv::Mat projPoints1 = (cv::Mat_<double>(2, 2) << 
        100, 150,
        200, 250);

    // 第二个视角中的点
    cv::Mat projPoints2 = (cv::Mat_<double>(2, 2) << 
        110, 160,
        210, 260);

    // 输出的四维点
    cv::Mat points4D;

    // 执行三角测量
    cv::triangulatePoints(projMatrix1, projMatrix2, projPoints1, projPoints2, points4D);

    // 打印三维点
    for (int i = 0; i < points4D.cols; ++i) {
        cv::Mat point = points4D.col(i);
        double X = point.at<double>(0) / point.at<double>(3);
        double Y = point.at<double>(1) / point.at<double>(3);
        double Z = point.at<double>(2) / point.at<double>(3);
        std::cout << "3D Point: (" << X << ", " << Y << ", " << Z << ")\n";
    }

    return 0;
}

使用细节

  • 投影矩阵 : projMatrix1projMatrix2 是 3x4 的矩阵,通常由相机的内参矩阵和外参矩阵组合得到。它们表示从三维空间到两个视角图像的映射关系。
  • 点的格式 : projPoints1projPoints2 必须是相同大小的点集合,每个点都是二维坐标 (x, y)
  • 四维点 : points4D 输出的点是四维齐次坐标,其中最后一维 W 通常是 1。计算实际的三维点坐标时,需要将齐次坐标除以 W

2. 由K[R|t] 得到映射矩阵P

要将相机投影矩阵 P P P写成 K [ R ∣ t ] \mathbf{K}[\mathbf{R} | \mathbf{t}] K[R∣t]的形式,并将其变换为一个 3 × 4 3 \times 4 3×4的矩阵,我们需要分别处理相机的内参矩阵 K \mathbf{K} K和外参矩阵 [ R ∣ t ] [\mathbf{R} | \mathbf{t}] [R∣t]。

1. 相机内参矩阵 K \mathbf{K} K

相机内参矩阵 K \mathbf{K} K是一个 3 × 3 3 \times 3 3×3的矩阵,描述相机的内部参数:

K = [ f x 0 c x 0 f y c y 0 0 1 ] \mathbf{K} = \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} K= fx000fy0cxcy1

其中:

  • f x f_x fx和 f y f_y fy是焦距,单位通常是像素。
  • c x c_x cx和 c y c_y cy是主点(光心)的坐标。

2. 相机外参矩阵 [ R ∣ t ] [\mathbf{R} | \mathbf{t}] [R∣t]

相机外参矩阵由旋转矩阵 R \mathbf{R} R和平移向量 t \mathbf{t} t组成,它是一个 3 × 4 3 \times 4 3×4的矩阵:

  • 旋转矩阵 R \mathbf{R} R 是一个 3 × 3 3 \times 3 3×3的矩阵,用于将三维点从世界坐标系旋转到相机坐标系:

R = [ R 11 R 12 R 13 R 21 R 22 R 23 R 31 R 32 R 33 ] \mathbf{R} = \begin{bmatrix} R_{11} & R_{12} & R_{13} \\ R_{21} & R_{22} & R_{23} \\ R_{31} & R_{32} & R_{33} \end{bmatrix} R= R11R21R31R12R22R32R13R23R33

  • 平移向量 t \mathbf{t} t 是一个 3 × 1 3 \times 1 3×1的向量,用于将旋转后的点从世界坐标系平移到相机坐标系:

t = [ t x t y t z ] \mathbf{t} = \begin{bmatrix} t_x \\ t_y \\ t_z \end{bmatrix} t= txtytz

  • 组合外参矩阵 :将 R \mathbf{R} R和 t \mathbf{t} t组合为一个 3 × 4 3 \times 4 3×4的矩阵:

[ R ∣ t ] = [ R 11 R 12 R 13 t x R 21 R 22 R 23 t y R 31 R 32 R 33 t z ] [\mathbf{R} | \mathbf{t}] = \begin{bmatrix} R_{11} & R_{12} & R_{13} & t_x \\ R_{21} & R_{22} & R_{23} & t_y \\ R_{31} & R_{32} & R_{33} & t_z \end{bmatrix} [R∣t]= R11R21R31R12R22R32R13R23R33txtytz

3. 组合内参和外参矩阵

相机投影矩阵 P P P是内参矩阵 K \mathbf{K} K和外参矩阵 [ R ∣ t ] [\mathbf{R} | \mathbf{t}] [R∣t]的乘积,结果是一个 3 × 4 3 \times 4 3×4的矩阵:

P = K [ R ∣ t ] \mathbf{P} = \mathbf{K}[\mathbf{R} | \mathbf{t}] P=K[R∣t]

将它们进行矩阵乘法:

P = [ f x 0 c x 0 f y c y 0 0 1 ] [ R 11 R 12 R 13 t x R 21 R 22 R 23 t y R 31 R 32 R 33 t z ] \mathbf{P} = \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} R_{11} & R_{12} & R_{13} & t_x \\ R_{21} & R_{22} & R_{23} & t_y \\ R_{31} & R_{32} & R_{33} & t_z \end{bmatrix} P= fx000fy0cxcy1 R11R21R31R12R22R32R13R23R33txtytz

通过矩阵乘法,可以得到:

P = [ f x R 11 + c x R 31 f x R 12 + c x R 32 f x R 13 + c x R 33 f x t x + c x t z f y R 21 + c y R 31 f y R 22 + c y R 32 f y R 23 + c y R 33 f y t y + c y t z R 31 R 32 R 33 t z ] \mathbf{P} = \begin{bmatrix} f_x R_{11} + c_x R_{31} & f_x R_{12} + c_x R_{32} & f_x R_{13} + c_x R_{33} & f_x t_x + c_x t_z \\ f_y R_{21} + c_y R_{31} & f_y R_{22} + c_y R_{32} & f_y R_{23} + c_y R_{33} & f_y t_y + c_y t_z \\ R_{31} & R_{32} & R_{33} & t_z \end{bmatrix} P= fxR11+cxR31fyR21+cyR31R31fxR12+cxR32fyR22+cyR32R32fxR13+cxR33fyR23+cyR33R33fxtx+cxtzfyty+cytztz

解释

  • 第一行 :表示在 x 方向的投影,结合了 x 焦距 f x f_x fx、主点 c x c_x cx,以及旋转和平移的影响。
  • 第二行 :表示在 y 方向的投影,结合了 y 焦距 f y f_y fy、主点 c y c_y cy,以及旋转和平移的影响。
  • 第三行:用于齐次坐标的归一化。

总结

通过内参矩阵和外参矩阵的组合,我们得到了用于描述三维点到二维图像平面投影的投影矩阵 P \mathbf{P} P。这个矩阵在多视图几何和计算机视觉的应用中至关重要,特别是在三维重建和相机校准中。

相关推荐
娅娅梨25 分钟前
C++ 错题本--not found for architecture x86_64 问题
开发语言·c++
兵哥工控29 分钟前
MFC工控项目实例二十九主对话框调用子对话框设定参数值
c++·mfc
我爱工作&工作love我36 分钟前
1435:【例题3】曲线 一本通 代替三分
c++·算法
娃娃丢没有坏心思1 小时前
C++20 概念与约束(2)—— 初识概念与约束
c语言·c++·现代c++
lexusv8ls600h1 小时前
探索 C++20:C++ 的新纪元
c++·c++20
lexusv8ls600h1 小时前
C++20 中最优雅的那个小特性 - Ranges
c++·c++20
白-胖-子1 小时前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-统计数字
开发语言·c++·算法·蓝桥杯·等考·13级
好睡凯1 小时前
c++写一个死锁并且自己解锁
开发语言·c++·算法
阿_旭2 小时前
如何使用OpenCV和Python进行相机校准
python·opencv·相机校准·畸变校准
依旧阳光的老码农2 小时前
标准C++ 字符串
开发语言·c++