详解相机的内参和外参,以及内外参的标定方法

1 四个坐标系

要想深入搞清楚相机的内参和外参含义, 首先得清楚以下4个坐标系的定义:

  • 世界坐标系: 名字看着很唬人, 其实没什么大不了的, 这个就是你自己定义的某一个坐标系。 比如, 你把房间的某一个点定为原点, 并且定义好方向, 这就是世界坐标系。 一般是个三维坐标系, 单位是m
  • 相机坐标系: 以相机光心为原点, 一般我们把z轴指向相机前方,x向右,y向下,是个三维坐标系, 单位是m
  • 成像平面坐标系: 这个是定义在物理成像平面的坐标系,方向定义与相机坐标系一致(没有z方向), 原点是光心在物理成像平面上的投影,是个二维坐标系, 单位是m。 注意, 我们一般都会忽略这个坐标系, 因为它是个中间过渡状态, 很少直接使用它。
  • 像素坐标系: 这个应该是最为常用, 也最为大家熟悉的坐标系, 计算机视觉任务的输出的坐标表达都是在这个坐标系。 它是个二维坐标系, 原点通常在图像的左上角, x向右,y向下, 单位是像素, 没有具体的尺度。

2 内参和外参

除了世界坐标系, 后面三个坐标系只跟相机本身有关。 相机内参表达的就是这三个坐标之间的转换关系, 而相机外参表达的是相机与世界坐标系之间的转换关系。

成像的过程实质上是几个坐标系的转换。首先空间中的一点由世界坐标系转换到相机坐标系 ,然后再将其投影到物理成像平面 ( 成像平面坐标系 ) ,最后再将成像平面上的数据转换像素坐标系 。

从世界坐标到像素坐标总共有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 p1 p2 k3]

其中 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 只需提供对应的点对即可。

完整代码实现如下:

python 复制代码
import cv2
import numpy as np

# 定义已知的3D空间点和对应的2D图像点
objectPoints = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]], dtype=np.float32)
imagePoints = np.array([[10, 20], [30, 50], [20, 70], [50, 40]], dtype=np.float32)

# 定义相机的内参矩阵和畸变系数
cameraMatrix = np.array([[1000, 0, 320], [0, 1000, 240], [0, 0, 1]], 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}")
相关推荐
视觉AI3 小时前
SiamMask原理详解:从SiamFC到SiamRPN++,再到多任务分支设计
人工智能·目标检测·计算机视觉·目标分割
白熊1885 小时前
【计算机视觉】CV实战项目- DFace: 基于深度学习的高性能人脸识别
人工智能·深度学习·计算机视觉
layneyao8 小时前
AI在医疗领域的10大应用:从疾病预测到手术机器人
人工智能·机器人
jndingxin9 小时前
OpenCV 图形API(69)图像与通道拼接函数------将一个 GMat 类型的对象转换为另一个具有不同深度GMat对象函数convertTo()
人工智能·opencv·计算机视觉
CoovallyAIHub9 小时前
Vision Transformers与卷积神经网络详细训练对比(附代码)
深度学习·算法·计算机视觉
白熊18810 小时前
【计算机视觉】TorchVision 深度解析:从核心功能到实战应用 ——PyTorch 官方计算机视觉库的全面指南
人工智能·pytorch·计算机视觉
AI视觉网奇11 小时前
python 求内轮廓
python·opencv·计算机视觉
遨博学院11 小时前
机器人结构认知与安装
机器人
小柒的博客11 小时前
联合体union的特殊之处
c语言·机器人
蹦蹦跳跳真可爱58912 小时前
Python----卷积神经网络(卷积为什么能识别图像)
人工智能·python·深度学习·神经网络·计算机视觉·cnn