第三讲 无标识AR
3.3 模式姿态估计
3.3.1 引理
在三维空间中,可以通过标记角点的精确位置来估计摄像机与标记之间的转换。这个过程叫做二维到三维的姿态估计。这个估计会在物体与摄像机之间找到一个欧氏变换的空间。
如上图所示,C代表相机中心,大写的P1-P4是现实三维世界中的点,p1-p4是物体在相机图像二维平面上投影的点。姿态估计的目标就是找到p1-p4到P1-P4之间的转换关系。回顾slam十四讲,我们可以知道,空间点P首先通过坐标转换,从世界坐标系下转换到相机坐标系下的点(是同一点,但是不同坐标系下的坐标不同,这属于相机外参),再通过针孔相机模型,投影到成像面上(服从相似三角形关系,焦距,像原点之类都有关于相机内参);
即
现在p1-p4是已知的,就是在图像平面求到的pattern的二维坐标点。
那么P1-P4怎么求呢,就需要我们检测到图像上的pattern并发现其四个角点,这里可以通过有标识的AR中的标识去类比理解。
然后借助opencv的solvePnP函数获取欧氏转换[R|T]。
这个函数求得的变换是相机相对于3维空间中的标记的位置,因此我们必须反转矩阵得到的变换,求出标记在相机坐标系统中的变换,有利于进行三维渲染。
这里所做的姿态估计和有标识的姿态估计有类似的地方,通常需要2D-3D的对应关系来估计相机的外参。分配四个三维点作为单位矩形的角点,这个矩形位于XY平面,沿着Z轴投影。二维点对应的是图像的位图的角点。
3.3.2 构建pattern对象
在PatternDetector.cpp中,使用buildPatternFromImage函数来创建pattern对象。
角点的设置很有用,因为这个pattern的坐标系将会被直接放在pattern 的中心并处于XY平面内,Z的方向刚好是摄像机的方向。
3.3.3相机内参获取
相机内参可以用OpenCV的示例程序camera_calibration.exe来计算。
用下面的命令行方式执行标定:
imagelist_creator imagelist.yaml *.png
calibration -w 9 -h 6 -o camera_intrinsic.yaml imagelist.yaml
第一条命令将创建 YAML 格式的一个图像列表,标定工具想用当前目录的 PNG 文件作为输入。当然,也可以使用具体的文件名字:例如:img1.png,img2.png 和 img2.png。产生的文件imagelist.yaml 将传递给标定应用程序。同样的,标定工具也可以从摄像机获取图像。
第二条命令是指定标定模式和输入以及标定数据的输出文件的规模。
完成后,会得到一个yaml文件,下面为一个例子
%YAML:1.0 calibration_time: "06/12/12 11:17:56" image_width: 640 image_height: 480 board_width: 9 [ 110 ]Chapter 3 board_height: 6 square_size: 1. flags: 0 camera_matrix: !!opencv-matrix rows: 3 cols: 3 dt: d data: [ 5.2658037684199849e+002, 0., 3.1841744018680112e+002, 0., 5.2465577209994706e+002, 2.0296659047014398e+002, 0., 0., 1. ] distortion_coefficients: !!opencv-matrix rows: 5 cols: 1 dt: d data: [ 7.3253671786835686e-002, -8.6143199924308911e-002, -2.0800255026966759e-002, -6.8004894417795971e-004, -1.7750733073535208e-001 ] avg_reprojection_error: 3.6539552933501085e-001 |
主要关注camera_matrix,一个3x3的矩阵。也就是相机内参
为了估计模型的位置,我们使用 OpenCV 的 cv::solvePnp 函数来解决 PnP 问题。我们需要当前图像上的pattern角点的坐标
和它的 3D reference 坐标(之前已经在pattern里定义了)。
***cv::solvePnP 函数可以在多于四个点下计算。同样的,如果你想创建一个 带有复杂pattern的 AR,它也是关键的函数。思想是一样的,你仅需要定义你的pattern的 3D 结构和相应的二维。
我们从训练的pattern对象中获取 reference3D 点,并且从 PatternTrackingInfo 结构中获取他们在 2维上的相应的投影。相机标定信息存储在 PatternDetector 私有变量里。