pangolin于SLAM的实战学习(一)

目录

前言

1.安装pangolin

2.绘制简单图像

3.绘制SLAM相机位姿变化

4.多线程绘制相机位姿变化


前言

程序:https://github.com/eminbogen/7.16Pangolin

下一节:https://blog.csdn.net/unlimitedai/article/details/96134857

手册:http://docs.ros.org/fuerte/api/pangolin_wrapper/html/namespacepangolin.html

学过视觉SLAM14讲的同学应该记得第三章有一个小程序是pangolin编写,用于演示三维刚体运动的。大概这样:

也应该知道ORB_SLAM,其显示模块是由pangolin编写的:

我学习了三章程序,库的例程,泡泡机器人35课这个博客后,决定对pangolin进行一个总结。目前效果如图:

 

可以选择运行速度,是否显示轨迹线,是否运行,显示当前相机旋转矩阵,相机在世界坐标系下位置,保存界面,保存视角图片,显示rgb与depth图,相机位姿,退出。


1.安装pangolin

使用cmd安装

依赖:

sudo apt-get install libglew-dev
sudo apt-get install cmake
sudo apt-get install libboost-dev libboost-thread-dev libboost-filesystem-dev

主要:

git clone https://github.com/stevenlovegrove/Pangolin.git
cd Pangolin
mkdir build
cd build
cmake -DCPP11_NO_BOOST=1 ..
make -j

2.绘制简单图像

绘制简单立方体和坐标系。

#include <pangolin/pangolin.h>

int main(  )
{
    //生成一个gui界面,定义大小
    pangolin::CreateWindowAndBind("Main",640,480);
    //进行深度测试,保证某视角下像素只有一种颜色,不混杂
    glEnable(GL_DEPTH_TEST);

    //放置一个相机
    pangolin::OpenGlRenderState s_cam(
        pangolin::ProjectionMatrix(640,480,420,420,320,240,0.2,100),
        pangolin::ModelViewLookAt(-2,2,-2, 0,0,0, pangolin::AxisY)
    );

    //创建视角窗口
    pangolin::Handler3D handler(s_cam);
    pangolin::View& d_cam = pangolin::CreateDisplay()
            .SetBounds(0.0, 1.0, 0.0, 1.0, -640.0f/480.0f)
            .SetHandler(&handler);

    while( !pangolin::ShouldQuit() )
    {
        //清除颜色缓冲和深度缓冲
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        d_cam.Activate(s_cam);

        //绘制立方体
        pangolin::glDrawColouredCube();
	
	//绘制坐标系  线宽 启动 颜色 起点 终点 停止 
	glLineWidth(3);
	glBegin ( GL_LINES );
	glColor3f ( 0.8f,0.f,0.f );
	glVertex3f( -1,-1,-1 );
	glVertex3f( 0,-1,-1 );
	glColor3f( 0.f,0.8f,0.f);
	glVertex3f( -1,-1,-1 );
	glVertex3f( -1,0,-1 );
	glColor3f( 0.2f,0.2f,1.f);
	glVertex3f( -1,-1,-1 );
	glVertex3f( -1,-1,0 );
	glEnd();

        //交换帧和并推进事件
        pangolin::FinishFrame();
    }
    
    return 0;
}

3.绘制SLAM相机位姿变化

首先,我们使用上一节的内容绘制一个相机。

#include <pangolin/pangolin.h>

int main(  )
{
    //生成一个gui界面,定义大小
    pangolin::CreateWindowAndBind("Main",640,480);
    //进行深度测试,保证某视角下像素只有一种颜色,不混杂
    glEnable(GL_DEPTH_TEST);

    //放置一个相机
    pangolin::OpenGlRenderState s_cam(
        pangolin::ProjectionMatrix(640,480,420,420,320,240,0.2,100),
        pangolin::ModelViewLookAt(-2,2,-2, 0,0,0, pangolin::AxisY)
    );

    //创建视角窗口
    pangolin::Handler3D handler(s_cam);
    pangolin::View& d_cam = pangolin::CreateDisplay()
            .SetBounds(0.0, 1.0, 0.0, 1.0, -640.0f/480.0f)
            .SetHandler(&handler);

    while( !pangolin::ShouldQuit() )
    {
        //清除颜色缓冲和深度缓冲
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        d_cam.Activate(s_cam);
	
	//背景先弄成白色的吧,我觉得白色比较好看
	glClearColor(1.0f,1.0f,1.0f,1.0f);
	
	//所谓相机的表示,不就是画线吗
	const float w=2;
	const float h=w*0.75;
	const float z=w*0.6;
	glLineWidth(2);
	glBegin(GL_LINES);
	glColor3f(0.0f,0.0f,1.0f);
	glVertex3f(0,0,0);		glVertex3f(w,h,z);
	glVertex3f(0,0,0);		glVertex3f(w,-h,z);
	glVertex3f(0,0,0);		glVertex3f(-w,-h,z);
	glVertex3f(0,0,0);		glVertex3f(-w,h,z);
	glVertex3f(w,h,z);		glVertex3f(w,-h,z);
	glVertex3f(-w,h,z);		glVertex3f(-w,-h,z);
	glVertex3f(-w,h,z);		glVertex3f(w,h,z);
	glVertex3f(-w,-h,z);		glVertex3f(w,-h,z);
	
	glEnd();

        //交换帧和并推进事件
        pangolin::FinishFrame();
    }
    
    return 0;
}

