今天调个程序,需要对一个点云进行下采样处理,本来很简单的事情,但是总在函数退出的时候出现Segmentation fault
,之前是将其独立编译为一个二进制文件,下采样后的点云保存后再退出。这样就算出错也没事,反正数据出来了我哪管bug洪水滔天 😎。
但是在数据量比较大的需求中,这个下采样功能就不能再独立为二进制文件了,因此我不得不修复这个问题。花费了好久终于把这个问题修复了。这个问题就是PCL的问题,只能是利用另一种方式绕过这个bug,得到的结果是一样的,这个放心。现在我把问题及解决方案整理如下
问题引出
简单来说,我需要对一个点云进行下采样,cloudin
是原始点云,cloudout
是下采样后的点云,关键函数摘出来如下所示:
void downscale(pcl::PointCloud<pcl::PointXYZ>::Ptr cloudin, float leafsize,pcl::PointCloud<pcl::PointXYZ>::Ptr cloudout)
{LOG(INFO) << "cloudin size: " << cloudin->points.size();pcl::VoxelGrid<pcl::PointXYZ> downSizeFilterCorner;downSizeFilterCorner.setLeafSize(leafsize, leafsize, leafsize);downSizeFilterCorner.setInputCloud(cloudin);downSizeFilterCorner.filter(*cloudout);LOG(INFO) << "cloudout size: " << cloudout->points.size();
}
执行后,代码输入如下所示,整体功能都能运行,但是在结束,进行内存释放时候,出现了Segmentation fault (core dumped)
。
I0628 test_pclVoxelGrid.cpp] cloudin size: 473300
I0628 test_pclVoxelGrid.cpp] cloudout size: 19180
Segmentation fault (core dumped)
问题分析
利用valgrind
工具进行内存检查valgrind --tool=memcheck --leak-check=full --show-reachable=yes ./build/test_pclVoxelGrid
,代码中存在内存溢出问题。
==21349== 306,880 bytes in 1 blocks are definitely lost in loss record 249 of 249
==21349== at 0x4C330B5: malloc (vg_replace_malloc.c:431)
==21349== by 0x5AF1A88: Eigen::internal::aligned_malloc(unsigned long) (in /usr/lib/x86_64-linux-gnu/libpcl_filters.so.1.8.1)
==21349== by 0x5B057D0: std::vector<pcl::PointXYZ, Eigen::aligned_allocator<pcl::PointXYZ> >::_M_default_append(unsigned long) (in /usr/lib/x86_64-linux-gnu/libpcl_filters.so.1.8.1)
==21349== by 0x5CE4D28: pcl::VoxelGrid<pcl::PointXYZ>::applyFilter(pcl::PointCloud<pcl::PointXYZ>&) (in /usr/lib/x86_64-linux-gnu/libpcl_filters.so.1.8.1)
==21349== by 0x1218CC: pcl::Filter<pcl::PointXYZ>::filter(pcl::PointCloud<pcl::PointXYZ>&) (in test_pclVoxelGrid)
==21349== by 0x118127: main (in test_pclVoxelGrid)
==21349==
==21349== LEAK SUMMARY:
==21349== definitely lost: 306,880 bytes in 1 blocks
==21349== indirectly lost: 0 bytes in 0 blocks
==21349== possibly lost: 0 bytes in 0 blocks
==21349== still reachable: 81,172 bytes in 1,006 blocks
==21349== suppressed: 0 bytes in 0 blocks
==21349==
==21349== For lists of detected and suppressed errors, rerun with: -s
==21349== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
在gg上搜了一大圈,大部分给出的建议是取消"c++11",或者用"c++11"重新编译下自己使用的PCL库,但这些都不现实,终于在《Segmentation fault when deallocating pcl::PointCloud》找到了解决办法。
将pcl::PointCloud<pcl::PointXYZ>
转为pcl::PCLPointCloud2
后下采样,然后再还原为原始格式点云,就可以规避这个问题了。
解决方案
前面的downscale
更换为如下代码
void downscale(pcl::PointCloud<pcl::PointXYZ>::Ptr cloudin, float leafsize,pcl::PointCloud<pcl::PointXYZ>::Ptr cloudout)
{pcl::PCLPointCloud2::Ptr tmpcloud(new pcl::PCLPointCloud2());pcl::PCLPointCloud2::Ptr cloud_filtered(new pcl::PCLPointCloud2());LOG(INFO) << "cloudin size: " << cloud->points.size();pcl::toPCLPointCloud2(*cloudin, *tmpcloud);pcl::VoxelGrid<pcl::PCLPointCloud2> sor;sor.setInputCloud(tmpcloud);sor.setLeafSize(leafsize, leafsize, leafsize);sor.filter(*cloud_filtered);pcl::fromPCLPointCloud2(*cloud_filtered, *cloudout);LOG(INFO) << "cloudout size: " << cloudout->points.size();
}
执行后,代码输入如下所示,输出的结果是一样的,而且也没有前面的错误了,问题Solved 💪 。
I0628 test_pclVoxelGrid.cpp] cloudin size: 473300
I0628 test_pclVoxelGrid.cpp] cloudout size: 19180
终于干掉了这个Bug,请叫我铲B官😎 。