openCV相机运动估计

该教程展示了如何利用OpenCV的StructureFromMotion(SFM)模块进行相机运动估计。通过读取带有跟踪2d点的文件,构建容器,然后运行libmv重建管道,最终使用Viz进行3D结果的可视化展示。用户需提供跟踪文件路径、焦距和主点坐标作为输入参数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

相机运动估计

目标

在本教程中,您将学习如何使用重建API进行摄像机运动估计:

加载具有跟踪的2d点的文件,并在所有框架上构建容器。

运行libmv重建管道。

使用Viz显示获得的结果。

代码

#include<opencv2/core.hpp>#include<opencv2/sfm.hpp>#include<opencv2/viz.hpp>#include<iostream>#include<fstream>usingnamespace std;usingnamespace cv;usingnamespace cv::sfm;staticvoidhelp(){
            
  cout
      <<"\n------------------------------------------------------------------\n"<<" This program shows the camera trajectory reconstruction capabilities\n"<<" in the OpenCV Structure From Motion (SFM) module.\n"<<" \n"<<" Usage:\n"<<"        example_sfm_trajectory_reconstruction <path_to_tracks_file> <f> <cx> <cy>\n"<<" where: is the tracks file absolute path into your system. \n"<<" \n"<<"        The file must have the following format: \n"<<"        row1 : x1 y1 x2 y2 ... x36 y36 for track 1\n"<<"        row2 : x1 y1 x2 y2 ... x36 y36 for track 2\n"<<"        etc\n"<<" \n"<<"        i.e. a row gives the 2D measured position of a point as it is tracked\n"<<"        through frames 1 to 36.  If there is no match found in a view then x\n"<<"        and y are -1.\n"<<" \n"<<"        Each row corresponds to a different point.\n"<<" \n"<<"        f  is the focal length 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;}/* Build the following structure data
 *
 *            frame1           frame2           frameN
 *  track1 | (x11,y11) | -> | (x12,y12) | -> | (x1N,y1N) |
 *  track2 | (x21,y11) | -> | (x22,y22) | -> | (x2N,y2N) |
 *  trackN | (xN1,yN1) | -> | (xN2,yN2) | -> | (xNN,yNN) |
 *
 *
 *  In case a marker (x,y) does not appear in a frame its
 *  values will be (-1,-1).
 */staticvoidparser_2D_tracks(const String &_filename, std::vector<Mat>&points2d ){
            
  ifstream myfile(_filename.c_str());if(!myfile.is_open()){
            
    cout <<"Unable to read file: "<< _filename << endl;exit(0);}else{
            double x, y;
    string line_str;int n_frames =0, n_tracks =0;// extract data from text file
    vector<vector<Vec2d>> tracks;for(;getline(myfile,line_str);++n_tracks){
            
      istringstream line(line_str);
      vector<Vec2d> track;for( n_frames =0; line >> x >> y;++n_frames){
            if( x >0&& y >0)
          track.push_back(Vec2d(x,y));else
          track.push_back(Vec2d(-1));}
      tracks.push_back(track);}// embed data in reconstruction api formatfor(int i =0; i < n_frames;++i){
            
      Mat_<double>frame(2, n_tracks);for(int j =0; j < n_tracks;++j){
            frame(0,j)= tracks[j][i][0];frame(1,j)= tracks[j][i][1];}
      points2d.push_back(Mat(frame));}
    myfile.close();}}/* Keyboard callback to control 3D visualization
 */bool camera_pov =false;staticvoidkeyboard_callback(const viz::KeyboardEvent &event,void* cookie){
            if( event.action ==0&&!event.symbol.compare("s"))
    camera_pov =!camera_pov;}/* Sample main code
 */intmain(int argc,char** argv){
            // Read input parametersif( argc !=5){
            help();exit(0);}// Read 2D points from text file
  std::vector<Mat> points2d;parser_2D_tracks( argv[1], points2d );// Set the camera calibration matrixconstdouble 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(points2d, 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;
  viz::Viz3d window_est("Estimation Coordinate Frame");
             window_est.setBackgroundColor();// black by default
             window_est.registerKeyboardCallback(&keyboard_callback);// 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;
  cout <<"Recovering cameras ... ";
  vector<Affine3d> path_est;for(size_t i =0; i < Rs_est.size();++i)
    path_est.push_back(Affine3d(Rs_est[i],ts_est[i]));
  cout <<"[DONE]"<< endl;
  cout <<"Rendering Trajectory  ... ";
  cout << endl <<"Press:                       "<< endl;
  cout <<" 's' to switch the camera pov"<< endl;
  cout <<" 'q' to close the windows    "<< endl;if( path_est.size()>0){
            // animated trajectoryint idx =0, forw =-1, n =static_cast<int>(path_est.size());while(!window_est.wasStopped()){
            for(size_t i =0; i < point_cloud_est.size();++i){
            
        Vec3d point = point_cloud_est[i];
        Affine3d point_pose(Mat::eye(3,3,CV_64F), point);char buffer[50];
        sprintf (buffer,"%d",static_cast<int>(i));
        viz::WCube cube_widget(Point3f(0.1,0.1,0.0),Point3f(0.0,0.0,-0.1),true, viz::Color::blue());
                   cube_widget.setRenderingProperty(viz::LINE_WIDTH,2.0);
        window_est.showWidget("Cube"+String(buffer), cube_widget, point_pose);}
      Affine3d cam_pose = path_est[idx];
      viz::WCameraPosition cpw(0.25);// Coordinate axes
      viz::WCameraPosition cpw_frustum(K,0.3, viz::Color::yellow());// Camera frustumif( camera_pov )
        window_est.setViewerPose(cam_pose);else{
            // render complete trajectory
        window_est.showWidget("cameras_frames_and_lines_est", viz::WTrajectory(path_est, viz::WTrajectory::PATH,1.0, viz::Color::green()));
        window_est.showWidget("CPW", cpw, cam_pose);
        window_est.showWidget("CPW_FRUSTUM", cpw_frustum, cam_pose);}// update trajectory index (spring effect)
      forw *=(idx==n || idx==0)?-1:1; idx += forw;// frame rate 1s
      window_est.spinOnce(1,true);
      window_est.removeAllWidgets();}}return0;}

解释

首先,我们需要加载包含在所有帧上跟踪的2d点的文件,并构造容器以提供重建api。在这种情况下,跟踪的2d点将具有以下结构,即2d点数组的矢量,其中每个内部数组代表一个不同的帧。每个帧由2d个点的列表组成,例如,帧1中的第一个点与帧2中的相同点。如果帧中没有点,则分配的值将为(-1,-1):

for(int i =0; i < n_frames;++i){
            
  Mat_<double>frame(2, n_tracks);for(int j =0; j < n_tracks;++j){
            frame(0,j)= tracks[j][i][0];frame(1,j)= tracks[j][i][1];}
  points2d.push_back(Mat(frame));}

其次,构建的容器将用于提供重建API。重要的一点是,估计结果必须存储在vector 中:

bool is_projective =true;
vector<Mat> Rs_est, ts_est, points3d_estimated;reconstruct(points2d, 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;

最后,所获得的结果将显示在Viz中,在这种情况下,相机将产生振荡效果。

用法和结果

为了运行此示例,我们需要指定跟踪点文件的路径,相机的焦距以及中心投影坐标(以像素为单位)。您可以在samples / data / desktop_trakcks.txt中找到示例文件

./example_sfm_trajectory_reconstruction desktop_tracks.txt 1914640360

下图显示了从跟踪的2d点获得的摄像机运动:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值