目录
内参矩阵
外参矩阵
是的,相机的外参矩阵(Extrinsic Matrix)确实描述了相机在世界坐标系中的位置以及它的朝向。
外参矩阵描述的是以相机坐标系为参考,世界坐标系如何变换的关系
它是用来将世界坐标系中的点转换到相机坐标系中的点。
内参 展平为9行,或者4x4
K_flat = K.flatten()
np.savetxt('intrinsics.txt', K_flat, fmt='%f')
K_4x4 = np.eye(4) # 生成 4x4 单位矩阵
# 将 3x3 内参矩阵嵌入到 4x4 矩阵中
K_4x4[:3, :3] = intrinsics['front']['intrinsic']
np.savetxt(cur_show_dir+f'/intrinsics/{index}.txt', K_4x4, fmt='%f') # fmt='%d' 表示保存为整数
投影矩阵的作用
通过将三维世界中的点乘以投影矩阵 PPP,可以得到该点在相机图像平面中的二维坐标,这个过程考虑了相机的位置、朝向、焦距和其他内外参信息。
检查内参 外参
import cv2
import numpy as np
# 假设我们有以下相机内参
K = np.array([[418.96369417, 0.0, 489.16315478],
[0.0, 419.04813353, 267.88796254],
[0.0, 0.0, 1.0]], dtype=np.float64)
# 假设相机外参矩阵 (旋转和平移)
R = np.array([[-3.9147413e-03, -9.9999213e-01, 6.7846401e-04],
[9.3531040e-03, -7.1505480e-04, -9.9995601e-01],
[9.9994862e-01, -3.9082235e-03, 9.3558291e-03]], dtype=np.float64)
t = np.array([1.0138103e-02, 1.2053192e+00, -2.1235154e+00], dtype=np.float64)
# 将旋转矩阵转换为旋转向量
R_vec, _ = cv2.Rodrigues(R)
# 假设我们有以下已知的三维点
object_points = np.array([[0, 0, 0],
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]], dtype=np.float64)
# 对应的图像中的像素点 (实际检测到的图像点)
image_points_detected = np.array([[489.2, 267.9],
[589.2, 267.9],
[489.2, 367.9],
[489.2, 267.9]], dtype=np.float64)
# 使用内参和外参将三维点投影到图像平面
image_points_projected, _ = cv2.projectPoints(object_points, R_vec, t, K, distCoeffs=None)
# 将 image_points_projected 从 (N, 1, 2) 转换为 (N, 2)
image_points_projected = image_points_projected.reshape(-1, 2)
# 计算重投影误差
error = cv2.norm(image_points_detected, image_points_projected, cv2.NORM_L2) / len(image_points_projected)
print(f"重投影误差: {error}")
像素点投影到世界坐标系,再投回到2d坐标系:
import numpy as np
import cv2
# 假设我们有以下相机内参矩阵 K
K = np.array([[418.96369417, 0.0, 489.16315478],
[0.0, 419.04813353, 267.88796254],
[0.0, 0.0, 1.0]], dtype=np.float64)
# 假设相机外参(旋转矩阵和平移向量)
R = np.array([[-3.9147413e-03, -9.9999213e-01, 6.7846401e-04],
[ 9.3531040e-03, -7.1505480e-04, -9.9995601e-01],
[ 9.9994862e-01, -3.9082235e-03, 9.3558291e-03]], dtype=np.float64)
t = np.array([1.0138103e-02, 1.2053192e+00, -2.1235154e+00], dtype=np.float64)
# 假设图像坐标系中的点 (u, v)
u, v = 500, 300
# 假设已知深度 Z
Z = 5.0 # 例如 5米
# 1. 图像坐标系 -> 世界坐标系
# 计算归一化相机坐标系中的点
p_n = np.linalg.inv(K) @ np.array([u, v, 1.0])
# 将归一化相机坐标系中的点转换为相机坐标系
P_c = p_n * Z
# 使用相机外参转换到世界坐标系
P_w = np.linalg.inv(R) @ (P_c - t)
# 2. 世界坐标系 -> 图像坐标系
# 从世界坐标系转换回相机坐标系
P_c_back = R @ P_w + t
# 再将相机坐标系转换回图像坐标系
p_n_back = P_c_back[:2] / P_c_back[2] # 归一化相机坐标
# 通过内参转换到图像坐标系
pixel_coords = K @ np.array([p_n_back[0], p_n_back[1], 1.0])
# 规范化,以获得最终的图像坐标
u_back = pixel_coords[0] / pixel_coords[2]
v_back = pixel_coords[1] / pixel_coords[2]
print(f"原始图像坐标: ({u}, {v})")
print(f"转换回来的图像坐标: ({u_back:.2f}, {v_back:.2f})")