当前位置:   article > 正文

《视觉SLAM十四讲》ch5学习记录_slam14讲安装opencv

slam14讲安装opencv

本文记录了在第五讲学习时遇到的问题及解决办法。


前言

小白上路,第一次写博客,主要用于记录学习中遇到的一些问题,后续有空的和话会把之前学习的内容补充进来,欢迎大家相互交流学习。


一、在ubuntu18.04下安装opencv

参考 Ubuntu18.04 安装OpenCV进行安装


二、运行测试代码

1.例程1的CMakeLists代码如下:

  1. project(imageBasics)
  2. # 添加C++ 11标准支持
  3. set( CMAKE_CXX_FLAGS "-std=c++11" )
  4. # 寻找opencv库
  5. find_package(OpenCV REQUIRED )
  6. # 添加头文件
  7. include_directories(${OpenCV_INCLUDE_DIRS})
  8. add_executable(imageBasics imageBasics.cpp)
  9. # 链接OpenCV库
  10. target_link_libraries(imageBasics ${OpenCV_LIBS})

2.imageBasics.cpp

  1. #include <iostream>
  2. #include <chrono>
  3. using namespace std;
  4. #include <opencv2/core/core.hpp>
  5. #include <opencv2/highgui/highgui.hpp>
  6. int main(int argc, char **argv) {
  7. // 读取argv[1]指定的图像
  8. cv::Mat image;
  9. image = cv::imread(argv[1]); //cv::imread函数读取指定路径下的图像
  10. // 判断图像文件是否正确读取
  11. if (image.data == nullptr) { //数据不存在,可能是文件不存在
  12. cerr << "文件" << argv[1] << "不存在." << endl;
  13. return 0;
  14. }
  15. // 文件顺利读取, 首先输出一些基本信息
  16. cout << "图像宽为" << image.cols << ",高为" << image.rows << ",通道数为" << image.channels() << endl;
  17. cv::imshow("image", image); // 用cv::imshow显示图像
  18. // cv::waitKey(0); // 暂停程序,等待一个按键输入
  19. // 判断image的类型
  20. if (image.type() != CV_8UC1 && image.type() != CV_8UC3) {
  21. // 图像类型不符合要求
  22. cout << "请输入一张彩色图或灰度图." << endl;
  23. return 0;
  24. }
  25. // 遍历图像, 请注意以下遍历方式亦可使用于随机像素访问
  26. // 使用 std::chrono 来给算法计时
  27. chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
  28. for (size_t y = 0; y < image.rows; y++) {
  29. // 用cv::Mat::ptr获得图像的行指针
  30. unsigned char *row_ptr = image.ptr<unsigned char>(y); // row_ptr是第y行的头指针
  31. for (size_t x = 0; x < image.cols; x++) {
  32. // 访问位于 x,y 处的像素
  33. unsigned char *data_ptr = &row_ptr[x * image.channels()]; // data_ptr 指向待访问的像素数据
  34. // 输出该像素的每个通道,如果是灰度图就只有一个通道
  35. for (int c = 0; c != image.channels(); c++) {
  36. unsigned char data = data_ptr[c]; // data为I(x,y)第c个通道的值
  37. }
  38. }
  39. }
  40. chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
  41. chrono::duration<double> time_used = chrono::duration_cast < chrono::duration < double >> (t2 - t1);
  42. cout << "遍历图像用时:" << time_used.count() << " 秒。" << endl;
  43. // 关于 cv::Mat 的拷贝
  44. // 直接赋值并不会拷贝数据
  45. cv::Mat image_another = image;
  46. // 修改 image_another 会导致 image 发生变化
  47. image_another(cv::Rect(0, 0, 100, 100)).setTo(0); // 将左上角100*100的块置零
  48. cv::imshow("image", image);
  49. cv::waitKey(0);
  50. // 使用clone函数来拷贝数据
  51. cv::Mat image_clone = image.clone();
  52. image_clone(cv::Rect(0, 0, 100, 100)).setTo(255);
  53. cv::imshow("image", image);
  54. cv::imshow("image_clone", image_clone);
  55. cv::waitKey(0);
  56. // 对于图像还有很多基本的操作,如剪切,旋转,缩放等,限于篇幅就不一一介绍了,请参看OpenCV官方文档查询每个函数的调用方法.
  57. cv::destroyAllWindows();
  58. return 0;
  59. }

