SLAM环境配置:Linux+Clion+Eigen+Ceres+g2o+Sophus+PCL+OpenCV+测试代码

SLAM环境配置

考虑到linux系统可能会出现很多bug,导致需要反复重装系统,所以这里对自己配置SLAM环境的相关细节进行记录,权当做个笔记。

linux系统

环境:Win10+Ubuntu16.04双系统

  • 安装方法:
    先安装14.04再升级成16.04;
  • 原因
    直接安装16.04会遇到问题:[error5]Input/output error,据说是制作启动盘时U盘格式为FAT32,需要格式化为NTFS格式。但是经实际测试,发现即使将U盘格式化为NTFS格式,使用UltraISO制作的启动盘最终仍然为FAT32。
  • 安装要点如下:
  1. 首先关闭系统的“快速启动”模式,然后进入BIOS设置BootMode为UEFI模式(重要),接着在Security选项卡下设置SecurityBoot为Disabled;
  2. 制作启动盘软件:UltraISO+压缩200G内存空间用于Ubuntu安装;
  3. 14.04分区&大小:
逻辑分区,512M,起始,Ext4日志文件系统,/boot;
逻辑分区,8192M,起始,交换空间,无挂载点;
逻辑分区,51200M,起始,Ext4日志文件系统,/;
逻辑分区,剩余空间数,起始,Ext4日志文件系统,/home;
  1. 进入Ubuntu14.04,直接升级到16.04,参考:从Ubuntu 14.04 LTS版升级到Ubuntu 16.04 LTS

安装完成后,默认进入的是Ubuntu系统,即采用的是ubuntu引导windows的方式。

ps: 这么做是迫不得已的方法,如果可以建议还是采取直接安装ubuntu16.04的方式;这么做有个很大的弊端,就是如果网速较慢的话,升级过程可能需要持续好几个小时,如果中途一不小心中断了,还要从头再来。

搜狗输入法

搜狗输入法的安装比较简单,参考:Ubuntu 16.04 LTS安装sogou输入法详解

谷歌浏览器、“*”

  1. 谷歌浏览器的安装参考:ubuntu16.04安装chrome
  2. “*”使用electron-ssr,直接双击安装即可,安装完成后,在桌面右上角会出现小飞机图标,接下来的使用方法同 windows系统:从这里获取免费上网帐号,然后直接“二维码扫描”即可连接服务器;
  3. electron-ssr软件链接:https://pan.baidu.com/s/1_jvXIb3a5b6CMekmQkRHqA ,密码:iuss;

卸载不必要的软件

参考:Ubuntu 16.04卸载一些不必要的预装软件

IDE:Clion

参考:Ubuntu16.04安装clion全过程 进行安装,激活码:JetBrains全系列在线激活中心 。这里安装的是2019.1.3版本亲测可用,且该网站激活码每年会更新一次。

环境配置

整个环境的配置,除Eigen以外的安装均采用源码编译安装的方式,编译、安装的整体流程套路都差不多。博主这里把除Eigen以外的环境文件全部放到了一个文件夹下,即/home/SLAM_Lib文件夹,编译的结果都存放在新建的build或release文件夹下,其文件目录结构如下所示:

├── SLAM_Lib
	└── ceres-solver
		└── build # 存放cmake编译结果
		└── ...
  	└── g2o
  		└── build 
  		└── ...
  	└── Sophus
  		└── build
  		└── ...	
  	└── pcl
  		└── release
  		└── ...
	└── opencv3.1.0
  		└── build 
  		└── opencv_contrib-3.1.0
  		└── ...

Eigen

  1. 安装
    Eigen的安装过程简单,网上也有很多安装教程,这里参考:ubuntu16.04+eigen3安装
  2. 注意
    Eigen的安装是后续Ceres和g2o安装的基础和前提。Eigen安装完成后,头文件存放在/usr/include/eigen3,且其只有头文件,没有实现的库文件。
  3. 测试代码
    虽然Eigen的安装比较简单,这里还是给出测试代码,以节省测试时间。

