当前位置:   article > 正文

PCL - 3D点云配准(registration)介绍_pcl点云配准

pcl点云配准

前面多篇博客都提到过,要善于从官网去熟悉一样东西。API部分详细介绍见

Point Cloud Library (PCL): Module registration

这里博主主要借鉴Tutorial里内容(博主整体都有看完)

Introduction — Point Cloud Library 0.0 documentation

接下来主要跑下Registration中的sample例子

一.直接运行下How to use iterative closet point中的代码(稍微做了变化,打印输出了Final点云)

  1. #include <iostream>
  2. #include <pcl/io/pcd_io.h>
  3. #include <pcl/point_types.h>
  4. #include <pcl/registration/icp.h>
  5. int main()
  6. {
  7. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>(5, 1));
  8. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_out(new pcl::PointCloud<pcl::PointXYZ>);
  9. // source->CloudIn data
  10. for (auto& point : *cloud_in)
  11. {
  12. point.x = 1024 * rand() / (RAND_MAX + 1.0f);
  13. point.y = 1024 * rand() / (RAND_MAX + 1.0f);
  14. point.z = 1024 * rand() / (RAND_MAX + 1.0f);
  15. }
  16. std::cout << "source->cloud_in:" << std::endl;
  17. for (auto& point : *cloud_in)
  18. std::cout << point << std::endl;
  19. std::cout << std::endl;
  20. //target->CloudOut data
  21. * cloud_out = *cloud_in;
  22. for (auto& point : *cloud_out)
  23. {
  24. point.x += 1.6f;
  25. point.y += 2.4f;
  26. point.z += 3.2f;
  27. }
  28. std::cout << "target->cloud_out:" << std::endl;
  29. for (auto& point : *cloud_out)
  30. std::cout << point << std::endl;
  31. std::cout << std::endl;
  32. pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;
  33. icp.setInputSource(cloud_in);
  34. icp.setInputTarget(cloud_out);
  35. //final->
  36. pcl::PointCloud<pcl::PointXYZ> Final;
  37. icp.align(Final);
  38. std::cout << "Final data points:" << std::endl;
  39. for (auto& point : Final)
  40. std::cout << point << std::endl;
  41. std::cout << std::endl;
  42. //transform info
  43. std::cout << "has converged:" << icp.hasConverged() << " score: " <<
  44. icp.getFitnessScore() << std::endl;
  45. std::cout << icp.getFinalTransformation() << std::endl;
  46. return (0);
  47. }

 输出结果如下:

 这里需要清楚的一点,是将源点云向目标点云对齐,让其变换到目标点云的样子。

从上面结果中也能够看出,输出的final点云数据是和target是非常近似的,也验证了上面的表述。同时也能够看到transform的信息也是对的。

这边在上面代码基础上增加设置迭代次数,部分代码如下

  1. //target->CloudOut data
  2. *cloud_out = *cloud_in;
  3. for (auto& point : *cloud_out)
  4. {
  5. point.x += 1.6f;
  6. point.y += 2.4f;
  7. point.z += 3.2f;
  8. }
  9. std::cout << "target->cloud_out:" << std::endl;
  10. for (auto& point : *cloud_out)
  11. std::cout << point << std::endl;
  12. std::cout << std::endl;
  13. pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;
  14. icp.setInputSource(cloud_in);
  15. icp.setInputTarget(cloud_out);
  16. std::cout << "default itera times: " << icp.getMaximumIterations() << std::endl;
  17. icp.setMaximumIterations(1);
  18. std::cout << "set itera times: " << icp.getMaximumIterations() << std::endl;
  19. std::cout << std::endl;
  20. //final->

可看到设为1时精度并没有迭代次数默认值为10高。

这边可以统计下对齐函数运行的时间,还是在上面代码的基础上

  1. //final->
  2. pcl::PointCloud<pcl::PointXYZ> Final;
  3. clock_t start = clock();
  4. icp.align(Final);
  5. clock_t end = clock();
  6. std::cout << end - start << " ms" << std::endl;
  7. std::cout << std::endl;

当迭代次数设为30时,耗时9ms.

 当迭代次数设为1时,耗时2ms

