Structure from Motion(附python代码)

本文详细介绍了SFM(Structure from Motion)三维重建算法的后三步骤:构建2D轨迹、解决SfM模型及利用束调整优化模型。涵盖数学原理、代码实现等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SFM算法的前两步:特征点提取、匹配,可以看我的这篇文章:《sift、surf、orb 特征提取——三维重建》,这里主要详细介绍后三步。
在这里插入图片描述

这个好像有点用,可以作为参考

3. Construct 2D tracks from the matches

当匹配关系建立后,需要生成track列表,指同名点的相片集合,比如第一幅图
的13号点和第二幅的14号点及第五幅的115号点是同名点,则(1,13)、
(2,14)、 (5,115)是属于一个track。据此可以生成一个track 集合,同时生
成track的时候也需要剔除无用匹配:

  • 如果一个track包含同一幅图多次,则应该剔除,这是因为同一幅图的多
    个特征点都匹配了同一个点,则匹配关系肯定是错误的。
  • 如果track太少,应该剔除,一般取2(最小值),是指只有两幅图有同一个点,三维重建的信息过少,容易产生误差。

4. Solve for the SfM model from the 2D tracks

数学原理

  • 第四步找初始化像对,目的是找到相机基线最大的像对,采用RANSC算法四点法计算单应矩阵,满足单应矩阵的匹配点称为内点,不满足单应矩阵的称为外点,根据单应矩阵公式可知当T?这是个什么东西? )越小时,内点占比越高,也就是低视差现象越明显,详见:Homography 知多少?
    因此找到一个内点占比最小的像对就是初始化像对,当然它前提必须满足可重建,这个可以通过匹配点个数保证。

  • 第四步是初始化像对的相对定向,根据RANSC八点法计算本征矩阵,可通过对本征矩阵SVD分解得到第二个图像的R、T,在这一步需要进行畸变校正,然后根据R、T和矫正后的像点坐标三角化计算出三维点(什么是坐标三角化?如何操作?详见:三角化求深度值(求三位坐标))。

Code

from utils import *
import logging


