给定同一相机在不同角度拍摄的不同照片,如何标定计算机的内参(焦距、主点)、外参(主要是旋转矩阵)?
opencv的图片拼接demo stitching_detailed中有示例
主要过程:
1.surf /orb算法查找两个图片的特征点;
2.匹配两个图片的特征点,匹配过程中使用RANSAC算法计算单应矩阵;
3.根据单应矩阵计算焦距;
4.根据单应矩阵、焦距等参数计算旋转矩阵;
5.计算主点.
1.单应矩阵计算
单应矩阵是在匹配特征点的过程中得到的
BestOf2NearestMatcher::match->cvFindHomography->runRANSAC
关键过程:
1)cvConvertPointsHomogeneous
二维坐标转齐次坐标,方便计算H矩阵,这里只是做了简单的行列转换,并增加了一列。
2)estimator.runRANSAC
运行RANSAC算法,目标是找到两福图像特征点之间的映射关系,也就是单应矩阵H,
基本原理:
从两幅图像的特征点中随机找到4对不同的特征点,每对特征点齐次坐标对记为(p1,p2),然后计算矩阵方程的p1=H*p2解,也就是H的估计值,然后把所有特征点代入,记录每次得到的内点(也就是符合解的点)的数量,
迭代若干次(初始2000次,根据RANSAC算法会指数性减少),每次都记录内点数最多的解,最终将内点最多的解作为单应矩阵H的最优解。
关键过程:
<1> CvModelEstimator2::getSubset 从输入的特征点中获取随机4对特征点,这些特征点要满足在各自图像上不能在同一直线(否则方程可能无法求解),为找到这些点需要迭代最多300次,调用checkSubset检查直线;
<2> CvHomographyEstimator::runKernel 求解4对特征点构成的8个方程组,得到一次H矩阵的解,H矩阵是3×3矩阵,归一化后剩余8个未知数,一对特征点产生两个方程,所以需要4个特征点对产生8个方程
<3> CvModelEstimator2::findInliers 根据得到的H估计解,代入所有特征点,计算内点,返回内点数、内点mask等,之后会根据每次返回的最大内点数,确定H的最优解;
<4> cvRANSACUpdateNumIters 通过置信度、当前解的内点数等参数更新需要迭代的次数,会从初始的2000次指数性降低。
之后opencv会对返回的内点mask将原来两幅图的特征点放入返回的MatchesInfo结构中,并且再次对这些内点计算其单应矩阵,作为最终的H矩阵。
BestOf2NearestMatcher::match
2.根据单应矩阵估计内参:焦距
HomographyBasedEstimator::estimate->estimateFocal->focalsFromHomography
直接用公式根据H矩阵计算得到焦距。
原理:
参考《Construction of Panoramic Image Mosaics with Global and Local Alignment.pdf》第3.2节以及第5节
基本解释:
同一个空间点P(x,y,z)在两个图像上的点分别为P1(x1,y1),P2(x2,y2),根据相机坐标系和世界坐标系变换公式:P1=K1*R1*P,P2=K2*R2*P,其中Ki,Ri分别为两个图像对应的相机的内参和旋转矩阵,
由于空间P是同一个点,那么P1=K1*R1*R2的逆*K2的逆*P2=K1*R12*K2的逆*P2,已知P1P2的单应矩阵H(通过RANSAC算法求出),那么H=K1*R12*K2的逆,Ki作为内参主要有焦距和主点,主点可以忽略,
R12为图像1到图像2的旋转矩阵,那么H矩阵中只包含旋转矩阵和焦距参数,根据旋转矩阵的正交性,可以求解得到焦距,使焦距成为H矩阵各个元素的表达式,从而求得焦距的估计值。
opencv对每幅图像求一个焦距然后取其中间值作为warp球体的半径。
3.计算外参:旋转矩阵
在HomographyBasedEstimator::estimate中除了估算焦距之外,还估算了旋转矩阵:
findMaxSpanningTree(num_images, pairwise_matches, span_tree, span_tree_centers);
span_tree.walkBreadthFirst(span_tree_centers[0], CalcRotation(num_images, pairwise_matches, cameras));
findMaxSpanningTree:
由于可能输入多个图像,产生了多个匹配特征点的MatchesInfo结构,每个MatchesInfo包含两幅图像之间匹配的特征点(内点)以及H矩阵,需要确定这些图像之间的邻接关系,
这里以两幅图像之间的内点数量为权值构建最大生成树,保证这样的一个图片序列两两之间的内点数最多,也就最有可能是邻接的;
span_tree.walkBreadthFirst:
用广度优先遍历这棵最大生成树,分别计算每两个邻接图像(也就是每个相机)的旋转矩阵R。
原理:
根据上面的公式:H=K1*R12*K2的逆,R12=K1的逆*H*K2,R1=R2*R12=R2*K1的逆*H*K2,已知上幅图像的R、两个相机的内参Ki(焦距、主点)、两幅图的单应矩阵H,可以求得下幅图的R。
4.计算内参:主点
简单设置为图像的中心位置