main.cpp

#include <iostream>
#include <cmath>
using namespace std;

#include <Eigen/Core>
// Eigen 几何模块
#include <Eigen/Geometry>

/****************************
* 本程序演示了 Eigen 几何模块的使用方法
****************************/

int main ( int argc, char** argv )
{
    // Eigen/Geometry 模块提供了各种旋转和平移的表示
    // 3D 旋转矩阵直接使用 Matrix3d 或 Matrix3f
    Eigen::Matrix3d rotation_matrix = Eigen::Matrix3d::Identity();
    // 旋转向量使用 AngleAxis, 它底层不直接是Matrix,但运算可以当作矩阵(因为重载了运算符)
    Eigen::AngleAxisd rotation_vector ( M_PI/4, Eigen::Vector3d ( 0,0,1 ) );     //沿 Z 轴旋转 45 度
    cout .precision(3);
    cout<<"rotation matrix =\n"<<rotation_vector.matrix() <<endl;                //用matrix()转换成矩阵
    // 也可以直接赋值
    rotation_matrix = rotation_vector.toRotationMatrix();
    // 用 AngleAxis 可以进行坐标变换
    Eigen::Vector3d v ( 1,0,0 );
    Eigen::Vector3d v_rotated = rotation_vector * v;
    cout<<"(1,0,0) after rotation = "<<v_rotated.transpose()<<endl;
    // 或者用旋转矩阵
    v_rotated = rotation_matrix * v;
    cout<<"(1,0,0) after rotation = "<<v_rotated.transpose()<<endl;

    // 欧拉角: 可以将旋转矩阵直接转换成欧拉角
    Eigen::Vector3d euler_angles = rotation_matrix.eulerAngles ( 2,1,0 ); // ZYX顺序,即roll pitch yaw顺序
    cout<<"yaw pitch roll = "<<euler_angles.transpose()<<endl;

    // 欧氏变换矩阵使用 Eigen::Isometry
    Eigen::Isometry3d T=Eigen::Isometry3d::Identity();                // 虽然称为3d,实质上是4*4的矩阵
    T.rotate ( rotation_vector );                                     // 按照rotation_vector进行旋转
    T.pretranslate ( Eigen::Vector3d ( 1,3,4 ) );                     // 把平移向量设成(1,3,4)
    cout << "Transform matrix = \n" << T.matrix() <<endl;

    // 用变换矩阵进行坐标变换
    Eigen::Vector3d v_transformed = T*v;                              // 相当于R*v+t
    cout<<"v tranformed = "<<v_transformed.transpose()<<endl;

    // 对于仿射和射影变换,使用 Eigen::Affine3d 和 Eigen::Projective3d 即可,略

    // 四元数
    // 可以直接把AngleAxis赋值给四元数,反之亦然
    Eigen::Quaterniond q = Eigen::Quaterniond ( rotation_vector );
    cout<<"quaternion = \n"<<q.coeffs() <<endl;   // 请注意coeffs的顺序是(x,y,z,w),w为实部,前三者为虚部
    // 也可以把旋转矩阵赋给它
    q = Eigen::Quaterniond ( rotation_matrix );
    cout<<"quaternion = \n"<<q.coeffs() <<endl;
    // 使用四元数旋转一个向量,使用重载的乘法即可
    v_rotated = q*v; // 注意数学上是qvq^{-1}
    cout<<"(1,0,0) after rotation = "<<v_rotated.transpose()<<endl;

    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.14)
project(eigen_test)

set(CMAKE_CXX_STANDARD 14)

include_directories("/usr/include/eigen3")

add_executable(eigen_test main.cpp)
  1. 程序运行结果:
SLAM环境配置:Linux+Clion+Eigen+Ceres+g2o+Sophus+PCL+OpenCV+测试代码

