【解决】illegal memory access in /pcl-pcl-1.9.0/gpu/octree/src/cuda/octree_builder.cu:403

【问题说明】

利用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的源代码并且重新安装一遍。可以一试。

至于还会不会有新坑,目前我还没发现。

 

【完】

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值