二. 这里改写下How to use iterative closest point中的代码,如下:

  1. // test_vtk63.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include <stdio.h>
  4. #include <tchar.h>
  5. #include "vtkAutoInit.h"
  6. //VTK_MODULE_INIT(vtkRenderingOpenGL2);
  7. //VTK_MODULE_INIT(vtkInteractionStyle);
  8. //#define vtkRenderingCore_AUTOINIT 2(vtkRenderingOpenGL2, vtkInteractionStyle)
  9. #include <boost/thread/thread.hpp>
  10. #include <pcl/visualization/cloud_viewer.h>
  11. #include <pcl/io/io.h>
  12. #include <pcl/io/pcd_io.h>//pcd 读写类相关的头文件。
  13. #include <pcl/PCLPointCloud2.h>
  14. #include <pcl/visualization/range_image_visualizer.h>
  15. #include <pcl/visualization/pcl_visualizer.h>
  16. #include <pcl/registration/icp.h>
  17. #include <iostream>
  18. using namespace pcl;
  19. using namespace pcl::io;
  20. using namespace std;
  21. int testpointcloudToPcd()
  22. {
  23. vtkObject::GlobalWarningDisplayOff();
  24. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>);
  25. char strfilepath[256] = "D:\\PCL\\rabbit.pcd";
  26. //第一种读入方法较多场合如此
  27. if (-1 == pcl::io::loadPCDFile(strfilepath, *cloud_in)) {
  28. cout << "error input!" << endl;
  29. return -1;
  30. }
  31. //输出源点云点坐标
  32. std::cout << "Saved " << cloud_in->size() << " data points to input:" << std::endl;
  33. //for (auto& point : *cloud_in)
  34. //std::cout << point << std::endl;
  35. //目标点云由输入点云来构造
  36. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_out(new pcl::PointCloud<pcl::PointXYZ>);
  37. *cloud_out = *cloud_in;
  38. std::cout << "size:" << cloud_out->size() << std::endl;
  39. for (auto& point : *cloud_out)
  40. {
  41. point.x += 0.7f;
  42. point.y += 0.7f;
  43. point.z += 1.0f;
  44. }
  45. //输出目标点云
  46. std::cout << "Transformed " << cloud_in->size() << " data points:" << std::endl;
  47. //for (auto& point : *cloud_out)
  48. //std::cout << point << std::endl;
  49. pcl::io::savePCDFileASCII("D:\\PCL\\rabbit_trans.pcd", *cloud_out);
  50. pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;
  51. icp.setInputSource(cloud_in);
  52. icp.setInputTarget(cloud_out);
  53. pcl::PointCloud<pcl::PointXYZ> Final;
  54. icp.align(Final);
  55. std::cout << "has converged:" << icp.hasConverged() << " score: " <<
  56. icp.getFitnessScore() << std::endl;
  57. std::cout << "Final data points size: " << Final.size() << std::endl;
  58. pcl::io::savePCDFileASCII("D:\\PCL\\Final.pcd", Final);
  59. //输出变换矩阵
  60. std::cout << icp.getFinalTransformation() << std::endl;
  61. }
  62. int _tmain(int argc, _TCHAR* argv[])
  63. {
  64. testpointcloudToPcd();
  65. return 0;
  66. }

 目标点云由输入点云变换得到,同时也保存到了本地,方便下次直接加载。运行结果如下:

理论上目标点云是由源点云x平移0.7,y平移0.7,z平移1获得。实际计算结果是如下矩阵的最后一列。和理论变换值还是有一些差距的。

 输入源点云,目标点云,Final点云的部分点坐标做了一个比较。可以看到源点云经过变换后,已经和目标点云很对齐了。

这里上传下上面的三份点云文件。

链接:https://pan.baidu.com/s/1LUB9jLOG1eIq8JT4wheqHw 
提取码:pfsy 
 

三. 小实验1