Ceres

  1. 参考:ubuntu16.04安装ceres库,进行依赖项的安装;
  2. 接下来采用git clone的方式下载ceres-solver源码,并新建build文件夹、定位到build文件夹,再进行编译、安装,具体操作如下:
mkdir SLAM_Lib
cd SLAM_Lib
git clone https://github.com/ceres-solver/ceres-solver.git
cd ceres-solver # git clone结果为ceres-solver文件夹
mkdir build
cmake ..
make
sudo make install

ceres安装完成之后,在/usr/local/include/ceres下可找到Ceres头文件,在/usr/local/lib下可找到libceres.a库文件。

  1. 测试代码:

main.cpp

/*
 * 拟合y=ax+b的代码,设置ground truth y=2x+3
 */

#include <iostream>
#include<chrono>
#include<ceres/ceres.h>
#include<stdlib.h>
#include<vector>
#include<math.h>

using namespace std;
struct LineFitCost
{
    LineFitCost(double x,double y):_x(x),_y(y){}//初始化列表
    template<typename T> //重载(),函数对象
    bool operator()(const T* const ab,T* residual)const
    {
        //y=ax+b
        residual[0]=T(_y)-(ab[0]*T(_x)+ab[1]);
        return true;

    }
    const double _x,_y;

};

int main(int argc, char *argv[])
{
    google::InitGoogleLogging(argv[0]);
    double a=2.0,b=3.0 ;//y=2x+3
    int N=30; //sample
    double ab[2]={};
    vector<double> x_data,y_data;//样本点
    for(int i=0;i<N;++i)
    {
        double x=i/100.0;
        x_data.push_back(x);
        y_data.push_back(a*x+b+(rand()%360/180.0)*M_PI/180);//加上噪声
        cout<<x_data[i]<<" "<<y_data[i]<<endl;
    }
    //构建最小二乘
    ceres::Problem problem;
    for(int i=0;i<N;++i)
    {
        ceres::CostFunction *costfunction=new ceres::AutoDiffCostFunction<LineFitCost,1,2>(new LineFitCost(x_data[i],y_data[i]));
        //将残差方程和观测值加入到problem,nullptr表示核函数为无,ab是待拟合参数
        problem.AddResidualBlock(costfunction,nullptr,ab);
    }
    //解方程,copy and paste
    ceres::Solver::Options options;
    options.linear_solver_type = ceres::DENSE_SCHUR;
    options.minimizer_progress_to_stdout = true;
    ceres::Solver::Summary summary;
    ceres::Solve(options, &problem, &summary);
    std::cout << summary.BriefReport() << "\n";
    cout<<"a,b:"<<endl;
    for(auto i:ab)
    {
        cout<<i<<endl;
    }
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
set( CMAKE_CXX_FLAGS "-std=c++11" )

project(useCeres)

list( APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules )
# 寻找Ceres库并添加它的头文件
find_package(Ceres REQUIRED PATHS ) # 注意:Ceres首字母为大写
include_directories( ${CERES_INCLUDE_DIRS})
link_directories(${CERES_LIBRARY_DIRS})

add_executable( curve_fitting main.cpp )
# 与Ceres链接
target_link_libraries( curve_fitting ${CERES_LIBRARIES} )
  1. 程序运行结果:
SLAM环境配置:Linux+Clion+Eigen+Ceres+g2o+Sophus+PCL+OpenCV+测试代码

注意:如果find_package(Ceres REQUIRED PATHS)中Ceres首字母为小写,可能出现如下问题:

SLAM环境配置:Linux+Clion+Eigen+Ceres+g2o+Sophus+PCL+OpenCV+测试代码

g2o

  1. g2o的安装方式同Ceres,首先更新依赖项:
sudo apt-get install libqt4-dev qt4-qmake libqglviewer-dev libsuitesparse-dev libcxsparse3.1.4 libcholmod3.0.6 
  1. 编译安装:
cd SLAM_Lib
git clone https://github.com/RainerKuemmerle/g2o.git
cd g2o # git clone结果为g2o文件夹
mkdir build
cd build
cmake ..
make
sudo make install

g2o安装完成之后,在/usr/local/include/g2o下可找到相关头文件,在/usr/local/lib下可找到库文件。

  1. 测试代码
    测试程序源自《视觉SLAM14讲》-ch6:g2o_curve_fitting程序,但源程序有写bug,这里已经修正如下。

main.cpp

#include <iostream>
#include <g2o/core/base_vertex.h>
#include <g2o/core/base_unary_edge.h>
#include <g2o/core/block_solver.h>
#include <g2o/core/optimization_algorithm_levenberg.h>
#include <g2o/core/optimization_algorithm_gauss_newton.h>
#include <g2o/core/optimization_algorithm_dogleg.h>
#include <g2o/solvers/dense/linear_solver_dense.h>
#include <Eigen/Core>
#include <opencv2/core/core.hpp>
#include <cmath>
#include <chrono>
using namespace std;

// 曲线模型的顶点,模板参数:优化变量维度和数据类型
class CurveFittingVertex: public g2o::BaseVertex<3, Eigen::Vector3d>
{
public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    virtual void setToOriginImpl() // 重置
    {
        _estimate << 0,0,0;
    }

    virtual void oplusImpl( const double* update ) // 更新
    {
        _estimate += Eigen::Vector3d(update);
    }
    // 存盘和读盘:留空
    virtual bool read( istream& in ) {}
    virtual bool write( ostream& out ) const {}
};

// 误差模型 模板参数:观测值维度,类型,连接顶点类型
class CurveFittingEdge: public g2o::BaseUnaryEdge<1,double,CurveFittingVertex>
{
public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    CurveFittingEdge( double x ): BaseUnaryEdge(), _x(x) {}
    // 计算曲线模型误差
    void computeError()
    {
        const CurveFittingVertex* v = static_cast<const CurveFittingVertex*> (_vertices[0]);
        const Eigen::Vector3d abc = v->estimate();
        _error(0,0) = _measurement - std::exp( abc(0,0)*_x*_x + abc(1,0)*_x + abc(2,0) ) ;
    }
    virtual bool read( istream& in ) {}
    virtual bool write( ostream& out ) const {}
public:
    double _x;  // x 值, y 值为 _measurement
};

int main( int argc, char** argv )
{
    double a=1.0, b=2.0, c=1.0;         // 真实参数值
    int N=100;                          // 数据点
    double w_sigma=1.0;                 // 噪声Sigma值
    cv::RNG rng;                        // OpenCV随机数产生器
    double abc[3] = {0,0,0};            // abc参数的估计值

    vector<double> x_data, y_data;      // 数据

    cout<<"generating data: "<<endl;
    for ( int i=0; i<N; i++ )
    {
        double x = i/100.0;
        x_data.push_back ( x );
        y_data.push_back (
                exp ( a*x*x + b*x + c ) + rng.gaussian ( w_sigma )
        );
        cout<<x_data[i]<<" "<<y_data[i]<<endl;
    }

    // 源程序
/*
    // 构建图优化,先设定g2o
    typedef g2o::BlockSolver< g2o::BlockSolverTraits<3,1> > Block;  // 每个误差项优化变量维度为3,误差值维度为1
    Block::LinearSolverType* linearSolver = new g2o::LinearSolverDense<Block::PoseMatrixType>(); // 线性方程求解器
    Block* solver_ptr = new Block( linearSolver );      // 矩阵块求解器
    // 梯度下降方法,从GN, LM, DogLeg 中选
    g2o::OptimizationAlgorithmLevenberg* solver = new g2o::OptimizationAlgorithmLevenberg( solver_ptr );

 */

    // 修正后程序,主要是添加了std::move()
    typedef g2o::BlockSolver<g2o::BlockSolverTraits<3,1> > Block;  // 每个误差项优化变量维度为3,误差值维度为1
    std::unique_ptr<Block::LinearSolverType> linearSolver ( new g2o::LinearSolverDense<Block::PoseMatrixType>());
    std::unique_ptr<Block> solver_ptr ( new Block ( std::move(linearSolver)));
    // 梯度下降方法,从GN, LM, DogLeg 中选
    g2o::OptimizationAlgorithmLevenberg* solver = new g2o::OptimizationAlgorithmLevenberg ( std::move(solver_ptr));



    g2o::SparseOptimizer optimizer;     // 图模型
    optimizer.setAlgorithm( solver );   // 设置求解器
    optimizer.setVerbose( true );       // 打开调试输出

    // 往图中增加顶点
    CurveFittingVertex* v = new CurveFittingVertex();
    v->setEstimate( Eigen::Vector3d(0,0,0) );
    v->setId(0);
    optimizer.addVertex( v );

    // 往图中增加边
    for ( int i=0; i<N; i++ )
    {
        CurveFittingEdge* edge = new CurveFittingEdge( x_data[i] );
        edge->setId(i);
        edge->setVertex( 0, v );                // 设置连接的顶点
        edge->setMeasurement( y_data[i] );      // 观测数值
        edge->setInformation( Eigen::Matrix<double,1,1>::Identity()*1/(w_sigma*w_sigma) ); // 信息矩阵:协方差矩阵之逆
        optimizer.addEdge( edge );
    }

    // 执行优化
    cout<<"start optimization"<<endl;
    chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
    optimizer.initializeOptimization();
    optimizer.optimize(100);
    chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
    chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>( t2-t1 );
    cout<<"solve time cost = "<<time_used.count()<<" seconds. "<<endl;

    // 输出优化值
    Eigen::Vector3d abc_estimate = v->estimate();
    cout<<"estimated model: "<<abc_estimate.transpose()<<endl;

    return 0;
}

CMakeLists.txt

cmake_minimum_required( VERSION 2.8 )
project( g2o_curve_fitting )

set( CMAKE_BUILD_TYPE "Release" )
set( CMAKE_CXX_FLAGS "-std=c++11 -O3" )

# 将工程目录下的cmake_modules文件夹添加到搜索路径里
list( APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules ) 

# 寻找g2o
find_package( G2O REQUIRED ) 
include_directories(
        ${G2O_INCLUDE_DIRS}
        "/usr/include/eigen3"
)

# OpenCV
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_DIRS} )

