OpenCV  4.10.0
开源计算机视觉
加载中...
搜索中...
没有匹配
场景重建

目标

在这个教程中,您将学习如何使用重建API进行稀疏重建

  • 加载一个包含图像路径列表的文件。
  • 运行libmv重建管道。
  • 使用Viz显示获得的结果。

代码

#include <opencv2/sfm.hpp>
#include <opencv2/viz.hpp>
#include <opencv2/core.hpp>
#include <iostream>
#include <fstream>
using namespace std;
using namespace cv;
using namespace cv::sfm;
static void help() {
cout
<< "\n------------------------------------------------------------------------------------\n"
<< " 本程序展示了OpenCV结构从运动(SFM)模块的多视图重建能力。\n"
<< " 它可以从一组2D图像中重建场景。\n"
<< " 使用方法:\n"
<< " example_sfm_scene_reconstruction <path_to_file> <f> <cx> <cy>\n"
<< " 其中: path_to_file 是系统中的文件绝对路径,其中包含\n"
<< " 用于重建的图像列表。 \n"
<< " f 是像素中的焦距。 \n"
<< " cx 是像素中图像主点的x坐标。 \n"
<< " cy 是像素中图像主点的y坐标。 \n"
<< "------------------------------------------------------------------------------------\n\n"
<< endl;
<< endl;
}
static int getdir(const string _filename, vector<String> &files)
{
ifstream myfile(_filename.c_str());
if (!myfile.is_open()) {
cout << "无法读取文件: " << _filename << endl;
exit(0);
} else {;
size_t found = _filename.find_last_of("/\\");
string line_str, path_to_file = _filename.substr(0, found);
while ( getline(myfile, line_str) )
files.push_back(path_to_file+string("/")+line_str);
}
return 1;
}
int main(int argc, char* argv[])
{
// 读取输入参数
if ( argc != 5 )
{
help();
exit(0);
}
// 解析图像路径
vector<String> images_paths;
getdir( argv[1], images_paths );
// 构建内参
float f = atof(argv[2]),
cx = atof(argv[3]), cy = atof(argv[4]);
Matx33d K = Matx33d( f, 0, cx,
0, f, cy,
0, 0, 1);
bool is_projective = true;
vector<Mat> Rs_est, ts_est, points3d_estimated;
reconstruct(images_paths, Rs_est, ts_est, K, points3d_estimated, is_projective);
// 打印输出
cout << "\n----------------------------\n" << endl;
cout << "重建: " << endl;
输出:<< "============================" << endl;
输出:<< "估计的3D点: " << points3d_estimated.size() << endl;
输出:<< "估计的相机: " << Rs_est.size() << endl;
输出:<< "精细化的内参: " << endl << K << endl << endl;
输出:<< "3D可视化: " << endl;
输出:<< "============================" << endl;
viz::Viz3d 窗口("坐标框架");
窗口设置窗口大小:Size(500,500));
窗口设置窗口位置:Point(150,150));
窗口设置背景颜色(); // 默认为黑色
// 创建点云
输出:<< "恢复点 ... ";
// 恢复估计的3d点
vector<Vec3f> 点云估计;
for (int i = 0; i < points3d_estimated.size(); ++i)
点云估计.push_back(Vec3f(points3d_estimated[i]));
输出:<< "[完成]" << endl;
输出:<< "恢复相机 ... ";
vector<Affine3d> 路径;
for (size_t i = 0; i < Rs_est.size(); ++i)
路径.push_back(Affine3d(Rs_est[i],ts_est[i]));
输出:<< "[完成]" << endl;
if ( 点云估计.size() > 0 )
{
输出:<< "渲染点 ... ";
viz::WCloud 云部件(点云估计, viz::Color::green());
窗口显示部件("point_cloud", 云部件);
输出:<< "[完成]" << endl;
}
else
{
输出:<< "无法渲染点:点云为空" << endl;
}
if ( 路径.size() > 0 )
{
输出:<< "渲染相机 ... ";
窗口显示部件("cameras_frames_and_lines", viz::WTrajectory(路径, viz::WTrajectory::BOTH, 0.1, viz::Color::green()));
窗口显示部件("cameras_frustums", viz::WTrajectoryFrustums(路径, K, 0.1, viz::Color::yellow()));
窗口设置观察者位置(路径[0]);
输出:<< "[完成]" << endl;
}
else
{
输出:<< "无法渲染相机:路径为空" << endl;
}
输出:<< endl << "按'q'键关闭每个窗口 ... " << endl;
窗口运行();
return 0;
}
仿射变换。
定义 affine.hpp:127
模板类,用于指定图像或矩形的尺寸。
定义 types.hpp:335
Viz3d 类表示一个 3D 可视化窗口。此类是隐式共享的。
定义 viz3d.hpp:68
云。
定义 widgets.hpp:681
此 3D 小部件表示一个轨迹。
定义 widgets.hpp:628
轨迹。
定义 widgets.hpp:605
void reconstruct(InputArrayOfArrays points2d, OutputArray Ps, OutputArray points3d, InputOutputArray K, bool is_projective=false)
在执行自校准的同时从二维对应点重建 3D 点。
int main(int argc, char *argv[])
定义 highgui_qt.cpp:3
定义 conditioning.hpp:44
与磁盘上文件相关联的文件存储的“黑盒”表示。
定义 core.hpp:102
STL 命名空间。