读取两份点云,在窗口中拆分显示, 测试点云来自于mirrors / pointcloudlibrary / data · GitCode

  1. #include <pcl/memory.h> // for pcl::make_shared
  2. #include <pcl/point_types.h>
  3. #include <pcl/point_cloud.h>
  4. #include <pcl/point_representation.h>
  5. #include <pcl/io/pcd_io.h>
  6. #include <pcl/filters/voxel_grid.h>
  7. #include <pcl/filters/filter.h>
  8. #include <pcl/features/normal_3d.h>
  9. #include <pcl/registration/icp.h>
  10. #include <pcl/registration/icp_nl.h>
  11. #include <pcl/registration/transforms.h>
  12. #include <pcl/visualization/pcl_visualizer.h>
  13. #include <boost/thread/thread.hpp>
  14. using pcl::visualization::PointCloudColorHandlerGenericField;
  15. using pcl::visualization::PointCloudColorHandlerCustom;
  16. //convenient typedefs
  17. typedef pcl::PointXYZ PointT;
  18. typedef pcl::PointCloud<PointT> PointCloud;
  19. typedef pcl::PointNormal PointNormalT;
  20. typedef pcl::PointCloud<PointNormalT> PointCloudWithNormals;
  21. int main()
  22. {
  23. PointCloud::Ptr cloud_src(new PointCloud);
  24. PointCloud::Ptr cloud_tgt(new PointCloud);
  25. pcl::io::loadPCDFile("D://PCL//data-master//tutorials//pairwise//capture0001.pcd", *cloud_src);
  26. pcl::io::loadPCDFile("D://PCL//data-master//tutorials//pairwise//capture0005.pcd", *cloud_tgt);
  27. std::cout << "cloud_src size: " << cloud_src->size() << std::endl;
  28. std::cout << "cloud_target size: " << cloud_tgt->size() << std::endl;
  29. pcl::VoxelGrid<PointT> grid;
  30. PointCloud::Ptr src(new PointCloud);
  31. PointCloud::Ptr tgt(new PointCloud);
  32. grid.setLeafSize(0.05, 0.05, 0.05);
  33. grid.setInputCloud(cloud_src);
  34. grid.filter(*src);
  35. std::cout << "src size: " << src->size() << std::endl;
  36. grid.setInputCloud(cloud_tgt);
  37. grid.filter(*tgt);
  38. std::cout << "target size: " << tgt->size() << std::endl;
  39. pcl::visualization::PCLVisualizer* p;
  40. int vp_1, vp_2;
  41. p = new pcl::visualization::PCLVisualizer("view");
  42. p->createViewPort(0.0, 0, 0.5, 1.0, vp_1);
  43. p->createViewPort(0.5, 0, 1.0, 1.0, vp_2);
  44. PointCloudColorHandlerCustom<PointT> src_h(cloud_src, 255, 0, 0);
  45. PointCloudColorHandlerCustom<PointT> tgt_h(cloud_tgt, 0, 255, 0);
  46. p->addPointCloud(cloud_src, src_h, "vp1_src", vp_1);
  47. p->addPointCloud(cloud_tgt, tgt_h, "vp1_target", vp_1);
  48. p->addPointCloud(cloud_tgt, tgt_h, "vp2_target", vp_2);
  49. p->spin();
  50. return (0);
  51. }

运行结果如下:

四. 小实验2