add_executable( curve_fitting main.cpp )
# 与G2O和OpenCV链接
target_link_libraries( curve_fitting
        ${OpenCV_LIBS}
        g2o_core g2o_stuff
        )
  1. 程序运行结果:
SLAM环境配置:Linux+Clion+Eigen+Ceres+g2o+Sophus+PCL+OpenCV+测试代码

注意:还需要将g2o安装目录(这里是~/SLAM_Lib/g2o)下的cmake_modules文件夹中的拷贝到当前工程目录下,主要是为了包含FindG2O.cmake文件,否则会报如下错误:

SLAM环境配置:Linux+Clion+Eigen+Ceres+g2o+Sophus+PCL+OpenCV+测试代码

ps:如果上述方法不奏效,也可尝试将find_package( G2O REQUIRED )中的G2O改成小写字母g2o,但拷贝cmake_modules文件夹仍是必须的操作。

Sophus

  1. 安装
    Sophus李代数库有模板类库和非模板类库两个版本,这里选择非模态类库,Sophus库只需编译,无需安装。具体编译流程如下:
cd SLAM_Lib
git clone http://github.com/strasdat/Sophus.git
cd Sophus # git clone结果为Sophus文件夹
git checkout a621ff
mkdir build
cd build
cmake ..
make
  1. 测试代码:
    源自:《视觉SLAM14讲》-ch4:useSophus,直接可用。

