OpenSfM/opensfm/reconstruction.py at main · mapillary/OpenSfM · GitHub
`two_view_reconstruction_and_refinement` 函数用于利用已知的旋转(`R`)和平移(`t`)信息进行两幅图像之间的三维重建和优化。具体来说,它根据相机的相对位姿(`R` 和 `t`),通过对图像中的特征点(`b1` 和 `b2`)进行反投影,找到满足几何约束的匹配点(称为内点),并对这些点进行优化。最终,它返回优化后的旋转矩阵、平移向量以及内点列表。
该函数的主要应用场景是两视图的三维重建。在立体视觉或多视图几何中,给定两幅不同视角下拍摄的图片,可以通过相机的相对位姿来推导出场景的三维信息。这个函数通过筛选出具有几何一致性的特征点,利用非线性优化进一步提升精度,从而为三维重建提供基础。
详细解释
1. 旋转与平移调整
函数的第一步是根据输入的 `transposed` 参数决定是否使用旋转矩阵和位移向量的转置版本。如果 `transposed` 为 `True`,则 `R` 和 `t` 被转置和调整,以保证与计算过程中的其他步骤保持一致。
if transposed:
t_curr = -R.T.dot(t)
R_curr = R.T
else:
t_curr = t.copy()
R_curr = R.copy()
2. 内点筛选
内点是满足几何约束的特征点匹配对,它们在两幅图像中投影时的误差小于某个阈值(`threshold`)。调用 `_two_view_reconstruction_inliers` 来计算当前 `R` 和 `t` 下的内点。这一过程通常基于重投影误差的计算,即使用当前相机参数将三维点投影回图像平面,并与实际图像上的点进行比较,筛选出误差在阈值范围内的匹配点。
inliers = _two_view_reconstruction_inliers(b1, b2, R_curr, t_curr, threshold)
_two_view_reconstruction_inliers
是一个用于筛选可以三角化的匹配点对的函数。它主要用于计算两幅图像之间的特征点匹配中哪些点可以用于三角化(即通过两视角计算出三维坐标)。函数的目的是返回匹配点对的索引,这些点符合某些几何约束(例如重投影误差小于给定阈值)。
def _two_view_reconstruction_inliers(
b1: np.ndarray, b2: np.ndarray, R: np.ndarray, t: np.ndarray, threshold: float
) -> List[int]:
"""Returns indices of matches that can be triangulated."""
ok = matching.compute_inliers_bearings(b1, b2, R, t, threshold)
# pyre-fixme[7]: Expected `List[int]` but got `ndarray[typing.Any,
# dtype[typing.Any]]`.
return np.nonzero(ok)[0]
该函数的核心在于调用 matching.compute_inliers_bearings
,它比较两幅图像中匹配点的投影方向与相机的相对运动(R
和 t
)。通过计算这些方向之间的误差(通常是重投影误差),函数判断哪些点是符合三维重建几何约束的点对(内点)。它基于两幅图像中给定的视线方向向量(b1
和 b2
),结合两幅图像间的旋转矩阵和位移向量(R
和 t
),计算出可以进行三角化的点。
OpenSfM/opensfm/matching.py at main · mapillary/OpenSfM · GitHub
3. 非线性优化
如果内点的数量大于 5,说明重建初步是可信的。此时,函数使用非线性优化relative_pose_ optimize_nonlinear来进一步优化旋转矩阵和位移向量。非线性优化是为了精细调整旋转矩阵和位移,尽量减少内点的重投影误差。优化后的旋转和位移被重新赋值给 `R_curr` 和 `t_curr`。
if len(inliers) > 5:
T = multiview.relative_pose_optimize_nonlinear(
b1[inliers], b2[inliers], t_curr, R_curr, iterations
)
R_curr = T[:, :3]
t_curr = T[:, 3]
inliers = _two_view_reconstruction_inliers(b1, b2, R_curr, t_curr, threshold)
4. 最终结果
返回优化后的旋转矩阵和位移向量,并且返回符合几何约束的内点列表。使用 OpenCV 的 `cv2.Rodrigues` 函数将旋转矩阵转换为旋转向量格式,便于后续处理。
return cv2.Rodrigues(R_curr.T)[0].ravel(), -R_curr.T.dot(t_curr), inliers