【PCL】Segmentation 模块—— 平面模型分割(Plane model segmentation)

news/2025/1/18 20:40:10/

1、简介

PCL(Point Cloud Library)中的平面模型分割(Plane Model Segmentation)是一种从点云数据中提取平面结构的方法。它通过识别点云中符合平面模型的点集,将场景中的平面区域分割出来。

1.1 主要步骤

  1. 选择模型:选择平面模型作为分割目标。
  2. 采样点:随机选取点云中的点用于模型拟合。
  3. 模型拟合:使用采样点拟合平面模型,通常通过最小二乘法或RANSAC算法。
  4. 内点检测:计算所有点到拟合平面的距离,距离小于阈值的点被视为内点。
  5. 分割:将内点标记为属于该平面,并从点云中移除,以便后续处理。

1.2 常用算法

  • RANSAC:鲁棒的拟合算法,能有效处理噪声和离群点。
  • 最小二乘法:适用于噪声较少的点云数据。

1.3 应用场景

  • 室内场景:提取地面、墙面等平面。
  • 机器人导航:识别可通行区域。
  • 三维重建:简化场景几何结构。

2、代码

从给定的点云数据集分割任意平面模型。
兼容性:> PCL 1.3

2.1 planar_segmentation.cpp

#include <iostream>
#include <pcl/ModelCoefficients.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>int main ()
{// 读取点云数据// pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);// pcl::io::loadPCDFile<pcl::PointXYZ>("table_scene_lms400.pcd", *cloud);//----------------------------------pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);// Fill in the cloud datacloud->width  = 15;cloud->height = 1;cloud->points.resize (cloud->width * cloud->height);// Generate the datafor (auto& point: *cloud){point.x = 1024 * rand () / (RAND_MAX + 1.0f);point.y = 1024 * rand () / (RAND_MAX + 1.0f);point.z = 1.0;}// Set a few outliers(*cloud)[0].z = 2.0;(*cloud)[3].z = -2.0;(*cloud)[6].z = 4.0;//----------------------------------std::cerr << "Point cloud data: " << cloud->size () << " points" << std::endl;for (const auto& point: *cloud)std::cerr << "    " << point.x << " "<< point.y << " "<< point.z << std::endl;pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);pcl::PointIndices::Ptr inliers (new pcl::PointIndices);// Create the segmentation objectpcl::SACSegmentation<pcl::PointXYZ> seg;// Optionalseg.setOptimizeCoefficients (true);// Mandatoryseg.setModelType (pcl::SACMODEL_PLANE);seg.setMethodType (pcl::SAC_RANSAC);seg.setDistanceThreshold (0.01);seg.setInputCloud (cloud);seg.segment (*inliers, *coefficients);if (inliers->indices.size () == 0){PCL_ERROR ("Could not estimate a planar model for the given dataset.\n");return (-1);}std::cerr << "Model coefficients: " << coefficients->values[0] << " " << coefficients->values[1] << " "<< coefficients->values[2] << " " << coefficients->values[3] << std::endl;std::cerr << "Model inliers: " << inliers->indices.size () << std::endl;for (const auto& idx: inliers->indices)std::cerr << idx << "    " << cloud->points[idx].x << " "<< cloud->points[idx].y << " "<< cloud->points[idx].z << std::endl;return (0);
}

2.2 CMakeLists.txt

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)project(planar_segmentation)find_package(PCL 1.2 REQUIRED)include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})add_executable (${PROJECT_NAME} planar_segmentation.cpp)
target_link_libraries (${PROJECT_NAME} ${PCL_LIBRARIES})

3、运行结果

  • 编译运行
mkdir build && cd build
cmake ..
make
./planar_segmentation
  • 运行结果
    在这里插入图片描述
  • 分割过程的图形显示如下(代码中未写可视化,这个只是补充说明)
    在这里插入图片描述

4、核心代码解读

这段代码使用PCL库进行平面模型分割,核心是通过RANSAC算法从点云数据中提取平面:


1. 创建分割对象
pcl::SACSegmentation<pcl::PointXYZ> seg;
  • 创建了一个SACSegmentation对象seg,用于执行基于采样一致性(Sample Consensus, SAC)的分割。
  • 模板参数pcl::PointXYZ表示点云中的点类型为三维点(包含x, y, z坐标)。

2. 设置优化系数(可选)
seg.setOptimizeCoefficients(true);
  • 这是一个可选设置,用于优化模型系数。
  • 如果设置为true,分割算法会在找到初始模型后进一步优化平面模型的系数(如平面的法向量和截距),以提高精度。

3. 设置模型类型(必选)
seg.setModelType(pcl::SACMODEL_PLANE);
  • 设置分割的模型类型为平面模型(SACMODEL_PLANE)。
  • 这意味着算法将尝试从点云中拟合一个平面。

4. 设置方法类型(必选)
seg.setMethodType(pcl::SAC_RANSAC);
  • 设置分割方法为RANSAC(Random Sample Consensus)。
  • RANSAC是一种鲁棒的拟合算法,能够有效处理噪声和离群点。它通过随机采样点来拟合模型,并选择内点(符合模型的点)最多的模型。

