PCL 点云超体素分割-SupervoxelClustering

 一、概述

原始文档与点云

Clustering of Pointclouds into Supervoxels - Theoretical primer — Point Cloud Library 0.0 documentation 

 超像素 Superpixels 

Segmentation algorithms aim to group pixels in images into perceptually meaningful regions which conform to object boundaries. Graph-based approaches, such as Markov Random Field (MRF) and Conditional Random Field (CRF), have become popular, as they merge relational low-level context within the image with object level class knowledge. The cost of solving pixel-level graphs led to the development of mid-level inference schemes which do not use pixels directly, but rather use groupings of pixels, known as superpixels, as the base level for nodes. Superpixels are formed by over-segmenting the image into small regions based on local low-level features, reducing the number of nodes which must be considered for inference。

重点:超像素是一个像素群体而不是但个像素点

超体素Supervoxels 

Voxel Cloud Connectivity Segmentation (VCCS) is a recent “superpixel” method which generates volumetric over-segmentations of 3D point cloud data, known as supervoxels. Supervoxels adhere to object boundaries better than state-of-the-art 2D methods, while remaining efficient enough to use in online applications. VCCS uses a region growing variant of k-means clustering for generating its labeling of points directly within a voxel octree structure. Supervoxels have two important properties; they are evenly distributed across the 3D space, and they cannot cross boundaries unless the underlying voxels are spatial connected. The former is accomplished by seeding supervoxels directly in the cloud, rather than the projected plane, while the latter uses an octree structure which maintains adjacency information of leaves. Supervoxels maintain adjacency relations in voxelized 3D space; specifically, 26-adjacency- that is neighboring voxels are those that share a face, edge, or vertex, as seen below.

Voxel Cloud Connectivity Segmentation (VCCS)使用K-均值分类的区域生长方法来对点云进行超体速分割,超体速有两个重要的特征 :在3D的空间中是均匀分布的,前者是通过直接在云中而不是投影平面中播种超体素来完成的,而后者使用八叉树结构来维护叶子的邻接信息。超级体素在体素化 3D 空间中维持邻接关系;具体来说,26-邻接-即相邻体素是那些共享面、边或顶点的体素,

如图:

 

VCCS is a region growing method which incrementally expand supervoxels from a set of seed points distributed evenly in space on a grid with resolution R_seed. To maintain efficiency, VCCS does not search globally, but rather only considers points within R_seed of the seed center. Additionally, seeds which are isolated are filtered out by establishing a small search radius R_search around each seed and removing seeds which do not have sufficient neighbor voxels connected to them.

VCCS 是一种区域生长方法,它从分辨率为 R_seed 的网格上均匀分布在空间中的一组种子点增量扩展超体素。为了保持效率,VCCS不会全局搜索,而是只考虑种子中心R_seed内的点。此外,通过在每个种子周围建立小搜索半径 R_search 并去除没有足够的相邻体素与其连接的种子,来过滤掉被隔离的种子。

影响超体素聚类的各种尺寸参数。 R_seed 和 R_voxel 都必须由用户设置

Expansion from the seed points is governed by a distance measure calculated in a feature space consisting of spatial extent, color, and normals. The spatial distance D_s is normalized by the seeding resolution, color distance D_c is the euclidean distance in normalized RGB space, and normal distance D_n measures the angle between surface normal vectors.

Supervoxels are grown iteratively, using a local k-means clustering which considers connectivity and flow. The general process is as follows. Beginning at the voxel nearest the cluster center, we flow outward to adjacent voxels and compute the distance from each of these to the supervoxel center using the distance equation above. If the distance is the smallest this voxel has seen, its label is set, and using the adjacency graph, we add its neighbors which are further from the center to our search queue for this label. We then proceed to the next supervoxel, so that each level outwards from the center is considered at the same time for all supervoxels (a 2d version of this is seen in the figure below). We proceed iteratively outwards until we have reached the edge of the search volume for each supervoxel (or have no more neighbors to check) 

超级体素使用考虑连通性和流量的局部 k 均值聚类迭代生长。大致流程如下。从距离聚类中心最近的体素开始,我们向外流动到相邻的体素,并使用上面的距离方程计算每个体素到超体素中心的距离。如果距离是该体素所见过的最小距离,则设置其标签,并使用邻接图,我们将距离中心更远的邻居添加到该标签的搜索队列中。然后我们继续处理下一个超级体素,以便对于所有超级体素同时考虑从中心向外的每个级别(下图中可以看到其二维版本)。我们向外迭代,直到到达每个超体素的搜索体积的边缘(或者没有更多的邻居需要检查)

 超体素分割过程

超体素分割(过分割)详细过程-CSDN博客

官方code 



#include <pcl/console/parse.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/segmentation/supervoxel_clustering.h>

