点云技术相关产学研社区

 找回密码
 立即注册加入PCL中国点云技术相关产学研社区

扫一扫,访问微社区

查看: 11058|回复: 16

聚类分割

[复制链接]
发表于 2013-4-25 09:34:26 | 显示全部楼层 |阅读模式
添加聚类所需的库文件
#include <pcl/ModelCoefficients.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/passthrough.h>
#include <pcl/features/normal_3d.h>
#include <pcl/kdtree/kdtree.h>
#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/visualization/point_cloud_color_handlers.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <iostream>
#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
int
main (int argc, char** argv)
{
  //从硬盘读取pcd格式的点云文件,点云数据含有RGB信息
  pcl::PCDReader reader;
  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGBA>), cloud_f (new pcl::PointCloud<pcl::PointXYZRGBA>);
  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr pass_filtered (new pcl::PointCloud<pcl::PointXYZRGBA>);
  reader.read ("scene_1.pcd", *cloud);//点云文件“scene_1.pcd”由Kinect采集获得

//滤波,只保留深度信息为0.4m到1.55m之间的点云数据
  std::cout << "PointCloud before filtering has: " << cloud->points.size () << " data points." << std::endl; //*
  pcl::PassThrough<pcl::PointXYZRGBA> pass;
  // Build a passthrough filter to remove spurious NaNs
  pass.setInputCloud (cloud);
  pass.setFilterFieldName ("z");
  pass.setFilterLimits (0.4, 1.55);
  pass.filter (*pass_filtered);
  //std::cerr << "PointCloud after filtering has: " << cloud_filtered->points.size () << " data points." << std::endl;

//可视化,显示滤波后的点云数据
  pcl::visualization::CloudViewer viewerr ("filter");
  viewerr.showCloud(pass_filtered);
  while (!viewerr.wasStopped ())
             {
               //iewerr.spinOnce ();
             }


  // 下采样滤波,在保持点云数据形状不变的前提下,减少点云数据,其中叶子尺寸值越大,点云数据量越少
  pcl::VoxelGrid<pcl::PointXYZRGBA> vg;
  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZRGBA>);
  vg.setInputCloud (pass_filtered);
  vg.setLeafSize (0.005f, 0.005f, 0.005f);
  vg.filter (*cloud_filtered);
  std::cout << "PointCloud after filtering has: " << cloud_filtered->points.size ()  << " data points." << std::endl; //*

  // 随机采样分割出平面
  pcl::SACSegmentation<pcl::PointXYZRGBA> seg;
  pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
  pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud_plane (new pcl::PointCloud<pcl::PointXYZRGBA> ());
  pcl::PCDWriter writer;
  seg.setOptimizeCoefficients (true);
  seg.setModelType (pcl::SACMODEL_PLANE);
  seg.setMethodType (pcl::SAC_RANSAC);
  seg.setMaxIterations (100);
  seg.setDistanceThreshold (0.02);

  int i=0, nr_points = (int) cloud_filtered->points.size ();
  while (cloud_filtered->points.size () > 0.3 * nr_points)
  {
    // Segment the largest planar component from the remaining cloud
    seg.setInputCloud (cloud_filtered);
    seg.segment (*inliers, *coefficients);
    if (inliers->indices.size () == 0)
    {
      std::cout << "Could not estimate a planar model for the given dataset." << std::endl;
      break;
    }

    //提取输入点云平面内点
    pcl::ExtractIndices<pcl::PointXYZRGBA> extract;
    extract.setInputCloud (cloud_filtered);
    extract.setIndices (inliers);
    extract.setNegative (false);

    // Write the planar inliers to disk
    extract.filter (*cloud_plane);
    std::cout << "PointCloud representing the planar component: " << cloud_plane->points.size () << " data points." << std::endl;

    // 删除平面内点,提取剩余的点云
    extract.setNegative (true);
    extract.filter (*cloud_f);
    cloud_filtered = cloud_f;
  }


  // 创建近临搜索对象,聚类分割对象
  pcl::search::KdTree<pcl::PointXYZRGBA>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZRGBA>);
  tree->setInputCloud (cloud_filtered);

  std::vector<pcl::PointIndices> cluster_indices;//类型是向量,存储分割后的各个聚类
  pcl::EuclideanClusterExtraction<pcl::PointXYZRGBA> ec;//聚类分割对象
  ec.setClusterTolerance (0.1); // 2cm设置ClusterTolerance,该值为近临搜索半径
  ec.setMinClusterSize (500);//聚类中点的数量下限
  ec.setMaxClusterSize (25000);//聚类中点的数量上限
  ec.setSearchMethod (tree);//搜索方法,radiusSearch
  ec.setInputCloud ( cloud_filtered);
  ec.extract (cluster_indices);//提取搜索半径内的近临索引即为聚类分割出的聚类

  int j = 0;

