从零开始学习Slam(四)

从零开始学习Slam(四) - 相机成像模型

本文基本照抄计算机视觉life, 做个人笔记用

齐次坐标

首先打个基础,回忆一下齐次坐标

齐次坐标就是在原有坐标上加上一个维度.

  • 如果(x, y, z)是点:

(1). 从普通坐标转换成齐次坐标

​ (x, y, z)------> (x, y, z, 1)

(2) .从齐次坐标转换成普通坐标时

​ (x, y, z, 1) ------> (x, y, z)

  • 如果(x, y, z)是向量:

(1). 从普通坐标转换成齐次坐标

​ (x, y, z)------> (x, y, z, 0)

(2). 从齐次坐标转换成普通坐标时

​ (x, y, z, 0) ------> (x, y, z)

使用齐次坐标可以将加法转换为乘法,方便的表达平移,比如要将坐标点[u, v]平移t[tu, tv]
[ u ′ v ′ ] = [ u + t u v + t v ] = x + t \begin{bmatrix} u'\\ v' \end{bmatrix}=\begin{bmatrix} u+{t}_{u}\\ v+{t}_{v} \end{bmatrix} = x+t [uv]=[u+tuv+tv]=x+t
如果使用 齐次坐标可以表示为:

[ u ′ v ′ 1 ] = [ 1 0 t u 0 1 t v 0 0 1 ] [ u v 1 ] = T x \begin{bmatrix} u'\\v' \\ 1 \end{bmatrix}= \begin{bmatrix} 1& 0& {t}_{u}\\ 0& 1& {t}_{v}\\ 0& 0& 1 \end{bmatrix} \begin{bmatrix} u\\v \\ 1 \end{bmatrix}={T}_{x} uv1 = 100010tutv1 uv1 =Tx

如果我们想要将向量a进行一个标准的欧氏变换,一般是先用旋转矩阵R进行旋转,然后再用向量t进行平移,其结果a’ = R*a + t, 使用齐次坐标可以表达为:

[ a ′ 1 ] = [ R t 0 1 ] [ a 1 ] = T [ a 1 ] \begin{bmatrix} a'\\ 1 \end{bmatrix} = \begin{bmatrix} R& t\\ 0& 1 \end{bmatrix}\begin{bmatrix} a\\ 1 \end{bmatrix} = T\begin{bmatrix} a\\ 1 \end{bmatrix} [a1]=[R0t1][a1]=T[a1]
如果进行多次欧式变换的时候就可以表达为a’ = TnTn-1…T1 a

相机成像模型

在这里插入图片描述

来看一张被盘到包浆的图片,相机坐标系下的点P(X, Y, Z)在相机成像平面上成的像为P’(X’, Y’, Z’) 。假设你已经知道小学二年级的小孔成像内容,根据三角形相似原理:
z f = X X ′ = Y Y ′ → X ′ = f X Z , Y ′ = f Y Z ( 1 ) \frac{z}{f} = \frac{X}{X'}= \frac{Y}{Y'} \to X'=f\frac{X}{Z}, Y'=f\frac{Y}{Z} (1) fz=XX=YYX=fZX,Y=fZY1
其中,f是相机的焦距。

但是成像过程一般是以图像中心点为坐标系原点的,如下图所示。而我们做图像处理的时候习惯于从左上角为图像坐标系原点。如下图:

在这里插入图片描述

所以需要平移:

U = Uo + Cx (2)

V = Vo + Cy

这里的Uo 、Vo 、Cx、Cy是以像素为单位的数据(在图像中), X和Y是距离单位(米或毫米),所以还需要一个尺度因子α和β:

U = αX’+ Cx (3)

V = βY’ + Cy

Cx和Cy分别是图像宽和高的一半。