上面main函数中的代码修改为如下:

  1. PointCloud::Ptr cloud_src(new PointCloud);
  2. PointCloud::Ptr cloud_tgt(new PointCloud);
  3. pcl::io::loadPCDFile("D://PCL//data-master//tutorials//pairwise//capture0001.pcd", *cloud_src);
  4. pcl::io::loadPCDFile("D://PCL//data-master//tutorials//pairwise//capture0005.pcd", *cloud_tgt);
  5. std::cout << "cloud_src size: " << cloud_src->size() << std::endl;
  6. std::cout << "cloud_target size: " << cloud_tgt->size() << std::endl;
  7. pcl::VoxelGrid<PointT> grid;
  8. PointCloud::Ptr src(new PointCloud);
  9. PointCloud::Ptr tgt(new PointCloud);
  10. grid.setLeafSize(0.05, 0.05, 0.05);
  11. grid.setInputCloud(cloud_src);
  12. grid.filter(*src);
  13. std::cout << "src size: " << src->size() << std::endl;
  14. grid.setInputCloud(cloud_tgt);
  15. grid.filter(*tgt);
  16. std::cout << "target size: " << tgt->size() << std::endl;
  17. // Compute surface normals and curvature
  18. PointCloudWithNormals::Ptr points_with_normals_src(new PointCloudWithNormals);
  19. PointCloudWithNormals::Ptr points_with_normals_tgt(new PointCloudWithNormals);
  20. pcl::NormalEstimation<PointT, PointNormalT> norm_est;
  21. pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
  22. norm_est.setSearchMethod(tree);
  23. norm_est.setKSearch(30);
  24. norm_est.setInputCloud(src);
  25. norm_est.compute(*points_with_normals_src);
  26. pcl::copyPointCloud(*src, *points_with_normals_src);
  27. norm_est.setInputCloud(tgt);
  28. norm_est.compute(*points_with_normals_tgt);
  29. pcl::copyPointCloud(*tgt, *points_with_normals_tgt);
  30. pcl::visualization::PCLVisualizer* p;
  31. int vp_1, vp_2;
  32. p = new pcl::visualization::PCLVisualizer("view");
  33. p->createViewPort(0.0, 0, 0.5, 1.0, vp_1);
  34. p->createViewPort(0.5, 0, 1.0, 1.0, vp_2);
  35. PointCloudColorHandlerCustom<PointNormalT> src_h(points_with_normals_src, 255, 0, 0);
  36. PointCloudColorHandlerCustom<PointNormalT> tgt_h(points_with_normals_tgt, 0, 255, 0);
  37. p->addPointCloud(points_with_normals_src, src_h, "vp1_src", vp_1);
  38. p->addPointCloud(points_with_normals_tgt, tgt_h, "vp1_target", vp_1);
  39. p->addPointCloud(points_with_normals_tgt, tgt_h, "vp2_target", vp_2);
  40. p->spin();
  41. return (0);

运行结果如下:

 若注释掉上面代码中copyPointCloud部分两句

  1. //pcl::copyPointCloud(*src, *points_with_normals_src);
  2. norm_est.setInputCloud(tgt);
  3. norm_est.compute(*points_with_normals_tgt);
  4. //pcl::copyPointCloud(*tgt, *points_with_normals_tgt);

运行结果如下:

 五. 小实验3

