PCL_物体分割

  最近发现一个点云分割的框架,安立以下。很是不错,用法简单,速度快。

  所需工具为:PCL和SegementerLight

  之前提到过安装PCL1.8,但是在默认情况下我们编译的PCL不带NURBS,但是这里需要,所以我们重新安装一下

 

mkdir build
cd build/
sudo apt-get install cmake-curses-gui
ccmake ..

选择”BUILD_surface_on_nurbs” 为 “ON” (default “OFF”)


cmake ..
make -j4
sudo make install

安装依赖项


sudo apt-get install libopenni-sensor-primesense-dev 
sudo apt-get install libopenni-dev 
sudo apt-get install libopenni-sensor-primesense0 
sudo apt-get install libopenni0 


下载SegmenterLight


cd SegmenterLight/

mkdir build
cd build/
ccmake ..

press c and then g


make -j4
sudo make install

最终测试


cd SegmenterLight/bin

./SegmenterLight -f learn0.pcd

learn0.pcd是放到bin下的待分割文件,出现Debug image的窗口后,点击该窗口按下F9,即可看到分割效果:


这里写图片描述


要嵌入到自己的工程中,可以直接使用编译出的动态库,


CMakeLists.txt内容


cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(v4r_test)
find_package( OpenCV 3 REQUIRED )
find_package(PCL 1.8 REQUIRED)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fopenmp")
SET(CMAKE_BUILD_TYPE Release)   # Mandatory for openmp!

add_executable(main main.cpp)
target_link_libraries(main ${PCL_LIBRARIES} ${OpenCV_LIBS} v4rTomGine v4rSegmenterLight)

main.cpp


#include <iostream>

#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/point_cloud.h>
#include <pcl/console/parse.h>
#include <pcl/common/transforms.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/visualization/cloud_viewer.h>


#include <iostream>

#include <boost/thread/thread.hpp>
#include <pcl/common/common_headers.h>
#include <pcl/features/normal_3d.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/console/parse.h>



#include <v4r/SegmenterLight/SegmenterLight.h>

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/opencv.hpp>


#include <time.h>
using namespace std;
using namespace cv;

// This function displays the help
void showHelp(char * program_name)
{
  std::cout << std::endl;
  std::cout << "Usage: " << program_name << " cloud_filename.[pcd|ply]" << std::endl;
  std::cout << "-h:  Show this help." << std::endl;
}


void PCLCloud2Image(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & pcl_cloud, cv::Mat_<cv::Vec3b> &image){
    unsigned pcWidth = pcl_cloud->width;
    unsigned pcHeight = pcl_cloud->height;
    unsigned position = 0;

    image = cv::Mat_<cv::Vec3b>(pcHeight, pcWidth);

    for (unsigned row = 0; row < pcHeight; row++) {
      for (unsigned col = 0; col < pcWidth; col++) {
        cv::Vec3b &cvp = image.at<cv::Vec3b> (row, col);
        position = row * pcWidth + col;
        const pcl::PointXYZRGB &pt = pcl_cloud->points[position];

        cvp[2] = pt.r;
        cvp[1] = pt.g;
        cvp[0] = pt.b;
      }
    }

}

int getLabels(pcl::PointCloud<pcl::PointXYZRGBL>::Ptr cloud){
    int max_label = 0;

    set<int> result;
    for(int i=0; i<cloud->points.size(); i++){
        if(cloud->points[i].label > max_label){
            max_label = cloud->points[i].label;
        }
        result.insert(cloud->points[i].label);

    }

    cout <<"set cout begin " <<endl;
    cout <<"set.size = " << result.size()<<endl;
    for(set<int>::iterator it = result.begin(); it != result.end(); it++){
        cout << *it <<" ";
    }
    cout <<endl;

    return max_label;

}

typedef union
{
  struct
  {
    unsigned char b; // Blue channel
    unsigned char g; // Green channel
    unsigned char r; // Red channel
    unsigned char a; // Alpha channel
  };
  float float_value;
  long long_value;
} RGBValue;

inline float GetRandomColor()
{
  RGBValue x;
  x.b = std::rand()%255;
  x.g = std::rand()%255;
  x.r = std::rand()%255;
  x.a = 0.;
  return x.float_value;
}


// This is the main function
int main (int argc, char** argv)
{
    pcl::PointCloud<pcl::PointXYZRGB>::Ptr pcl_cloud(new pcl::PointCloud<pcl::PointXYZRGB>);    

    pcl::io::loadPCDFile("learn1.pcd", *pcl_cloud);
    cout << pcl_cloud->points[0].r <<endl;
    pcl::io::savePCDFileASCII("1111.txt", *pcl_cloud);
    std::string modelPath = "../model/";
    pcl::PointCloud<pcl::PointXYZRGBL>::Ptr pcl_cloud_labeled(new pcl::PointCloud<pcl::PointXYZRGBL>);
    segment::SegmenterLight seg(modelPath);
    seg.setFast(true);
    seg.setDetail(2);
    pcl_cloud_labeled = seg.processPointCloud(pcl_cloud);

    int max_label = getLabels(pcl_cloud_labeled);

    RGBValue colors[max_label+1];
    for(int i=0; i<=max_label; i++){
        colors[i].float_value = GetRandomColor();
    }

    for(int i=0; i<pcl_cloud_labeled->points.size(); i++){
        pcl::PointXYZRGB &p = pcl_cloud->points[i];
        p.rgb = colors[pcl_cloud_labeled->points[i].label].float_value;

    }

    pcl::visualization::PCLVisualizer viewer("saldfjald");

    viewer.addPointCloud(pcl_cloud);
    viewer.addCoordinateSystem(1.0, "cloud", 0);
    while(!viewer.wasStopped()){
        viewer.spinOnce();
    }
    std::cout << "okkkkk" << std::endl;
    cv::Mat_<cv::Vec3b> src;
    long int t1,t2;
    t1 = getTickCount();

    PCLCloud2Image(pcl_cloud, src);
    t2 = getTickCount();
    cout << "frequency = " << getTickFrequency() <<endl;
    cout << (t2- t1)/getTickFrequency() << " s" <<endl;

    cout << "time = " << t2 - t1 << " ms " <<endl;
    cv::imshow("saf", src);
    cv::waitKey(0);

    return 0;
}