main.cpp

#include <iostream>
#include <cmath>
using namespace std;

#include <Eigen/Core>
#include <Eigen/Geometry>

#include "sophus/so3.h"
#include "sophus/se3.h"

int main( int argc, char** argv )
{
    // 沿Z轴转90度的旋转矩阵
    Eigen::Matrix3d R = Eigen::AngleAxisd(M_PI/2, Eigen::Vector3d(0,0,1)).toRotationMatrix();

    Sophus::SO3 SO3_R(R);               // Sophus::SO(3)可以直接从旋转矩阵构造
    Sophus::SO3 SO3_v( 0, 0, M_PI/2 );  // 亦可从旋转向量构造
    Eigen::Quaterniond q(R);            // 或者四元数
    Sophus::SO3 SO3_q( q );
    // 上述表达方式都是等价的
    // 输出SO(3)时,以so(3)形式输出
    cout<<"SO(3) from matrix: "<<SO3_R<<endl;
    cout<<"SO(3) from vector: "<<SO3_v<<endl;
    cout<<"SO(3) from quaternion :"<<SO3_q<<endl;

    // 使用对数映射获得它的李代数
    Eigen::Vector3d so3 = SO3_R.log();
    cout<<"so3 = "<<so3.transpose()<<endl;
    // hat 为向量到反对称矩阵
    cout<<"so3 hat=\n"<<Sophus::SO3::hat(so3)<<endl;
    // 相对的,vee为反对称到向量
    cout<<"so3 hat vee= "<<Sophus::SO3::vee( Sophus::SO3::hat(so3) ).transpose()<<endl; // transpose纯粹是为了输出美观一些

    // 增量扰动模型的更新
    Eigen::Vector3d update_so3(1e-4, 0, 0); //假设更新量为这么多
    Sophus::SO3 SO3_updated = Sophus::SO3::exp(update_so3)*SO3_R;
    cout<<"SO3 updated = "<<SO3_updated<<endl;

    return 0;
}