对上面两个点云进行配准,迭代次数设为30。

  1. #include <pcl/memory.h> // for pcl::make_shared
  2. #include <pcl/point_types.h>
  3. #include <pcl/point_cloud.h>
  4. #include <pcl/point_representation.h>
  5. #include <pcl/io/pcd_io.h>
  6. #include <pcl/filters/voxel_grid.h>
  7. #include <pcl/filters/filter.h>
  8. #include <pcl/features/normal_3d.h>
  9. #include <pcl/registration/icp.h>
  10. #include <pcl/registration/icp_nl.h>
  11. #include <pcl/registration/transforms.h>
  12. #include <pcl/visualization/pcl_visualizer.h>
  13. #include <boost/thread/thread.hpp>
  14. using pcl::visualization::PointCloudColorHandlerGenericField;
  15. using pcl::visualization::PointCloudColorHandlerCustom;
  16. //convenient typedefs
  17. typedef pcl::PointXYZ PointT;
  18. typedef pcl::PointCloud<PointT> PointCloud;
  19. typedef pcl::PointNormal PointNormalT;
  20. typedef pcl::PointCloud<PointNormalT> PointCloudWithNormals;
  21. // Define a new point representation for < x, y, z, curvature >
  22. class MyPointRepresentation : public pcl::PointRepresentation < PointNormalT>
  23. {
  24. using pcl::PointRepresentation<PointNormalT>::nr_dimensions_;
  25. public:
  26. MyPointRepresentation()
  27. {
  28. // Define the number of dimensions
  29. nr_dimensions_ = 4;
  30. }
  31. // Override the copyToFloatArray method to define our feature vector
  32. virtual void copyToFloatArray(const PointNormalT & p, float* out) const
  33. {
  34. // < x, y, z, curvature >
  35. out[0] = p.x;
  36. out[1] = p.y;
  37. out[2] = p.z;
  38. out[3] = p.curvature;
  39. }
  40. };
  41. int main()
  42. {
  43. PointCloud::Ptr cloud_src(new PointCloud);
  44. PointCloud::Ptr cloud_tgt(new PointCloud);
  45. pcl::io::loadPCDFile("D://PCL//data-master//tutorials//pairwise//capture0001.pcd", *cloud_src);
  46. pcl::io::loadPCDFile("D://PCL//data-master//tutorials//pairwise//capture0005.pcd", *cloud_tgt);
  47. std::cout << "cloud_src size: " << cloud_src->size() << std::endl;
  48. std::cout << "cloud_target size: " << cloud_tgt->size() << std::endl;
  49. pcl::VoxelGrid<PointT> grid;
  50. PointCloud::Ptr src(new PointCloud);
  51. PointCloud::Ptr tgt(new PointCloud);
  52. grid.setLeafSize(0.05, 0.05, 0.05);
  53. grid.setInputCloud(cloud_src);
  54. grid.filter(*src);
  55. std::cout << "src size: " << src->size() << std::endl;
  56. grid.setInputCloud(cloud_tgt);
  57. grid.filter(*tgt);
  58. std::cout << "target size: " << tgt->size() << std::endl;
  59. // Compute surface normals and curvature
  60. PointCloudWithNormals::Ptr points_with_normals_src(new PointCloudWithNormals);
  61. PointCloudWithNormals::Ptr points_with_normals_tgt(new PointCloudWithNormals);
  62. pcl::NormalEstimation<PointT, PointNormalT> norm_est;
  63. pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
  64. norm_est.setSearchMethod(tree);
  65. norm_est.setKSearch(30);
  66. norm_est.setInputCloud(src);
  67. norm_est.compute(*points_with_normals_src);
  68. pcl::copyPointCloud(*src, *points_with_normals_src);
  69. norm_est.setInputCloud(tgt);
  70. norm_est.compute(*points_with_normals_tgt);
  71. pcl::copyPointCloud(*tgt, *points_with_normals_tgt);
  72. //
  73. // Instantiate our custom point representation (defined above) ...
  74. MyPointRepresentation point_representation;
  75. // ... and weight the 'curvature' dimension so that it is balanced against x, y, and z
  76. float alpha[4] = { 1.0, 1.0, 1.0, 1.0 };
  77. point_representation.setRescaleValues(alpha);
  78. // Align
  79. pcl::IterativeClosestPointNonLinear<PointNormalT, PointNormalT> reg;
  80. reg.setTransformationEpsilon(1e-6);
  81. // Set the maximum distance between two correspondences (src<->tgt) to 10cm
  82. // Note: adjust this based on the size of your datasets
  83. reg.setMaxCorrespondenceDistance(0.1);
  84. // Set the point representation
  85. reg.setPointRepresentation(pcl::make_shared<const MyPointRepresentation>(point_representation));
  86. reg.setInputSource(points_with_normals_src);
  87. reg.setInputTarget(points_with_normals_tgt);
  88. PointCloudWithNormals::Ptr reg_result(new PointCloudWithNormals);
  89. reg.setMaximumIterations(30);
  90. reg.align(*reg_result);
  91. Eigen::Matrix4f transform = reg.getFinalTransformation();
  92. std::cout << "has converaged: " << reg.hasConverged() << " score: " << reg.getFitnessScore() << std::endl;
  93. std::cout << "transform: " << std::endl;
  94. std::cout << transform << std::endl;
  95. std::cout << std::endl;
  96. pcl::io::savePCDFileASCII("D:\\PCL\\trans_method1_final.pcd", *reg_result);
  97. pcl::io::savePCDFileASCII("D:\\PCL\\trans_method1_out.pcd", *points_with_normals_tgt);
  98. PointCloudWithNormals::Ptr transform_src(new PointCloudWithNormals);
  99. pcl::transformPointCloud(*points_with_normals_src, *transform_src, transform);
  100. pcl::io::savePCDFileASCII("D:\\PCL\\trans_method1_tranform_src.pcd", *transform_src);
  101. //
  102. pcl::visualization::PCLVisualizer* p;
  103. int vp_1, vp_2;
  104. p = new pcl::visualization::PCLVisualizer("view");
  105. p->createViewPort(0.0, 0, 0.5, 1.0, vp_1);
  106. p->createViewPort(0.5, 0, 1.0, 1.0, vp_2);
  107. PointCloudColorHandlerCustom<PointNormalT> src_h(points_with_normals_src, 255, 0, 0);
  108. PointCloudColorHandlerCustom<PointNormalT> tgt_h(points_with_normals_tgt, 0, 255, 0);
  109. PointCloudColorHandlerCustom<PointNormalT> final_h(reg_result, 0, 0, 255);
  110. p->addPointCloud(points_with_normals_src, src_h, "vp1_src", vp_1);
  111. p->addPointCloud(reg_result, final_h, "reg_result", vp_1);
  112. p->addPointCloud(points_with_normals_src, src_h, "vp1_src_copy", vp_2);
  113. p->addPointCloud(points_with_normals_tgt, tgt_h, "vp2_target", vp_2);
  114. p->spin();
  115. return (0);
  116. }