把公式(2)带入公式(1)得到:
{ u = f x X Z + c x v = f y Y Z + c y \left\{\begin{matrix} u={f}_{x}\frac{X}{Z}+{c}_{x}\\ v={f}_{y}\frac{Y}{Z}+{c}_{y} \end{matrix}\right. {u=fxZX+cxv=fyZY+cy
使用齐次坐标表达为:

[ x y 1 ] = 1 Z [ f x 0 c x 0 f y c y 0 0 1 ] [ X Y Z ] ≜ 1 Z K P ( 4 ) \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} = \frac{1}{Z}\begin{bmatrix} {f}_{x}& 0 & {c}_{x}\\ 0& {f}_{y} &{c}_{y}\\ 0& 0& 1 \end{bmatrix}\begin{bmatrix} X\\ Y\\ Z \end{bmatrix} \triangleq \frac{1}{Z}KP (4) xy1 =Z1 fx000fy0cxcy1 XYZ Z1KP(4)

这个Z是相机坐标系下P点的Z坐标,如果把这个 1/Z 和 P(X,Y,Z) 进行相乘,就得到了相机坐标系下P的归一化坐标 P = (X/Z, Y/Z, 1)

公式(4)左侧图像坐标是齐次坐标,中间红色框内的矩阵K称为内参数,最右侧蓝色框内的就是相机坐标系下的三维点P。

我们结合前面从世界坐标系到相机坐标系的变换(如公式3),就有了如下式子:

在这里插入图片描述

其中 fx, fy 分别是x, y方向焦距,一般都是相等的, cx,cy是光心位置,一般是长和宽的一半,他们都叫内参,此外还有畸变系数也属于内参,他们都是相机固有参数。

总结一下整个过程

1、首先,世界坐标系下有一个三维点Pw
2、若世界坐标系到相机坐标系下的变换为旋转矩阵 R 和平移向量t 组成的变换矩阵 T,那么Pw在相机坐标系下的坐标为 Pc = R * Pw + t = T * Pw
3、此时的Pc三个分量分别是X, Y, Z,我们需要把它投影到归一化平面Z=1上,这样我们得到了相机坐标系下Pc的归一化坐标 Pc’ = (X/Z, Y/Z, 1)
4、用内参矩阵乘以归一化坐标就得到了像素坐标 Puv = K*Pc’
R * Pw + t = T * Pw
3、此时的Pc三个分量分别是X, Y, Z,我们需要把它投影到归一化平面Z=1上,这样我们得到了相机坐标系下Pc的归一化坐标 Pc’ = (X/Z, Y/Z, 1)
4、用内参矩阵乘以归一化坐标就得到了像素坐标 Puv = K * Pc’

相机畸变

当光线通过透镜时,不同位置的光线可能以不同的方式折射,导致图像边缘与中心的比例失调。这种偏差会导致几何变形(径向畸变),如桶形畸变和枕形畸变。
在这里插入图片描述

畸变参数

径向畸变的参数,它们是由相机标定过程确定的。径向畸变参数的值影响镜头的畸变程度,通常由标定过程自动计算得到。
下面给出畸变矫正的代码:

/*将畸变图像中一个特定位置的像素值(通过v_distorted和
u_distorted确定)复制到去畸变图像的一个指定位置(v和u)。
简单来说,它是在执行图像的逆向映射,利用畸变模型将每个去畸
变图像上的像素值从原始畸变图像中提取出来。

这种映射通常在去畸变处理过程中使用,以便将图像从畸变的状态恢复到
较为真实的状态。*/
#include <opencv2/opencv.hpp>
using namespace std;

string image_file = "./test.png";   // 图像文件的路径,确保路径正确

int main(int argc, char **argv) {
    double k1 = -0.28340811, k2 = 0.07395907;  // 畸变参数
    double fx = 458.654, fy = 457.296, cx = 367.215, cy = 248.375;  // 相机内参

    cv::Mat image = cv::imread(image_file, CV_8UC1);   // 读取灰度图像
    int rows = image.rows, cols = image.cols;
    cv::Mat image_undistort = cv::Mat(rows, cols, CV_8UC1);   // 创建去畸变后的图像矩阵
    cv::imshow("image distorted", image);  // 显示原始畸变图像

    // 计算去畸变后图像的内容
    for (int v = 0; v < rows; v++)
        for (int u = 0; u < cols; u++) {
            double u_distorted = 0, v_distorted = 0;
            
            // 这里是需要计算去畸变后的 (u_distorted, v_distorted)
            // 开始代码
            
            double x = (u - cx) / fx;  // 计算归一化坐标
            double y = (v - cy) / fy;
            double r2 = x * x + y * y;
            double r4 = r2 * r2;
            double distortion_factor = 1 + k1 * r2 + k2 * r4;
            double x_distorted = x * distortion_factor;
            double y_distorted = y * distortion_factor;
            
            u_distorted = x_distorted * fx + cx;  // 计算去畸变后的像素坐标
            v_distorted = y_distorted * fy + cy;

            // 结束代码

            // 确保去畸变后的坐标在图像范围内
            if (u_distorted >= 0 && v_distorted >= 0 && u_distorted < cols && v_distorted < rows) {
                image_undistort.at<uchar>(v, u) = image.at<uchar>((int) v_distorted, (int) u_distorted);
            } else {
                image_undistort.at<uchar>(v, u) = 0;  // 超出范围的像素设为0
            }
        }

    cv::imshow("image undistorted", image_undistort);  // 显示去畸变图像
    cv::waitKey();  // 等待按键

    return 0;
}
  • k1和 k2 是径向畸变的参数,它们是由相机标定过程确定的。k1 和 k2 的值影响镜头的畸变程度,通常由标定过程自动计算得到。
  • r 是像素点到图像中心的距离。为了简化计算,通常用 r2和 r4 来表示畸变的影响。
  • distortion_factor = 1 + k1 * r2 + k2 * r4; 是径向畸变校正中的一个因子。它表示畸变系数随着距离增加而逐渐增大的情况。通过这个因子,可以将畸变的像素值调整回相机模型的预期值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值