前言
各种光学传感器技术的发展,包含物体三维结构信息的深度图像数据获取开始普及。尤其时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文件的边界提取