//显示各个分割后的聚类
  for (std::vector<pcl::PointIndices>::const_iterator it = cluster_indices.begin (); it != cluster_indices.end (); ++it)//迭代查询聚类向量cluster_indices中所存储的聚类
  {
    pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud_cluster (new pcl::PointCloud<pcl::PointXYZRGBA>);
    for (std::vector<int>::const_iterator pit = it->indices.begin (); pit != it->indices.end (); pit++)//将cluster_indices中第pit个聚类的点云数据写入cloud_cluster
      cloud_cluster->points.push_back (cloud_filtered->points[*pit]); //*
    cloud_cluster->width = cloud_cluster->points.size ();
    cloud_cluster->height = 1;
    cloud_cluster->is_dense = true;

    std::cout << "PointCloud representing the Cluster: " << cloud_cluster->points.size () << " data points." << std::endl;
    std::stringstream ss;
    ss << "cloud_cluster_" << j << ".pcd";
    writer.write<pcl::PointXYZRGBA> (ss.str (), *cloud_cluster, false); //将聚类点云文件写入当前目录下
     j++;
    pcl::visualization::PCLVisualizer viewer("Cloud Viewer"); //窗口显示第pit个聚类
    pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGBA> color(cloud_cluster); //显示点云RGB信息
    viewer.addPointCloud(cloud_cluster,color);
    viewer.setBackgroundColor(1,1,1);

    while (!viewer.wasStopped ())
    {
    //ÔÚŽËŽŠ¿ÉÒÔÌíŒÓÆäËûŽŠÀí
     viewer.spinOnce();
    }
  }

  return (0);
}

//编译运行文件,将下面代码写入CMakeLists.txt文件的最后面
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)

project(cluster_extraction)

find_package(PCL 1.7 REQUIRED)

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

add_executable (cluster_extraction src/cluster_extraction.cpp)
target_link_libraries (cluster_extraction ${PCL_LIBRARIES})

//编译文件
rosmake
//运行
./cluster_extraction
//显示运行结果


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册加入PCL中国点云技术相关产学研社区

x
回复

使用道具 举报

发表于 2013-4-25 21:10:15 | 显示全部楼层
感谢分享,学习了,rosmake,还真没用过。你是在台式机上,还是在什么开发板上跑的ubuntu。
一直想在linux下面,玩玩,但一直没换过去。羡慕ing
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-4-26 08:11:37 | 显示全部楼层
mypcl 发表于 2013-4-25 21:10
感谢分享,学习了,rosmake,还真没用过。你是在台式机上,还是在什么开发板上跑的ubuntu。
一直想在linux ...

是在台式机上,现在想看看能不能移植到开发板上玩玩
回复 支持 反对

使用道具 举报

发表于 2013-4-28 09:28:46 | 显示全部楼层
本帖最后由 一大波蓝猫 于 2013-4-28 10:18 编辑

请问下采样滤波是什么意思?  刚接触 求指导 谢谢!!
回复 支持 反对

使用道具 举报

发表于 2013-4-28 10:10:29 | 显示全部楼层
好像明白下采样滤波了 就是利用设定的一定大小的体素对点云进行简化吧
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-4-28 10:41:04 | 显示全部楼层
一大波蓝猫 发表于 2013-4-28 10:10
好像明白下采样滤波了 就是利用设定的一定大小的体素对点云进行简化吧

嗯嗯,点云数据量太大必须滤波啊
回复 支持 反对

使用道具 举报

发表于 2013-4-28 15:05:24 | 显示全部楼层
zq07075335 发表于 2013-4-28 10:41
嗯嗯,点云数据量太大必须滤波啊

恩啊  但是对于有序点云 如果我想保留滤波之后的点云中的点的位置 是不是就要去改源码了? 这个滤波对于这个没有做什么处理吧?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-4-28 16:14:36 | 显示全部楼层
一大波蓝猫 发表于 2013-4-28 15:05
恩啊  但是对于有序点云 如果我想保留滤波之后的点云中的点的位置 是不是就要去改源码了? 这个滤波对于 ...

这个滤波是用体素内的点的重心来近似替代其他的点,破坏了有序点云的结构,要保留原来的结构,这个貌似是不行的,叶子尺寸值越小,应该是对原结构破坏越小,这个我以前也没仔细想过,互相探讨
回复 支持 反对

使用道具 举报

发表于 2013-4-28 16:38:25 | 显示全部楼层
zq07075335 发表于 2013-4-28 16:14
这个滤波是用体素内的点的重心来近似替代其他的点,破坏了有序点云的结构,要保留原来的结构,这个貌似是 ...

近似代替。。好吧 我没读过这个的源码。。以为是在体素内选择一个原来点云中的点呢 谢谢!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-4-28 16:56:29 | 显示全部楼层
一大波蓝猫 发表于 2013-4-28 16:38
近似代替。。好吧 我没读过这个的源码。。以为是在体素内选择一个原来点云中的点呢 谢谢! ...

:handshake
回复 支持 反对

使用道具 举报

本版积分规则

QQ|小黑屋|点云技术相关产学研社区 ( 陕ICP备13001629号 )

GMT+8, 2024-4-29 09:03 , Processed in 2.058464 second(s), 17 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表