CMakeLists.txt

cmake_minimum_required( VERSION 2.8 )
project( useSophus )

# 为使用 sophus,您需要使用find_package命令找到它
find_package( Sophus REQUIRED )
include_directories( ${Sophus_INCLUDE_DIRS} )
include_directories("/usr/include/eigen3")

add_executable( useSophus main.cpp )
target_link_libraries( useSophus ${Sophus_LIBRARIES} )
  1. 程序运行结果:
SLAM环境配置:Linux+Clion+Eigen+Ceres+g2o+Sophus+PCL+OpenCV+测试代码

PCL1.8

直接从github上git clone下来的版本是pcl-1.9,但是使用pcl-1.9安装会出现如下问题:fatal error:pcl/visualization/pcl_visualizer.h: No such file or directory。具体表现是在/usr/include/pcl中没有visualization文件夹,因此可采取如下两种方法进行安装,博主采取的是方法1,即直接下载pcl-1.8.0进行解压,再编译、安装的方式。

方法1

参考:linux:ubuntu16.04LTS 安装PCL1.8,进行如下安装过程:

  1. 下载pcl-1.8.0源码
    Release.PCL.Github找到并下载pcl-1.8.0源码,并解压缩到SLAM_Lib文件夹下;
  2. 安装依赖项、编译、安装;
  3. 建立链接,在安装完成后需要建立链接;

方法2

方法2是借鉴《视觉SLAM十四讲》里的方法,该方法安装的pcl-1.7版本。

sudo add-apt-repository ppa:v-launchpad-jochen-sprickerhof-de/pcl
sudo apt-get update
# sudo apt-get install libpcl-all # ubuntu14
sudo apt-get install libpcl-dev pcl-tools # ubuntu16

链接

