【计算机视觉】从运动中恢复结构SfM-场景重建,三维重建[图像序列]

3.2.0-dev  http://docs.opencv.org/master/d4/d18/tutorial_sfm_scene_reconstruction.html

目标

在本教程中,您将学习如何使用重建api稀疏重建:

  • 加载和图像文件的路径。
  • libmv重建传递途径运行。
  • 使用即显示结果。

模块安装

从运动中恢复结构SfM模块安装

https://blog.csdn.net/KYJL888/article/details/72843166

明德殿例子

用法和结果

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

米德尔伯里寺

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

./example_sfm_scene_reconstruction image_paths_file.txt 800 400 225

 

temple_input.jpg

下图显示了获得的相机运动以及估计的稀疏三维重建:

temple_reconstruction.jpg

2.圣家堂

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

./example_sfm_scene_reconstruction image_paths_file.txt 350 240 360

sagrada_familia_input.jpg

下图显示了获得的相机运动以及估计的稀疏三维重建:

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

[2] Penate Sanchez,A。和Moreno-Noguer,F。和Andrade Cetto,J。和Fleuret,F。(2014)。 LETHA:从高质量输入中学习低质量图像中的3D姿态估计。 国际3D视觉会议(3DV)会议录。 网址

 

 

Code

#include <opencv2/sfm.hpp>
#include <opencv2/viz.hpp>
#include <opencv2/calib3d.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"
      << " This program shows the multiview reconstruction capabilities in the \n"
      << " OpenCV Structure From Motion (SFM) module.\n"
      << " It reconstruct a scene from a set of 2D images \n"
      << " Usage:\n"
      << "        example_sfm_scene_reconstruction <path_to_file> <f> <cx> <cy>\n"
      << " where: path_to_file is the file absolute path into your system which contains\n"
      << "        the list of images to use for reconstruction. \n"
      << "        f  is the focal lenght in pixels. \n"
      << "        cx is the image principal point x coordinates in pixels. \n"
      << "        cy is the image principal point y coordinates in pixels. \n"
      << "------------------------------------------------------------------------------------\n\n"
      << endl;
}


int getdir(const string _filename, vector<String> &files)
{
  ifstream myfile(_filename.c_str());
  if (!myfile.is_open()) {
    cout << "Unable to read file: " << _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[])
{
  // Read input parameters

  if ( argc != 5 )
  {
    help();
    exit(0);
  }

  // Parse the image paths

  vector<String> images_paths;
  getdir( argv[1], images_paths );


  // Build instrinsics

  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);


  /// Reconstruct the scene using the 2d images

  bool is_projective = true;
  vector<Mat> Rs_est, ts_est, points3d_estimated;
  reconstruct(images_paths, Rs_est, ts_est, K, points3d_estimated, is_projective);


  // Print output

  cout << "\n----------------------------\n" << endl;
  cout << "Reconstruction: " << endl;
  cout << "============================" << endl;
  cout << "Estimated 3D points: " << points3d_estimated.size() << endl;
  cout << "Estimated cameras: " << Rs_est.size() << endl;
  cout << "Refined intrinsics: " << endl << K << endl << endl;
  cout << "3D Visualization: " << endl;
  cout << "============================" << endl;


  /// Create 3D windows

  viz::Viz3d window("Coordinate Frame");
             window.setWindowSize(Size(500,500));
             window.setWindowPosition(Point(150,150));
             window.setBackgroundColor(); // black by default

  // Create the pointcloud
  cout << "Recovering points  ... ";

  // recover estimated points3d
  vector<Vec3f> point_cloud_est;
  for (int i = 0; i < points3d_estimated.size(); ++i)
    point_cloud_est.push_back(Vec3f(points3d_estimated[i]));

  cout << "[DONE]" << endl;


  /// Recovering cameras
  cout << "Recovering cameras ... ";

  vector<Affine3d> path;
  for (size_t i = 0; i < Rs_est.size(); ++i)
    path.push_back(Affine3d(Rs_est[i],ts_est[i]));

  cout << "[DONE]" << endl;


  /// Add the pointcloud
  if ( point_cloud_est.size() > 0 )
  {
    cout << "Rendering points   ... ";

    viz::WCloud cloud_widget(point_cloud_est, viz::Color::green());
    window.showWidget("point_cloud", cloud_widget);

    cout << "[DONE]" << endl;
  }
  else
  {
    cout << "Cannot render points: Empty pointcloud" << endl;
  }


  /// Add cameras
  if ( path.size() > 0 )
  {
    cout << "Rendering Cameras  ... ";

    window.showWidget("cameras_frames_and_lines", viz::WTrajectory(path, viz::WTrajectory::BOTH, 0.1, viz::Color::green()));
    window.showWidget("cameras_frustums", viz::WTrajectoryFrustums(path, K, 0.1, viz::Color::yellow()));

    window.setViewerPose(path[0]);

    cout << "[DONE]" << endl;
  }
  else
  {
    cout << "Cannot render the cameras: Empty path" << endl;
  }

  /// Wait for key 'q' to close the window
  cout << endl << "Press 'q' to close each windows ... " << endl;

  window.spin();

  return 0;
}

§ reconstruct() [3/4]

void cv::sfm::reconstruct(const std::vector< Stringimages,
  OutputArray Ps,
  OutputArray points3d,
  InputOutputArray K,
  bool is_projective = false 
 ) 

在执行自动校准的同时从2d图像重建3d点。

参数

images带有图像路径的字符串向量。
Ps输出向量与每个图像的3x4投影矩阵。
points3d具有估计的3d点的输出数组。
K输入/输出相机矩阵。 输入参数用作初始猜测。
is_projective如果是真的,相机应该是投射的。

该方法调用以下签名并从估计的K,R和t中提取投影矩阵。

注意

  • 图像必须按照图像序列进行排序。 此外,每个框架应尽可能靠近前一个和后一个框架。
  • 目前,DAISY功能用于计算2d点轨迹,它仅适用于3-4个图像。

___________________________________________

§ reconstruct() [4/4]

void cv::sfm::reconstruct(const std::vector< Stringimages,
  OutputArray Rs,
  OutputArray Ts,
  InputOutputArray K,
  OutputArray points3d,
  bool is_projective = false 
 ) 

在执行自动校准的同时从2d图像重建3d点。

参数

images带有图像路径的字符串向量。
Rs摄像机3x3旋转的输出矢量。
Ts相机的3x1平移的输出矢量。
points3d具有估计的3d点的输出数组。
ķ输入/输出相机矩阵\(K = \ vecthreethree {f_x} {0} {c_x} {0} {f_y} {c_y} {0} {0} {1} \)。 输入参数用作初始猜测。
is_projective如果是真的,相机应该是投射的。

通过实例化SFMLibmvEuclideanReconstruction类,在内部调用libmv简单管道例程和一些默认参数。

注意

  • 图像必须按照图像序列进行排序。 此外,每个框架应尽可能靠近前一个和后一个框架。
  • 目前,DAISY功能用于计算2d点轨道,它仅适用于3-4个图像。
  • 要查看场景重建的工作示例,请查看以下教程: 场景重建

说明

首先,我们需要加载包含图像路径列表的文件,以便为重建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)

 

其次,建造的容器将用于重建api.重要的是,估计结果必须存储在矢量<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;

cout << “============================” << endl;

cout << “估计的3D点数:” << points3d_estimated.size()<< endl;

cout << “估计相机:” << Rs_est.size()<< endl;

cout << “Refined intrinsics:” << endl << K << endl << endl;

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

 

 

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值