3.运行结果如下:


4. 例程二的CMakeLists代码如下:

  1. project(undistortImage)
  2. # 添加C++ 11标准支持
  3. set( CMAKE_CXX_FLAGS "-std=c++11" )
  4. # 寻找opencv库
  5. find_package(OpenCV REQUIRED )
  6. # 添加头文件
  7. include_directories(${OpenCV_INCLUDE_DIRS})
  8. add_executable(undistortImage undistortImage.cpp)
  9. # 链接OpenCV库
  10. target_link_libraries(undistortImage ${OpenCV_LIBS})

5.undistortImage.cpp

  1. #include <opencv2/opencv.hpp>
  2. #include <string>
  3. using namespace std;
  4. string image_file = "./distorted.png"; // 请确保路径正确
  5. int main(int argc, char **argv) {
  6. // 本程序实现去畸变部分的代码。尽管我们可以调用OpenCV的去畸变,但自己实现一遍有助于理解。
  7. // 畸变参数
  8. double k1 = -0.28340811, k2 = 0.07395907, p1 = 0.00019359, p2 = 1.76187114e-05;
  9. // 内参
  10. double fx = 458.654, fy = 457.296, cx = 367.215, cy = 248.375;
  11. cv::Mat image = cv::imread(image_file, 0); // 图像是灰度图,CV_8UC1
  12. int rows = image.rows, cols = image.cols;
  13. cv::Mat image_undistort = cv::Mat(rows, cols, CV_8UC1); // 去畸变以后的图
  14. // 计算去畸变后图像的内容
  15. for (int v = 0; v < rows; v++) {
  16. for (int u = 0; u < cols; u++) {
  17. // 按照公式,计算点(u,v)对应到畸变图像中的坐标(u_distorted, v_distorted)
  18. double x = (u - cx) / fx, y = (v - cy) / fy;
  19. double r = sqrt(x * x + y * y);
  20. double x_distorted = x * (1 + k1 * r * r + k2 * r * r * r * r) + 2 * p1 * x * y + p2 * (r * r + 2 * x * x);
  21. double y_distorted = y * (1 + k1 * r * r + k2 * r * r * r * r) + p1 * (r * r + 2 * y * y) + 2 * p2 * x * y;
  22. double u_distorted = fx * x_distorted + cx;
  23. double v_distorted = fy * y_distorted + cy;
  24. // 赋值 (最近邻插值)
  25. if (u_distorted >= 0 && v_distorted >= 0 && u_distorted < cols && v_distorted < rows) {
  26. image_undistort.at<uchar>(v, u) = image.at<uchar>((int) v_distorted, (int) u_distorted);
  27. } else {
  28. image_undistort.at<uchar>(v, u) = 0;
  29. }
  30. }
  31. }
  32. // 画图去畸变后图像
  33. cv::imshow("distorted", image);
  34. cv::imshow("undistorted", image_undistort);
  35. cv::waitKey();
  36. return 0;
  37. }

 6.运行结果如下:

左边图像是畸变的图像,经过去畸变处理后得到的图像如右图所示。


