1. 数据处理
以大疆无人机为例,读取照片的内参,外参信息,其中外参以云台为主,内参搜索官方确定
2. 内外参数求解
2.1 相机内参矩阵K是相机固有属性,其标准形式如下:
K = [[fx, 0, cx],
0, fy, cy\], \[0, 0, 1\]
包括焦距fx、fy和主点cx,cy,fx为在感光元件上单位mm存在的像素数量,乘以焦距mm,最后的单位是像素
2.2 相机外参的推导
外参矩阵由旋转矩阵R和平移向量t组成,描述世界坐标系到相机坐标系的变换:P_c = R·P_w + t,旋转矩阵R的计算
已知欧拉角(航向角Yaw(Yaw+90)、俯仰角Pitch(无人机坐标系与常见空间坐标系不同:90+abs(Pitch))、横滚角Roll),需按特定顺序转换为旋转矩阵:
旋转顺序:通常为Z轴(Yaw) → Y轴(Pitch) → X轴(Roll)。
计算公式:
R_z(Yaw) = [[cosθ, -sinθ, 0], [sinθ, cosθ, 0], [0,0,1]]
R_y(Pitch) = [[cosθ, 0, sinθ], [0,1,0], [-sinθ, 0, cosθ]]
R_x(Roll) = [[1,0,0], [0,cosθ, -sinθ], [0,sinθ, cosθ]]
最终旋转矩阵:R = R_x·R_y·R_z(注意顺序影响结果)27。
平移向量t的确定,已知条件:相机在世界坐标系中的空间坐标(x,y,z),直接赋值:平移向量t = -R·[x,y,z]^T(需将相机位置转换到相机坐标系)。
-
外参矩阵的组合为3×4矩阵:
[ R | t ] = [[r11, r12, r13, tx], [r21, r22, r23, ty], [r31, r32, r33, tz]]
3. 转换代码
世界坐标系中,坐标转换到图片上:
Z·[u, v, 1]^T = K·[R | t]·[X, Y, Z, 1]^T
opencv-python代码如下:
python
import cv2
import numpy as np
# ================== 输入已知参数 ==================
# 相机内参
fx, fy = 800, 800 # 焦距(像素单位)
cx, cy = 320, 240 # 主点坐标
camera_matrix = np.array([[fx, 0, cx],
[0, fy, cy],
[0, 0, 1]], dtype=np.float32) # :ml-citation{ref="1,4" data="citationList"}
# 相机在世界坐标系中的位置(单位:米)
camera_position = np.array([1.0, 2.0, 3.0], dtype=np.float32) # (x,y,z) :ml-citation{ref="3,6" data="citationList"}
# 欧拉角(单位:弧度)
yaw = np.deg2rad(30) # 航向角(绕Z轴)
pitch = np.deg2rad(-15) # 俯仰角(绕Y轴)
roll = np.deg2rad(10) # 横滚角(绕X轴) :ml-citation{ref="2,3" data="citationList"}
# ================== 计算旋转矩阵 ==================
# 按Z→Y→X顺序构建旋转矩阵 :ml-citation{ref="2,3" data="citationList"}
R_z = np.array([[np.cos(yaw), -np.sin(yaw), 0],
[np.sin(yaw), np.cos(yaw), 0],
[0, 0, 1]], dtype=np.float32) # Z轴旋转
R_y = np.array([[np.cos(pitch), 0, np.sin(pitch)],
[0, 1, 0],
[-np.sin(pitch), 0, np.cos(pitch)]], dtype=np.float32) # Y轴旋转
R_x = np.array([[1, 0, 0],
[0, np.cos(roll), -np.sin(roll)],
[0, np.sin(roll), np.cos(roll)]], dtype=np.float32) # X轴旋转
R = R_x @ R_y @ R_z # 组合旋转矩阵 :ml-citation{ref="2,3" data="citationList"}
# ================== 计算平移向量 ==================
t = -R @ camera_position.reshape(3,1) # :ml-citation{ref="3,6" data="citationList"}
# ================== 外参矩阵合成 ==================
extrinsic_matrix = np.hstack([R, t]) # 3x4矩阵 :ml-citation{ref="3,4" data="citationList"}
# ================== 验证投影 ==================
# 世界坐标系中的点(单位:米)
world_point = np.array([0, 0, 0, 1], dtype=np.float32).reshape(4,1)
# 投影到像素坐标系
projected = camera_matrix @ extrinsic_matrix @ world_point
pixel_coord = (projected / projected:ml-citation{ref="2" data="citationList"}).flatten()[:2] # 归一化 :ml-citation{ref="4,6" data="citationList"}
print("内参矩阵 K:\n", camera_matrix)
print("外参矩阵 [R|t]:\n", extrinsic_matrix)
print("世界原点投影坐标:", pixel_coord)
求解过程可通过cv2.projectPoints()函数验证更复杂场景的投影精度