PCL 深度图像

简介: PCL 深度图像

前言

各种光学传感器技术的发展,包含物体三维结构信息的深度图像数据获取开始普及。尤其时kinect等设备的出现。

什么是深度图像?
定义:深度图像(Depth Images),也被称为距离影像(Range Images),是指将图像采集器到场景中各点的距离(深度)值作为像素值的图像。

它直接反应了景物可见表面的几何形状,利用它可以很方便的解决3D目标描述中的许多问题。

获取深度图像的方法:

  • 激光雷达深度成像法
  • 计算机立体视觉成像
  • 坐标测量机法
  • 莫尔条纹法
  • 结构光法等

深度图像经过坐标转换可以计算为点云数据,有规则及必要信息的点云数据可以反算为深度图像数据。

PCL 中的深度图像

在PCL中 操作和表达深度图像主要依据 pcl_range_image 库中包含的两个类

为什么PCL要把深度图像的概念引入呢?
主要是由于深度图像与点云 近邻检索方式不同
点云数据通过kd-tree等索引来对数据进行检索,而深度图和图像类似,可通过上下左右等近邻来直接索引。

所以为了使用深度图的计算方法,以提高效率等,可以将点云转化为深度图像

将点云转化为深度图像

Code

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#include <pcl/range_image/range_image.h>//深度图像头文件

操作pcl深度图像时应该包含的头文件
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    pcl::PointCloud<pcl::PointXYZ>::Ptr pointCloud(new pcl::PointCloud<pcl::PointXYZ>);//声明点云

    for(float y=-0.5f;y<=0.5f;y+=0.01f)
    {
        for (float z=-0.5f; z<=0.5f; z+=0.01f) 
        {
            pcl::PointXYZ point;//声明pcl的一个点
            //赋值点云里点 的 xyz坐标
            point.x = 2.0f - y;
            point.y = y;
            point.z = z;
            pointCloud->points.push_back(point);
        }
    }
    //赋值点云的宽度与高度
    pointCloud->width = (uint32_t) pointCloud->points.size();
    pointCloud->height = 1;  

生成一个矩形的点云

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    //给点云显示出来   
    // 显示直通滤波后的点云
    /* 创建显示 类 实例 */
    pcl::visualization::CloudViewer viewer1("Cloud Viewer "); 

    /* 显示点云 */
    viewer1.showCloud(pointCloud);

        /*持续显示*/
    while (!viewer1.wasStopped ())
    {
    }

将刚生成的点云显示出来
在这里插入图片描述

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    //设置角度分辨率  弧度 相邻像素点 所对应的每束 光束之间相差 1 度
    float angularResolution = (float)( 1.0f*(M_PI/180.0f) );
    //模拟的距离传感器对周围环境 有360度的视场角
    float maxAngleWidth =  (float)( 360.0f*(M_PI/180.0f) );
    //相当于前面所有的 视角
    float maxAngleHeight =  (float)( 180.0f*(M_PI/180.0f) );

    //传感器位置
    Eigen::Affine3f sensorPose = (Eigen::Affine3f)Eigen::Translation3f(0.0f, 0.0f, 0.0f);
    //传感器的坐标系 各轴方向
    pcl::RangeImage::CoordinateFrame coordinate_frame = pcl::RangeImage::CAMERA_FRAME;
    //传感器噪声
    float noiseLevel=0.00;
    //最小距离
    float minRange = 0.0f;
    //在剪裁图像时若果 此值>0,将在图像周围留下当前视点不可见的边界
    int borderSize = 1;

这部分定义了创建深度图像时需要设置的参数

  • angularResolution 角度分辨率 1度 即 相邻像素点 所对应的每束 光束之间相差 1 度
  • maxAngleWidth maxAngleHeight 传感器的水平视场角和垂直视场角
  • sensorPose 传感器的6自由度位置
  • coordinate_frame CAMERA_FRAME 系统的X轴向右,Y轴向下,Z轴向前 如果是LASER_FRAME 则x向前,y向左,z向上
  • noiseLevel 此值为0,则意味着使用一个归一化的Z缓冲器来创建深度图像, 为0.05可以理解为深度距离通过查询点半径为5cm的圆内包含的点以平均计算得到的。
  • minRange 就是盲区的概念
  • borderSize 在剪裁图像时若果 此值>0,将在图像周围留下当前视点不可见的边界

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    pcl::RangeImage rangeImage;//声明深度图像

    /* 将点云转为 深度图像的 操作 */
    rangeImage.createFromPointCloud(*pointCloud, angularResolution, maxAngleWidth, maxAngleHeight, sensorPose, coordinate_frame, noiseLevel, minRange, borderSize);

    //输出图像的一些信息
    std::cout << rangeImage << "\n";