不管采用哪种方法安装,安装完成后都需要进行链接,所谓链接其实将对应的.so文件复制到/usr/lib/x86_64-linux-gnu文件夹下,使得cmake在编译时能找到对应的文件。

  1. 获取文件路径
    首先使用:whereis libpcl_common.so,来查找libpcl_common.so文件的路径;如确认为:/usr/lib/libpcl_common.so。

  2. 执行链接程序

sudo ln -s /usr/local/lib/libpcl_common.so /usr/lib/x86_64-linux-gnu/libpcl_common.so
 
sudo ln -s /usr/local/lib/libpcl_octree.so /usr/lib/x86_64-linux-gnu/libpcl_octree.so
 
sudo ln -s /usr/local/lib/libpcl_io.so /usr/lib/x86_64-linux-gnu/libpcl_io.so
  1. 编译
    执行编译,若出现如下的.so缺失问题,使用同样的链接方法进行链接即可。
*** No rule to make target '/usr/lib/x86_64-linux-gnu/libpcl_common.so', needed by 'test'.  Stop.
  1. 测试代码:

main.cpp

#include <io从stream>
#include <pcl/common/common_headers.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/console/parse.h>


int main(int argc, char **argv) {
    std::cout << "Test PCL !!!" << std::endl;

    pcl::PointCloud<pcl::PointXYZRGB>::Ptr point_cloud_ptr (new pcl::PointCloud<pcl::PointXYZRGB>);
    uint8_t r(255), g(15), b(15);
    for (float z(-1.0); z <= 1.0; z += 0.05)
    {
        for (float angle(0.0); angle <= 360.0; angle += 5.0)
        {
            pcl::PointXYZRGB point;
            point.x = 0.5 * cosf (pcl::deg2rad(angle));
            point.y = sinf (pcl::deg2rad(angle));
            point.z = z;
            uint32_t rgb = (static_cast<uint32_t>(r) << 16 |
                            static_cast<uint32_t>(g) << 8 | static_cast<uint32_t>(b));
            point.rgb = *reinterpret_cast<float*>(&rgb);
            point_cloud_ptr->points.push_back (point);
        }
        if (z < 0.0)
        {
            r -= 12;
            g += 12;
        }
        else
        {
            g -= 12;
            b += 12;
        }
    }
    point_cloud_ptr->width = (int) point_cloud_ptr->points.size ();
    point_cloud_ptr->height = 1;

    pcl::visualization::CloudViewer viewer ("test");
    viewer.showCloud(point_cloud_ptr);
    while (!viewer.wasStopped()){ };
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.6)
project(pcl_test)

find_package(PCL 1.8 REQUIRED)

include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

add_executable(pcl_test main.cpp)

target_link_libraries (pcl_test ${PCL_LIBRARIES})

install(TARGETS pcl_test RUNTIME DESTINATION bin)
  1. 程序运行结果:
SLAM环境配置:Linux+Clion+Eigen+Ceres+g2o+Sophus+PCL+OpenCV+测试代码

OpenCV

OpenCV的安装参考:OpenCV - Linux(Ubuntu 16.04)中安装OpenCV + OpenCV_Contrib,采取同时编译安装OpenCV和OpenCV_Contrib扩展模块的方式。这里对上述博客进行一些改进和补充,而且安装的是OpenCV3.1.0版本,具体流程如下:

  1. 分别从opencvopencv_contrib,下载opencv3.1及其对应的opencv_contrib模块;解压后,将opencv_contrib-3.1.0文件夹拷贝到~/SLAM_Lib/opencv3.1.0文件夹下。
  2. 添加依赖项
sudo apt-get install build-essential
sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev
  1. 编译、安装
cd SLAM_Lib/opencv3.1.0
mkdir build
cd build

cmake -D CMAKE_INSTALL_PREFIX=/usr/local -D CMAKE_BUILD_TYPE=Release -D OPENCV_EXTRA_MODULES_PATH=../opencv_contrib-3.1.0/modules/ ..

