为了更进一步理解相机内外参数对应的几何意义,特意设计了一个Python实验。希望对相关初学者有帮助。
实验思路:在世界坐标系上构建一个正方体,然后通过相机内外参数矩阵映射到屏幕坐标系上,观察映射结果。
实验素材:两个外参数矩阵(表示不同视角的相机),这两个相机共用一套内参数矩阵;一个空间坐标系的正方体。
实验代码:(代码为本人原创,引用须注明出处)
import cv2
import numpy as np
extri1 = np.array(
[[-9.9990e-01, 4.1922e-03, -1.3346e-02, -5.3798e-02],
[-1.3989e-02, -2.9966e-01, 9.5394e-01, 3.8455e+00],
[-4.6566e-10, 9.5404e-01, 2.9969e-01, 1.2081e+00],
[0.0, 0.0, 0.0, 1.0]])
extri2 = np.array(
[[0.4429636299610138, 0.31377720832824707, -0.8398374915122986, -3.385493516921997],
[-0.8965396881103516, 0.1550314873456955, -0.41494810581207275, -1.6727094650268555],
[0.0, 0.936754584312439, 0.3499869406223297, 1.4108426570892334],
[0.0, 0.0, 0.0, 1.0]])
intrinsics = [[1111.0, 0.0, 400.0],
[0.0, 1111.0, 400.0],
[0.0, 0.0, 1.0]]
def world2screen(intri, extri, pw, to_int=False):
R = extri[:3, :3] # rotation
T = extri[:3, -1] # trans
cam_p = np.dot(pw - T, R)
if not to_int:
screen_p = np.array([-cam_p[0] * intri[0][0] / cam_p[2] + intri[0][2],
cam_p[1] * intri[1][1] / cam_p[2] + intri[1][2]])
else:
screen_p = np.array([int(-cam_p[0] * intri[0][0] / cam_p[2] + intri[0][2] + .5),
int(cam_p[1] * intri[1][1] / cam_p[2] + intri[1][2] + .5)])
return screen_p
vertex = [[-.5, -.5, -.5], [.5, -.5, -.5], [.5, .5, -.5], [-.5, .5, -.5], [-.5, .5, .5], [.5, .5, .5], [.5, -.5, .5], [-.5, -.5, .5]]
# cube in world
blank = np.zeros((800, 800, 3), np.uint8)
p_s = [world2screen(intrinsics, extri1, p_, to_int=True) for p_ in vertex]
for i in range(len(p_s)):
p1 = p_s[i]
p2 = p_s[i + 1] if i < len(p_s) - 1 else p_s[0]
cv2.line(blank, p1, p2, (255, 255, 0), 1)
cv2.line(blank, p_s[3], p_s[0], (255, 255, 0), 1)
cv2.line(blank, p_s[4], p_s[7], (255, 255, 0), 1)
cv2.line(blank, p_s[1], p_s[6], (255, 255, 0), 1)
cv2.line(blank, p_s[2], p_s[5], (255, 255, 0), 1)
cv2.imwrite("extri1.png", blank)
blank = np.zeros((800, 800, 3), np.uint8)
p_s = [world2screen(intrinsics, extri2, p_, to_int=True) for p_ in vertex]
for i in range(len(p_s)):
p1 = p_s[i]
p2 = p_s[i + 1] if i < len(p_s) - 1 else p_s[0]
cv2.line(blank, p1, p2, (255, 255, 0), 1)
cv2.line(blank, p_s[3], p_s[0], (255, 255, 0), 1)
cv2.line(blank, p_s[4], p_s[7], (255, 255, 0), 1)
cv2.line(blank, p_s[1], p_s[6], (255, 255, 0), 1)
cv2.line(blank, p_s[2], p_s[5], (255, 255, 0), 1)
cv2.imwrite("extri2.png", blank)
得到的结果为:
外参矩阵1:
外参矩阵2:
不同视角下的正方体的样子~