SfM多视图三维点云重建--【VS2015+OpenCV3.4+PCL1.8】

本文详细介绍了在多视图三维重建过程中遇到的难点,如确定相机位姿,以及解决方法,利用OpenCV的solvePnP函数解决PnP问题。通过增量SfM方式,实现了从6张图片的三维点云重建。虽然随着图片数量增加,点云在PCL中显示尺寸减小,但重建结果无误。提供完整工程下载链接。
摘要由CSDN通过智能技术生成
难点

在完成两视图三维重建之后,接下来就是进行多视图重建。多视图重建的难点在于如何确定第 i i i( i i i>2)个相机到世界坐标系的位姿变换矩阵。

两视图重建时,是将第一个相机所在的坐标系视为世界坐标系,并计算第二个相机相对于第一个相机的位姿变换矩阵。但这种方法并不能用在多视图重建中,即不能将第 i i i( i i i>2)个视图依次与第一个视图进行特征点匹配,并根据匹配的特征点进行双目重建,因为随着帧数增加,当前帧与第一帧之间可能无法找到足够的匹配特征点;也不能采取1与2、2与3、3与4这样依次两两视图重建的方式,因为如此两视图重建得出的是 i + 1 i+1 i+1帧与第 i i i帧的相对位姿,且丢失了 t t t的尺度信息,无法通过依次连乘转到第1帧代表的世界坐标系下。

可参考:OpenCV实现SfM(三):多目三维重建

解决方法

其实这就是所谓的PnP问题了,“PnP是求解3D到2D点对运动的方法,它描述了在已知n个3D空间点以及它们的投影位置时,如何估计相机所在的位姿”。而Opencv中提供了相关的函数solvePnP及solvePnPRansac可直接使用。已知的3D空间点的坐标是世界坐标系下的坐标,因此使用solvePnP获得的相机位置也是在世界坐标系下位置,即第 i i i个相机到第一个相机的变换矩阵,在此基础上就可以使用三角法进行三维重建了。

本文采用增量SfM方式进行多视图三维重建

代码

环境:Win10+VS2015+OpenCV3.4+PCL1.8

#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>

#include <opencv2/features2d/features2d.hpp> 
#include <opencv2/xfeatures2d/nonfree.hpp>

#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>

using namespace std;
using namespace cv;
using namespace pcl;
using namespace cv::xfeatures2d;

// 提取所有图像的特征点 及 特征点处的RGB
void extract_features(vector<string>& image_names, vector<vector<KeyPoint>>& keypoints_for_all, vector<Mat>& descriptor_for_all, vector<vector<Vec3b>>& colors_for_all);
// ratio & symmetry test
void ratioTest(vector<vector<DMatch>> &matches, vector<DMatch> &goodMatches);
void symmetryTest(const vector<DMatch>& matches1, const vector<DMatch>& matches2, vector<DMatch>& symMatches);

// 匹配所有特征点
void match_features(vector<Mat>& descriptor_for_all, vector<vector<DMatch>>& matches_for_all);
// 由匹配对提取特征点对
void get_matched_points(vector<KeyPoint> keypoints1,vector<KeyPoint> keypoints2,vector<DMatch> goodMatches,vector<Point2f>& points1,vector<Point2f>& points2);
// 获取匹配点的RGB
void get_matched_colors(vector<Vec3b>& color1, vector<Vec3b>& color2, vector<DMatch> matches, vector<Vec3b>& out_c1, vector<Vec3b>& out_c2);

// 剔除p1中mask值为0的元素
void maskout_points(vector<Point2f>& p1, Mat& mask);
void maskout_colors(vector<Vec3b>& p1, Mat& mask);

// 重建前2张图片
void reconstruct_first2imgs(Mat K, vector<vector<KeyPoint>>& key_points_for_all, vector<vector<Vec3b>>& colors_for_all, vector<vector<DMatch>>& matches_for_all, vector<Point3f>& structure, vector<vector<int>>& correspond_struct_idx, vector<Vec3b>& colors, vector<Mat>& rotations, vector<Mat>& translations);

// 三维重建
// 前两张图片重建
void reconstruct(Mat& K, vector<Point2f>& points1, vector<Point2f>& points2, Mat& R, Mat& t, Mat& mask, vector<Point3f>& points3D);
// 后续图片重建
void reconstruct(Mat& K, Mat& R1, Mat& T1, Mat& R2, Mat& T2, vector<Point2f>& points1, vector<Point2f>& points2, vector<Point3f>& points3D);