之后,我们利用TUM数据集进行绘制。我好像用的这个集,不过我在我的程序那边保存了关键的一个文件,所以不到使用图片时,用我的github下载的内容就够。

groundtruth.txt文件存储着各时刻的位姿信息。时间,x,y,z,qx , qy , qz , qw。我们要将其提取,转化为pangolin需要的变换矩阵的转置形式。如果你学习了14讲第三章,那么应该非常容易完成。

#include <iostream>
#include <iomanip>
#include <ctime>
using namespace std;

#include <Eigen/Core>
#include <Eigen/Geometry>
using namespace Eigen;

#include <pangolin/pangolin.h>

//定义一个全局变量,用于保存生成的位姿
vector<vector<float>> pose_fin;

//从groundtruth文件获取位姿信息
int get_pose(string path_to_dataset,vector<vector<float>> &pose,int index,int interval);

//生成地图
void get_map();

int main()
{
    //给予文件地址
    string path_to_dataset = "../groundtruth.txt";
    //定义暂时读取位姿信息存储的vector,读取总帧数和读取间隔
    vector<vector<float>> pose;int index=50;int interval =160;
    //取得pose
    get_pose(path_to_dataset,pose,index,interval);
    //转换原groundtruth下的数据格式(四元数)到适合pangolin的数据格式(旋转矩阵)
    for (int i=0;i<index;i++)
    {
	  //存储四元数
	  Eigen::Quaterniond quaternion(pose[i][3],pose[i][4],pose[i][5],pose[i][6]);
	  //存储旋转矩阵
	  Eigen::Matrix3d rotation_matrix;
	  //四元数转化旋转矩阵
	  rotation_matrix=quaternion.matrix();
	  //定义一个暂时的pose_temp存储12个位姿数据,9个旋转矩阵的元素,3各位置元素
	  vector<float> pose_temp;
	  //旋转矩阵元素
	  pose_temp.push_back(rotation_matrix(0,0));	pose_temp.push_back(rotation_matrix(1,0));	pose_temp.push_back(rotation_matrix(2,0));
	  pose_temp.push_back(rotation_matrix(0,1));	pose_temp.push_back(rotation_matrix(1,1));	pose_temp.push_back(rotation_matrix(2,1));
	  pose_temp.push_back(rotation_matrix(0,2));	pose_temp.push_back(rotation_matrix(1,2));	pose_temp.push_back(rotation_matrix(2,2));
	  //位置元素
	  pose_temp.push_back(pose[i][0]);			pose_temp.push_back(pose[i][1]);				pose_temp.push_back(pose[i][2]);
	  //将pose_temp存入全局变量pose用于构图,也就是每一行的pose都是一个pose_temp,12个数,最后会有index行
	  pose_fin.push_back(pose_temp);
	  //清空pose_temp内存
	  pose_temp.clear();
    }
    //清空pose内存
    pose.clear();
    //构图
    get_map();
    return 0;
}

