You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

PCL 1.12.1版本中过滤移除RGB(255,0,0)红色点云失败的问题求助

解决PCL移除红色点云失败的问题

我看了你的代码和问题描述,你遇到的过滤后点云为空的问题主要有两个原因,咱们一步步来解决:

问题分析

  1. 过滤逻辑搞反了pcl::ConditionalRemoval默认行为是保留满足条件的点,但你的需求是移除RGB(255,0,0)的红色点,所以需要反转过滤规则。
  2. 字段类型不匹配PointXYZRGB的r/g/b是unsigned char(uint8_t)类型,但你用的FieldComparison默认会把字段当作float处理,直接用浮点数255去匹配uint8_t的255会导致隐式转换问题,最终找不到符合条件的点,所以过滤后保留的点集为空。

解决方案一:修复ConditionalRemoval的实现

我们改用pcl::IntComparison来处理uint8_t类型的字段,同时设置setNegative(true)来移除符合条件的红色点:

#include <pcl/point_types.h>
#include <pcl/filters/conditional_removal.h>
#include <pcl/filters/intensity_filter.h> // 包含IntComparison的头文件

int main() {
  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZRGB>);
  cloud->width = 5;
  cloud->height = 1;
  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) / 1000;
    cloud->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f) / 1000;
    cloud->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f) / 1000;
    cloud->points[i].r = 110;
    cloud->points[i].g = 110;
    cloud->points[i].b = 110;
  }
  // 设置一个红色点
  cloud->points[2].r = 255;cloud->points[2].g = 0;cloud->points[2].b = 0;

  // 使用IntComparison处理uint8_t类型的RGB字段
  pcl::ConditionAnd<pcl::PointXYZRGB>::Ptr range_cond(new pcl::ConditionAnd<pcl::PointXYZRGB>());
  range_cond->addComparison(pcl::IntComparison<pcl::PointXYZRGB>::ConstPtr(
    new pcl::IntComparison<pcl::PointXYZRGB>("r", pcl::ComparisonOps::EQ, 255)));
  range_cond->addComparison(pcl::IntComparison<pcl::PointXYZRGB>::ConstPtr(
    new pcl::IntComparison<pcl::PointXYZRGB>("g", pcl::ComparisonOps::EQ, 0)));
  range_cond->addComparison(pcl::IntComparison<pcl::PointXYZRGB>::ConstPtr(
    new pcl::IntComparison<pcl::PointXYZRGB>("b", pcl::ComparisonOps::EQ, 0)));

  pcl::ConditionalRemoval<pcl::PointXYZRGB> condrem;
  condrem.setCondition(range_cond);
  condrem.setInputCloud(cloud);
  condrem.setKeepOrganized(true);
  // 关键:设置为true,移除满足条件的点(红色点)
  condrem.setNegative(true);
  condrem.filter(*cloud_filtered);

  // 输出结果
  std::cerr << "Cloud before filtering: " << std::endl;
  for (size_t i = 0; i < cloud->points.size(); ++i)
    std::cerr << " " << cloud->points[i].x << " " << cloud->points[i].y << " " << cloud->points[i].z 
              << " " << (int)cloud->points[i].r << " " << (int)cloud->points[i].g << " " << (int)cloud->points[i].b << std::endl;
  std::cerr << "Cloud after filtering: " << std::endl;
  for (size_t i = 0; i < cloud_filtered->points.size(); ++i)
    std::cerr << " " << cloud_filtered->points[i].x << " " << cloud_filtered->points[i].y << " " << cloud_filtered->points[i].z 
              << " " << (int)cloud_filtered->points[i].r << " " << (int)cloud_filtered->points[i].g << " " << (int)cloud_filtered->points[i].b << std::endl;
  return (0);
}

解决方案二:使用FilterIndices自定义过滤逻辑

如果觉得ConditionalRemoval的字段类型处理太麻烦,也可以用pcl::FilterIndices,自己写一个简单的判断函数,灵活性更高:

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

// 自定义过滤函数:返回true表示保留该点,false表示移除
bool isNotRed(const pcl::PointXYZRGB& point) {
  return !(point.r == 255 && point.g == 0 && point.b == 0);
}

int main() {
  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZRGB>);
  cloud->width = 5;
  cloud->height = 1;
  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) / 1000;
    cloud->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f) / 1000;
    cloud->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f) / 1000;
    cloud->points[i].r = 110;
    cloud->points[i].g = 110;
    cloud->points[i].b = 110;
  }
  // 设置一个红色点
  cloud->points[2].r = 255;cloud->points[2].g = 0;cloud->points[2].b = 0;

  pcl::FilterIndices<pcl::PointXYZRGB> filter;
  filter.setInputCloud(cloud);
  filter.setKeepOrganized(true);
  // 传入自定义过滤函数
  filter.filterIndices(*cloud_filtered, boost::bind(&isNotRed, _1));

  // 输出结果
  std::cerr << "Cloud before filtering: " << std::endl;
  for (size_t i = 0; i < cloud->points.size(); ++i)
    std::cerr << " " << cloud->points[i].x << " " << cloud->points[i].y << " " << cloud->points[i].z 
              << " " << (int)cloud->points[i].r << " " << (int)cloud->points[i].g << " " << (int)cloud->points[i].b << std::endl;
  std::cerr << "Cloud after filtering: " << std::endl;
  for (size_t i = 0; i < cloud_filtered->points.size(); ++i)
    std::cerr << " " << cloud_filtered->points[i].x << " " << cloud_filtered->points[i].y << " " << cloud_filtered->points[i].z 
              << " " << (int)cloud_filtered->points[i].r << " " << (int)cloud_filtered->points[i].g << " " << (int)cloud_filtered->points[i].b << std::endl;
  return (0);
}

这两种方法都能帮你正确移除RGB(255,0,0)的红色点,第二种方法因为是直接操作点的成员变量,完全避免了字段类型匹配的问题,推荐如果有复杂过滤逻辑的话使用。

内容的提问来源于stack exchange,提问作者DXnima

火山引擎 最新活动