1. 相关基础知识
一幅视图是通过透视变换将三维空间中的点投影到图像平面。投影公式 x ~ K[R|t]X,即如下:
这里(X, Y, Z)是一个点的世界坐标,(x, y)是点投影在图像平面的坐标,以像素为单位。K被称作摄像机矩阵,或者内参数矩阵。(cx, cy)是基准点(通常在图像的中心),fx, fy是以像素为单位的焦距。所以如果因为某些因素对来自于摄像机的一幅图像升采样或者降采样(如图像压缩),所有这些参数(fx, fy, cx和cy)都将被缩放(乘或者除)同样的尺度。内参数矩阵不依赖场景的视图,一旦计算出可以被重复使用(只要焦距固定)。旋转-平移矩阵[R|t]被称作外参数矩阵,它用来描述相机相对于一个固定场景的运动,或者相反,物体围绕相机的的刚性运动。也就是[R|t]将点(X, Y, Z)的坐标变换到某个坐标系,这个坐标系相对于摄像机来说是固定不变的。
考虑到一般性,可以选择定义物体平面使Z=0,则旋转矩阵R=[r1 r2 r3]中的列向量r3不再需要,此时公式简化为
x ~ K[r1 r2 t]X = HX,只考虑映射目标点到成像仪的单应性矩阵H(一个3x3矩阵)相关部分,即
x = sHX,这里引入参数s,它是一个任意尺度比例(目的是使得单应性被定义到该尺度比例),通常根据习惯放在H外面。
OpenCV使用上述公式来计算单应性矩阵。它使用同一物体的多个图像来计算每个视场的旋转和平移,同时也计算摄像机的内参数(对所有视场不变)。
通过下面的简单方程,单应性矩阵H把源图像平面上的点集位置与目标图像平面(通常为成像仪平面)上的点集位置联系起来。
2. 遇到的问题
毕设过程中,为了实现定位功能,我通过单幅图像上4个特定点与实际标志物对应的4个点来求H,然后再利用预先估计的内参数矩阵K来计算摄像机外参数[R,t]。在实际编程中,为了提高算法速度,预先将图像长宽均压缩到0.25倍后再进行处理,根据第一部分相关基础知识介绍可知,此时应该将所有相关参数(fx, fy, cx, cy)都缩放同样的尺度,但我错误地只将cx, cy进行了0.25倍的缩放,而fx, fy仍然以原始值代入计算,因而得到错误的外参数:
发现这个错误后,我相应地更正了
f
(fx和fy相等,以下均简称f)
的值,但我意外发现,这样更正后再进行计算的得到的外参数结果,与直接将之前错误的外参数tz乘0.25倍结果非常相近,如下(第一行为仅修改f为0.25f后的t向量,第二行为仅将错误结果的tz变为0.25tz的结果):
实际上这个错误很容易发现,只改变参数cx, cy,而f保持不变,这已经违背了摄像机的成像原理,并且
对于一张拍好的照片来说,上图的右边物体部分所对应的外参数就已经确定,即t是不可变的,更不可能单独去改变tz的值,这样的图示无疑是错的。
老师为了使我熟悉用数学推导弄明白问题,从数学的角度理解我之前求错的时候和正确的时候两者之间哪些参数发生了变化,以及t在这两次之前有没有比例关系等,让我根据公式推导出两者之间的关系,具体推导过程如下(
λ=1/s
):
推导结果说明,tz等于0.25-1倍的tz',且大部分时候都是接近0.25倍,同理,tx,ty等于1-4倍的tx', ty',且大部分时候接近1倍。因此上述现象(仅修改f和仅修改tz的结果相似)得以解释。
2015年3月23日 JoAnn