//VTK include needed for drawing graph lines
#include <vtkPolyLine.h>

// Types
typedef pcl::PointXYZRGBA PointT;
typedef pcl::PointCloud<PointT> PointCloudT;
typedef pcl::PointNormal PointNT;
typedef pcl::PointCloud<PointNT> PointNCloudT;
typedef pcl::PointXYZL PointLT;
typedef pcl::PointCloud<PointLT> PointLCloudT;

void addSupervoxelConnectionsToViewer(PointT& supervoxel_center,
    PointCloudT& adjacent_supervoxel_centers,
    std::string supervoxel_name,
    pcl::visualization::PCLVisualizer::Ptr& viewer);

int   main(int argc, char** argv)
{
    PointCloudT::Ptr cloud(new PointCloudT);
    pcl::console::print_highlight("Loading point cloud...\n");
    if (pcl::io::loadPCDFile<PointT>("D:\\work\\Pointclouds\\clouds\\milk_cartoon_all_small_clorox.pcd", *cloud))
    {
        pcl::console::print_error("Error loading cloud file!\n");
        return (1);
    }


    bool disable_transform = true;
    float voxel_resolution = 0.008f;  // 体素分辨率
    float seed_resolution = 0.1f;  // 种子 分辨率
    float color_importance = 0.2f;  // 颜色权重
    float spatial_importance = 0.2f;  // 空间权重
    float normal_importance = 2.0f;   // 法向量角度差 



    pcl::SupervoxelClustering<PointT> super(voxel_resolution, seed_resolution);
    if (disable_transform)
        super.setUseSingleCameraTransform(false);
    super.setInputCloud(cloud);
    super.setColorImportance(color_importance);
    super.setSpatialImportance(spatial_importance);
    super.setNormalImportance(normal_importance);

    std::map <std::uint32_t, pcl::Supervoxel<PointT>::Ptr > supervoxel_clusters;

    pcl::console::print_highlight("Extracting supervoxels!\n");
    super.extract(supervoxel_clusters);
    pcl::console::print_info("Found %d supervoxels\n", supervoxel_clusters.size());

    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
    viewer->setBackgroundColor(0, 0, 0);

    PointCloudT::Ptr voxel_centroid_cloud = super.getVoxelCentroidCloud();
    viewer->addPointCloud(voxel_centroid_cloud, "voxel centroids");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2.0, "voxel centroids");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY, 0.95, "voxel centroids");

    PointLCloudT::Ptr labeled_voxel_cloud = super.getLabeledVoxelCloud();
    viewer->addPointCloud(labeled_voxel_cloud, "labeled voxels");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY, 0.8, "labeled voxels");

    PointNCloudT::Ptr sv_normal_cloud = super.makeSupervoxelNormalCloud(supervoxel_clusters);
    //We have this disabled so graph is easy to see, uncomment to see supervoxel normals
    //viewer->addPointCloudNormals<PointNormal> (sv_normal_cloud,1,0.05f, "supervoxel_normals");

    pcl::console::print_highlight("Getting supervoxel adjacency\n");
    std::multimap<std::uint32_t, std::uint32_t> supervoxel_adjacency;
    super.getSupervoxelAdjacency(supervoxel_adjacency);
    //To make a graph of the supervoxel adjacency, we need to iterate through the supervoxel adjacency multimap
    for (auto label_itr = supervoxel_adjacency.cbegin(); label_itr != supervoxel_adjacency.cend(); )
    {
        //First get the label
        std::uint32_t supervoxel_label = label_itr->first;
        //Now get the supervoxel corresponding to the label
        pcl::Supervoxel<PointT>::Ptr supervoxel = supervoxel_clusters.at(supervoxel_label);

        //Now we need to iterate through the adjacent supervoxels and make a point cloud of them
        PointCloudT adjacent_supervoxel_centers;
        for (auto adjacent_itr = supervoxel_adjacency.equal_range(supervoxel_label).first; adjacent_itr != supervoxel_adjacency.equal_range(supervoxel_label).second; ++adjacent_itr)
        {
            pcl::Supervoxel<PointT>::Ptr neighbor_supervoxel = supervoxel_clusters.at(adjacent_itr->second);
            adjacent_supervoxel_centers.push_back(neighbor_supervoxel->centroid_);
        }
        //Now we make a name for this polygon
        std::stringstream ss;
        ss << "supervoxel_" << supervoxel_label;
        //This function is shown below, but is beyond the scope of this tutorial - basically it just generates a "star" polygon mesh from the points given
        addSupervoxelConnectionsToViewer(supervoxel->centroid_, adjacent_supervoxel_centers, ss.str(), viewer);
        //Move iterator forward to next label
        label_itr = supervoxel_adjacency.upper_bound(supervoxel_label);
    }

    while (!viewer->wasStopped())
    {
        viewer->spinOnce(100);
    }
    return (0);
}