// 获得三维点与对应的像素点
void get_objpoints_and_imgpoints(vector<DMatch>& matches, vector<int>& struct_indices, vector<Point3f>& structure, vector<KeyPoint>& key_points, vector<Point3f>& object_points, vector<Point2f>& image_points);

// 点云融合
void fusion_pointscloud(vector<DMatch>& matches, vector<int>& struct_indices, vector<int>& next_struct_indices, vector<Point3f>& structure, vector<Point3f>& next_structure, vector<Vec3b>& colors, vector<Vec3b>& next_colors);

int main(int argc, char* argv[])
{
   
	vector<string> img_names;
	img_names.push_back(".\\images\\000.png");
	img_names.push_back(".\\images\\001.png");
	img_names.push_back(".\\images\\002.png");
	img_names.push_back(".\\images\\003.png");
	img_names.push_back(".\\images\\004.png");
	img_names.push_back(".\\images\\005.png");
	//img_names.push_back(".\\images\\006.png");
	//img_names.push_back(".\\images\\007.png");
	//img_names.push_back(".\\images\\008.png");
	//img_names.push_back(".\\images\\009.png");

	Mat K = (Mat_<double>(3, 3) << 2759.48, 0, 1520.69, 0, 2764.16, 1006.81, 0, 0, 1); // Fountain的内参数矩阵

	vector<vector<KeyPoint>> key_points_for_all;
	vector<Mat> descriptor_for_all;
	vector<vector<Vec3b>> colors_for_all; // 以图片为一个vector单元,存放所有特征点的RGB,防止混淆
	vector<vector<DMatch>> matches_for_all;

	// 提取所有图像的特征点
	extract_features(img_names, key_points_for_all, descriptor_for_all, colors_for_all);

	// 对所有图像进行顺次的特征匹配
	match_features(descriptor_for_all, matches_for_all);

	// 重建前两张图片
	vector<Point3f> points3D;	// 存放重建后所有三维点
	vector<vector<int>> correspond_struct_idx;	// 若第i副图像中第j特征点对应位置的值是N,则代表该特征点对应的是重建后的第N个三维点
	vector<Vec3b> colors;		// 存放重建后所有三维点的RGB(作为最终重建结果,不需要以图片为单元分隔,)
	vector<Mat> rotations;		// 所有相机相对第一个相机的旋转矩阵
	vector<Mat> translations;	// 所有相机相对第一个相机的平移矩阵
	
	cout << "key_points_for_all.size() = " << key_points_for_all.size() << endl;
	cout << "matches_for_all.size() = " << matches_for_all
  • 1
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
SFM(Structure from Motion)是一种通过从多个相机图像中恢复出场景的三维结构和相机运动的技术。SFM三维重建SFM技术的一个应用,即通过对多个相机图像进行分析和处理,生成一个精确的三维场景模型。 在SFM三维重建中,BA(Bundle Adjustment)是一个优化方法,用于通过优化相机的位姿和场景的三维结构,以最小化重建误差。在本次回答中,我们使用了一些工具和库来实现SFM三维重建的BA优化。 首先,我们使用VS2015作为开发环境,以便编译和运行我们的代码。其次,我们使用OpenCV3.4,作为我们图像处理和计算机视觉算法的主要库。OpenCV提供了许多用于图像特征提取、匹配和相机校准的函数和类。 此外,我们还使用PCL(Point Cloud Library)1.8来处理点云数据。PCL是一个广泛使用的库,用于点云处理和三维重建。它提供了许多用于点云滤波、配准和特征提取的算法。 最后,我们使用Ceres Solver来进行BA优化。Ceres Solver是一个用于非线性优化的开源库,它提供了强大的优化算法和工具。在SFM三维重建中,我们使用Ceres Solver来优化相机的位姿和场景的三维结构,以获得更高质量的重建结果。 总之,通过使用VS2015OpenCV3.4PCL1.8和Ceres Solver,我们可以实现SFM三维重建的BA优化。这些工具和库提供了许多用于图像处理、点云处理和非线性优化的算法和函数,使我们能够更好地重建三维场景。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值