连接两个点云中的字段或数据形成新点云以及Opennni Grabber初识

简介: (1)学习如何连接两个不同点云为一个点云,进行操作前要确保两个数据集中字段的类型相同和维度相等,同时了解如何连接两个不同点云的字段(例如颜色 法线)这种操作的强制约束条件是两个数据集中点的数目必须一样,例如:点云A是N个点XYZ点,点云B是N个点的RGB点,则连接两个字段形成点云C是N个点xyzrgb类型新建文件concatenate_clouds.

(1)学习如何连接两个不同点云为一个点云,进行操作前要确保两个数据集中字段的类型相同和维度相等,同时了解如何连接两个不同点云的字段(例如颜色 法线)这种操作的强制约束条件是两个数据集中点的数目必须一样,例如:点云A是N个点XYZ点,点云B是N个点的RGB点,则连接两个字段形成点云C是N个点xyzrgb类型

新建文件concatenate_clouds.cpp  CMakeLists.txt

concatenate_clouds.cpp :

 

#include <iostream>
#include <pcl/io/pcd_io.h>      //io模块 
#include <pcl/point_types.h>   //数据类型

int
  main (int argc, char** argv)
{
  if (argc != 2) //提示如果执行可执行文件输入两个参数 -f 或者-p
  {
    std::cerr << "please specify command line arg '-f' or '-p'" << std::endl;
    exit(0);
  }
  //申明三个pcl::PointXYZ点云数据类型,分别为cloud_a, cloud_b, cloud_c
  pcl::PointCloud<pcl::PointXYZ> cloud_a, cloud_b, cloud_c;
  //存储进行连接时需要的Normal点云,Normal (float n_x, float n_y, float n_z)
  pcl::PointCloud<pcl::Normal> n_cloud_b;
   //存储连接XYZ与normal后的点云
  pcl::PointCloud<pcl::PointNormal> p_n_cloud_c;

  // 创建点云数据
  //设置cloud_a的个数为5
  cloud_a.width  = 5;
  cloud_a.height = cloud_b.height = n_cloud_b.height = 1; //设置都为无序点云
    cloud_a.points.resize (cloud_a.width * cloud_a.height); //总数
  if (strcmp(argv[1], "-p") == 0)   //判断是否为连接a+b=c(点云连接)
  {
    cloud_b.width  = 3;
    cloud_b.points.resize (cloud_b.width * cloud_b.height);
  }
  else{
    n_cloud_b.width = 5; //如果是连接XYZ与normal则生成5个法线(字段间连接)
    n_cloud_b.points.resize (n_cloud_b.width * n_cloud_b.height);
  }
//以下循环生成无序点云填充上面定义的两种类型的点云数据
  for (size_t i = 0; i < cloud_a.points.size (); ++i)
  {  //cloud_a产生三个点(每个点都有X Y Z 三个随机填充的值)
    cloud_a.points[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
    cloud_a.points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
    cloud_a.points[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
  }
  if (strcmp(argv[1], "-p") == 0)
    for (size_t i = 0; i < cloud_b.points.size (); ++i)
    {   //如果连接a+b=c,则cloud_b用三个点作为xyz的数据
      cloud_b.points[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
      cloud_b.points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
      cloud_b.points[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
    }
  else
    for (size_t i = 0; i < n_cloud_b.points.size (); ++i)
    {  //如果连接xyz+normal=xyznormal则n_cloud_b用5个点作为normal数据
      n_cloud_b.points[i].normal[0] = 1024 * rand () / (RAND_MAX + 1.0f);
      n_cloud_b.points[i].normal[1] = 1024 * rand () / (RAND_MAX + 1.0f);
      n_cloud_b.points[i].normal[2] = 1024 * rand () / (RAND_MAX + 1.0f);
    }
/*******************************************************************
定义了连接点云会用到的5个点云对象:3个输入(cloud_a cloud_b 和n_cloud_b)
两个输出(cloud_c  n_cloud_c)然后就是为两个输入点云cloud_a和 cloud_b或者cloud_a 和n_cloud_b填充数据  

********************************************************************/
//输出Cloud A
  std::cerr << "Cloud A: " << std::endl;
  for (size_t i = 0; i < cloud_a.points.size (); ++i)
    std::cerr << "    " << cloud_a.points[i].x << " " << cloud_a.points[i].y << " " << cloud_a.points[i].z << std::endl;
//输出Cloud B
  std::cerr << "Cloud B: " << std::endl;
  if (strcmp(argv[1], "-p") == 0)
    for (size_t i = 0; i < cloud_b.points.size (); ++i)
      std::cerr << "    " << cloud_b.points[i].x << " " << cloud_b.points[i].y << " " << cloud_b.points[i].z << std::endl;
  else//输出n_Cloud_b
    for (size_t i = 0; i < n_cloud_b.points.size (); ++i)
      std::cerr << "    " << n_cloud_b.points[i].normal[0] << " " << n_cloud_b.points[i].normal[1] << " " << n_cloud_b.points[i].normal[2] << std::endl;

  // Copy the point cloud data
  if (strcmp(argv[1], "-p") == 0)
  {
    cloud_c  = cloud_a;
    cloud_c += cloud_b;//把cloud_a和cloud_b连接一起创建cloud_c  后输出
    std::cerr << "Cloud C: " << std::endl;
    for (size_t i = 0; i < cloud_c.points.size (); ++i)
      std::cerr << "    " << cloud_c.points[i].x << " " << cloud_c.points[i].y << " " << cloud_c.points[i].z << " " << std::endl;
  }
  else
  {  //连接字段  把cloud_a和 n_cloud_b字段连接 一起创建 p_n_cloud_c)
    pcl::concatenateFields (cloud_a, n_cloud_b, p_n_cloud_c);
    std::cerr << "Cloud C: " << std::endl;
    for (size_t i = 0; i < p_n_cloud_c.points.size (); ++i)
      std::cerr << "    " <<
        p_n_cloud_c.points[i].x << " " << p_n_cloud_c.points[i].y << " " << p_n_cloud_c.points[i].z << " " <<
        p_n_cloud_c.points[i].normal[0] << " " << p_n_cloud_c.points[i].normal[1] << " " << p_n_cloud_c.points[i].normal[2] << std::endl;
  }
  return (0);
}

 

CMakeLists.txt

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)

project(ch2_2)

find_package(PCL 1.2 REQUIRED)

include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

add_executable (concatenate_clouds concatenate_clouds.cpp)
target_link_libraries (concatenate_clouds ${PCL_LIBRARIES})

编译执行后的结果,仔细研究看一下就可以看出点云连接和字段间连接的区别,字段间连接是在行的基础后连接,而点云连接是在列的下方连接,最重要的就是要考虑维度问题,同时每个点云都有XYZ三个数据值

 

字段间连接:

 点云连接

(2)对于获取传感器的深度信息可以使用OpenNI Grabber类,(其中涉及到如何安装传感器的驱动等问题,比如我使用的是kinect 1.0 可能会遇到一些安装问题,但是网上还是有很多的解决办法的,在这里不对于叙述)

新建文件openni_grabber.cpp

#include <pcl/point_cloud.h>   //点云类定义头文件
#include <pcl/point_types.h>    //点 类型定义头文件
#include <pcl/io/openni_grabber.h>  //OpenNI数据流获取头文件
#include <pcl/common/time.h>         //时间头文件


//类SimpleOpenNIProcessor  的回调函数,作为在获取数据时,对数据进行处理的回调函数的封装,在本例中并没有什么处理,只是实时的在标准输出设备打印处信息。
class SimpleOpenNIProcessor
{
public:
  void cloud_cb_ (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr &cloud)
  {
    static unsigned count = 0;
    static double last = pcl::getTime ();  //获取当前时间
    if (++count == 30)      //每30ms一次输出
    {
      double now = pcl::getTime ();
      //  >>右移
      std::cout << "distance of center pixel :" << cloud->points [(cloud->width >> 1) * (cloud->height + 1)].z << " mm. Average framerate: " << double(count)/double(now - last) << " Hz" <<  std::endl;
      count = 0;
      last = now;
    }
  }
  
  void run ()
  {
    pcl::Grabber* interface = new pcl::OpenNIGrabber();  //创建OpenNI采集对象

    // 定义回调函数
    boost::function<void (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr&)> f =
      boost::bind (&SimpleOpenNIProcessor::cloud_cb_, this, _1);

    boost::signals2::connection c = interface->registerCallback (f);//注册回调函数

    interface->start ();   //开始接受点云数据
     //直到用户按下Ctrl -c
    while (true)
      boost::this_thread::sleep (boost::posix_time::seconds (1));

    //   停止采集
    interface->stop ();
  }
};

int main ()
{
  SimpleOpenNIProcessor v;
  v.run ();
  return (0);
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)

project(openni_grabber)

find_package(PCL 1.2 REQUIRED)

include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

add_executable (openni_grabber openni_grabber.cpp)
target_link_libraries (openni_grabber ${PCL_LIBRARIES})

编译后执行可执行文件的结果如下

微信公众号号可扫描二维码一起共同学习交流

未完待续*******************************************8

相关文章
|
机器学习/深度学习 存储 编解码
Open3d系列 | 3. Open3d实现点云上采样、点云聚类、点云分割以及点云重建
Open3d系列 | 3. Open3d实现点云上采样、点云聚类、点云分割以及点云重建
6372 0
Open3d系列 | 3. Open3d实现点云上采样、点云聚类、点云分割以及点云重建
|
存储 数据采集 数据可视化
Open3d系列 | 1. Open3d实现点云数据读写、点云配准、点云法向量计算
Open3d系列 | 1. Open3d实现点云数据读写、点云配准、点云法向量计算
9817 1
Open3d系列 | 1. Open3d实现点云数据读写、点云配准、点云法向量计算
|
存储 算法 数据可视化
PCL 随机采样一致性--识别球面和平面
PCL 随机采样一致性--识别球面和平面
PCL 随机采样一致性--识别球面和平面
|
2月前
GEE:获取sentinel2指定区域多个单景影像的值(样本点提取)
GEE:获取sentinel2指定区域多个单景影像的值(样本点提取)
37 0
|
4月前
|
编解码 定位技术
ENVI对不含地理参考信息的栅格图像添加地理或投影坐标系信息
ENVI对不含地理参考信息的栅格图像添加地理或投影坐标系信息
|
4月前
|
算法 机器人
[3D&Halcon] 3D鞋点胶的点云边界提取
[3D&Halcon] 3D鞋点胶的点云边界提取
202 0
|
9月前
ArcGIS:如何进行离散点数据插值分析(IDW)、栅格数据的重分类、栅格计算器的简单使用、缓冲区分析、掩膜?
ArcGIS:如何进行离散点数据插值分析(IDW)、栅格数据的重分类、栅格计算器的简单使用、缓冲区分析、掩膜?
228 0
|
9月前
|
传感器
ENVI: 如何进行图像的自动配准?
ENVI: 如何进行图像的自动配准?
302 0
|
6月前
|
存储
ArcGIS模型构建器实现批量按掩膜提取影像
ArcGIS模型构建器实现批量按掩膜提取影像
239 0
|
7月前
|
C++ Python
pcl/pcd/liblas点云强度intensity反射图像过滤显示
pcl/pcd/liblas点云强度intensity反射图像过滤显示
183 0
pcl/pcd/liblas点云强度intensity反射图像过滤显示