使用 PCL 和 RANSAC 进行墙壁检测
Posted
技术标签:
【中文标题】使用 PCL 和 RANSAC 进行墙壁检测【英文标题】:Wall detection using PCL and RANSAC 【发布时间】:2020-11-23 23:30:40 【问题描述】:我一直在使用 PCL(点云库)在 PCD(点云数据)文件中进行墙壁检测。 PCD 文件是通过深度相机生成的。我发现在许多类似的应用程序中,例如地板检测,已使用RANSAC。所以,我也想在这里申请 RANSAC,我尽我所能理解 RANSAC,但我仍然有一些与我的申请有关的问题:
简而言之,RANSAC 尝试移除给定数据中的异常值,并通过模型迭代地概括这些异常值。那么,在地板检测的情况下,是否会将与其他对象对应的其余点云视为异常值而将地板视为内部点?墙壁也是这样吗?
根据 PCL 的Plane model segmentation tutorial,RANSAC 在平面方程中给出模型平面的系数,即a
、b
、c
和d
:a*x + b*y + c*z + d = 0
到coefficients->values
向量。所以,我假设在墙壁检测的情况下,它会尝试给出对应于墙壁的平面方程。但是,如果深度相机位于房间的角落并且墙壁的顶视图如下所示:
墙 1 _____________ | | |墙 2 | |
那么,在这种情况下,最终的模型飞机会是什么样子?它会是一种斜边(做一个三角形)吗?
墙 1 --------------------- | |墙 2 | ---------------------- 墙3
即使在这种情况下,它会是什么样子?
根据 PCL 的Extracting indices from a PointCloud tutorial,ExtractIndices <pcl::ExtractIndices>
过滤器用于根据分割算法输出的索引从点云中提取点的子集。但是,这个过滤器到底在做什么?事实上,在地板检测或墙壁检测的情况下(假设只有一面直墙),RANSAC 已经给出了一个平面的方程。那么,是否需要使用该过滤器?如果是,那么为什么以及如何?
在以下情况下如何检测多面墙? ExtractIndices <pcl::ExtractIndices>
过滤器可以这样做吗?如果是那怎么办?
墙 1 --------------------- | |墙 2 | ---------------------- 墙 3
如果您认为有比使用 RANSAC 更好的方法,也请告诉我。
【问题讨论】:
【参考方案1】:回答您提出的几个问题:
据我所知,在使用平面模型的情况下,RANSAC 会从云中随机选择 3 个点,并将其视为一个平面。(这是一个暂定声明,稍后将予以证实)所有更接近的点对于这个平面,作为垂直距离的给定阈值被视为内点。 该算法返回其中包含最多点的平面(找到的平面还取决于您选择的迭代次数,如果它太低可能会错过最大的平面)。 在墙壁的情况下,故事是一样的。您可以搜索飞机,但应选择好搜索方向。墙壁随意垂直于平面 x-y。考虑到这一点,应设置参数。 示例:
pcl::SACSegmentation<pcl::PointXYZI> seg;
Eigen::Vector3f axis;
//HELPER VARIABLES
float angle = 12.0;
void set_segmentation(float threshold, int max_iteration, float probability)
seg.setModelType(pcl::SACMODEL_PERPENDICULAR_PLANE);
seg.setMethodType(pcl::SAC_RANSAC);
// set cloud, threshold, and other paramatres
seg.setDistanceThreshold(threshold);//Distance need to be adjusted according
to the obj
seg.setMaxIterations(max_iteration);
seg.setProbability(probability);
PlaneSegment(float x, float y, float z, float set_angle, float threshold, int
max_iteration, float probability)
axis = Eigen::Vector3f(x, y, z);
angle = set_angle;
seg.setAxis(axis);
seg.setEpsAngle(angle * (3.1415 / 180.0f));
//SET SEGMENTATION
set_segmentation(threshold, max_iteration, probability);
pcl::PointIndices::Ptr segment_plane(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud,
pcl::PointIndices::Ptr inliers)
seg.setInputCloud(cloud);
seg.segment(*inliers, *coefficients);
if (inliers->indices.size() == 0)
PCL_ERROR("COULD NOT ESTIMATE PLANAR MODEL.\n");
exit(-1);
return inliers;
pcl::PointCloud<pcl::PointXYZI>::Ptr
extraction(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, pcl::PointIndices::Ptr
inliers)
extract.setInputCloud(cloud);
extract.setIndices(inliers);
extract.setNegative(true);
extract.filter(*cloud);
return cloud;
您可以设置接受角度,在本例中为 12 度,以及基于轴的搜索方向。
第二点:
如果有多个墙,它将返回包含最多点的墙。但是如果需要,您也应该能够提取其他平面。 (建议,保存所有包含比您选择的阈值更多的点的平面) 我检查了你的问题,这也是一个解决方案:pcl::RANSAC segmentation, get all planes in cloud?。第一条评论给出了很好的答案。
第三点:
检查示例代码。请注意,这是一个类,所以这就是为什么有一个构造函数。 segment_plane 函数返回内点。基于此,您可以调用提取函数,它会从云中删除内点。这是一个非常简单和快速的灵魂。您可以避免使用系数值的痛苦。此外,如果您不想删除它们,只需通过迭代内点为它们着色并将其强度设置为所选值。
RANSAC 算法可以很强大,但有时它真的不起作用。由于迭代次数,它也可能很慢。 有多种方法可以通过另一种方式解决这个问题。 只是一个例子:考虑云下的网格。许多大小相等的方形单元格。在每个单元格中,您检查最小和最大点高度。基于此,您可以获得地平面(如果这些值略有不同,并且彼此接近。在地面单元的情况下,最大高度和最小高度的差异非常小)或墙壁。对于墙壁,您可以假设这些点在每个单元格中分布均匀,并且最大值 - 最小值的差异很大。 最好的问候。
【讨论】:
以上是关于使用 PCL 和 RANSAC 进行墙壁检测的主要内容,如果未能解决你的问题,请参考以下文章
(转载)利用SIFT和RANSAC算法(openCV框架)实现物体的检测与定位,并求出变换矩阵(findFundamentalMat和findHomography的比较) 置顶