class Baseline:
    """Represents the functions that compute the baseline pose from the initial images of a reconstruction"""

    def __init__(self, view1, view2, match_object):

        self.view1 = view1  # first view
        self.view1.R = np.eye(3, 3)  # identity rotation since the first view is said to be at the origin
        '''
        array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])
        '''
        self.view2 = view2  # second view
        self.match_object = match_object  # match object between first and second view

    def get_pose(self, K):
        """Computes and returns the rotation and translation components for the second view"""

        F = remove_outliers_using_F(self.view1, self.view2, self.match_object)#return fundamental matrix
        E = K.T @ F @ K  # compute the essential matrix from the fundamental matrix
        #E:本质矩阵,从F到E?如何变过来的,K是intrinsic matrix
        #python中 @的作用:1.装饰符 2.矩阵乘法
        logging.info("Computed essential matrix")
        logging.info("Choosing correct pose out of 4 solutions")

        return self.check_pose(E, K)

    def check_pose(self, E, K):
        """Retrieves the rotation and translation components from the essential matrix by decomposing it and verifying the validity of the 4 possible solutions"""

        R1, R2, t1, t2 = get_camera_from_E(E)  # decompose E
        #从本质矩阵恢复摄像机参数矩阵
        if not check_determinant(R1):
            R1, R2, t1, t2 = get_camera_from_E(-E)  # change sign of E if R1 fails the determinant test
            #?
        # solution 1
        reprojection_error, points_3D = self.triangulate(K, R1, t1)#筛选误匹配
        #
        # check if reprojection is not faulty and if the points are correctly triangulated in the front of the camera
        if reprojection_error > 100.0 or not check_triangulation(points_3D, np.hstack((R1, t1))):

            # solution 2
            reprojection_error, points_3D = self.triangulate(K, R1, t2)
            if reprojection_error > 100.0 or not check_triangulation(points_3D, np.hstack((R1, t2))):

                # solution 3
                reprojection_error, points_3D = self.triangulate(K, R2, t1)
                if reprojection_error > 100.0 or not check_triangulation(points_3D, np.hstack((R2, t1))):

                    # solution 4
                    return R2, t2

                else:
                    return R2, t1

            else:
                return R1, t2

        else:
            return R1, t1

    def triangulate(self, K, R, t):
        """Triangulate points between the baseline views and calculates the mean reprojection error of the triangulation"""

        K_inv = np.linalg.inv(K)
        P1 = np.hstack((self.view1.R, self.view1.t))
        P2 = np.hstack((R, t))#本质矩阵分解得来的

        # only reconstructs the inlier points filtered using the fundamental matrix
        pixel_points1, pixel_points2 = get_keypoints_from_indices(keypoints1=self.view1.keypoints,
                                                                  keypoints2=self.view2.keypoints,
                                                                  index_list1=self.match_object.inliers1,
                                                                  index_list2=self.match_object.inliers2)

        # convert 2D pixel points to homogeneous coordinates
        pixel_points1 = cv2.convertPointsToHomogeneous(pixel_points1)[:, 0, :]#convertPointsToHomogeneous把点从欧式空间转换到齐次空间,
        pixel_points2 = cv2.convertPointsToHomogeneous(pixel_points2)[:, 0, :]

        reprojection_error = []

        points_3D = np.zeros((0, 3))  # stores the triangulated points

        for i in range(len(pixel_points1)):
            u1 = pixel_points1[i, :]
            u2 = pixel_points2[i, :]

            # convert homogeneous 2D points to normalized device coordinates
            #与内参矩阵进行运算,叫做normalized
            u1_normalized = K_inv.dot(u1)
            u2_normalized = K_inv.dot(u2)

            # calculate 3D point
            point_3D = get_3D_point(u1_normalized, P1, u2_normalized, P2)

            # calculate reprojection error
            error = calculate_reprojection_error(point_3D, u2[0:2], K, R, t)#重建误差
            reprojection_error.append(error)

            # append point
            points_3D = np.concatenate((points_3D, point_3D.T), axis=0)

        return np.mean(reprojection_error), points_3D

5.Refine the SfM model using bundle adjustment

  • 加入更多图像,以第三副图为例,根据第四步生成的三维点和第三副图与前两图的track关系,可以反算第三副图的R、T,然后继续三角化计算
    更多的三维点,这样反复重复第5步,最后就会得到所有像片的POSE (R、T)和三维点,这就是稀疏重建SFM的结果了。
  • 从第四步开始需要进行光束法平差Bundle+Adjustment,是一个非线性优化的过程,目的是使重建误差降低到最小,通过调整POSE和三维点使反向投影差最小,如果相机没有标定,还应该将焦距也参与平差。
  • Bundle+Adjustment是一个迭代的过程,在一次迭代过后,将所有三维点反向投影到各自相片的像素坐标并分别与初始坐标比对,如果大于某个阈值,则应将其从track中去掉,如果track中已经小于2个了,则整个track也去掉,一直优化到没有点可去为止

完整参考代码:structure-from-motion