运行效果如下(左边显示的是对齐后的点云和目标点云,右边是源点云和目标点云),左边两组点云的一致性很好,而右边两组由于未对齐,可看到是错乱分布的。

 源点云到目标点云迭代30次配准的变换矩阵如下:

 由变换矩阵将源点云映射得到的点云和直接通过配准函数获得的对齐后点云,部分数据如下,很接近。

  

六. 小实验4

将ICP的最小迭代次数设为1,外面加一个循环执行此过程30次。

  1. #include <pcl/memory.h> // for pcl::make_shared
  2. #include <pcl/point_types.h>
  3. #include <pcl/point_cloud.h>
  4. #include <pcl/point_representation.h>
  5. #include <pcl/io/pcd_io.h>
  6. #include <pcl/filters/voxel_grid.h>
  7. #include <pcl/filters/filter.h>
  8. #include <pcl/features/normal_3d.h>
  9. #include <pcl/registration/icp.h>
  10. #include <pcl/registration/icp_nl.h>
  11. #include <pcl/registration/transforms.h>
  12. #include <pcl/visualization/pcl_visualizer.h>
  13. #include <boost/thread/thread.hpp>
  14. using pcl::visualization::PointCloudColorHandlerGenericField;
  15. using pcl::visualization::PointCloudColorHandlerCustom;
  16. //convenient typedefs
  17. typedef pcl::PointXYZ PointT;
  18. typedef pcl::PointCloud<PointT> PointCloud;
  19. typedef pcl::PointNormal PointNormalT;
  20. typedef pcl::PointCloud<PointNormalT> PointCloudWithNormals;
  21. // Define a new point representation for < x, y, z, curvature >
  22. class MyPointRepresentation : public pcl::PointRepresentation < PointNormalT>
  23. {
  24. using pcl::PointRepresentation<PointNormalT>::nr_dimensions_;
  25. public:
  26. MyPointRepresentation()
  27. {
  28. // Define the number of dimensions
  29. nr_dimensions_ = 4;
  30. }
  31. // Override the copyToFloatArray method to define our feature vector
  32. virtual void copyToFloatArray(const PointNormalT & p, float* out) const
  33. {
  34. // < x, y, z, curvature >
  35. out[0] = p.x;
  36. out[1] = p.y;
  37. out[2] = p.z;
  38. out[3] = p.curvature;
  39. }
  40. };
  41. int main()
  42. {
  43. PointCloud::Ptr cloud_src(new PointCloud);
  44. PointCloud::Ptr cloud_tgt(new PointCloud);
  45. pcl::io::loadPCDFile("D://PCL//data-master//tutorials//pairwise//capture0001.pcd", *cloud_src);
  46. pcl::io::loadPCDFile("D://PCL//data-master//tutorials//pairwise//capture0005.pcd", *cloud_tgt);
  47. std::cout << "cloud_src size: " << cloud_src->size() << std::endl;
  48. std::cout << "cloud_target size: " << cloud_tgt->size() << std::endl;
  49. pcl::VoxelGrid<PointT> grid;
  50. PointCloud::Ptr src(new PointCloud);
  51. PointCloud::Ptr tgt(new PointCloud);
  52. grid.setLeafSize(0.05, 0.05, 0.05);
  53. grid.setInputCloud(cloud_src);
  54. grid.filter(*src);
  55. std::cout << "src size: " << src->size() << std::endl;
  56. grid.setInputCloud(cloud_tgt);
  57. grid.filter(*tgt);
  58. std::cout << "target size: " << tgt->size() << std::endl;
  59. // Compute surface normals and curvature
  60. PointCloudWithNormals::Ptr points_with_normals_src(new PointCloudWithNormals);
  61. PointCloudWithNormals::Ptr points_with_normals_tgt(new PointCloudWithNormals);
  62. pcl::NormalEstimation<PointT, PointNormalT> norm_est;
  63. pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
  64. norm_est.setSearchMethod(tree);
  65. norm_est.setKSearch(30);
  66. norm_est.setInputCloud(src);
  67. norm_est.compute(*points_with_normals_src);
  68. pcl::copyPointCloud(*src, *points_with_normals_src);
  69. norm_est.setInputCloud(tgt);
  70. norm_est.compute(*points_with_normals_tgt);
  71. pcl::copyPointCloud(*tgt, *points_with_normals_tgt);
  72. //
  73. // Instantiate our custom point representation (defined above) ...
  74. MyPointRepresentation point_representation;
  75. // ... and weight the 'curvature' dimension so that it is balanced against x, y, and z
  76. float alpha[4] = { 1.0, 1.0, 1.0, 1.0 };
  77. point_representation.setRescaleValues(alpha);
  78. // Align
  79. pcl::IterativeClosestPointNonLinear<PointNormalT, PointNormalT> reg;
  80. reg.setTransformationEpsilon(1e-6);
  81. // Set the maximum distance between two correspondences (src<->tgt) to 10cm
  82. // Note: adjust this based on the size of your datasets
  83. reg.setMaxCorrespondenceDistance(0.1);
  84. // Set the point representation
  85. reg.setPointRepresentation(pcl::make_shared<const MyPointRepresentation>(point_representation));
  86. reg.setInputSource(points_with_normals_src);
  87. reg.setInputTarget(points_with_normals_tgt);
  88. //
  89. // Run the same optimization in a loop and visualize the results
  90. Eigen::Matrix4f Ti = Eigen::Matrix4f::Identity(), prev, targetToSource;
  91. PointCloudWithNormals::Ptr reg_result = points_with_normals_src;
  92. reg.setMaximumIterations(1);
  93. pcl::visualization::PCLVisualizer* p;
  94. p = new pcl::visualization::PCLVisualizer("view");
  95. for (int i = 0; i < 30; ++i)
  96. {
  97. PCL_INFO("Iteration Nr. %d.\n", i);
  98. // save cloud for visualization purpose
  99. points_with_normals_src = reg_result;
  100. // Estimate
  101. reg.setInputSource(points_with_normals_src);
  102. reg.align(*reg_result);
  103. //accumulate transformation between each Iteration
  104. Ti = reg.getFinalTransformation() * Ti;
  105. //if the difference between this transformation and the previous one
  106. //is smaller than the threshold, refine the process by reducing
  107. //the maximal correspondence distance
  108. if (std::abs((reg.getLastIncrementalTransformation() - prev).sum()) < reg.getTransformationEpsilon())
  109. reg.setMaxCorrespondenceDistance(reg.getMaxCorrespondenceDistance() - 0.001);
  110. prev = reg.getLastIncrementalTransformation();
  111. // visualize current state
  112. p->removePointCloud("source");
  113. p->removePointCloud("target");
  114. PointCloudColorHandlerGenericField<PointNormalT> src_color_handler(points_with_normals_src, "curvature");
  115. if (!src_color_handler.isCapable())
  116. PCL_WARN("Cannot create curvature color handler!\n");
  117. PointCloudColorHandlerGenericField<PointNormalT> tgt_color_handler(points_with_normals_tgt, "curvature");
  118. if (!tgt_color_handler.isCapable())
  119. PCL_WARN("Cannot create curvature color handler!\n");
  120. p->addPointCloud(points_with_normals_src, src_color_handler, "source");
  121. p->addPointCloud(points_with_normals_tgt, tgt_color_handler, "target");
  122. p->spinOnce();
  123. }
  124. std::cout << "transform: " << std::endl;
  125. std::cout << Ti << std::endl;
  126. std::cout << std::endl;
  127. pcl::io::savePCDFileASCII("D:\\PCL\\trans_method2_final.pcd", *reg_result);
  128. return (0);
  129. }

