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。 - 安装要点如下:
- 首先关闭系统的“快速启动”模式,然后进入BIOS设置BootMode为UEFI模式(重要),接着在Security选项卡下设置SecurityBoot为Disabled;
- 制作启动盘软件:UltraISO+压缩200G内存空间用于Ubuntu安装;
- 14.04分区&大小:
逻辑分区,512M,起始,Ext4日志文件系统,/boot;
逻辑分区,8192M,起始,交换空间,无挂载点;
逻辑分区,51200M,起始,Ext4日志文件系统,/;
逻辑分区,剩余空间数,起始,Ext4日志文件系统,/home;
- 进入Ubuntu14.04,直接升级到16.04,参考:从Ubuntu 14.04 LTS版升级到Ubuntu 16.04 LTS;
安装完成后,默认进入的是Ubuntu系统,即采用的是ubuntu引导windows的方式。
ps: 这么做是迫不得已的方法,如果可以建议还是采取直接安装ubuntu16.04的方式;这么做有个很大的弊端,就是如果网速较慢的话,升级过程可能需要持续好几个小时,如果中途一不小心中断了,还要从头再来。
搜狗输入法
搜狗输入法的安装比较简单,参考:Ubuntu 16.04 LTS安装sogou输入法详解
谷歌浏览器、“*”
- 谷歌浏览器的安装参考:ubuntu16.04安装chrome
- “*”使用electron-ssr,直接双击安装即可,安装完成后,在桌面右上角会出现小飞机图标,接下来的使用方法同 windows系统:从这里获取免费上网帐号,然后直接“二维码扫描”即可连接服务器;
- electron-ssr软件链接:https://pan.baidu.com/s/1_jvXIb3a5b6CMekmQkRHqA ,密码:iuss;
卸载不必要的软件
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
- 安装
Eigen的安装过程简单,网上也有很多安装教程,这里参考:ubuntu16.04+eigen3安装。 - 注意
Eigen的安装是后续Ceres和g2o安装的基础和前提。Eigen安装完成后,头文件存放在/usr/include/eigen3,且其只有头文件,没有实现的库文件。 - 测试代码
虽然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)
- 程序运行结果:
Ceres
- 参考:ubuntu16.04安装ceres库,进行依赖项的安装;
- 接下来采用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库文件。
- 测试代码:
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} )
- 程序运行结果:
注意:如果find_package(Ceres REQUIRED PATHS)中Ceres首字母为小写,可能出现如下问题:
g2o
- g2o的安装方式同Ceres,首先更新依赖项:
sudo apt-get install libqt4-dev qt4-qmake libqglviewer-dev libsuitesparse-dev libcxsparse3.1.4 libcholmod3.0.6
- 编译安装:
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下可找到库文件。
- 测试代码
测试程序源自《视觉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
)
- 程序运行结果:
注意:还需要将g2o安装目录(这里是~/SLAM_Lib/g2o)下的cmake_modules文件夹中的拷贝到当前工程目录下,主要是为了包含FindG2O.cmake文件,否则会报如下错误:
ps:如果上述方法不奏效,也可尝试将find_package( G2O REQUIRED )中的G2O改成小写字母g2o,但拷贝cmake_modules文件夹仍是必须的操作。
Sophus
- 安装
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
- 测试代码:
源自:《视觉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} )
- 程序运行结果:
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,进行如下安装过程:
- 下载pcl-1.8.0源码
从Release.PCL.Github找到并下载pcl-1.8.0源码,并解压缩到SLAM_Lib文件夹下; - 安装依赖项、编译、安装;
- 建立链接,在安装完成后需要建立链接;
方法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在编译时能找到对应的文件。
-
获取文件路径
首先使用:whereis libpcl_common.so,来查找libpcl_common.so文件的路径;如确认为:/usr/lib/libpcl_common.so。 -
执行链接程序
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
- 编译
执行编译,若出现如下的.so缺失问题,使用同样的链接方法进行链接即可。
*** No rule to make target '/usr/lib/x86_64-linux-gnu/libpcl_common.so', needed by 'test'. Stop.
- 测试代码:
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)
- 程序运行结果:
OpenCV
OpenCV的安装参考:OpenCV - Linux(Ubuntu 16.04)中安装OpenCV + OpenCV_Contrib,采取同时编译安装OpenCV和OpenCV_Contrib扩展模块的方式。这里对上述博客进行一些改进和补充,而且安装的是OpenCV3.1.0版本,具体流程如下:
- 分别从opencv与opencv_contrib,下载opencv3.1及其对应的opencv_contrib模块;解压后,将opencv_contrib-3.1.0文件夹拷贝到~/SLAM_Lib/opencv3.1.0文件夹下。
- 添加依赖项
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
- 编译、安装
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中。
- 测试代码:
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:
在运行时,发现imshow()无法使用,出现如下错误:
解决方法:google了一下发现是libgtk2.0-dev没有安装成功,按照如下顺序安装,并重新编译、安装:
sudo apt-get install libgtk2.0-dev
cd opencv/build
cmake ..
make
sudo make install
- 遇到的问题2:
无法找到hd5.h文件、 #define sign(s) ((s > 0 ) ? 1 : ((s<0) ? -1 : 0))等问题,可参考:ubuntu 16.04 opencv3.1.0 opencvv_contrib编译遇到的问题 解决。 - 遇到的问题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”)”,并重新编译即可。
备注
- OpenCV版本不兼容
在安装OpenCV时,如果采取git clone的方式,则安装的是最新版本(如OpenCV4.1)。这种方式会因OpenCV版本不兼容,导致在运行《视觉SLAM十四讲》第九讲源码程序时,出现 Segmentation fault(core dumped) 的问题。 - 多版本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”)即可实现版本切换