今天动手运行了高翔《视觉SLAM十四讲》第3讲“三维空间刚体运动”中的代码部分,前面的部分非常顺利,但是到了3.7节可视化演示的部分,出现了非常棘手的问题,大约画了3个小时的时间才解决。趁热乎记录一下,并且把最终实现的代码贴在本博客中,以便于后面踩坑的时候能及时解决。
最主要的坑就是标题所示的那个:
undefined reference to symbol ‘glTexImage2D‘
完整的报错类似:
undefined reference to symbol 'glTexImage2D'
error adding symbols: DSO missing from
搜了一下原因,这篇博客写的比较清楚。最终,我采用了他所说的“可能是因为make编译未找到链接的共享库 LibGL.so文件 ,我们可以在CMakeLists.txt文件中的 target_link_libraries 语句中添加 LibGL.so”这个方法,事实证明是很管用的。具体来说,就是在CMakeLists.txt中添加这一句话:
target_link_libraries(plotTrajectory GL)
可能是因为路径的问题,源代码中的findpackage没有找到pangolin的头文件和库文件,于是会报类似下的错误:
undefined reference to 'panbolin'::CreateWindowAndBind(std...........blabla)
这显然是引用失败,我自己写了findPangolin.cmake文件(详情见下方),并且按照截图的方式组织的工程结构如下。
./cmake/FindPangolin.cmake
find_path(PANGOLIN_INCLUDE_DIR
NAMES pangolin.h
PATHS "/usr/local/include/pangolin/"
)
find_library(PANGOLIN_LIBRARY
NAMES pangolin
PATHS "/usr/local/lib/"
)
MESSAGE("THIS IS A DEBUG INFO.")
MESSAGE("${PANGOLIN_INCLUDE_DIR}")
MESSAGE("${PANGOLIN_LIBRARY}")
IF (PANGOLIN_INCLUDE_DIR AND PANGOLIN_LIBRARY)
SET(PANGOLIN_FOUND TRUE)
MESSAGE("PANGOLIN FOUND = TRUE")
ENDIF (PANGOLIN_INCLUDE_DIR AND PANGOLIN_LIBRARY)
IF (PANGOLIN_FOUND)
IF(NOT PANGOLIN_FIND_QUIETLY)
MESSAGE(STATUS "FOUND PANGOLIN_LIB:${PANGOLIN_LIBRARY}")
ENDIF(NOT PANGOLIN_FIND_QUIETLY)
ELSE (PANGOLIN_FOUND)
IF(PANGOLIN_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "COULD NOT FIND PANGOLIN LIBRARY.")
ENDIF(PANGOLIN_FIND_REQUIRED)
ENDIF(PANGOLIN_FOUND)
./CMakeLists.txt
cmake_minimum_required( VERSION 2.8 )
set( CMAKE_BUILD_TYPE "Debug")
project(plotTrajectory)
set(CMAKE_MODULE_PATH ~/slam/examplesInTheBook/Chapter3/plotTrajectory/cmake)
MESSAGE("IWUCH DEBUG PROJECT_MODULE_PATH:${CMAKE_MODULE_PATH}")
find_package(Pangolin REQUIRED)
if(PANGOLIN_FOUND)
include_directories(${PANGOLIN_INCLUDE_DIR})
add_executable(plotTrajectory plotTrajectory.cpp)
target_link_libraries(plotTrajectory ${PANGOLIN_LIBRARY})
target_link_libraries(plotTrajectory GL)
else(PANGOLIN_FOUND)
message(FATAL_ERROR " PANGOLIN LIBRARY NOT FOUND.")
endif(PANGOLIN_FOUND)
include_directories("/usr/local/include/eigen3")
源代码中给的trajectory.txt路径无法使用,我最终暴力给了绝对路径,当然也可以使用相对路径,这个地方可以研究一下,应该有简单的方法可以学一学。
string trajectory_file = "/home/robotlab1/slam/examplesInTheBook/Chapter3/plotTrajectory/trajectory.txt";
最终我使用的源代码如下,有些多余的代码是在调试过程中增加的。
plotTrajctory.cpp
#include
#include
#include
#include
// extern "C"{
// #include
// }
// 本例演示了如何画出一个预先存储的轨迹
using namespace std;
using namespace Eigen;
using namespace pangolin;
// path to trajectory file
string trajectory_file = "/home/robotlab1/slam/examplesInTheBook/Chapter3/plotTrajectory/trajectory.txt";
void DrawTrajectory(vector<Isometry3d, Eigen::aligned_allocator<Isometry3d>>);
int main(int argc, char **argv) {
vector<Isometry3d, Eigen::aligned_allocator<Isometry3d>> poses;
ifstream fin(trajectory_file);
if (!fin) {
cout << "cannot find trajectory file at " << trajectory_file << endl;
return 1;
}
while (!fin.eof()) {
double time, tx, ty, tz, qx, qy, qz, qw;
fin >> time >> tx >> ty >> tz >> qx >> qy >> qz >> qw;
Isometry3d Twr(Quaterniond(qw, qx, qy, qz));
Twr.pretranslate(Vector3d(tx, ty, tz));
poses.push_back(Twr);
}
cout << "read total " << poses.size() << " pose entries" << endl;
// draw trajectory in pangolin
DrawTrajectory(poses);
return 0;
}
/*******************************************************************************************/
void DrawTrajectory(vector<Isometry3d, Eigen::aligned_allocator<Isometry3d>> poses) {
// create pangolin window and plot the trajectory
pangolin::CreateWindowAndBind("Trajectory Viewer", 1024, 768);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
pangolin::OpenGlRenderState s_cam(
pangolin::ProjectionMatrix(1024, 768, 500, 500, 512, 389, 0.1, 1000),
pangolin::ModelViewLookAt(0, -0.1, -1.8, 0, 0, 0, 0.0, -1.0, 0.0)
);
pangolin::View &d_cam = pangolin::CreateDisplay()
.SetBounds(0.0, 1.0, 0.0, 1.0, -1024.0f / 768.0f)
.SetHandler(new pangolin::Handler3D(s_cam));
while (pangolin::ShouldQuit() == false) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
d_cam.Activate(s_cam);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glLineWidth(2);
for (size_t i = 0; i < poses.size(); i++) {
// 画每个位姿的三个坐标轴
Vector3d Ow = poses[i].translation();
Vector3d Xw = poses[i] * (0.1 * Vector3d(1, 0, 0));
Vector3d Yw = poses[i] * (0.1 * Vector3d(0, 1, 0));
Vector3d Zw = poses[i] * (0.1 * Vector3d(0, 0, 1));
glBegin(GL_LINES);
glColor3f(1.0, 0.0, 0.0);
glVertex3d(Ow[0], Ow[1], Ow[2]);
glVertex3d(Xw[0], Xw[1], Xw[2]);
glColor3f(0.0, 1.0, 0.0);
glVertex3d(Ow[0], Ow[1], Ow[2]);
glVertex3d(Yw[0], Yw[1], Yw[2]);
glColor3f(0.0, 0.0, 1.0);
glVertex3d(Ow[0], Ow[1], Ow[2]);
glVertex3d(Zw[0], Zw[1], Zw[2]);
glEnd();
}
// 画出连线
for (size_t i = 0; i < poses.size(); i++) {
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_LINES);
auto p1 = poses[i], p2 = poses[i + 1];
glVertex3d(p1.translation()[0], p1.translation()[1], p1.translation()[2]);
glVertex3d(p2.translation()[0], p2.translation()[1], p2.translation()[2]);
glEnd();
}
pangolin::FinishFrame();
usleep(5000); // sleep 5 ms
}
}
最终的结果如下,几个小时的努力没有白费,还是很开心的_
同样的,我们重新修改visualizeGeometry这个工程中的CMakeList.txt和cmake目录下的FindPangolin.cmake文件,我们可以运行得到相机位姿的可视化表达,以及其对应的ERAQ(Eulerangle、Rotationmatrix、Axisangle、Quaternion)数值。