在上一块设定了所有的参数后
就可以通过调用 createFromPointCloud 将点云转换为深度图像了。
该函数的参数很多,就是上面设置的。

打印结果
在这里插入图片描述
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

CMakeLIst.txt

# 声明要求的 cmake 最低版本
cmake_minimum_required(VERSION 2.8 )
# 声明工程名称
project(range_image_creation)
# 添加c++ 11 标准支持
set(CMAKE_CXX_FLAGS "-std=c++11")
# 寻找PCL的库
find_package(PCL REQUIRED COMPONENT common io visualization filters)
link_directories(${PCL_LIBRARY_DIRS})
# 添加头文件
include_directories(${PCL_INCLUDE_DIRS})
add_definitions( ${PCL_DEFINITIONS} )
#添加一个可执行程序
add_executable(range_image_creation range_image_creation.cpp)
#链接PCL 库
target_link_libraries(range_image_creation ${PCL_LIBRARIES})

从深度图像中提取边界

什么是深度图像的边界:从前景跨越到背景的位置定义为边界

关于边界点云集 关心的有 三 类

  • 物体边界:物体最外层与阴影边界的可见点集
  • 阴影边界:毗连于遮挡的背景上的点集
  • Veil点集:被遮挡物边界和阴影边界直接的内插点

下面通过代码实例 展示 提取三种边界

Code

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#include <pcl/features/range_image_border_extractor.h>// 深度图边界提取 模块

包含相关的头文件
用到pcl库中的 深度图 边界提取 模块 的时候 需要包含此文件
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    //创建点云
    pcl::PointCloud<pcl::PointXYZ>::Ptr pointCloud(new pcl::PointCloud<pcl::PointXYZ>);//声明点云

    for(float x=-0.5f;x<=0.5f;x+=0.01f)
    {
        for (float y=-0.5f; y<=0.5f; y+=0.01f) 
        {
            pcl::PointXYZ point;//声明pcl的一个点
            //赋值点云里点 的 xyz坐标
            point.x = x;
            point.y = y;
            point.z = 2.0f - y;
            pointCloud->points.push_back(point);
        }
    }
    //赋值点云的宽度与高度
    pointCloud->width = (uint32_t) pointCloud->points.size();
    pointCloud->height = 1;  
    //设置角度分辨率  弧度 相邻像素点 所对应的每束 光束之间相差 1 度
    float angularResolution = (float)( 1.0f*(M_PI/180.0f) );
    //模拟的距离传感器对周围环境 有360度的视场角
    float maxAngleWidth =  (float)( 360.0f*(M_PI/180.0f) );
    //相当于前面所有的 视角
    float maxAngleHeight =  (float)( 180.0f*(M_PI/180.0f) );
    //传感器位置
    Eigen::Affine3f sensorPose = (Eigen::Affine3f)Eigen::Translation3f(0.0f, 0.0f, 0.0f);
    //传感器的坐标系
    pcl::RangeImage::CoordinateFrame coordinate_frame = pcl::RangeImage::CAMERA_FRAME;
    //传感器噪声
    float noiseLevel=0.00;
    //最小距离
    float minRange = 0.0f;
    //在剪裁图像时若果 此值>0,将在图像周围留下当前视点不可见的边界
    int borderSize = 1;
    pcl::RangeImage rangeImage;//声明深度图像
    /* 将点云转为 深度图像的 操作 */
    rangeImage.createFromPointCloud(*pointCloud, angularResolution, maxAngleWidth, maxAngleHeight, sensorPose, coordinate_frame, noiseLevel, minRange, borderSize);
    rangeImage.setUnseenToMaxRange ();
    //输出图像的一些信息
    std::cout << rangeImage << "\n";
    //显示点云
    pcl::visualization::PCLVisualizer viewer ("3D Viewer");
    viewer.setBackgroundColor (1, 1, 1);
    viewer.addCoordinateSystem (1.0f);
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> point_cloud_color_handler (pointCloud, 0, 0, 0);
    viewer.addPointCloud (pointCloud, point_cloud_color_handler, "original point cloud");
 

