相机模型关系推导

针对针孔相机模型在工业检测中应用所会遇到的情况进行总结。镜头畸变的原理,内参外参的标定,各个坐标系之间的转换关系。

一 针孔相机

针孔相机来源于初中物理肯本上的经典实验,小孔成像。所以在分析的时候利用相似三角形进行分析,经典的针孔相机几何模型如图所示。

图1 小孔成像模型

 由图一可知

X' =f {\frac X Z} \\ Y' =f {\frac Y Z}

在实际使用过程中,会通过归一化来方便计算,归一化就是让成像平面距离远点O的距离为单位1的坐标。

二 相机标定

由于相机在生产和使用过程中的误差,不可避免的会导致误差,通常是桶形畸变或者枕形畸变会导致画面并非平面,而会在边缘处略微弯曲;如果在组装过程中,镜片和成像平面无法平行,则会引起切向畸变,导致整个平面倾斜。使用标定的方式去弥补这部分误差。

畸变矫正一般都是先校正,再讨论空间坐标。

\begin{bmatrix} u\\ v\\ 1 \end{bmatrix} = \begin{bmatrix} f_x & 0 &c_x \\ 0 & f_y & c_y\\ 0& 0 &1 \end{bmatrix} \begin{bmatrix} x\\ y\\1 \end{bmatrix}

张正友标定法详解

三 坐标系转换

图2 坐标转换推导

 \left\{\begin{matrix} x=& (x'-y'tan\theta)cos\theta = x'cos\theta-y'tan\theta \\ y=& \frac {y'}{cos\theta}+x'tan\theta =x'sin\theta+y'cos\theta \\ z=& z' \end{matrix}\right.

 \begin{bmatrix} x\\ y\\ z \end{bmatrix} = \begin{bmatrix} cos\theta & -sin\theta &0 \\ sin\theta & cos\theta & 0\\ 0& 0 &1 \end{bmatrix} \begin{bmatrix} x'\\ y'\\ z' \end{bmatrix} = R_1\begin{bmatrix} x'\\ y'\\ z'\end{bmatrix}

\begin{bmatrix} x\\ y\\ z \end{bmatrix} = \begin{bmatrix} 1 & 0&0 \\ 0& cos\phi & sin\phi\\ 0& -sin\phi &cos\phi \end{bmatrix} \begin{bmatrix} x'\\ y'\\ z'\end{bmatrix} = R_2\begin{bmatrix} x'\\ y'\\ z'\end{bmatrix}

\begin{bmatrix} x\\ y\\ z \end{bmatrix} = \begin{bmatrix} cos\varphi& 0&-sin\varphi \\ 0& 1 & 0\\ sin\varphi& 0&cos\varphi \end{bmatrix} \begin{bmatrix} x'\\ y'\\ z' \end{bmatrix} = R_3\begin{bmatrix} x'\\ y'\\ z'\end{bmatrix}

 这是绕Z轴做旋转时所得到到旋转矩阵R1,绕X轴Y轴时会有R2,R3的矩阵。旋转矩阵加上平移向量,则可完成两个坐标之间的转换。

\begin{bmatrix} x\\ y\\ z \end{bmatrix} = \begin{bmatrix} R & T \\ 0 & 1 \end{bmatrix} \begin{bmatrix} x'\\ y'\\ z' \end{bmatrix}

由世界坐标系到像素坐标系的关系如下图所示

 四 三维坐标系转换

在三维空间中直接进行坐标转换,当知道具体旋转角度时可以直接代入公式中计算出旋转矩阵。当知道两个坐标系对应点时,可以采用罗德里格矩阵模型求出旋转矩阵,直接求解会导致误差过大,使用非线性优化的方式减少误差。或使用SVD手眼标定。

相关资料:

基于罗德里格矩阵的空间坐标转换 韩梦泽

三维坐标转换精度及其影响因素的研究 张皓琳

相机标定(三)——手眼标定_white_Learner的博客-CSDN博客

OpenCV手眼标定(calibrateHandeye())_hellohake的博客-CSDN博客

三维坐标系之间转换方法 - 知乎

import numpy as np

# 代码表明,使用罗德里格求出旋转矩阵误差为0.001
def caculate_cross_matrix(old_coordinate, R):

    a = R*old_coordinate
    return a


def caculate_Rodrigues(old_point, new_point):
    o1 = old_point[:, 0]
    o2 = old_point[:, 1]
    o3 = old_point[:, 2]

    x1, y1, z1 = float(o1[0]), float(o1[1]), float(o1[2])
    x2, y2, z2 = float(o2[0]), float(o2[1]), float(o2[2])
    x3, y3, z3 = float(o3[0]), float(o3[1]), float(o3[2])

    n1 = new_point[:, 0]
    n2 = new_point[:, 1]
    n3 = new_point[:, 2]

    u1, v1, w1 = float(n1[0]), float(n1[1]), float(n1[2])
    u2, v2, w2 = float(n2[0]), float(n2[1]), float(n2[2])
    u3, v3, w3 = float(n3[0]), float(n3[1]), float(n3[2])

    u21 = u2-u1
    v21 = v2-v1
    w21 = w2-w1
    x21 = x2-x1
    y21 = y2-y1
    z21 = z2-z1

    u31 = u3-u1
    v31 = v3-v1
    w31 = w3-w1
    x31 = x3-x1
    y31 = y3-y1
    z31 = z3-z1

    L = np.matrix([[u21-x21],
                   [v21-y21],
                   [w21-z21],
                   [u31-x31],
                   [v31-y31],
                   [w31-z31]])

    A = np.matrix([[0, -z21-w21, -y21-v21],
                  [-z21-w21, 0, x21+u21],
                  [y21+v21, x21+u21, 0],
                  [0, -z31-w31, -y31-v31],
                  [-z31-w31, 0, x31+u31],
                  [y31+v31, x31+u31, 0]])
    # 直接求解很难
    # a = np.linalg.solve(B, L)

    # 最小二乘法间接求
    X = np.linalg.inv(((A.T)*A))*(A.T)*L

    a, b, c = float(X[0]), float(X[1]), float(X[2])
    tmp = 1/(1+a*a+b*b+c*c)
    R = tmp * np.matrix([
        [1+a**2-b**2-c**2, -2*c-2*a*b, -2*b+2*a*c],
        [2*(c-a*b), 1-a*2+b*2-c*2, -2*a-2*c*b],
        [2*(b+a*c), 2*(a-b*c), 1-a**2-b**2+c**2]])

    return R


# 旋转角度依次为 20,40,60
R3 = np.matrix([[0.2795, -0.9237, -0.2620],
                [0.6634, 0.3830, -0.6428],
                [0.6941, 0.0058, 0.7198]])


# 原坐标系坐标
old_coordinate = np.matrix([[5, 10, 20],
                            [8, 10, 30],
                            [15, 10, 40]])

# 文章给的另一组坐标
new_coordinate_paper = np.matrix([[-9.9225, -3.2606, 14.3147],
                                  [-9.0627, 4.0365, 14.1977],
                                  [-32.6027, -0.9526, 42.8504]])
new_coordinate_paper = new_coordinate_paper.T

# 通过旋转矩阵计算得到心坐标系坐标
new_coordinate = caculate_cross_matrix(old_coordinate, R3)
R = caculate_Rodrigues(old_coordinate, new_coordinate_paper)

print("知道角度后的旋转矩阵\n",R3)
print("通过罗德里格矩阵求得旋转矩阵\n",R)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

低调小萱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值