赞
踩
本文记录了在第五讲学习时遇到的问题及解决办法。
小白上路,第一次写博客,主要用于记录学习中遇到的一些问题,后续有空的和话会把之前学习的内容补充进来,欢迎大家相互交流学习。
参考 Ubuntu18.04 安装OpenCV进行安装
- project(imageBasics)
-
- # 添加C++ 11标准支持
- set( CMAKE_CXX_FLAGS "-std=c++11" )
-
- # 寻找opencv库
- find_package(OpenCV REQUIRED )
-
- # 添加头文件
- include_directories(${OpenCV_INCLUDE_DIRS})
-
- add_executable(imageBasics imageBasics.cpp)
- # 链接OpenCV库
- target_link_libraries(imageBasics ${OpenCV_LIBS})
- #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); // 暂停程序,等待一个按键输入
-
- // 判断image的类型
- if (image.type() != CV_8UC1 && image.type() != CV_8UC3) {
- // 图像类型不符合要求
- cout << "请输入一张彩色图或灰度图." << endl;
- return 0;
- }
-
- // 遍历图像, 请注意以下遍历方式亦可使用于随机像素访问
- // 使用 std::chrono 来给算法计时
- chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
- for (size_t y = 0; y < image.rows; y++) {
- // 用cv::Mat::ptr获得图像的行指针
- unsigned char *row_ptr = image.ptr<unsigned char>(y); // row_ptr是第y行的头指针
- for (size_t x = 0; x < image.cols; x++) {
- // 访问位于 x,y 处的像素
- unsigned char *data_ptr = &row_ptr[x * image.channels()]; // data_ptr 指向待访问的像素数据
- // 输出该像素的每个通道,如果是灰度图就只有一个通道
- for (int c = 0; c != image.channels(); c++) {
- unsigned char data = data_ptr[c]; // data为I(x,y)第c个通道的值
- }
- }
- }
- chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
- chrono::duration<double> time_used = chrono::duration_cast < chrono::duration < double >> (t2 - t1);
- cout << "遍历图像用时:" << time_used.count() << " 秒。" << endl;
-
- // 关于 cv::Mat 的拷贝
- // 直接赋值并不会拷贝数据
- cv::Mat image_another = image;
- // 修改 image_another 会导致 image 发生变化
- image_another(cv::Rect(0, 0, 100, 100)).setTo(0); // 将左上角100*100的块置零
- cv::imshow("image", image);
- cv::waitKey(0);
-
- // 使用clone函数来拷贝数据
- cv::Mat image_clone = image.clone();
- image_clone(cv::Rect(0, 0, 100, 100)).setTo(255);
- cv::imshow("image", image);
- cv::imshow("image_clone", image_clone);
- cv::waitKey(0);
-
- // 对于图像还有很多基本的操作,如剪切,旋转,缩放等,限于篇幅就不一一介绍了,请参看OpenCV官方文档查询每个函数的调用方法.
- cv::destroyAllWindows();
- return 0;
- }
- project(undistortImage)
-
- # 添加C++ 11标准支持
- set( CMAKE_CXX_FLAGS "-std=c++11" )
-
- # 寻找opencv库
- find_package(OpenCV REQUIRED )
-
- # 添加头文件
- include_directories(${OpenCV_INCLUDE_DIRS})
-
- add_executable(undistortImage undistortImage.cpp)
- # 链接OpenCV库
- target_link_libraries(undistortImage ${OpenCV_LIBS})
- #include <opencv2/opencv.hpp>
- #include <string>
-
- using namespace std;
-
- string image_file = "./distorted.png"; // 请确保路径正确
-
- int main(int argc, char **argv) {
-
- // 本程序实现去畸变部分的代码。尽管我们可以调用OpenCV的去畸变,但自己实现一遍有助于理解。
- // 畸变参数
- double k1 = -0.28340811, k2 = 0.07395907, p1 = 0.00019359, p2 = 1.76187114e-05;
- // 内参
- double fx = 458.654, fy = 457.296, cx = 367.215, cy = 248.375;
-
- cv::Mat image = cv::imread(image_file, 0); // 图像是灰度图,CV_8UC1
- int rows = image.rows, cols = image.cols;
- cv::Mat image_undistort = cv::Mat(rows, cols, CV_8UC1); // 去畸变以后的图
-
- // 计算去畸变后图像的内容
- for (int v = 0; v < rows; v++) {
- for (int u = 0; u < cols; u++) {
- // 按照公式,计算点(u,v)对应到畸变图像中的坐标(u_distorted, v_distorted)
- double x = (u - cx) / fx, y = (v - cy) / fy;
- double r = sqrt(x * x + y * y);
- double x_distorted = x * (1 + k1 * r * r + k2 * r * r * r * r) + 2 * p1 * x * y + p2 * (r * r + 2 * x * x);
- double y_distorted = y * (1 + k1 * r * r + k2 * r * r * r * r) + p1 * (r * r + 2 * y * y) + 2 * p2 * x * y;
- double u_distorted = fx * x_distorted + cx;
- double v_distorted = fy * y_distorted + cy;
-
- // 赋值 (最近邻插值)
- if (u_distorted >= 0 && v_distorted >= 0 && u_distorted < cols && v_distorted < rows) {
- image_undistort.at<uchar>(v, u) = image.at<uchar>((int) v_distorted, (int) u_distorted);
- } else {
- image_undistort.at<uchar>(v, u) = 0;
- }
- }
- }
-
- // 画图去畸变后图像
- cv::imshow("distorted", image);
- cv::imshow("undistorted", image_undistort);
- cv::waitKey();
- return 0;
- }
左边图像是畸变的图像,经过去畸变处理后得到的图像如右图所示。
- cmake_minimum_required(VERSION 2.9)
-
- project(Stereo)
-
-
- find_package(Pangolin REQUIRED)
- find_package(OpenCV REQUIRED)
-
- include_directories(${OpenCV_INCLUDE_DIRS})
-
- add_executable(stereoVision stereoVision.cpp)
-
- target_link_libraries(stereoVision ${OpenCV_LIBS} ${Pangolin_LIBRARIES})
- #include <opencv2/opencv.hpp>
- #include <vector>
- #include <string>
- #include <Eigen/Core>
- #include <pangolin/pangolin.h>
- #include <unistd.h>
-
- using namespace std;
- using namespace Eigen;
-
- // 文件路径
- string left_file = "./left.png";
- string right_file = "./right.png";
-
- // 在pangolin中画图,已写好,无需调整
- void showPointCloud(
- const vector<Vector4d, Eigen::aligned_allocator<Vector4d>> &pointcloud);
-
- int main(int argc, char **argv) {
-
- // 内参
- double fx = 718.856, fy = 718.856, cx = 607.1928, cy = 185.2157;
- // 基线
- double b = 0.573;
-
- // 读取图像
- cv::Mat left = cv::imread(left_file, 0);
- cv::Mat right = cv::imread(right_file, 0);
- cv::Ptr<cv::StereoSGBM> sgbm = cv::StereoSGBM::create(
- 0, 96, 9, 8 * 9 * 9, 32 * 9 * 9, 1, 63, 10, 100, 32); // 神奇的参数
- cv::Mat disparity_sgbm, disparity;
- sgbm->compute(left, right, disparity_sgbm);
- disparity_sgbm.convertTo(disparity, CV_32F, 1.0 / 16.0f);
-
- // 生成点云
- vector<Vector4d, Eigen::aligned_allocator<Vector4d>> pointcloud;
-
- // 如果你的机器慢,请把后面的v++和u++改成v+=2, u+=2
- for (int v = 0; v < left.rows; v++)
- for (int u = 0; u < left.cols; u++) {
- if (disparity.at<float>(v, u) <= 0.0 || disparity.at<float>(v, u) >= 96.0) continue;
-
- Vector4d point(0, 0, 0, left.at<uchar>(v, u) / 255.0); // 前三维为xyz,第四维为颜色
-
- // 根据双目模型计算 point 的位置
- double x = (u - cx) / fx;
- double y = (v - cy) / fy;
- double depth = fx * b / (disparity.at<float>(v, u));
- point[0] = x * depth;
- point[1] = y * depth;
- point[2] = depth;
-
- pointcloud.push_back(point);
- }
-
- cv::imshow("disparity", disparity / 96.0);
- cv::waitKey(0);
- // 画出点云
- showPointCloud(pointcloud);
- return 0;
- }
-
- void showPointCloud(const vector<Vector4d, Eigen::aligned_allocator<Vector4d>> &pointcloud) {
-
- if (pointcloud.empty()) {
- cerr << "Point cloud is empty!" << endl;
- return;
- }
-
- pangolin::CreateWindowAndBind("Point Cloud 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, pangolin::Attach::Pix(175), 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);
-
- glPointSize(2);
- glBegin(GL_POINTS);
- for (auto &p: pointcloud) {
- glColor3f(p[3], p[3], p[3]);
- glVertex3d(p[0], p[1], p[2]);
- }
- glEnd();
- pangolin::FinishFrame();
- usleep(5000); // sleep 5 ms
- }
- return;
- }
SBGM视差图:
点云图:
- cmake_minimum_required(VERSION 2.9)
- project(JoinMap)
-
- set( CMAKE_CXX_FLAGS "-std=c++11" )
-
- find_package(OpenCV REQUIRED)
- include_directories(${OpenCV_INCLUDE_DIRS})
-
- find_package(Sophus REQUIRED)
- include_directories(${Sophus_INCLUDE_DIRS})
-
- find_package(Boost REQUIRED)
- include_directories(${Boost_INCLUDE_DIRS})
-
- find_package(Pangolin REQUIRED)
-
-
- add_executable(joinMap joinMap.cpp)
- target_link_libraries(joinMap ${OpenCV_LIBS} ${Pangolin_LIBRARIES} ${Boost_LIBRARIES})
- #include <iostream>
- #include <fstream>
- #include <opencv2/opencv.hpp>
- #include <boost/format.hpp> // for formating strings
- #include <pangolin/pangolin.h>
- #include <sophus/se3.hpp>
-
-
- using namespace std;
- typedef vector<Sophus::SE3d, Eigen::aligned_allocator<Sophus::SE3d>> TrajectoryType;
- typedef Eigen::Matrix<double, 6, 1> Vector6d;
-
- // 在pangolin中画图,已写好,无需调整
- void showPointCloud(
- const vector<Vector6d, Eigen::aligned_allocator<Vector6d>> &pointcloud);
-
- int main(int argc, char **argv) {
- vector<cv::Mat> colorImgs, depthImgs; // 彩色图和深度图
- TrajectoryType poses; // 相机位姿
-
- ifstream fin("./pose.txt");
- if (!fin) {
- cerr << "请在有pose.txt的目录下运行此程序" << endl;
- return 1;
- }
-
- for (int i = 0; i < 5; i++) {
- boost::format fmt("./%s/%d.%s"); //图像文件格式
- colorImgs.push_back(cv::imread((fmt % "color" % (i + 1) % "png").str()));
- depthImgs.push_back(cv::imread((fmt % "depth" % (i + 1) % "pgm").str(), -1)); // 使用-1读取原始图像
-
- double data[7] = {0};
- for (auto &d:data)
- fin >> d;
- Sophus::SE3d pose(Eigen::Quaterniond(data[6], data[3], data[4], data[5]),
- Eigen::Vector3d(data[0], data[1], data[2]));
- poses.push_back(pose);
- }
-
- // 计算点云并拼接
- // 相机内参
- double cx = 325.5;
- double cy = 253.5;
- double fx = 518.0;
- double fy = 519.0;
- double depthScale = 1000.0;
- vector<Vector6d, Eigen::aligned_allocator<Vector6d>> pointcloud;
- pointcloud.reserve(1000000);
-
- for (int i = 0; i < 5; i++) {
- cout << "转换图像中: " << i + 1 << endl;
- cv::Mat color = colorImgs[i];
- cv::Mat depth = depthImgs[i];
- Sophus::SE3d T = poses[i];
- for (int v = 0; v < color.rows; v++)
- for (int u = 0; u < color.cols; u++) {
- unsigned int d = depth.ptr<unsigned short>(v)[u]; // 深度值
- if (d == 0) continue; // 为0表示没有测量到
- Eigen::Vector3d point;
- point[2] = double(d) / depthScale;
- point[0] = (u - cx) * point[2] / fx;
- point[1] = (v - cy) * point[2] / fy;
- Eigen::Vector3d pointWorld = T * point;
-
- Vector6d p;
- p.head<3>() = pointWorld;
- p[5] = color.data[v * color.step + u * color.channels()]; // blue
- p[4] = color.data[v * color.step + u * color.channels() + 1]; // green
- p[3] = color.data[v * color.step + u * color.channels() + 2]; // red
- pointcloud.push_back(p);
- }
- }
-
- cout << "点云共有" << pointcloud.size() << "个点." << endl;
- showPointCloud(pointcloud);
- return 0;
- }
-
- void showPointCloud(const vector<Vector6d, Eigen::aligned_allocator<Vector6d>> &pointcloud) {
-
- if (pointcloud.empty()) {
- cerr << "Point cloud is empty!" << endl;
- return;
- }
-
- pangolin::CreateWindowAndBind("Point Cloud 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, pangolin::Attach::Pix(175), 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);
-
- glPointSize(2);
- glBegin(GL_POINTS);
- for (auto &p: pointcloud) {
- glColor3d(p[3] / 255.0, p[4] / 255.0, p[5] / 255.0);
- glVertex3d(p[0], p[1], p[2]);
- }
- glEnd();
- pangolin::FinishFrame();
- usleep(5000); // sleep 5 ms
- }
- return;
- }
调试程序时遇到如下错误:
- terminate called after throwing an instance of 'cv::Exception'
- what(): OpenCV(3.4.3) /home/lcy/slambook2-master/3rdparty/opencv-3.4.3/modules/highgui/src/window.cpp
- :632: error: (-2:Unspecified error) The function is not implemented. Rebuild the library
- with Windows, GTK+ 2.x or Carbon support. If you are on Ubuntu or Debian, install
- libgtk2.0-dev and pkg-config, then re-run cmake or configure script in function
- 'cvShowImage'
-
- 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
执行如下命令:
- mkdir release
- cd release
- 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 ..
- sudo make
- sudo make install
问题解决。参考自社区博客。
其含义表示:
在一个给定的时间内(单位ms)等待用户按键触发,按下任意键都会直接关闭创建的窗口。
如果在 X ms期间,按下任意键,则立刻结束并返回按下键的ASCll码。
如果在 X ms期间,没有按下任意键,也会直接退出,同时关闭创建的窗口,返回0。
如果设置waitKey(0),表示程序会无限制的等待用户的按键事件,永远不会自动退出。
(参考自社区博客)
在程序运行过程中,需要任意按键来执行下一步操作,若直接关闭显示窗口,则程序无法结束,需要ctrl+c强行退出程序。
只添加了Pangolin库导致出错:cv::imread(cv::String const,int)未定义的引用等错误(低级错误)。
书上所说只需要编译该库而不需要安装,运行前几章的代码也未报错,参考文章后,重新进行编译并安装后就能正常编译了。
本文主要记录本人在运行《SLAM十四讲》ch5时遇到的问题及解决办法
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。