地形数据测量是许多地貌研究应用程序的基本方面,尤其是那些包括地形监测和地形变化研究的应用程序。然而,大多数测量技术需要相对昂贵的技术或专门的用户监督。 Motion(SfM)摄影测量技术的结构通过允许使用消费级数码相机和高度自动化的数据处理(可以免费使用)减少了这两个限制。因此,SfM摄影测量法提供了快速,自动化和低成本获取3D数据的可能性,这不可避免地引起了地貌界的极大兴趣。在此贡献中,介绍了SfM摄影测量的基本概念,同时也承认了其传统。举几个例子来说明SfM在地貌研究中的应用潜力。特别是,SfM摄影测量为地貌学家提供了一种工具,用于在一定范围内对3-D形式进行高分辨率表征,并用于变化检测。 SfM数据处理的高度自动化既创造了机遇,也带来了威胁,特别是因为用户控制倾向于将重点放在最终产品的可视化上,而不是固有的数据质量上。因此,这项贡献旨在指导潜在的新用户成功地将SfM应用于一系列地貌研究。 关键词:运动结构,近距离摄影测量,智能手机技术,测量系统,表面形态echnology reduces both these constraints by allowing the use of consumer grade digital cameras and highly automated data processing, which can be free to use. SfM photogrammetry therefore offers the possibility of fast, automated and low-cost acquisition of 3-D data, which has inevitably created great interest amongst the geomorphological community. In this contribution, the basic concepts of SfM photogrammetry are presented, whilst recognising its heritage. A few examples are employed to illustrate the potential of SfM applications for geomorphological research. In particular, SfM photogrammetry offers to geomorphologists a tool for high-resolution characterisation of 3-D forms at a range of scales and for change detection purposes. The high level of automation of SfM data processing creates both opportunities and threats, particularly because user control tends to focus upon visualisation of the final product rather than upon inherent data quality. Accordingly, this contribution seeks to guide potential new users in successfully applying SfM for a range of geomorphic studies.
### 3D 结构从运动(Structure from Motion)算法中文概述 #### 定义与目标 结构从运动(Structure from Motion, SFM)是一种计算机视觉技术,旨在通过分析一组二维图像来推断场景的三维几何结构以及摄像机的位置和姿态。该方法的核心在于利用多视角下的特征点对应关系,结合几何约束条件,实现对三维空间中物体形状的重建。 #### 基本原理 SFM 的基本流程可以分为几个主要部分:首先是提取图像中的特征点并匹配这些点之间的对应关系;其次是基于这些匹配结果计算初始的相机参数估计值;最后通过对整体模型进行优化得到精确的结果。这一过程通常涉及解决 Perspective-n-Point (PnP) 问题以获取相机的姿态信息[^2]。 #### 技术挑战与发展 尽管传统 SFM 方法已形成较为完整的理论框架和技术路线,但在实际应用过程中仍面临诸多困难。例如,在处理低纹理区域、存在遮挡现象或者面对动态对象时,系统的鲁棒性和准确性会受到严重影响[^4]。为了克服这些问题,研究者们不断探索新的解决方案,其中包括引入深度学习机制改进传统的束调整环节,即所谓的 Deep Bundle Adjustment 方案。 #### 应用领域扩展 除了经典的增量式 SFM 实现外,还有许多创新性的全局化策略被提出用于提升效率及效果质量。比如 GLOMAP 系统就尝试将平移均值法和平面三角测量融合成一步完成的整体定位操作模式,以此区别于常规做法达到更优表现水平[^3]。 ```python import numpy as np def sfm_example(): """ A simple example function demonstrating basic operations involved in an SfM pipeline. This is purely illustrative and does not represent a full implementation. """ points_2d = np.random.rand(10, 2) # Simulated 2D feature points across multiple views camera_matrix = estimate_camera_pose(points_2d) # Hypothetical PnP estimation step reconstructed_points_3d = triangulate_points(camera_matrix, points_2d) optimized_model = bundle_adjustment(reconstructed_points_3d, camera_matrix) return optimized_model def estimate_camera_pose(feature_matches): pass # Placeholder for actual pose estimation logic using e.g., RANSAC + PnP def triangulate_points(cameras, features): pass # Placeholder for multi-view triangulation algorithm def bundle_adjustment(model, cameras): pass # Placeholder for optimization procedure over all parameters simultaneously ``` 上述代码片段展示了简化版的 SFM 流程概览,其中包含了关键组成部分如相机姿态估算、多视图下三维坐标的反向投影以及最终联合调参等步骤。 ---
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值