system: [SYSTEM]

user: 3. 场景高精度三维模型重建算法 3.1. 算法概述 首先，获取同一个目标的两张图片。然后，计算两幅图对应的特征点，利用这些特征点计算获取两幅图像位置关系。接着，利用位置关系通过图像校正使得极线和扫描线的位置一致。最后，用一种基于种子像素点扩张技术的立体匹配算法：随机选择任意一个像素点，视为初始种子像素，运用初始种子像素通过计算可获得两幅视差图，再从两幅视差图中各自选取两个尺寸相同的窗口，通过比较两个窗口内相同位置的像素值就可以获得高置信度的种子像素，我们对这个高置信度的种子像素进行扩张，可以大大降低视差错误区域出现的可能性。同时提出一种基于累积图的快速NCC匹配代价计算方法从而高效地获得两幅图像对应的视差图，这样我们能得到快速准确的视差图。最后利用视差图和摄像机参数信息就可以得到目标场景的高精度三维模型重建结果。算法流程见图1。 3.2. 摄像机内参数标定 首先要获得单目摄像机的内参以及畸变系数，然后利用平面模板方法 [ 12 ] 计算相机内参数矩阵和镜头非线性畸变系数即通过摄像机标定过程计算未知的摄像机内部参数矩阵K和非线性畸变系数k c 1 、k c 2 。该方法利用了位于同一高度上的特征点通过计算可以获得摄像机内参的二个约束等式这个方法。通过拍摄不同位置的同一块标定板即可实现。 图1. 算法流程框图 3.3. 图像采集和特征匹配 首先用摄像机对目标区域拍摄一幅图像；然后要求摄像机向与光轴指向基本垂直的方向运动一段距离，然后再次拍摄目标区域。两次拍摄只要求都能看到目标区域。 由于两幅图像之间视角相差较大，需要使用SIFT特征匹配算法 [ 13 ] ，对两幅图片进行特征匹配。然而一般的SIFT匹配比较粗糙，存在不少误配点，需要利用诸如RANSAC技术以减少错误点。特征匹配原图见图2。 3.4. 图像间相对位置计算 通过计算图像对对应的SIFT特征点得到一个齐次坐标集合，结合摄像机内参数K，通过8点算法以及RANSAC技术 [ 14 ] 可得到本质矩阵E。最终利用矩阵E可以获得旋转矩阵R和平移矢量T。 上述方法计算旋转和平移运动基于对代数误差的最小化，虽然速度较快但是缺乏几何意义。因此估计得到的运动参数精度不高，影响下一步的图像校正过程。所以需要对运动参数进行优化，这里可以采取非线性优化算法。本章使用的非线性优化算法基于极线约束关系，也就是说通过最小化SIFT特征点到其所在的极线的距离来获得优化的运动参数。 3.5. 图像校正 每幅图像都有极线和扫浙描线，为了使这两者对齐需要进行图像校正。当图像中的某一个像素点与对应图像中对应的像素点在同一扫描行上时，就使得图像匹配的问题得到简化，将匹配的复杂度从二维搜索降低到一维搜索。利用已知的相机内参和图像间的位置关系，我们设置两幅图使其相互平行，最后分别投影成新的平面图像。 图3显示了原图中的两幅图像进行图像校正并且进行了SIFT特征匹配的结果。从匹配结果可以看出， 图2. 实验原图 图3. 校正后的两幅图像SIFT特征匹配的结果 左右两幅图片匹配上的特征点在同一高度上，因此可以做立体匹配。 3.6. 立体匹配 为了获得两幅图中对应像素点之间的位移(通常称作视差)，我们需要在两幅图像的每一个对应的像素点之间建立一种关系，通过立体匹配可以得到这种关系。然而，基于窗口的局部匹配运算速度较快但是产生误匹配区较多，而基于优化预设能量函数的全局优化匹配算法得出的视差图质量较高但是算法复杂。为了能解决算法功能和复杂度之间的矛盾，为此提出了一种同时具备上述两种算法优点的方法----基于种子像素扩张的图像匹配算法。 首先在立体图对中寻找一些匹配可信度较高的种子像素点，然后从这些种子像素点出发利用视差梯度约束来确定周围像素点的视差值。因为该算法利用置信度较高的种子像素点的视差值来约束周围像素点的视差搜索范围，从而降低了图中平滑区域误匹率；同时算法利用视差梯度约束保证了最终视差图的平滑性。该算法不运用能量函数并且不进行全局优化以此保证运算复杂度较低；该算法在扩张过程中兼顾了像素周围四邻域视差值产生的影响，因而不会像动态规划算法那样产生扫描行之间视差值不统一。 其次本章还提出了一种基于累积图的NCC匹配方法，该算法的计算复杂度和匹配窗口大小无关，因此加快了运算速度。 3.6.1. 基于累积图的快速NCC匹配代价计算 基于累积图的快速NCC匹配在经典的NCC匹配算法的基础上去除了大量的不必要的计算，简化了匹配搜索过程从而实现快速匹配，大大降低了计算复杂度。 NCC匹配代价为： C ( p ， d ) = ∑ ( x ， y ) ∈ W p ( I 1 ( x ， y ) − I ¯ 1 ( p x ， p y ) ) ⋅ ( I 2 ( x + d ， y ) − I ¯ 2 ( p x + d ， p y ) ) ∑ ( x ， y ) ∈ W p ( I 1 ( x ， y ) − I ¯ 1 ( p x ， p y ) ) 2 ⋅ ∑ ( x ， y ) ∈ W p ( I 2 ( x + d ， y ) − I ¯ 2 ( p x + d ， p y ) ) 2 (1) 其中W p 为以像素 p = ( p x ， p y ) 为中心的匹配窗口。 I ¯ 1 ( x ， y ) 为I 1 中以 ( x ， y ) 为中心的窗口中所有像素平均的亮度。 I ¯ 2 ( x + d ， y ) 为I 2 中以 ( x + d ， y ) 为中心的窗口中所有像素平均的亮度。若直接利用上述式子计算I 1 中每一个像素在每一个可能视差值处的匹配代价，则运算复杂度为O (WHD r |W p |)。定义视差搜索范围为D r 且|W p |为匹配窗口内像素的个数。通过分析可以知道，上式的计算复杂度受匹配窗口大小的影响。所以当立体图像对分辨率高时，需要比较大的匹配窗口，如果直接利用上式计算NCC匹配代价会很慢。 优化后的计算方式如下： 令I k 对应的累积图为ii k ，该累积图可以通过 i i ( x ， y ) = i ( x ， y ) + i i ( x − 1 ， y ) + i i ( x ， y − 1 ) − i i ( x − 1 ， y − 1 ) 快速计算。我们定义： i i k ( W p ) = ∑ ( x ， y ) ∈ W p I k ( x ， y ) (2) 对于校正过后的立体图像对，计算方法有以下3步： 步骤1：根据立体图像对的分辨率设定匹配窗口W p 。 步骤2：计算累积图ii 1 和ii 2 。我们计算： I 22 ( x ， y ) = I 2 ( x ， y ) × I 2 ( x ， y ) (3) 利用上新产生的两幅图像计算其分别对应的累积图ii 11 和ii 22 。 步骤3：设最小和最大视差搜索级分别为D min 和D max 。在仅考虑整数级别的视差级的情况下，可得： D r = D max − D min + 1 (4) 对于视差搜索范围内的每一个视差搜索级d，其满足 D min ≤ d ≤ D max ，我们计算： I 12 ( x ， y ) = I 1 ( x ， y ) × I 2 ( x + d ， y ) (5) 然后计算其对应的累积图ii 12 。最后计算视差搜索级为d时像素点p处的NCC匹配代价： C ( p ， d ) = i i 12 ( W p ) − 1 | W p | ⋅ i i 1 ( W p ) ⋅ i i 2 ( W p + d ) [ i i 11 ( W p ) − 1 | W p | ⋅ i i 1 ( W p ) 2 ] ⋅ [ i i 22 ( W p + d ) − 1 | W p | ⋅ i i 2 ( W p + d ) 2 ] (6) 其中 W p + d 是以坐标 ( p x + d ， p y ) 的像素作为为中心像素的匹配窗口。 分析该算法复杂度：在步骤2中可知每一幅累积图的运算复杂度均为O (WH)。根据I 11 和I 22 的定义可知计算其中每一幅图像的运算复杂度也为O (WH)。为了得到它们对应的累积图需要额外的O (WH)运算复杂度。所以总运算复杂度为： O ( W H ) + O ( W H ) + ( O ( W H ) + O ( W H ) ) + ( O ( W H ) + O ( W H ) ) = O ( W H ) (7) 在步骤3中，当d固定时，计算I 12 的复杂度为O (WH)。利用I 12 ，当d固定时，整幅图像的NCC匹配代价计算复杂度为O (WH)。因此对于某一固定的视差搜索级d，步骤3总的运算复杂度为 O ( W H ) + O ( W H ) = O ( W H ) 。由于需要遍历视差搜索范围中的每一个视差级，因此步骤3总的运算复杂度为O (WHD r )。本算法总的运算复杂度为步骤2和步骤3运算复杂度之和： O ( W H ) + O ( W H D r ) = O ( W H D r ) 在前文中我们提到直接用定义式计算NCC匹配代价运算复杂度为O (WHD r |W p |)。可见本算法的运算复杂度大大减小。 3.6.2. 种子像素提取算法 种子像素提取算法优化了种子像素的视差值，降低了其误匹配点，从而使得三维重建更加精确。该算法包括三个步骤： 步骤1：初始种子像素。因为初始种子像素不影响最终的种子像素。所以初始种子像素的数量以及视差值对最终结果的影响较小。当 ( p x ， p y ， d i s p ) 满足下述下条件时认定为种子像素： { k × C ( p x ， p y ， d i s p ) ≥ C ( p x ， p y ， d ) ， ∀ d ≠ d i s p k × C ( p x ， p y ， d i s p ) ≥ C ( p ′ x ， p y ， d ′ ) ， p ′ x + d ′ = p x + d i s p ， d ′ ≠ d i s p (8) 其中， k ∈ ( 0 ， 1 ] ，由需要的种子像素点的多少和种子像素视差值的错误率决定。 步骤2：初始视差图生成。H为摄像机高度。 ( p x ， p y ， d i s p ) 为初始种子像素，可得两个集合，分别为： S u = { ( p x ， p y ， d i s p ) | p y < H 2 } (9) S d = { ( p x ， p y ， d i s p ) | p y ≥ H 2 } (10) 利用S u 中的种子像素通过视差曲面扩张算法获得视差图D u ，同理得出视差图D d 。通过这两幅视差图可以得出最后中种子像素。 步骤3：获取种子像素。定义视差图D u 中位置 ( p x ， p y ) 处的视差值为 D u ( p x ， p y ) ，同理定义视差图D d 的视差值。选择各个边长均为2w + 1的矩形为窗口。如果公式(11)，则 ( p x ， p y ， D u ( p x ， p y ) ) 就是最终的种子像素： ∑ i = p x − w p x + w ∑ j = p y − w p y + w ( D u ( i ， j ) − D d ( i ， j ) ) 2 = 0 (11) 当获取到所有的种子像素后，需要进行基于视差置信度的扩张。其扩张算法如下： 定义 ( p x ， p y ) 处像素视差值为d，置信度为 P ( p x ， p y ， d ) ，利用相似度衡量函数反映匹配点对的置信度，则取： P ( p x ， p y ， d ) ∝ C ( p x ， p y ， d ) (12) 步骤1：创建像素的队列，对所有获取到的种子像素计算 P ( p x ， p y ， d ) 并按照P的值从大到小填入队列中。 步骤2：上述队列不为空时，对队列开始的第一个种子像素做扩张计算。对于该种子像素的四邻域像素 ( p ′ x ， p ′ y ) ，若该像素的视差值尚不存在，则视差值为： d ′ = arg d i s p max ( C ( p ′ x ， p ′ y ， d i s p ) ) d i s p ∈ { d − 1 ， d ， d + 1 } (13) 若该像素的视差值已经存在且为d 1 ，则新的视差值为： d ′ = arg d i s p max ( C ( p ′ x ， p ′ y ， d i s p ) ) d i s p ∈ { d − 1 ， d ， d + 1 ， d 1 } (14) 如果队列为空则结束，输出视差图。 步骤3：若步骤2中没有生成新的种子像素时，删除队列开头的数据并再次做步骤2。否则计算每一个种子像素的 P ( p x ， p y ， d ) ，并根据其值的大小按从大到小的顺序插入到队列相应位置，删除队列头部种子像素再重复步骤2。