int get_pose(string path_to_dataset,vector<vector<float>> &pose,int index,int interval)
{
    //检测文件是否存在
    ifstream fin( path_to_dataset );
    if ( !fin ) 
    {
        cerr<<"I cann't find txt!"<<endl;
	return 1;
    }
    //循环取值给pose,取帧数量为index
    for ( int i=0; i<index; i++ )
    {
	//定义暂时量用于读取操作,定义pose_temp用于向pose添加数据,设定选取间隔为interval
	float temp[8];vector< float>pose_temp;int interval_temp = interval;
	//循环读取文件每行数据,直到满足interval行
	while(interval_temp--) fin>>temp[0]>>temp[1]>>temp[2]>>temp[3]>>temp[4]>>temp[5]>>temp[6]>>temp[7];
	//先把7个数给pose_temp,3个位置元素,还有四元数,注意我先加入的temp[7]也就是四元数的实部
	pose_temp.push_back(temp[1]);pose_temp.push_back(temp[2]);pose_temp.push_back(temp[3]);
	pose_temp.push_back(temp[7]);pose_temp.push_back(temp[4]);pose_temp.push_back(temp[5]);pose_temp.push_back(temp[6]);
	//把pose_temp堆入pose
	pose.push_back(pose_temp);
	//清空pose_temp内存
	pose_temp.clear();
    }
    return 1;
}

void get_map()
{
    const float w=0.2;
    const float h=w*0.75;
    const float z=w*0.6;
    //生成一个gui界面,定义大小
    pangolin::CreateWindowAndBind("Main",640,480);
    //进行深度测试,保证某视角下像素只有一种颜色,不混杂
    glEnable(GL_DEPTH_TEST);

    //放置一个相机
    pangolin::OpenGlRenderState s_cam(
        pangolin::ProjectionMatrix(640,480,420,420,320,240,0.2,100),
        pangolin::ModelViewLookAt(-2,2,-2, 0,0,0, pangolin::AxisY)
    );

    //创建视角窗口
    pangolin::Handler3D handler(s_cam);
    pangolin::View& d_cam = pangolin::CreateDisplay()
            .SetBounds(0.0, 1.0, 0.0, 1.0, -640.0f/480.0f)
            .SetHandler(&handler);

    while( !pangolin::ShouldQuit() )
    {
        //清除颜色缓冲和深度缓冲
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        d_cam.Activate(s_cam);
	
	//背景先弄成白色的吧,我觉得白色比较好看
	glClearColor(1.0f,1.0f,1.0f,1.0f);
	
	//使用变换矩阵画图
	for(int i=0;i<pose_fin.size();i++)
	{
	    //使用位置变换矩阵
	    glPushMatrix();
	    //变换如该矩阵,注意这个变换矩阵是转置的
	    std::vector<GLfloat> Twc ={ pose_fin[i][0],pose_fin[i][1],pose_fin[i][2],0,
							      pose_fin[i][3],pose_fin[i][4],pose_fin[i][5],0,
							      pose_fin[i][6],pose_fin[i][7],pose_fin[i][8],0,
							      pose_fin[i][9],pose_fin[i][10],pose_fin[i][11],1 };
	    
	    //变换
	    glMultMatrixf(Twc.data());
	    //每次变换后绘制相机
	    glLineWidth(2);
	    glBegin(GL_LINES);
	    glColor3f(0.0f,0.0f,1.0f);
	    glVertex3f(0,0,0);		glVertex3f(w,h,z);
	    glVertex3f(0,0,0);		glVertex3f(w,-h,z);
	    glVertex3f(0,0,0);		glVertex3f(-w,-h,z);
	    glVertex3f(0,0,0);		glVertex3f(-w,h,z);
	    glVertex3f(w,h,z);		glVertex3f(w,-h,z);
	    glVertex3f(-w,h,z);		glVertex3f(-w,-h,z);
	    glVertex3f(-w,h,z);		glVertex3f(w,h,z);
	    glVertex3f(-w,-h,z);		glVertex3f(w,-h,z);
	    
	    glEnd();
	    glPopMatrix();
	}
	
	//绘制连接的绿色线
	glLineWidth(2);
        glBegin ( GL_LINES );
	glColor3f ( 0.0f,1.f,0.f );
	for(int i=0;i<pose_fin.size()-1;i++)
	{
	    glVertex3f( pose_fin[i][9],pose_fin[i][10],pose_fin[i][11]);
	    glVertex3f( pose_fin[i+1][9],pose_fin[i+1][10],pose_fin[i+1][11] );
	}
	glEnd();

        //交换帧和并推进事件
        pangolin::FinishFrame();
    }
}

4.多线程绘制相机位姿变化

想如同orb_slam那样实时演示,就需要多线程。

主要内容如下:

//多线程的库
#include <thread>

//定义线程
std::thread render_loop;
//开启线程
render_loop = std::thread(get_map);

//暂定(在获取pose_fin的循环中使用,让位姿的获取类似slam的获取一样慢)
usleep(100000);

//收束线程
render_loop.join();

 

  • 25
    点赞
  • 107
    收藏
    觉得还不错? 一键收藏
  • 21
    评论
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值