pcl库实现点云带索引/编号,统计滤波后能看到过滤点云的索引/编号

c++内的pcl库想实现一个功能,原始点云是带索引或者编号的(实现带索引或者编号其一功能即可。编号不是1,2,3,4,5这种一一排序的,可能是11,34,66这种跳跃的。能实现编号功能最好,方便后期定位查找),通过统计滤波后想知道哪些索引或者编号的点是被过滤掉的,可以直接定位这些过滤掉的点的编号。但是pcl自带库似乎是只传出点云数据,但是编号是不传出的,想实现也能传出编号功能。

由于刚接触c++内的pcl库功能,有很多不太了解的功能代码书写,还望细致解答,谢谢!

以下回答结合了ChatGPT:
您好!关于您的问题,如果您想在 PCL 中实现带索引或编号的点云功能,可以使用 PCL 中的 PointXYZRGBL 或 PointXYZIL 类型。这两种类型都包含了一个字段,可以用于存储点的索引或编号。

例如,您可以使用 PointCloud 类型来表示一个带有 RGB 颜色和索引的点云:


#include <pcl/point_types.h>
#include <pcl/point_cloud.h>

typedef pcl::PointXYZRGBL PointT;
typedef pcl::PointCloud<PointT> PointCloud;

PointCloud::Ptr cloud (new PointCloud);
// ... 添加点到点云中 ...

// 读取第一个点的索引
uint32_t index = cloud->points[0].label;

同样,使用 PointXYZIL 类型也类似:


#include <pcl/point_types.h>
#include <pcl/point_cloud.h>

typedef pcl::PointXYZIL PointT;
typedef pcl::PointCloud<PointT> PointCloud;

PointCloud::Ptr cloud (new PointCloud);
// ... 添加点到点云中 ...

// 读取第一个点的编号
uint32_t id = cloud->points[0].label;

注意,如果您使用 PointCloud 类型来表示点云,则必须为每个点手动设置索引或编号。这可以通过将字段设置为 PointCloud 中每个点的 label 字段来完成。

希望这可以帮助到您!如果您有任何其他问题,请随时问我。

以下答案来自chatgpt,有用的话,给个采纳吧
在 PCL 中,点云可以通过 pcl::PointCloud 来表示,每个点可以使用 pcl::PointXYZ,pcl::PointXYZRGB,pcl::PointXYZRGBA 等类型来存储。这些点类型都是结构体,可以在结构体中添加自定义的属性,例如编号。下面是一个添加编号属性的示例代码:


#include <iostream>
#include <pcl/point_types.h>
#include <pcl/filters/statistical_outlier_removal.h>

int main() {
    // 定义点云类型,包含 x、y、z 和 index 四个属性
    struct PointXYZIndex {
        PCL_ADD_POINT4D;
        int index;
        EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
    } EIGEN_ALIGN16;
    POINT_CLOUD_REGISTER_POINT_STRUCT(PointXYZIndex, (float, x, x)(float, y, y)(float, z, z)(int, index, index))

    // 创建点云
    pcl::PointCloud<PointXYZIndex>::Ptr cloud(new pcl::PointCloud<PointXYZIndex>);
    cloud->width = 5;
    cloud->height = 1;
    cloud->is_dense = false;
    cloud->points.resize(cloud->width * cloud->height);

    // 给点云赋值
    for (size_t i = 0; i < cloud->points.size(); ++i) {
        cloud->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);
        cloud->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);
        cloud->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
        cloud->points[i].index = i * 2;
    }

    // 执行统计滤波
    pcl::StatisticalOutlierRemoval<PointXYZIndex> sor;
    sor.setInputCloud(cloud);
    sor.setMeanK(50);
    sor.setStddevMulThresh(1.0);
    sor.filter(*cloud);

    // 输出被过滤掉的点的编号
    std::cout << "Filtered out points' indices: ";
    for (size_t i = 0; i < cloud->points.size(); ++i) {
        if (pcl::isFinite(cloud->points[i])) continue;
        std::cout << cloud->points[i].index << " ";
    }
    std::cout << std::endl;

    return 0;
}

在这个示例中,我们定义了一个新的点类型 PointXYZIndex,并在其中添加了一个名为 index 的属性。在主函数中,我们创建了一个点云并给每个点随机赋值一个编号。接着,我们使用 pcl::StatisticalOutlierRemoval 对点云进行了统计滤波。最后,我们输出了被过滤掉的点的编号。