运行结果如下(可看到和上面一次迭代次数设为30的方法对比,结果是一致的,只是这样做的一个好处是可以对齐过程可视化,不像上面黑盒子一样):

 七. 两个点云的融合(相加)

  1. #include <pcl/memory.h> // for pcl::make_shared
  2. #include <pcl/point_types.h>
  3. #include <pcl/point_cloud.h>
  4. #include <pcl/point_representation.h>
  5. #include <pcl/io/pcd_io.h>
  6. #include <pcl/filters/voxel_grid.h>
  7. #include <pcl/filters/filter.h>
  8. #include <pcl/features/normal_3d.h>
  9. #include <pcl/registration/icp.h>
  10. #include <pcl/registration/icp_nl.h>
  11. #include <pcl/registration/transforms.h>
  12. #include <pcl/visualization/pcl_visualizer.h>
  13. #include <boost/thread/thread.hpp>
  14. using pcl::visualization::PointCloudColorHandlerGenericField;
  15. using pcl::visualization::PointCloudColorHandlerCustom;
  16. //convenient typedefs
  17. typedef pcl::PointXYZ PointT;
  18. typedef pcl::PointCloud<PointT> PointCloud;
  19. typedef pcl::PointNormal PointNormalT;
  20. typedef pcl::PointCloud<PointNormalT> PointCloudWithNormals;
  21. int main()
  22. {
  23. PointCloud::Ptr cloud_src(new PointCloud);
  24. PointCloud::Ptr cloud_tgt(new PointCloud);
  25. pcl::io::loadPCDFile("D://PCL//data-master//tutorials//pairwise//capture0001.pcd", *cloud_src);
  26. pcl::io::loadPCDFile("D://PCL//data-master//tutorials//pairwise//capture0005.pcd", *cloud_tgt);
  27. std::cout << "cloud_src size: " << cloud_src->size() << std::endl;
  28. std::cout << "cloud_target size: " << cloud_tgt->size() << std::endl;
  29. pcl::VoxelGrid<PointT> grid;
  30. PointCloud::Ptr src(new PointCloud);
  31. PointCloud::Ptr tgt(new PointCloud);
  32. grid.setLeafSize(0.05, 0.05, 0.05);
  33. grid.setInputCloud(cloud_src);
  34. grid.filter(*src);
  35. std::cout << "src size: " << src->size() << std::endl;
  36. grid.setInputCloud(cloud_tgt);
  37. grid.filter(*tgt);
  38. std::cout << "target size: " << tgt->size() << std::endl;
  39. pcl::visualization::PCLVisualizer* p;
  40. int vp_1, vp_2;
  41. p = new pcl::visualization::PCLVisualizer("view");
  42. p->createViewPort(0.0, 0, 0.5, 1.0, vp_1);
  43. p->createViewPort(0.5, 0, 1.0, 1.0, vp_2);
  44. PointCloudColorHandlerCustom<PointT> src_h(cloud_src, 255, 0, 0);
  45. PointCloudColorHandlerCustom<PointT> tgt_h(cloud_tgt, 0, 255, 0);
  46. p->addPointCloud(cloud_src, src_h, "vp1_src", vp_1);
  47. p->addPointCloud(cloud_tgt, tgt_h, "vp1_target", vp_1);
  48. PointCloud::Ptr total(new PointCloud);
  49. total = cloud_src;
  50. *total += *cloud_tgt;
  51. PointCloudColorHandlerCustom<PointT> total_h(total, 0, 0, 255);
  52. p->addPointCloud(total, total_h, "vp2_target", vp_2);
  53. p->spin();
  54. return (0);
  55. }

运行效果如下:

八. How to incrementally register pairs of clouds

有了上面的例子后,再去看官网上的这段代码就很容易了

How to incrementally register pairs of clouds — Point Cloud Library 0.0 documentation

代码会加载5张点云数据,A,B,C,D,E分别代表这5个点云,然后AB,BC,CD,DE分别两两配准,这样就可以把B,C,D,E都变换到A空间中去, 向A对齐,完毕后将这5个点云数据做融合(相加),这样就可以实现一个拼接或者融合的功能,后续任务就可以基于这份包含更细致信息的点云做文章。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/122714?site
推荐阅读
相关标签
  

闽ICP备14008679号