void addSupervoxelConnectionsToViewer(PointT& supervoxel_center,
    PointCloudT& adjacent_supervoxel_centers,
    std::string supervoxel_name,
    pcl::visualization::PCLVisualizer::Ptr& viewer)
{
    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
    vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
    vtkSmartPointer<vtkPolyLine> polyLine = vtkSmartPointer<vtkPolyLine>::New();

    //Iterate through all adjacent points, and add a center point to adjacent point pair
    for (auto adjacent_itr = adjacent_supervoxel_centers.begin(); adjacent_itr != adjacent_supervoxel_centers.end(); ++adjacent_itr)
    {
        points->InsertNextPoint(supervoxel_center.data);
        points->InsertNextPoint(adjacent_itr->data);
    }
    // Create a polydata to store everything in
    vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
    // Add the points to the dataset
    polyData->SetPoints(points);
    polyLine->GetPointIds()->SetNumberOfIds(points->GetNumberOfPoints());
    for (unsigned int i = 0; i < points->GetNumberOfPoints(); i++)
        polyLine->GetPointIds()->SetId(i, i);
    cells->InsertNextCell(polyLine);
    // Add the lines to the dataset
    polyData->SetLines(cells);
    viewer->addModelFromPolyData(polyData, supervoxel_name);
}

显示:

修改参数:

    bool disable_transform = true;
    float voxel_resolution = 0.08f;  // 体素分辨率
    float seed_resolution = 0.1f;  // 种子 分辨率
    float color_importance = 0.2f;  // 颜色权重
    float spatial_importance = 0.5f;  // 空间权重
    float normal_importance = 12.0f;   // 法向量角度差 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/153429.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】文件系统中inode与软硬链接以及读写权限问题

文章目录 前言一、 简单理解文件系统二、文件操作具体步骤1.新建文件2.删除文件3.查找文件 三、目录的重新理解1.目录下没有w权限&#xff0c;无法对其下的文件进行创建与删除2.目录下没有r权限&#xff0c;无法对其下的文件进行查看3.目录下没有x权限&#xff0c;无法进入这个…

空调能量表

数字化应用场景&#xff1a;空调能量监测 定义 空调能量表产品又被称为冷量积算仪、冷量积分仪、能量积分仪、能量积算仪、空调冷热量表、冷量表、能量表等&#xff0c;现阶段行业内没有统一的名称。 作用 用于计量中央空调能耗的仪表&#xff0c;它通过和空调管道流量计和温…

numpy数据库

numpy中的数组 0、导包 import numpy as np 1、创建数组 >>> # 创建数组&#xff0c;得到darray类型 >>> t1 np.array([1, 2, 3]) >>> t2 np.array(range(8)) >>> t3 np.arange(1, 9, 2) 2、数组为 numpy.ndarray 类型 >>…

基于单片机C51全自动洗衣机仿真设计

**单片机设计介绍&#xff0c; 基于单片机C51全自动洗衣机仿真设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机C51的全自动洗衣机仿真设计是一个复杂的项目&#xff0c;它涉及到硬件和软件的设计和实现。以下是对这…

redis常见问题及解决方案

缓存预热 定义 缓存预热是一种优化方案&#xff0c;它可以提高用户的使用体验。 缓存预热是指在系统启动的时候&#xff0c;先把查询结果预存到缓存中&#xff0c;以便用户后面查询时可以直接从缓存中读取&#xff0c;节省用户等待时间 实现思路 把需要缓存的方法写在初始化方…

Linux三剑客:grep的基本使用

目录 grep介绍 什么是grep和egrep 使用grep 命令格式 命令功能 命令参数 grep配合正则表达式使用 认识正则 基本正则表达式 匹配字符 配置次数 位置锚定&#xff1a;定位出现的位置 分组和后向引用 作为学习一名计算机专业的学生&#xff0c;我想Linux应该需要了解…

HTML5学习系列之实用性标记

HTML5学习系列之实用性标记 前言实用性标记高亮显示进度刻度时间联系信息显示方向换行断点标注 总结 前言 学习记录 实用性标记 高亮显示 mark元素可以进行高亮显示。 <p><mark>我感冒了</mark></p>进度 progress指示某项任务的完成进度。 <p…

Python基础教程之模块介绍及用法,适合新手小白的入门教程~

文章目录 什么是模块&#xff1f;创建模块使用模块模块中的变量为模块命名重命名模块内建模块使用 dir() 函数从模块导入 什么是模块&#xff1f; 请思考与代码库类似的模块。 模块是包含一组函数的文件&#xff0c;希望在应用程序中引用。 创建模块 如需创建模块&#xff…

(C++类的初始化和清理)构造函数与析构函数