自己创建一个点云 然后 转为深度图像 和 上一节内容 一样

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    pcl::RangeImageBorderExtractor border_extractor(&rangeImage);

创建 RangeImageBorderExtractor(深度图像边界提取类) 并赋予深度图像

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /* 创建边界 的点云  pcl::BorderDescription 是一种点云类型  */
    pcl::PointCloud<pcl::BorderDescription> border_descriptions;

创建边界 的点云 pcl::BorderDescription 是一种点云类型
这种点云类型不常见,也就是在提取边界时使用。 主要的功能是 存放 三种点云边界(物体边界、阴影边界、Veil点集)
在这里插入图片描述
里面含义三种成员 x、y、traits
怎么使用 会在下面展示

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /*声明 物体边界 的 点云 指针*/
    pcl::PointCloud<pcl::PointWithRange>::Ptr border_points_ptr(new pcl::PointCloud<pcl::PointWithRange>);
    /*声明 Veil边界 的 点云 指针*/
    pcl::PointCloud<pcl::PointWithRange>::Ptr veil_points_ptr(new pcl::PointCloud<pcl::PointWithRange>);
    /*声明 阴影边界 的 点云 指针*/
    pcl::PointCloud<pcl::PointWithRange>::Ptr shadow_points_ptr(new pcl::PointCloud<pcl::PointWithRange>);
    /* 对应的引用 */
    pcl::PointCloud<pcl::PointWithRange> & border_points = *border_points_ptr;
    pcl::PointCloud<pcl::PointWithRange> & veil_points = * veil_points_ptr; 
    pcl::PointCloud<pcl::PointWithRange> & shadow_points = *shadow_points_ptr;

声明三种边界的点云指针和其对应引用

同样 pcl::PointWithRange 也是一种点云类型
含有x、y、z和range
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    //遍历深度图像的每一个点
    for (int y=0; y< (int)rangeImage.height; ++y)//每一行
    {
        for (int x=0; x< (int)rangeImage.width; ++x)//每一列
        {
            /*判断是否为物体边界*/
        if (border_descriptions.points[y*rangeImage.width + x].traits[pcl::BORDER_TRAIT__OBSTACLE_BORDER])
            border_points.points.push_back (rangeImage.points[y*rangeImage.width + x]);//如果是存入对应点云
            /*判断是否为Veil边界*/
        if (border_descriptions.points[y*rangeImage.width + x].traits[pcl::BORDER_TRAIT__VEIL_POINT])
            veil_points.points.push_back (rangeImage.points[y*rangeImage.width + x]);//如果是存入对应点云
            /*判断是否为阴影边界*/
        if (border_descriptions.points[y*rangeImage.width + x].traits[pcl::BORDER_TRAIT__SHADOW_BORDER])
            shadow_points.points.push_back (rangeImage.points[y*rangeImage.width + x]);//如果是存入对应点云
        }
    }

遍历深度图像的每一个点
判断 这个点 是否时边界点 并且是 什么点
这个就是 pcl::BorderDescription traits 的 用法 traits[pcl::BORDER_TRAIT__OBSTACLE_BORDER]
可以判断是哪种边界
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /* 显示 边界 点云  */
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointWithRange> border_points_color_handler (border_points_ptr, 0, 255, 0);
    viewer.addPointCloud<pcl::PointWithRange> (border_points_ptr, border_points_color_handler, "border points");
    viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 7, "border points");
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointWithRange> veil_points_color_handler (veil_points_ptr, 255, 0, 0);
    viewer.addPointCloud<pcl::PointWithRange> (veil_points_ptr, veil_points_color_handler, "veil points");
    viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 7, "veil points");
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointWithRange> shadow_points_color_handler (shadow_points_ptr, 0, 255, 255);
    viewer.addPointCloud<pcl::PointWithRange> (shadow_points_ptr, shadow_points_color_handler, "shadow points");
    viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 7, "shadow points");

显示 边界 点云

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

CMakeList.txt

和上面的基本一致 ,但是用到了 features 模块 加入即可

# 寻找PCL的库
find_package(PCL REQUIRED COMPONENT common io visualization filters features)

