【问题说明】
利用pcl的gpu法线计算功能,"pcl::gpu::NormalEstimation",出现以下错误(已将输入点云去除了无效点 NaN,然后再进行法线计算):
Error: an illegal memory access was encountered .../pcl-pcl-1.9.0/gpu/octree/src/cuda/octree_builder.cu:403
【解决方案】
在github上找到了类似问题的帖子,以及解决方案。
直接上解决方案:https://github.com/PointCloudLibrary/pcl/pull/3627
然后是,其他相关帖子:
https://github.com/PointCloudLibrary/pcl/issues/2103
https://github.com/PointCloudLibrary/pcl/issues/2371
https://github.com/PointCloudLibrary/pcl/issues/3355
https://github.com/PointCloudLibrary/pcl/issues/2008
【备注】
以下是开发环境:
- 笔记本电脑,显卡为 GeForce 940MX, 环境 Ubuntu 16.04 + CUDA 9.0 + PCL 1.9.0
- 台式机电脑,显卡为 GeForce GTX 1070, 环境 Ubuntu 18.04 + CUDA 10.0 + PCL 1.9.0
以上两套环境下都运行了,同样的问题。解决后都好使了。
【再提供另外一种思路】
经过实验验证,确实是输入的点云数据中存在大量的 (0, 0, 0) 导致的。
验证很简单,可以在没问题的数据上(即上述运行正常的)push back一堆 (0, 0, 0) ,然后再运行,就会发生该错误。所以从这触出发,可以有以下解决办法:
点云的无效值,有些时候(某些相机)会定义为NaN,即 (nan, nan, nan),而另外一些时候(其他相机)会定义为 (0, 0, 0) 。从这个思路出发。将被定义为 (0, 0, 0) 的无效数据全部统一更改为 (nan, nan, nan) 即可。这样后续的法线计算部分无需更改,还是只需要先去除nan点,再用 "pcl::gpu::NormalEstimation" 计算即可。
简单地代码示例如下:
// 假设点云数据存放在 cv::Mat 矩阵中 (数据类型 CV_32FC3),命名为 pointCloud
// 将点云中 (0,0,0) 的数值 (相机获取的某些无效像素的数值) 统一更改为 (NaN,NaN,NaN)
for (int i = 0; i < pointCloud.rows * pointCloud.cols; i++)
{
if( std::abs(pointCloud.at<cv::Vec3f>(i)[0]) < 1e-6 &&
std::abs(pointCloud.at<cv::Vec3f>(i)[1]) < 1e-6 &&
std::abs(pointCloud.at<cv::Vec3f>(i)[2]) < 1e-6
)
{
pointCloud.at<cv::Vec3f>(i)[0] = std::numeric_limits<float>::quiet_NaN();
pointCloud.at<cv::Vec3f>(i)[1] = std::numeric_limits<float>::quiet_NaN();
pointCloud.at<cv::Vec3f>(i)[2] = std::numeric_limits<float>::quiet_NaN();
}
}
// 然后,当然,需要将 cv::Mat 矩阵中的数据转换成 pcl 格式的点云数据
// 另外,记得在法线计算前先去除 NaN 无效点数据,这可以通过 pcl 函数 pcl::removeNaNFromPointCloud(...) 来实现
上面之所以这么麻烦的,没有直接将 (0, 0, 0) 对应的点丢掉,而是转换成NaN,这是有用的。
有些场合,我们虽然在计算法线之前去除了NaN,但是法线计算后我们需要恢复NaN数据,也就是将法线结果与原来的点云数据对齐,这固然需要知道去除NaN前后的索引是多少。上面的pcl函数 pcl::removeNaNFromPointCloud() 恰好提供了这个功能,它会返回一个 std::vector<int> &index 来表示去除前后的索引。利用这个就可以很容易的处理了。
相反,如果自己直接将(0, 0, 0) 的点丢掉,那么还需要自己保存这种索引。有现成的为啥不用?
当然,如果没有这样的需求,直接丢弃 (0, 0, 0) 也是不错的选择。
目前就是这样,上面的方法经过了验证,可行。所以如果不想修改pcl的源代码并且重新安装一遍。可以一试。
至于还会不会有新坑,目前我还没发现。
【完】