引言
为了处理三维图像和平面图像之间的映射,需要在映射中加入照相机产生图像的投影过程,我们将讨论如何确定照相机的参数,以及在增强现实(AR)等方面的具体应用。
4.1 针孔照相机模型
针孔照相机模型(射影照相机模型),在光线投影到图像平面之前,从照相机中心C经过(唯一一个点),模型如下图。
图像坐标轴和三维坐标系中的x轴、y轴对齐平行,光学坐标轴和z轴一致,在投影之前通过旋转和平移变换,在坐标系中加入三维点,会出现完整的投影变换。
针孔照相机中,三维点X投影为图像点x(齐次坐标表示),也就是把一个三维立体图形投影为二维图像,关系可由如下:λx=PX
P为(3,4)的投影矩阵,图像点的系数为逆深度,x=[X,Y,Z,W] (齐次坐标系),根据矩阵运算,行向量应为4。
4.1.1 投影矩阵
投影矩阵可分解为:
P=K[R∣t]
R为旋转矩阵,t为三维平移向量,内标定矩阵K描述照相机的投影性质,大多数情况下,K可表示为:
f是图像平面和C点的距离,即焦距,另一个参数是光心c = [ c x , c y ] ,是z轴和图像平面的交点(在二维平面上),常接近于图像宽度和高度的一半,唯一未知的变量是焦距。
4.1.2 三维点的投影
根据三维点和图像点的关系,及三维投影的定义,可以写出投影的函数。
#导入线性代数部分
from scipy import linalg
class Camera(object):
""" Class for representing pin-hole cameras. """
def __init__(self,P):
""" Initialize P = K[R|t] camera model. """
self.P = P
# 标定矩阵
self.K = None # calibration matrix
self.R = None # rotation
self.t = None # translation
# 照相机中心
self.c = None # camera center
def project(self,X):
""" Project points in X (4*n array) and normalize coordinates. """
#定义和坐标归一化
# (3,n)
x = dot(self.P,X)
for i in range(3):
x[i] /= x[2]
return x
下载三维几何图像文件,来源于牛津大学的‘Model House’
import camera
# 载入点
points = loadtxt('house.p3d').T
points = vstack((points,ones(points.shape[1])))
# 设置照相机参数
# eye(3)是三阶单位矩阵
P = hstack((eye(3),array([[0],[0],[-10]])))
# 使用类Camera
cam = camera.Camera(P)
# 投影点
x = cam.project(points)
# 绘制投影
figure()
plot(x[0],x[1],'k.')
axis('off')
show()
制作围绕的三维向量,模拟旋转的投影
# 研究相机的移动如何影响投影的效果
# 获得三个随机数
r = 0.05*random.rand(3)
#创建围绕一个向量进行三维旋转的旋转矩阵
rot = camera.rotation_matrix(r)
# 旋转矩阵和投影
figure()
for t in range(20):
# 可见增减投影是在K的基础上点积
cam.P = dot(cam.P,rot)
x = cam.project(points)
plot(x[0],x[1],'k.')
show()
rotation_matrix:
def rotation_matrix(a):
""" Creates a 3D rotation matrix for rotation
around the axis of the vector a. """
R = eye(4)
R[:3,:3] = linalg.expm([[0,-a[2],a[1]],[a[2],0,-a[0]],[-a[1],a[0],0]])
return R
4.1.3 照相机矩阵的分解
如已给定照相机矩阵P,我们需要恢复内参数K以及照相机位置t和姿势R。这里使用RQ因子分解矩阵。
def factor(self):
""" Factorize the camera matrix into K,R,t as P = K[R|t]. """
# 分解前(3,3)
K,R = linalg.rq(self.P[:,:3])
# make K 对角为正值
T = diag(sign(diag(K)))
if linalg.det(T) < 0:
T[1,1] *= -1
self.K = dot(K,T)
# 令R为正定矩阵
self.R = dot(T,R) # T is its own inverse
self.t = dot(linalg.inv(self.K),self.P[:,3])
return self.K, self.R, self.t
import camera
K = array([[1000,0,500],[0,1000,300],[0,0,1]])
tmp = camera.rotation_matrix([0,0,1])[:3,:3]
Rt = hstack((tmp,array([[50],[40],[30]])))
cam = camera.Camera(dot(K,Rt))
print (K,Rt)
print (cam.factor())