7.例程三的CMakeLists代码如下:

  1. cmake_minimum_required(VERSION 2.9)
  2. project(Stereo)
  3. find_package(Pangolin REQUIRED)
  4. find_package(OpenCV REQUIRED)
  5. include_directories(${OpenCV_INCLUDE_DIRS})
  6. add_executable(stereoVision stereoVision.cpp)
  7. target_link_libraries(stereoVision ${OpenCV_LIBS} ${Pangolin_LIBRARIES})

 8.stereoVision.cpp

  1. #include <opencv2/opencv.hpp>
  2. #include <vector>
  3. #include <string>
  4. #include <Eigen/Core>
  5. #include <pangolin/pangolin.h>
  6. #include <unistd.h>
  7. using namespace std;
  8. using namespace Eigen;
  9. // 文件路径
  10. string left_file = "./left.png";
  11. string right_file = "./right.png";
  12. // 在pangolin中画图,已写好,无需调整
  13. void showPointCloud(
  14. const vector<Vector4d, Eigen::aligned_allocator<Vector4d>> &pointcloud);
  15. int main(int argc, char **argv) {
  16. // 内参
  17. double fx = 718.856, fy = 718.856, cx = 607.1928, cy = 185.2157;
  18. // 基线
  19. double b = 0.573;
  20. // 读取图像
  21. cv::Mat left = cv::imread(left_file, 0);
  22. cv::Mat right = cv::imread(right_file, 0);
  23. cv::Ptr<cv::StereoSGBM> sgbm = cv::StereoSGBM::create(
  24. 0, 96, 9, 8 * 9 * 9, 32 * 9 * 9, 1, 63, 10, 100, 32); // 神奇的参数
  25. cv::Mat disparity_sgbm, disparity;
  26. sgbm->compute(left, right, disparity_sgbm);
  27. disparity_sgbm.convertTo(disparity, CV_32F, 1.0 / 16.0f);
  28. // 生成点云
  29. vector<Vector4d, Eigen::aligned_allocator<Vector4d>> pointcloud;
  30. // 如果你的机器慢,请把后面的v++和u++改成v+=2, u+=2
  31. for (int v = 0; v < left.rows; v++)
  32. for (int u = 0; u < left.cols; u++) {
  33. if (disparity.at<float>(v, u) <= 0.0 || disparity.at<float>(v, u) >= 96.0) continue;
  34. Vector4d point(0, 0, 0, left.at<uchar>(v, u) / 255.0); // 前三维为xyz,第四维为颜色
  35. // 根据双目模型计算 point 的位置
  36. double x = (u - cx) / fx;
  37. double y = (v - cy) / fy;
  38. double depth = fx * b / (disparity.at<float>(v, u));
  39. point[0] = x * depth;
  40. point[1] = y * depth;
  41. point[2] = depth;
  42. pointcloud.push_back(point);
  43. }
  44. cv::imshow("disparity", disparity / 96.0);
  45. cv::waitKey(0);
  46. // 画出点云
  47. showPointCloud(pointcloud);
  48. return 0;
  49. }
  50. void showPointCloud(const vector<Vector4d, Eigen::aligned_allocator<Vector4d>> &pointcloud) {
  51. if (pointcloud.empty()) {
  52. cerr << "Point cloud is empty!" << endl;
  53. return;
  54. }
  55. pangolin::CreateWindowAndBind("Point Cloud Viewer", 1024, 768);
  56. glEnable(GL_DEPTH_TEST);
  57. glEnable(GL_BLEND);
  58. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  59. pangolin::OpenGlRenderState s_cam(
  60. pangolin::ProjectionMatrix(1024, 768, 500, 500, 512, 389, 0.1, 1000),
  61. pangolin::ModelViewLookAt(0, -0.1, -1.8, 0, 0, 0, 0.0, -1.0, 0.0)
  62. );
  63. pangolin::View &d_cam = pangolin::CreateDisplay()
  64. .SetBounds(0.0, 1.0, pangolin::Attach::Pix(175), 1.0, -1024.0f / 768.0f)
  65. .SetHandler(new pangolin::Handler3D(s_cam));
  66. while (pangolin::ShouldQuit() == false) {
  67. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  68. d_cam.Activate(s_cam);
  69. glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
  70. glPointSize(2);
  71. glBegin(GL_POINTS);
  72. for (auto &p: pointcloud) {
  73. glColor3f(p[3], p[3], p[3]);
  74. glVertex3d(p[0], p[1], p[2]);
  75. }
  76. glEnd();
  77. pangolin::FinishFrame();
  78. usleep(5000); // sleep 5 ms
  79. }
  80. return;
  81. }

 9.运行结果如下:

SBGM视差图:

点云图:


10.例程三的CMakeLists:

  1. cmake_minimum_required(VERSION 2.9)
  2. project(JoinMap)
  3. set( CMAKE_CXX_FLAGS "-std=c++11" )
  4. find_package(OpenCV REQUIRED)
  5. include_directories(${OpenCV_INCLUDE_DIRS})
  6. find_package(Sophus REQUIRED)
  7. include_directories(${Sophus_INCLUDE_DIRS})
  8. find_package(Boost REQUIRED)
  9. include_directories(${Boost_INCLUDE_DIRS})
  10. find_package(Pangolin REQUIRED)
  11. add_executable(joinMap joinMap.cpp)
  12. target_link_libraries(joinMap ${OpenCV_LIBS} ${Pangolin_LIBRARIES} ${Boost_LIBRARIES})

11.joinMap.cpp

  1. #include <iostream>
  2. #include <fstream>
  3. #include <opencv2/opencv.hpp>
  4. #include <boost/format.hpp> // for formating strings
  5. #include <pangolin/pangolin.h>
  6. #include <sophus/se3.hpp>
  7. using namespace std;
  8. typedef vector<Sophus::SE3d, Eigen::aligned_allocator<Sophus::SE3d>> TrajectoryType;
  9. typedef Eigen::Matrix<double, 6, 1> Vector6d;
  10. // 在pangolin中画图,已写好,无需调整
  11. void showPointCloud(
  12. const vector<Vector6d, Eigen::aligned_allocator<Vector6d>> &pointcloud);
  13. int main(int argc, char **argv) {
  14. vector<cv::Mat> colorImgs, depthImgs; // 彩色图和深度图
  15. TrajectoryType poses; // 相机位姿
  16. ifstream fin("./pose.txt");
  17. if (!fin) {
  18. cerr << "请在有pose.txt的目录下运行此程序" << endl;
  19. return 1;
  20. }
  21. for (int i = 0; i < 5; i++) {
  22. boost::format fmt("./%s/%d.%s"); //图像文件格式
  23. colorImgs.push_back(cv::imread((fmt % "color" % (i + 1) % "png").str()));
  24. depthImgs.push_back(cv::imread((fmt % "depth" % (i + 1) % "pgm").str(), -1)); // 使用-1读取原始图像
  25. double data[7] = {0};
  26. for (auto &d:data)
  27. fin >> d;
  28. Sophus::SE3d pose(Eigen::Quaterniond(data[6], data[3], data[4], data[5]),
  29. Eigen::Vector3d(data[0], data[1], data[2]));
  30. poses.push_back(pose);
  31. }
  32. // 计算点云并拼接
  33. // 相机内参
  34. double cx = 325.5;
  35. double cy = 253.5;
  36. double fx = 518.0;
  37. double fy = 519.0;
  38. double depthScale = 1000.0;
  39. vector<Vector6d, Eigen::aligned_allocator<Vector6d>> pointcloud;
  40. pointcloud.reserve(1000000);
  41. for (int i = 0; i < 5; i++) {
  42. cout << "转换图像中: " << i + 1 << endl;
  43. cv::Mat color = colorImgs[i];
  44. cv::Mat depth = depthImgs[i];
  45. Sophus::SE3d T = poses[i];
  46. for (int v = 0; v < color.rows; v++)
  47. for (int u = 0; u < color.cols; u++) {
  48. unsigned int d = depth.ptr<unsigned short>(v)[u]; // 深度值
  49. if (d == 0) continue; // 为0表示没有测量到
  50. Eigen::Vector3d point;
  51. point[2] = double(d) / depthScale;
  52. point[0] = (u - cx) * point[2] / fx;
  53. point[1] = (v - cy) * point[2] / fy;
  54. Eigen::Vector3d pointWorld = T * point;
  55. Vector6d p;
  56. p.head<3>() = pointWorld;
  57. p[5] = color.data[v * color.step + u * color.channels()]; // blue
  58. p[4] = color.data[v * color.step + u * color.channels() + 1]; // green
  59. p[3] = color.data[v * color.step + u * color.channels() + 2]; // red
  60. pointcloud.push_back(p);
  61. }
  62. }
  63. cout << "点云共有" << pointcloud.size() << "个点." << endl;
  64. showPointCloud(pointcloud);
  65. return 0;
  66. }
  67. void showPointCloud(const vector<Vector6d, Eigen::aligned_allocator<Vector6d>> &pointcloud) {
  68. if (pointcloud.empty()) {
  69. cerr << "Point cloud is empty!" << endl;
  70. return;
  71. }
  72. pangolin::CreateWindowAndBind("Point Cloud Viewer", 1024, 768);
  73. glEnable(GL_DEPTH_TEST);
  74. glEnable(GL_BLEND);
  75. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  76. pangolin::OpenGlRenderState s_cam(
  77. pangolin::ProjectionMatrix(1024, 768, 500, 500, 512, 389, 0.1, 1000),
  78. pangolin::ModelViewLookAt(0, -0.1, -1.8, 0, 0, 0, 0.0, -1.0, 0.0)
  79. );
  80. pangolin::View &d_cam = pangolin::CreateDisplay()
  81. .SetBounds(0.0, 1.0, pangolin::Attach::Pix(175), 1.0, -1024.0f / 768.0f)
  82. .SetHandler(new pangolin::Handler3D(s_cam));
  83. while (pangolin::ShouldQuit() == false) {
  84. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  85. d_cam.Activate(s_cam);
  86. glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
  87. glPointSize(2);
  88. glBegin(GL_POINTS);
  89. for (auto &p: pointcloud) {
  90. glColor3d(p[3] / 255.0, p[4] / 255.0, p[5] / 255.0);
  91. glVertex3d(p[0], p[1], p[2]);
  92. }
  93. glEnd();
  94. pangolin::FinishFrame();
  95. usleep(5000); // sleep 5 ms
  96. }
  97. return;
  98. }