这里写图片描述

### PCL点云中的物体分割实现方法 #### 使用Voxel滤波器进行点云预处理 在实际应用中,原始点云通常存在噪声和不均匀采样的问题。为了提高后续算法的效果,在进行物体分割之前可以先对点云进行下采样处理。PCL提供了一个名为`pcl::VoxelGrid`的类来执行这一操作。通过设置体素网格大小(即空间分辨率),可以有效地减少点的数量并使点云更加均匀。 ```cpp double voxel_size = 0.01; pcl::VoxelGrid<pcl::PointXYZRGB> vg; pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_filtered1(new pcl::PointCloud<pcl::PointXYZRGB>); vg.setInputCloud(back_cloud); vg.setLeafSize(voxel_size, voxel_size, voxel_size); vg.filter(*cloud_filtered1); *cloud_filtered = *cloud_filtered1; std::cout << "show the filtered data!" << std::endl; showCloudstmp(cloud_filtered); ``` 上述代码展示了如何利用Voxel滤波器对点云进行降采样[^3]。 --- #### 平面拟合与地面移除 许多场景下的物体分割任务需要首先去除背景平面(如地板)。这可以通过RANSAC算法实现。具体来说,PCL提供了`pcl::SACSegmentation`类来进行模型拟合并提取感兴趣的对象区域。 ```cpp // 创建 SACSegmentation 对象实例化 pcl::ModelCoefficients::Ptr coefficients_plane (new pcl::ModelCoefficients ()); pcl::PointIndices::Ptr inliers_plane (new pcl::PointIndices ()); pcl::SACSegmentation<pcl::PointXYZRGB> seg; seg.setOptimizeCoefficients(true); seg.setModelType(pcl::SACMODEL_PLANE); seg.setMethodType(pcl::SAC_RANSAC); seg.setMaxIterations(100); seg.setDistanceThreshold(0.02); seg.setInputCloud(cloud_filtered); seg.segment(*inliers_plane, *coefficients_plane); if(inliers_plane->indices.size() == 0){ std::cerr << "Could not estimate a planar model for the given dataset." << std::endl; } // 提取非平面部分作为目标候选区 pcl::ExtractIndices<pcl::PointXYZRGB> extract; extract.setInputCloud(cloud_filtered); extract.setIndices(inliers_plane); extract.setNegative(true); pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_without_plane(new pcl::PointCloud<pcl::PointXYZRGB>()); extract.filter(*cloud_without_plane); ``` 此段程序实现了基于随机抽样一致性(RANSAC)的方法找到最佳拟合平面,并将其余部分视为可能的目标对象。 --- #### 基于欧几里得聚类的物体分割 对于去除了背景后的点云集合,下一步就是将剩余的数据划分为不同的簇(cluster),每一个簇对应着一个单独的实体或者物体。这里采用的是欧式距离度量标准完成分组工作: ```cpp pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZRGB>); tree->setInputCloud(cloud_without_plane); std::vector<pcl::PointIndices> cluster_indices; pcl::EuclideanClusterExtraction<pcl::PointXYZRGB> ec; ec.setClusterTolerance(0.02); // 设置邻近阈值为2cm ec.setMinClusterSize(100); // 定义最小有效集群尺寸 ec.setMaxClusterSize(25000); // 设定最大允许群集规模 ec.setSearchMethod(tree); ec.setInputCloud(cloud_without_plane); ec.extract(cluster_indices); for(const auto& indices : cluster_indices){ pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_cluster(new pcl::PointCloud<pcl::PointXYZRGB>()); for(auto index : indices.indices){ cloud_cluster->points.push_back(cloud_without_plane->points[index]); } cloud_cluster->width = static_cast<uint32_t>(cloud_cluster->points.size()); cloud_cluster->height = 1; cloud_cluster->is_dense = true; std::cout << "Found Cluster with size:" << cloud_cluster->size() << std::endl; } ``` 以上脚本完成了从无背景干扰的点集中发现多个独立个体的任务。 --- ### 总结 综上所述,使用PCL进行物体分割主要包括三个阶段:首先是运用Voxel Grid技术简化输入数据;其次是借助RANSAC策略剔除不需要考虑的大面积表面特征比如地面等;最后依靠欧氏距离准则把剩下的要素分类成若干子单元表示各个分离出来的物件。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值