5. 设置距离阈值(必选)
seg.setDistanceThreshold(0.01);
  • 设置点到模型的最大距离阈值,用于判断点是否为内点。
  • 如果一个点到拟合平面的距离小于0.01(单位与点云数据一致),则该点被视为内点。
  • 这个值需要根据点云的尺度调整,值越小,拟合的平面越精确,但可能遗漏一些点;值越大,拟合的平面可能不够精确。

6. 设置输入点云
seg.setInputCloud(cloud);
  • 将待分割的点云数据cloud设置为分割对象的输入。
  • cloud是一个pcl::PointCloud<pcl::PointXYZ>::Ptr类型的指针,指向点云数据。

7. 执行分割
seg.segment(*inliers, *coefficients);
  • 执行分割操作。
  • inliers是一个pcl::PointIndices::Ptr类型的指针,用于存储分割结果中的内点(即属于平面的点)的索引。
  • coefficients是一个pcl::ModelCoefficients::Ptr类型的指针,用于存储拟合平面的模型系数(平面方程ax + by + cz + d = 0的系数a, b, c, d)。

总结

这段代码的核心是通过RANSAC算法从点云中提取平面:

  1. 创建一个分割对象。
  2. 设置平面模型和RANSAC方法。
  3. 设置距离阈值以判断内点。
  4. 输入点云数据并执行分割。
  5. 输出内点索引和平面模型系数。
输出结果
  • inliers:包含所有属于平面的点的索引。
  • coefficients:包含平面方程的系数(a, b, c, d),表示平面方程ax + by + cz + d = 0

如果点云中没有找到平面,inliers->indices将为空。


http://www.ppmy.cn/news/1564233.html

相关文章

【2025 Rust学习 --- 18 IO操作和网络】

输入与输出 Rust 标准库中的输入和输出的特性是围绕 3 个特型组织的&#xff0c;即 Read、 BufRead 和 Write。 实现了 Read 的值具有面向字节的输入方法。它们叫作读取器。实现了 BufRead 的值是缓冲读取器。它是 Read的子特型 &#xff0c;外加读取文本行等方法。实现了 Wr…

Java连接TDengine和MySQL双数据源

git文件地址&#xff1a;项目首页 - SpringBoot连接TDengine和MySQL双数据源:SpringBoot连接TDengine和MySQL双数据源 - GitCode 1、yml配置 spring:datasource:druid:mysql:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/testusername: roo…

【CSS】 ---- CSS 实现图片随鼠标移动局部放大特效

1. 效果【京东商品放大特效】 2. 实现方法 2.1 JS 实现 创建原图片的盒子&#xff0c;并放入原图片&#xff1b;创建需要放大区域的遮罩块&#xff1b;创建显示放大后图片显示的盒子和盒子内放大的图片&#xff1b;给原图绑定移出移入和鼠标移动的监听事件&#xff1b;移入和…

【华为OD-E卷 - 数组连续和 100分(python、java、c++、js、c)】

【华为OD-E卷 - 数组连续和 100分&#xff08;python、java、c、js、c&#xff09;】 题目 给定一个含有N个正整数的数组, 求出有多少个连续区间&#xff08;包括单个正整数&#xff09;, 它们的和大于等于x 输入描述 第一行两个整数N x&#xff08;0 < N < 100000, …

Centos 宝塔安装

yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh 安装成功界面 宝塔说明文档 https://www.bt.cn/admin/servers#wcu 或者可以注册宝塔账号 1 快速部署 安装docker 之后 2 需要在usr/bin下下载do…

5 分钟复刻你的声音,一键实现 GPT-Sovits 模型部署

想象一下&#xff0c;只需简单几步操作&#xff0c;就能生成逼真的语音效果&#xff0c;无论是为客户服务还是为游戏角色配音&#xff0c;都能轻松实现。GPT-Sovits 模型&#xff0c;其高效的语音生成能力为实现自然、流畅的语音交互提供了强有力的技术支持。本文将详细介绍如何…

C++实现设计模式---迭代器模式 (Iterator)

迭代器模式 (Iterator) 迭代器模式 是一种行为型设计模式&#xff0c;它提供了一种方法&#xff0c;顺序访问一个聚合对象中的各个元素&#xff0c;而又不需要暴露该对象的内部表示。 意图 提供一种方法&#xff0c;可以顺序访问一个容器对象中的元素&#xff0c;而无需暴露其…

MyBatis缓存原理及插件实现

目录 MyBatis缓存原理 缓存的工作机制 一级缓存&#xff1a; 二级缓存&#xff1a; MyBatis插件实现 MyBatis缓存原理 缓存的工作机制 如果会话查询了一条数据&#xff0c;此数据会存入一级缓存&#xff1b;若会话被关闭或提交&#xff0c;则&#xff0c;其数据转存入二级缓…