• 视觉十四讲:第十二讲_RGB-D稠密点云


    1.点云地图

    所谓点云,就是由一组离散的点表示的地图,最基本的点包含x,y,z三维坐标,也可以带有r,g,b的彩色信息.

    #include <iostream>
    #include <fstream>
    
    using namespace std;
    
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <Eigen/Geometry>
    #include <boost/format.hpp>  // for formating strings
    #include <pcl/point_types.h>
    #include <pcl/io/pcd_io.h>
    #include <pcl/filters/voxel_grid.h>
    #include <pcl/visualization/pcl_visualizer.h>
    #include <pcl/filters/statistical_outlier_removal.h>
    
    int main(int argc, char **argv)
    {
        vector<cv::Mat> colorImgs, depthImgs;    // 彩色图和深度图
        vector<Eigen::Isometry3d> poses;         // 相机位姿
    
        ifstream fin("../data/pose.txt");
        if (!fin) {
            cerr << "cannot find pose file" << endl;
            return 1;
        }
    
        for (int i = 0; i < 5; i++) {
            boost::format fmt("../data/%s/%d.%s"); //图像文件格式
            colorImgs.push_back(cv::imread((fmt % "color" % (i + 1) % "png").str()));
            depthImgs.push_back(cv::imread((fmt % "depth" % (i + 1) % "png").str(), -1)); // 使用-1读取原始图像
    
            double data[7] = {0};
            for (int i = 0; i < 7; i++) {
                fin >> data[i];
            }
            Eigen::Quaterniond q(data[6], data[3], data[4], data[5]);
            Eigen::Isometry3d T(q);
            T.pretranslate(Eigen::Vector3d(data[0], data[1], data[2]));
            poses.push_back(T);
        }
    
        // 计算点云并拼接
        // 相机内参
        double cx = 319.5;
        double cy = 239.5;
        double fx = 481.2;
        double fy = -480.0;
        double depthScale = 5000.0;
    
        cout << "正在将图像转换为点云..." << endl;
    
        // 定义点云使用的格式:这里用的是XYZRGB
        typedef pcl::PointXYZRGB PointT;
        typedef pcl::PointCloud<PointT> PointCloud;
    
        // 新建一个点云
        PointCloud::Ptr pointCloud(new PointCloud);
        for (int i = 0; i < 5; i++) {
            PointCloud::Ptr current(new PointCloud);
            cout << "转换图像中: " << i + 1 << endl;
            cv::Mat color = colorImgs[i];
            cv::Mat depth = depthImgs[i];
            Eigen::Isometry3d 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;
    
                    PointT p;
                    p.x = pointWorld[0];
                    p.y = pointWorld[1];
                    p.z = pointWorld[2];
                    p.b = color.data[v * color.step + u * color.channels()];
                    p.g = color.data[v * color.step + u * color.channels() + 1];
                    p.r = color.data[v * color.step + u * color.channels() + 2];
                    current->points.push_back(p);
                }
            // depth filter and statistical removal
            PointCloud::Ptr tmp(new PointCloud);
            pcl::StatisticalOutlierRemoval<PointT> statistical_filter;
            statistical_filter.setMeanK(50);
            statistical_filter.setStddevMulThresh(1.0);
            statistical_filter.setInputCloud(current);
            statistical_filter.filter(*tmp);
            (*pointCloud) += *tmp;  //没有+只建一点图,不知道为什么
        }
    
        pointCloud->is_dense = false;
        cout << "点云共有" << pointCloud->size() << "个点." << endl;
    
        // voxel filter
        pcl::VoxelGrid<PointT> voxel_filter;
        double resolution = 0.03;
        voxel_filter.setLeafSize(resolution, resolution, resolution);       // resolution
        PointCloud::Ptr tmp(new PointCloud);
        voxel_filter.setInputCloud(pointCloud);
        voxel_filter.filter(*tmp);
        tmp->swap(*pointCloud);
    
        cout << "滤波之后,点云共有" << pointCloud->size() << "个点." << endl;
    
        pcl::io::savePCDFileBinary("map.pcd", *pointCloud);
        return 0;
    }
    

    程序主要使用PCL将3D点重建为点云,过程采用统计滤波器去掉了孤立点,然后利用体素网络滤波器进行降采样.
    该点云地图的问题:

    • 没有存储特征点的信息,无法用于基于特征点的定位方法.
    • 没有对该点云进行优化,所以精度不够
    • 无法直接用于导航和避障,不过可以将该点云进行加工,得到适合导航和避障的地图
  • 相关阅读:
    第十五篇:在SOUI中消息通讯
    为GDI函数增加透明度处理
    第十四篇:在SOUI中使用定时器
    第十三篇:在SOUI中使用有窗口句柄的子窗口
    第十二篇:SOUI的utilities模块为什么要用DLL编译?
    第十一篇:SOUI系统资源管理
    第十篇:扩展SOUI的控件及绘图对象(ISkinObj)
    第九篇:在SOUI中使用多语言翻译
    第八篇:SOUI中控件事件的响应
    Linked List Cycle
  • 原文地址:https://www.cnblogs.com/penuel/p/13645206.html
Copyright © 2020-2023  润新知