make
sudo make install

OpenCV安装完成后,头文件存放在/usr/local/include中,库文件存放在/usr/local/lib中。

  1. 测试代码:

main.cpp

#include <iostream>
#include <chrono>
using namespace std;

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

int main ( int argc, char** argv )
{
    // 读取argv[1]指定的图像
    cv::Mat image;
    image = cv::imread ( argv[1] ); //cv::imread函数读取指定路径下的图像
    // 判断图像文件是否正确读取
    if ( image.data == nullptr ) //数据不存在,可能是文件不存在
    {
        cerr<<"文件"<<argv[1]<<"不存在."<<endl;
        return 0;
    }

    // 文件顺利读取, 首先输出一些基本信息
    cout<<"图像宽为"<<image.cols<<",高为"<<image.rows<<",通道数为"<<image.channels()<<endl;
    cv::imshow ( "image", image );      // 用cv::imshow显示图像
    cv::waitKey ( 0 );                  // 暂停程序,等待一个按键输入

    cv::destroyAllWindows();
    return 0;
}

CMakeLists.txt

cmake_minimum_required( VERSION 2.8 )
project( imageBasics )

# 添加c++ 11标准支持
set( CMAKE_CXX_FLAGS "-std=c++11" )

# 寻找OpenCV库
find_package( OpenCV 3.1 REQUIRED )
# 添加头文件
include_directories( ${OpenCV_INCLUDE_DIRS} )

add_executable( imageBasics main.cpp )
# 链接OpenCV库
target_link_libraries( imageBasics ${OpenCV_LIBS} )

编译完成后,使用如下语句执行程序:

cd build
./imageBasics ubuntu.png  # 使用ubuntu.png作为原图
  1. 程序运行结果
SLAM环境配置:Linux+Clion+Eigen+Ceres+g2o+Sophus+PCL+OpenCV+测试代码
  1. 遇到的问题1:
    在运行时,发现imshow()无法使用,出现如下错误:
SLAM环境配置:Linux+Clion+Eigen+Ceres+g2o+Sophus+PCL+OpenCV+测试代码

解决方法:google了一下发现是libgtk2.0-dev没有安装成功,按照如下顺序安装,并重新编译、安装:

sudo apt-get install libgtk2.0-dev
cd opencv/build
cmake ..
make
sudo make install
  1. 遇到的问题2:
    无法找到hd5.h文件、 #define sign(s) ((s > 0 ) ? 1 : ((s<0) ? -1 : 0))等问题,可参考:ubuntu 16.04 opencv3.1.0 opencvv_contrib编译遇到的问题 解决。
  2. 遇到的问题3:
    如果在编译opencv_contrib中的sfm模块遇到:【“relocation R_X86_64_32 against … can not be used when making a shared object; recompile with -fPIC”】的问题,则在/opencv_contrib/modules/sfm/src/libmv_light/libmv下的各个文件夹中的CMakeLists.txt中添加:“set(CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS} -fPIC”)”,并重新编译即可。

备注

  1. OpenCV版本不兼容
    在安装OpenCV时,如果采取git clone的方式,则安装的是最新版本(如OpenCV4.1)。这种方式会因OpenCV版本不兼容,导致在运行《视觉SLAM十四讲》第九讲源码程序时,出现 Segmentation fault(core dumped) 的问题。
  2. 多版本OpenCV共存
    参照ubuntu16.04安装opencv3.1.0与opencv2.4.9共存,安装OpenCV3.1.0,实现OpenCV4.1与OpenCV3.1.0共存。在使用时,只需要在CMakeLists.txt文件中添加:set(CMAKE_PREFIX_PATH “/usr/local/opencv3/share/OpenCV”)即可实现版本切换
上一篇:c – 如何用特征中的向量制作矩阵?


下一篇:特征库 – >用文件或现有std :: vector内容中的数据初始化矩阵(c)