详解相机的内参和外参,以及表里参的标定方法
1 四个坐标系要想深入搞清楚相机的内参和外参含义, 首先得清楚以下4个坐标系的定义:
[*]世界坐标系: 名字看着很唬人, 实在没什么大不了的, 这个就是你自己定义的某一个坐标系。 比如, 你把房间的某一个点定为原点, 而且定义好方向, 这就是世界坐标系。 一样平常是个三维坐标系, 单位是m
[*]相机坐标系: 以相机光心为原点, 一样平常我们把z轴指向相机前方,x向右,y向下,是个三维坐标系, 单位是m
[*]成像平面坐标系: 这个是定义在物理成像平面的坐标系,方向定义与相机坐标系同等(没有z方向), 原点是光心在物理成像平面上的投影,是个二维坐标系, 单位是m。 注意, 我们一样平常都会忽略这个坐标系, 因为它是个中间过渡状态, 很少直接使用它。
[*]像素坐标系: 这个应该是最为常用, 也最为大家认识的坐标系, 计算机视觉任务的输出的坐标表达都是在这个坐标系。 它是个二维坐标系, 原点通常在图像的左上角, x向右,y向下, 单位是像素, 没有具体的尺度。
https://i-blog.csdnimg.cn/direct/358225a5c5844a5ea17918adf723b6d1.png
2 内参和外参
除了世界坐标系, 后面三个坐标系只跟相机本身有关。 相机内参表达的就是这三个坐标之间的转换关系, 而相机外参表达的是相机与世界坐标系之间的转换关系。
成像的过程实质上是几个坐标系的转换。首先空间中的一点由世界坐标系转换到相机坐标系 ,然后再将其投影到物理成像平面 ( 成像平面坐标系 ) ,末了再将成像平面上的数据转换像素坐标系 。
https://i-blog.csdnimg.cn/direct/07a553bed99942b991725dfffda4cc24.png
从世界坐标到像素坐标总共有3步转换, 前面2个合在一起就是相机内参, 末了一个是相机外参。
上面矩阵中的参数很好理解, 也都有明确的物理含义: a 和b 表示从成像平面坐标转到像素坐标时, 分别在x和y轴上的缩放系数, u 0 u_0 u0和 v 0 v_0 v0是原点的平移量。 r r r是扭曲因子, 一样平常为0。 f f f是相机的焦距。 R和T是旋转宁静移矩阵。
把前面2个合一起, 就得到了如下更为常见的内参矩阵:
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
下面的解说中, 我们直接用这种形式,跳过成像平面坐标系。
注意, 实际上内参包罗2部分: 内参矩阵K和畸变系数D, 上面只讲到了内参矩阵的原理, 没有讲畸变系数。 这里简单列一下畸变系数, 不做详细先容。
D =
此中 k1、k2、k3 是径向畸变系数(radial distortion coefficients) p1、p2 是切向畸变系数(tangential distortion coefficients)。
3 常用的坐标转换
假设有某一个点, 在世界坐标下的坐标为 P w = ( X w , Y w , Z w ) P_w = (X_w, Y_w, Z_w) Pw=(Xw,Yw,Zw), 在相机坐标系下的坐标为 P = ( X c , Y c , Z c ) P = (X_c, Y_c, Z_c) P=(Xc,Yc,Zc), 在像素坐标系下的坐标为 P u v = ( u , v ) P_{uv} = (u, v) Puv=(u,v)。
[*] 世界坐标转到相机坐标:
P = R P w + t P = RP_w + t P=RPw+t
[*] 相机坐标转到像素坐标:
P u v = 1 Z c K P P_{uv} =\frac 1{Z_c} KP Puv=Zc1KP
展开就是:
[ u v 1 ] = 1 Z c K [ X c Y c Z c ] = 1 Z c [ f x 0 c x 0 f y c y 0 0 1 ] [ X c Y c Z c ] \begin{bmatrix} u \\ v \\ 1 \end{bmatrix} = \frac 1{Z_c} \mathbf{K} \begin{bmatrix} X_c \\ Y_c \\ Z_c \\ \end{bmatrix} = \frac 1{Z_c} \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} X_c \\ Y_c \\ Z_c \\ \end{bmatrix} uv1 =Zc1K XcYcZc =Zc1 fx000fy0cxcy1 XcYcZc
[*] 像素坐标转到像素坐标
这个转换是最为常用的, 因为我们通常得到的都是像素坐标系下的信息, 如目标检测、分割的效果就是像素坐标, 得到像素坐标后 ,可以转为相机坐标, 进一步再转为世界坐标。别的, 在点云目标检测中, 通常要把原始的彩色图像和深度信息转换为点云, 就必要用到这个转换。
P = Z c K − 1 P u v P = Z_cK^{-1}P_{uv} P=ZcK−1Puv
展开就是:
X c = u − c x f x ∗ Z c X_c = \frac {u-c_x}{f_x}*Z_c Xc=fxu−cx∗Zc
Y c = v − c y f y ∗ Z c Y_c = \frac {v-c_y}{f_y}*Z_c Yc=fyv−cy∗Zc
注意上面有个尺度因子 Z c Z_c Zc, 从相机坐标系的三维坐标投影到像素平面的二维坐标, 实际上丢失了z方向也就是深度信息。 以是如果不知道深度, 从像素坐标就无法恢复出正确的相机坐标。深度通常可以通过深度相机直接丈量得到, 或通过深度估计算法猜测。
4 表里参标定方法
4.1 内参标定方法
内参标定通常使用张正友标定法, 也就是常见的棋盘格标定。
代码可参考https://github.com/leo038/hand_eye_calibrate/blob/main/hand_eye_calibrate.py 中的camera_calibrate函数。
4.2 外参标定方法
外参标定的核心是:已知多个点分别在相机坐标系下的坐标和在世界坐标系下的坐标, 求它们之间的映射关系。
常用求解PnP 的方法,即已知多个点, 在像素坐标系的二维坐标, 和在世界坐标系的三维坐标,而且已知内参, 求解旋转平移矩阵。
cv2 中提供了外参标定方法, cv2.solvePnP 只需提供对应的点对即可。
完备代码实现如下:
import cv2
import numpy as np
# 定义已知的3D空间点和对应的2D图像点
objectPoints = np.array([, , , ], dtype=np.float32)
imagePoints = np.array([, , , ], dtype=np.float32)
# 定义相机的内参矩阵和畸变系数
cameraMatrix = np.array([, , ], dtype=np.float32)
distCoeffs = np.zeros((4, 1), dtype=np.float32)
# 使用solvePnP函数求解相机的位姿
ret, rvec, tvec = cv2.solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs, flags=cv2.SOLVEPNP_EPNP)
if ret:
print("Rotation vector:\n", rvec)
print("Translation vector:\n", tvec)
else:
print("Failed to solve PnP.")
res, _ = cv2.Rodrigues(rvec)
print(f"旋转矩阵: {res}")
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]