以下内容部分参考ChatGPT模型:


首先,在pcl库中,点云数据是通过PointCloud类来表示的,该类中有一个points属性,存储了点云中所有的点,但是并没有提供编号或索引的支持。为了实现这个功能,我们可以考虑自定义一个新的类,继承自PointCloud类,并添加编号或索引属性。具体实现如下:

#include <pcl/point_cloud.h>
#include <pcl/point_types.h>

template <typename PointT>
class IndexedPointCloud : public pcl::PointCloud<PointT>
{
public:
    struct PointIndex
    {
        PointT point;
        int index;
    };

    std::vector<PointIndex> indexed_points_;

    void push_back(const PointT& point, int index)
    {
        pcl::PointCloud<PointT>::push_back(point);
        PointIndex indexed_point;
        indexed_point.point = point;
        indexed_point.index = index;
        indexed_points_.push_back(indexed_point);
    }
};

在这个类中,我们添加了一个indexed_points_属性,用于存储带编号或索引的点云数据。同时,我们重载了push_back方法,使得每次向点云中添加一个新的点时,都能够同时添加对应的编号或索引。

接下来,我们考虑如何实现统计滤波后查看被过滤掉的点的编号或索引。pcl库中提供了StatisticalOutlierRemoval类来实现统计滤波功能,该类的filter函数可以将被过滤掉的点存储在indices属性中。因此,我们可以在使用StatisticalOutlierRemoval类进行滤波时,将原始点云中的编号或索引信息一并存储在indices属性中,从而实现统计滤波后查看被过滤掉的点的编号或索引。具体实现如下:

#include <pcl/filters/statistical_outlier_removal.h>

int main()
{
    // 创建带编号的点云数据
    IndexedPointCloud<pcl::PointXYZ> cloud;
    for (int i = 0; i < 100; ++i)
    {
        pcl::PointXYZ point;
        point.x = static_cast<float>(rand()) / RAND_MAX;
        point.y = static_cast<float>(rand()) / RAND_MAX;
        point.z = static_cast<float>(rand()) / RAND_MAX;
        cloud.push_back(point, i);
    }

    // 创建统计滤波器
    pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
    sor.setInputCloud(cloud.makeShared());
    sor.setMeanK(50);
    sor.setStddevMulThresh(1.0);

    // 执行统计滤波
    pcl::PointCloud<pcl::PointXYZ>::Ptr filtered_cloud(new pcl::PointCloud<pcl::PointXYZ>);
    std::vector<int> indices;
    sor.filter(*filtered_cloud);
    sor.getRemovedIndices(indices);

    // 输出被过滤掉的点的编号
    std::cout << "Removed indices: ";
    for (int i = 0; i < indices.size(); ++i)
    {
        std::cout << cloud.indexed_points_[indices[i]].index << " ";
    }
    std::cout << std::endl;

    return 0;
}

在这个例子中,我们创建了一个带编号的点云数据,并使用StatisticalOutlierRemoval类进行统计滤波。在执行filter函数后,我们调用getRemovedIndices函数获取被过滤掉的点的索引,并通过indexed_points_属性获取对应的编号信息,最终输出被过滤掉的点的编号。


如果我的建议对您有帮助、请点击采纳、祝您生活愉快

要实现带有编号或索引的点云,并在滤波后定位被过滤掉的点的编号,可以在定义点云结构体时加入一个索引或编号字段。比如可以在pcl::PointXYZ结构体中增加一个int类型的id字段,表示该点在原始点云中的编号或索引:

struct PointXYZID
{
   PCL_ADD_POINT4D;                  // 添加PCL定义的点云数据的x、y、z坐标
   int id;                           // 点的编号或索引
   EIGEN_MAKE_ALIGNED_OPERATOR_NEW   // 向量的内存对齐
} EIGEN_ALIGN16;

POINT_CLOUD_REGISTER_POINT_STRUCT(PointXYZID,
                                  (float, x, x)
                                  (float, y, y)
                                  (float, z, z)
                                  (int, id, id))

加载原始点云时,需要将点云中每个点的编号或索引读入,并保存在该点的id字段中。可以使用pcl::io::loadPCDFile函数读取带有id字段的点云文件,也可以使用pcl::PointCloud<PointXYZID>结构体来手动添加点并赋予编号或索引:

pcl::PointCloud<PointXYZID>::Ptr cloud_with_id(new pcl::PointCloud<PointXYZID>);
for (int i = 0; i < cloud->size(); i++)
{
    PointXYZID point;
    point.x = cloud->points[i].x;
    point.y = cloud->points[i].y;
    point.z = cloud->points[i].z;
    // 将原始点云的编号或索引赋值给point的id字段
    point.id = i;
    cloud_with_id->push_back(point);
}

然后进行滤波操作。在统计滤波后,可以将被过滤掉的点的编号或索引保存到一个容器中(如vector),以便后期查询。可以通过遍历滤波后的点云,将点的id字段添加到该容器中,代码示例:

pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
sor.setInputCloud(cloud);
sor.setMeanK(50);
sor.setStddevMulThresh(1.0);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
sor.filter(*cloud_filtered);

// 保存被滤掉的点的编号或索引
std::vector<int> removed_point_indices;
pcl::PointCloud<PointXYZID>::Ptr cloud_with_id_filtered(new pcl::PointCloud<PointXYZID>);
for (int i = 0; i < cloud_filtered->size(); i++)
{
    bool found = false;
    // 遍历带有编号或索引的滤波前点云,查找哪些点被过滤掉了
    for (int j = 0; j < cloud_with_id->size(); j++)
    {
        // 如果该点在滤波前点云中被保留下来,但在滤波后被过滤掉了,则将其编号保存
        if (cloud_with_id->points[j].x == cloud_filtered->points[i].x &&
            cloud_with_id->points[j].y == cloud_filtered->points[i].y &&
            cloud_with_id->points[j].z == cloud_filtered->points[i].z)
        {
            found = true;
            break;
        }
    }
    if (!found)
    {
        removed_point_indices.push_back(cloud_with_id->points[i].id);
    }

    pcl::PointXYZ point;
    point.x = cloud_filtered->points[i].x;
    point.y = cloud_filtered->points[i].y;
    point.z = cloud_filtered->points[i].z;
    cloud_with_id_filtered->push_back(PointXYZID(point.x, point.y, point.z, cloud_with_id->points[i].id));
}

在上述代码中,使用两个点云结构体,一个是带有编号或索引的滤波前点云cloud_with_id,另一个是不带编号或索引的滤波后点云cloud_filtered。在遍历滤波后的点云时,通过遍历滤波前的点云来查找哪些点被过滤掉了,并将其编号保存在removed_point_indices容器中。最后将被过滤掉的点的编号或索引作为返回值,供后续使用:

return removed_point_indices;

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
可以使用pcl::PointCloud<pcl::PointXYZ>来创建一个带索引的点云数据结构,其中pcl::PointXYZ表示只有XYZ坐标的点。同时,还需要使用pcl::PointIndices来存储过滤掉的点的索引或编号。

具体实现如下:

  1. 定义一个带编号的点云数据结构pcl::PointCloud<pcl::PointXYZI>,其中pcl::PointXYZI表示除了XYZ坐标还有一个Intensity成员变量,用于存储点的编号。例如,可以将点云中每个点的Index放到Intensity中。
typedef pcl::PointXYZI PointType;
typedef pcl::PointCloud<PointType> PointCloudType;
  1. 读取点云数据及其编号,并将其存储到定义的带编号的点云结构体中。
PointCloudType::Ptr cloud(new PointCloudType);
pcl::PCDReader reader;
reader.read("input.pcd", *cloud);

// 将点云中的Index存储到Intensity中
for (size_t i = 0; i < cloud->size(); ++i) {
  cloud->points[i].intensity = i;  // 示例中将索引作为编号
}
  1. 执行统计滤波操作,并将过滤掉的点的索引或编号存储到pcl::PointIndices中。
pcl::StatisticalOutlierRemoval<PointType> sor;
sor.setInputCloud(cloud);
sor.setMeanK(50);  // 设置K值
sor.setStddevMulThresh(1.0);
PointCloudType::Ptr filtered_cloud(new PointCloudType);
sor.filter(*filtered_cloud);

// 存储过滤掉的点的索引或编号
pcl::IndicesPtr indices(new std::vector<int>);
sor.getRemovedIndices(*indices);
pcl::PointIndices::Ptr removed_indices(new pcl::PointIndices);
removed_indices->indices = *indices;
  1. 访问过滤掉的点的索引或编号,并根据需要进行操作。