说明

首先,我们需要加载包含图像路径列表的文件,以便向重建API提供数据。

/home/eriba/software/opencv_contrib/modules/sfm/samples/data/images/resized_IMG_2889.jpg
/home/eriba/software/opencv_contrib/modules/sfm/samples/data/images/resized_IMG_2890.jpg
/home/eriba/software/opencv_contrib/modules/sfm/samples/data/images/resized_IMG_2891.jpg
/home/eriba/software/opencv_contrib/modules/sfm/samples/data/images/resized_IMG_2892.jpg
...
int getdir(const string _filename, vector<string> &files)
{
ifstream myfile(_filename.c_str());
if (!myfile.is_open()) {
cout << "无法读取文件: " << _filename << endl;
exit(0);
} else {
string line_str;
while ( getline(myfile, line_str) )
files.push_back(line_str);
}
return 1;
}

其次,构造的容器将被用来向重建API提供数据。需要注意的是,估计的结果必须存储在vector<Mat>中。在这种情况下,它被称为真实图像的重载签名,从这些图像内部提取并使用DAISY描述符计算稀疏2D特征,以便使用FlannBasedMatcher进行匹配并构建跟踪结构。

bool is_projective = true;
vector<Mat> Rs_est, ts_est, points3d_estimated;
reconstruct(images_paths, Rs_est, ts_est, K, points3d_estimated, is_projective);
// 打印输出
cout << "\n----------------------------\n" << endl;
cout << "重建: " << endl;
输出:<< "============================" << endl;
输出:<< "估计的3D点: " << points3d_estimated.size() << endl;
输出:<< "估计的相机: " << Rs_est.size() << endl;
输出:<< "精细化的内参: " << endl << K << endl << endl;

最后,获得的结果将在Viz中显示。

使用方法和结果

为了运行此示例,我们需要指定图像路径文件的路径、相机的焦距以及中心投影坐标(以像素为单位)。

1. Middlebury寺庙

使用以下图像序列[1]和以下相机参数,我们可以计算稀疏3D重建

./example_sfm_scene_reconstruction image_paths_file.txt 800 400 225

以下图片显示了获得的相机运动以及估计的稀疏3D重建

2. Sagrada Familia

使用以下图像序列[2]和以下相机参数,我们可以计算稀疏3D重建

./example_sfm_scene_reconstruction image_paths_file.txt 350 240 360

以下图片显示了获得的相机运动以及估计的稀疏3D重建

[1] http://vision.middlebury.edu/mview/data

[2] Penate Sanchez, A. and Moreno-Noguer, F. and Andrade Cetto, J. and Fleuret, F. (2014). LETHA: Learning from High Quality Inputs for 3D Pose Estimation in Low Quality Images. Proceedings of the International Conference on 3D vision (3DV). URL