目录 1. 类的六个默认成员函数2. 构造函数&#xff08;Constructor&#xff09;2.1 概念2.2 特性 3. 析构函数&#xff08;Destructor&#xff09;3.1 概念3.2 特性 1. 类的六个默认成员函数 一个类中如果什么成员都没有&#xff0c;称为空类 class Date {};但是这并不代表空…

Windows 系统彻底卸载 SQL Server 通用方法

Windows 系统彻底卸载 SQL Server 通用方法 无论什么时候&#xff0c;SQL Server 的安装和卸载都是一件让我们头疼的事情。因为不管是 SQL Server 还是 MySQL 的数据库&#xff0c;当我们在使用数据库时因为未知原因出现问题&#xff0c;想要卸载重装时&#xff0c;如果数据库…

如何分析伦敦金的价格走势预测?

伦敦金作为国际黄金市场的重要指标&#xff0c;其价格走势一直备受投资者关注。但是&#xff0c;黄金市场的价格变化受到多种因素的影响&#xff0c;因此要准确预测伦敦金的价格走势并非易事。在本文中&#xff0c;将介绍一些常用的方法和工具&#xff0c;帮助您分析伦敦金的价…

Docker-compose 下载安装测试完成

源文件-http://t.csdnimg.cn/7NxHchttp://t.csdnimg.cn/7NxHc 1 docker-compose说明 Docker Compose 是Docker的组装工具&#xff0c;用于创建和调试多个Docker容器&#xff0c;并在同一个Docker主机上运行它们。Docker Compose基于YAML文件&#xff0c;描述多个容器之间的相…

在Spring Boot中使用Redis的发布订阅功能

Redis的发布订阅模式是一种消息传递模式&#xff0c;它允许多个订阅者订阅一个或多个频道&#xff0c;同时一个发布者可以将消息发布到指定的频道。这种模式在分布式系统中非常有用&#xff0c;可以解决以下问题&#xff1a; 实时消息传递&#xff1a;发布订阅模式可以用于实时…

django——公众号服务开发

开发过程 项目背景&#xff1a;功能描述&#xff1a;参考文档以及调试链接&#xff1a;技术架构&#xff1a;准备工作公众号的注册以及设置域名的准备服务器的租赁内网穿透微信支付的注册 功能开发细节微信公众号自定义菜单获取access_token创建菜单查询菜单删除菜单 个性化菜单…

Nginx反向代理与负载均衡与504错误

Nginx反向代理与负载均衡概念简介 关于代理 什么是代理 类似中介 在没有代理模式的情况下&#xff0c;客户端和Nginx服务端&#xff0c;都是客户端直接请求服务端&#xff0c;服务端直接响应客户端。 那么在互联网请求里面&#xff0c;客户端往往无法直接向服务端发起请求…

【LeetCode刷题-滑动窗口】--76.最小覆盖子串

76.最小覆盖子串 class Solution {//建立两个hashMap&#xff0c;ori用于存储目标字符串t中每个字符的出现次数//cnt用于存储当前窗口中每个字符的出现次数Map<Character,Integer> ori new HashMap<Character,Integer>();Map<Character,Integer> cnt new H…

PyTorch:计算图

在深度学习和神经网络领域&#xff0c;计算图是一种重要的概念&#xff0c;它在理解和实现神经网络模型的训练过程中起着至关重要的作用。PyTorch作为一款优秀的深度学习框架&#xff0c;自然也包含了计算图的概念和实现。本文将深入探讨PyTorch中计算图的原理、应用以及对深度…

mp4封装格式各box类型讲解及IBP帧计算

作者 —— 靑い空゛ 出处&#xff1a;http://www.cnblogs.com/ailumiyana/ 音视频流媒体高级开发教程 MP4文件封装格式&#xff0c;对应的标准为ISO/IEC 14496-12&#xff0c;即信息技术 视听对象编码的第12部分 ISO 基本媒体文件格式&#xff08;Information technology Codi…

最新版仿东郊到家小程序源码 上门服务小程序源码

最新版仿东郊到家小程序源码 上门服务小程序源码 1、数据概况&#xff08;新增业务城市用户投票功能&#xff0c;更加直观的查看业务城市的关注度、人气和影响力,促进业务开展&#xff09; 2、数据概况 &#xff08;增加可视化数据大盘&#xff0c;代理商端可查看自己下面的技…

【java学习—十五】线程的同步与死锁(5)

文章目录 1. 多线程产生的问题2. Synchronized 的使用方法3. 线程的死锁问题 1. 多线程产生的问题 问题&#xff1a; 同一个账户&#xff0c;支付宝转账&#xff0c;微信转账。两个手机&#xff0c;一个手机开支付宝&#xff0c;另一个手机开微信。假设账户上有3000元&#xff…