Result

在这里插入图片描述
提取的边界改为绿色 尺寸变大

在这里插入图片描述
测试了下其它pcd文件的边界提取

相关文章
|
6月前
|
机器学习/深度学习 算法 数据挖掘
基于凹凸性PCL—低层次视觉
基于凹凸性PCL—低层次视觉
62 0
|
存储 算法
|
数据可视化 算法
|
编解码 数据可视化 数据挖掘
PCL特征点与配准(1)
关于输入一个具体的物体的点云,从场景中找出与该物体点云相匹配的,这种方法可以用来抓取指定的物体等等,具体的代码的解释如下,需要用到的一些基础的知识,在之前的博客中都有提及,其中用到的一些方法可以翻阅前面的博客,当然有问题可以关注公众号,与众多爱好者一起交流 具体的代码实现 #include #include //点云类型头文件 #include //对应表示两个实体之间的匹配(例如,点,描述符等)。
2468 0
|
数据挖掘 Windows
PCL超体聚类
超体聚类是一种图像的分割方法。 超体(supervoxel)是一种集合,集合的元素是“体”。与体素滤波器中的体类似,其本质是一个个的小方块。与大部分的分割手段不同,超体聚 类的目的并不是分割出某种特定物体,超体是对点云实施过分割(over segmentation),将场景点云化成很多小块,并研究每个小块之间的关系。
1688 0
|
数据可视化 算法
PCL点云配准(2)
(1)正态分布变换进行配准(normal Distributions Transform) 介绍关于如何使用正态分布算法来确定两个大型点云之间的刚体变换,正态分布变换算法是一个配准算法,它应用于三维点的统计模型,使用标准最优化技术来确定两个点云间的最优匹配,因为其在配准的过程中不利用对应点的特征计算和匹配,所以时间比其他方法比较快, 对于代码的解析 /* 使用正态分布变换进行配准的实验 。
2313 0
|
存储 算法 数据可视化
PCL点云配准(1)
在逆向工程,计算机视觉,文物数字化等领域中,由于点云的不完整,旋转错位,平移错位等,使得要得到的完整的点云就需要对局部点云进行配准,为了得到被测物体的完整数据模型,需要确定一个合适的坐标系,将从各个视角得到的点集合并到统一的坐标系下形成一个完整的点云,然后就可以方便进行可视化的操作,这就是点云数据的配准。
2586 0
|
机器学习/深度学习 数据可视化 算法
PCL行人检测
首先我们知道Hog特征结合SVM分类器已经被广泛应用于图像识别中,尤其在行人检测中获得了极大的成功,HOG+SVM进行行人检测的方法是法国研究人员Dalal在2005的CVPR上提出的,而如今虽然有很多行人检测算法不断提出,但基本都是以HOG+SVM的思路为主,那么PCL中也是利用这一思想来进行行人的检测, 总体思路: 1、提取正负样本hog特征 2、投入svm分类器训练,得到model 3、由model生成检测子 4、利用检测子检测负样本,得到hardexample 5、提取hardexample的hog特征并结合第一步中的特征一起投入训练,得到最终检测子。
1622 0
|
算法 数据可视化
PCL法线估计
平面的法线是垂直于它的单位向量。在点云的表面的法线被定义为垂直于与点云表面相切的平面的向量。表面法线也可以计算点云中一点的法线,被认为是一种十分重要的性质。常常在被使用在很多计算机视觉的应用里面,比如可以用来推出光源的位置,通过阴影与其他视觉影响,表面法线的问题可以近似化解为切面的问题,这个切面的问题又会变成最小二乘法拟合平面的问题 解决表面法线估计的问题可以最终化简为对一个协方差矩阵的特征向量和特征值的分析(或者也叫PCA-Principal Component Analysis 主成分分析),这个协方差矩阵是由查询点的最近邻产生的。
1692 0
PCL点云分割(2)
关于点云的分割算是我想做的机械臂抓取中十分重要的俄一部分,所以首先学习如果使用点云库处理我用kinect获取的点云的数据,本例程也是我自己慢慢修改程序并结合官方API 的解说实现的,其中有很多细节如果直接更改源程序,可能会因为数据类型,或者头文件等各种原因编译不过,会导致我们比较难得找出其中的错误,...
1961 0