12.运行结果如下:

 


13.遇到的问题

(1)opencv编译配置出错

调试程序时遇到如下错误:

  1. terminate called after throwing an instance of 'cv::Exception'
  2. what(): OpenCV(3.4.3) /home/lcy/slambook2-master/3rdparty/opencv-3.4.3/modules/highgui/src/window.cpp
  3. :632: error: (-2:Unspecified error) The function is not implemented. Rebuild the library
  4. with Windows, GTK+ 2.x or Carbon support. If you are on Ubuntu or Debian, install
  5. libgtk2.0-dev and pkg-config, then re-run cmake or configure script in function
  6. 'cvShowImage'
  7. Aborted (core dumped)

 按照报错提示执行下述命令后并不能解决问题:

sudo apt-get install libgtk2.0-dev
sudo apt-get install pkg-config

查阅资料后得知是安装opencv编译配置出错,解决方法如下:

进入opencv安装所在的文件夹

cd /home/lcy/slambook2-master/3rdparty/opencv-3.4.3

执行如下命令: 

  1. mkdir release
  2. cd release
  3. cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=ON -D BUILD_NEW_PYTHON_SUPPORT=ON -D WITH_V4L=ON -D WITH_QT=ON -D WITH_OPENGL=ON ..
  4. sudo make
  5. sudo make install

 问题解决。参考自社区博客

(2)对cv::waitKey(0)的理解不够

其含义表示:

在一个给定的时间内(单位ms)等待用户按键触发,按下任意键都会直接关闭创建的窗口。

    如果在 X ms期间,按下任意键,则立刻结束并返回按下键的ASCll码。
    如果在 X ms期间,没有按下任意键,也会直接退出,同时关闭创建的窗口,返回0。

如果设置waitKey(0),表示程序会无限制的等待用户的按键事件,永远不会自动退出。

(参考自社区博客

在程序运行过程中,需要任意按键来执行下一步操作,若直接关闭显示窗口,则程序无法结束,需要ctrl+c强行退出程序。

(3)运行stereo例程时CMakeLists没有添加opencv库

只添加了Pangolin库导致出错:cv::imread(cv::String const,int)未定义的引用等错误(低级错误)。

(4)在运行例程四的时候出现找不到Sophus中se3.hpp的问题

书上所说只需要编译该库而不需要安装,运行前几章的代码也未报错,参考文章后,重新进行编译并安装后就能正常编译了。

总结

本文主要记录本人在运行《SLAM十四讲》ch5时遇到的问题及解决办法

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/103001
推荐阅读
相关标签
  

闽ICP备14008679号