for (size_t i = 0; i < removed_indices->indices.size(); ++i) {
  int removed_index = removed_indices->indices[i];
  std::cout << "Removed point index: " << removed_index << std::endl;
  // 根据需要对过滤掉的点进行操作,比如删除对应的原始点
}

完整代码如下:

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/statistical_outlier_removal.h>

typedef pcl::PointXYZI PointType;
typedef pcl::PointCloud<PointType> PointCloudType;

int main() {
  // 1. 定义带编号的点云结构体
  PointCloudType::Ptr cloud(new PointCloudType);
  pcl::PCDReader reader;
  reader.read("input.pcd", *cloud);

  // 将点云中的Index存储到Intensity中
  for (size_t i = 0; i < cloud->size(); ++i) {
    cloud->points[i].intensity = i;  // 示例中将索引作为编号
  }

  // 2. 执行统计滤波操作
  pcl::StatisticalOutlierRemoval<PointType> sor;
  sor.setInputCloud(cloud);
  sor.setMeanK(50);  // 设置K值
  sor.setStddevMulThresh(1.0);
  PointCloudType::Ptr filtered_cloud(new PointCloudType);
  sor.filter(*filtered_cloud);

  // 3. 存储过滤掉的点的索引或编号
  pcl::IndicesPtr indices(new std::vector<int>);
  sor.getRemovedIndices(*indices);
  pcl::PointIndices::Ptr removed_indices(new pcl::PointIndices);
  removed_indices->indices = *indices;

  // 4. 访问过滤掉的点的索引或编号,并根据需要进行操作
  for (size_t i = 0; i < removed_indices->indices.size(); ++i) {
    int removed_index = removed_indices->indices[i];
    std::cout << "Removed point index: " << removed_index << std::endl;
    // 根据需要对过滤掉的点进行操作,比如删除对应的原始点
  }

  return 0;
}

如果我的回答解决了您的问题,请采纳!

引用chatGPT作答,在 PCL 中,每个点都是一个数据结构体,可以通过定义一个新的数据结构体来存储原始点云中每个点的编号信息。在统计滤波之前,可以将点云数据和点的编号信息都存储在这个新的数据结构体中,然后进行滤波操作。

在滤波之后,可以通过比较滤波前后两个数据结构体的差异来确定哪些点被过滤掉了,并且可以直接定位这些被过滤掉的点的编号信息。

下面是一个示例代码:

#include <pcl/point_types.h>
#include <pcl/filters/statistical_outlier_removal.h>

// 定义新的数据结构体,包含点云数据和点的编号信息
struct PointWithIndex
{
  PCL_ADD_POINT4D;
  int index;
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
} EIGEN_ALIGN16;

POINT_CLOUD_REGISTER_POINT_STRUCT(PointWithIndex,           // 定义新的点数据结构体
                                  (float, x, x)
                                  (float, y, y)
                                  (float, z, z)
                                  (int, index, index))

int main ()
{
  // 定义原始点云数据和点的编号信息
  pcl::PointCloud<PointWithIndex>::Ptr cloud (new pcl::PointCloud<PointWithIndex>);
  // 填充点云数据和点的编号信息

  // 定义统计滤波器
  pcl::StatisticalOutlierRemoval<PointWithIndex> sor;
  sor.setInputCloud (cloud);
  sor.setMeanK (50);
  sor.setStddevMulThresh (1.0);

  // 执行统计滤波
  pcl::PointCloud<PointWithIndex>::Ptr cloud_filtered (new pcl::PointCloud<PointWithIndex>);
  sor.filter (*cloud_filtered);

  // 比较滤波前后两个数据结构体的差异,找到被过滤掉的点的编号信息
  std::vector<int> filtered_indices;
  pcl::PointIndices::Ptr indices = sor.getRemovedIndices ();
  for (size_t i = 0; i < indices->indices.size (); ++i)
  {
    filtered_indices.push_back (cloud->points[indices->indices[i]].index);
  }

  // 处理被过滤掉的点的编号信息
  // ...
  
  return (0);
}

需要注意的是,需要在点数据结构体中定义点的编号信息,并且在存储原始点云数据和点的编号信息时,需要将点数据类型设置为新定义的点数据结构体。在滤波之后,可以通过 getRemovedIndices() 方法获取被过滤掉的点的索引信息,然后通过索引信息来获取点的编号信息。

不知道你这个问题是否已经解决, 如果还没有解决的话:

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^