【三维重建】增量SFM系统

在学习完鲁鹏老师的三维重建基础后,打算用C++代码复现一下增量SFM系统(https://github.com/ldx-star/SFM)。

本项目的最终目标就是通过相机拍摄的多视角视图获取三维点云。由于资金有效,博主使用的是相机是小米12。

先来看一下最终效果:
在这里插入图片描述
当然了,和开源系统比起来还是差很多的。
在这里插入图片描述

二、项目流程

整个项目大致可以分为三步:

  1. 相机标定
  2. 构建共视图
  3. 重建

接下来将逐步介绍这三个流程,以及其实现细节。

三、实现细节

手机相机的焦距一般是固定,我们在使用手机拍照时说的调焦其实是算法调焦。为什么避免这个问题,在用手机拍摄标定板时需要关闭手机的自动调焦。

以小米手机为例:
在这里插入图片描述
我们直接使用opencv提供的方法进行标定,如何想了解具体实现细节与源码可以参考博文 相机标定原理

我们项目的提供的标定图,最终的重投影误差为0.25,并且我们拍摄图片所使用的是同一个相机,所以所有相机的初始内参全部一样。

2、构建共视图

共视图就是建立图与图间的特征匹配关系。

这部分使用的事opencv的SIFT特征匹配算法,详细原理见博文 SIFT特征检测

在共视图中,我们定义了以下结构:

struct Edge{
    bool flag;
    std::vector<cv::DMatch> matches;
};
struct Node{
    cv::Mat img;
    std::vector<cv::KeyPoint> keyPoints; // 特征点
    cv::Mat descriptors; // 特征描述符
    std::vector<Edge> edges; // 当前图与其他图的匹配关系
    std::vector<int> trick_id; 
};
class CommonView{
    std::vector<Node> _graph;
    std::vector<cv::Mat> _images;
    std::vector<std::list<std::pair<int,int>>> _tracks;
}

std::vector<cv::Mat> _images:用于存放8副原始视图。

std::vector<Node> _graph:用两个视图间的匹配关系,构建一个图结构

std::vector<std::list<std::pair<int,int>>> _tracks: 用于存放track

  • 什么是track?
    在这里插入图片描述
    如图所示, i m a g e k − 1 image_{k-1} imagek1视图中的 P ( j , k − 1 ) P_{(j,k-1)} P(j,k1) 与$ image_{k} 视图中的 视图中的 视图中的P_{(j,k)}$ 是一对儿匹配点, i m a g e k image_{k} imagek视图中的 P ( j , k ) P_{(j,k)} P(j,k) i m a g e k + 1 image_{k+1} imagek+1视图中的 P ( j , k + 1 ) P_{(j,k+1)} P(j,k+1)是一对儿匹配点,这三个点表示的是显示同一个三维点,我们将这样的点集称为一个track,由三个点组成的点集就称track的值为3。为了使重建结果稳定,需要将track值小于2的匹配点去掉 。一个track对应一个三维点。

  • std::vector<std::list<std::pair<int,int>>>:这个结构是什么意思?

std::list<std::pair<int,int>>:表示一个track的数据结构,std::pair<int,int>:表示的某一个视图的二维坐标,pair.first表示的是视图id,pair.second表示的是特征点id。

  • Node结构体

std::vector<cv::KeyPoint> keyPoints:用于存放特征点

cv::Mat descriptors:当前视图的特征描述符

std::vector<Edge> edges:当前图与其他图的匹配关系,例如 edges[2]就表示当前视图与视图2的匹配关系。

std::vector<int> trick_id: trick_id.size()==keyPoints.size()用于表示每个特征点属于哪一个track

  • Edge结构体

bool flag:用一个布尔值表示两幅视图是否可以用于重建,初始值设为true,在两个视图进行重建后将其设为false

std::vector<cv::DMatch>:表示两视图的匹配关系
在这里插入图片描述

3、重建

  1. 选取可用匹配点最多的两个视图,得到初始的重建结果(初始重建结果至关重要,会直接影响到整个重建效果)
  • 初始重建步骤:

    1. 计算基础矩阵(博文链接:对极几何

    2. 从基础矩阵中得到相机外参(博文链接:运动恢复结构

    3. 三角化,得到初始三维点(博文链接:三角化

    4. while(存在可以重建的视图)

      • 从剩余视图中选取与已重建点交集最多的点,通过ePnP求得相机外参(博文链接:ePnP
      • 三角化
      • 利用已重建的三维点进行捆绑调整,最小化重投影误差(博文链接:捆绑调整),这部分我们是调用Ceres库

四、结果
在这里插入图片描述

  • 25
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
三维重建是通过多个二维图像来还原物体的三维结构。在Matlab中,可以使用Structure from Motion (SfM)算法进行三维重建。下面是一个简单的流程示例: 1. 加载图像和相机标定: ```matlab imageDir = fullfile('D:','picture','box'); % 图像文件夹路径 imds = imageDatastore(imageDir); % 加载图像数据集 load('calibrationSession'); % 加载相机参数 cameraParams = calibrationSession.CameraParameters; % 获取相机参数 ``` 2. 提取图像特征点: ```matlab % 创建一个视觉里程计对象 vSet = viewSet; % 遍历每个图像,提取特征点并添加到视觉里程计对象中 for i = 1:numel(imds.Files) I = readimage(imds, i); % 读取图像 grayImage = rgb2gray(I); % 转换为灰度图像 % 提取特征点和特征描述符 points = detectSURFFeatures(grayImage); [features, validPoints] = extractFeatures(grayImage, points); % 添加特征点到视觉里程计对象中 vSet = addView(vSet, i, 'Points', validPoints, 'Features', features); end ``` 3. 估计相机姿态: ```matlab % 估计相机姿态 vSet = estimateCameraPose(vSet, 'MaxReprojectionError', 1); ``` 4. 三角测量: ```matlab % 三角测量 vSet = find3D(vSet); % 获取三维点云 pointCloud = vSet.Views.Points; ``` 5. 可视化结果: ```matlab % 可视化三维点云 pcshow(pointCloud); ``` 请注意,这只是一个简单的示例流程,实际的三维重建过程可能更加复杂。你可以根据自己的需求和数据进行相应的调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值