目标
在这个教程中,您将学习如何使用重建API进行稀疏重建
- 加载一个包含图像路径列表的文件。
- 运行libmv重建管道。
- 使用Viz显示获得的结果。
代码
#include <iostream>
#include <fstream>
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]);
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;
窗口设置窗口位置:
Point(150,150));
窗口设置背景颜色();
输出:<< "恢复点 ... ";
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 )
{
输出:<< "渲染点 ... ";
窗口显示部件("point_cloud", 云部件);
输出:<< "[完成]" << endl;
}
else
{
输出:<< "无法渲染点:点云为空" << endl;
}
if ( 路径.size() > 0 )
{
输出:<< "渲染相机 ... ";
窗口显示部件(
"cameras_frames_and_lines",
viz::WTrajectory(路径, viz::WTrajectory::BOTH, 0.1, viz::Color::green()));
窗口设置观察者位置(路径[0]);
输出:<< "[完成]" << endl;
}
else
{
输出:<< "无法渲染相机:路径为空" << endl;
}
输出:<< endl << "按'q'键关闭每个窗口 ... " << endl;
窗口运行();
return 0;
}
模板类,用于指定图像或矩形的尺寸。
定义 types.hpp:335
Viz3d 类表示一个 3D 可视化窗口。此类是隐式共享的。
定义 viz3d.hpp:68
此 3D 小部件表示一个轨迹。
定义 widgets.hpp:628
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
与磁盘上文件相关联的文件存储的“黑盒”表示。
定义 core.hpp:102
说明
首先,我们需要加载包含图像路径列表的文件,以便向重建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