PCL 1.12.1版本中过滤移除RGB(255,0,0)红色点云失败的问题求助
解决PCL移除红色点云失败的问题
我看了你的代码和问题描述,你遇到的过滤后点云为空的问题主要有两个原因,咱们一步步来解决:
问题分析
- 过滤逻辑搞反了:
pcl::ConditionalRemoval默认行为是保留满足条件的点,但你的需求是移除RGB(255,0,0)的红色点,所以需要反转过滤规则。 - 字段类型不匹配:
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




