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


    前面多篇博客都提到过,要善于从官网去熟悉一样东西。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
    2. #include
    3. #include
    4. #include
    5. int main()
    6. {
    7. pcl::PointCloud::Ptr cloud_in(new pcl::PointCloud(5, 1));
    8. pcl::PointCloud::Ptr cloud_out(new pcl::PointCloud);
    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 icp;
    33. icp.setInputSource(cloud_in);
    34. icp.setInputTarget(cloud_out);
    35. //final->
    36. pcl::PointCloud 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 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 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
    4. #include
    5. #include "vtkAutoInit.h"
    6. //VTK_MODULE_INIT(vtkRenderingOpenGL2);
    7. //VTK_MODULE_INIT(vtkInteractionStyle);
    8. //#define vtkRenderingCore_AUTOINIT 2(vtkRenderingOpenGL2, vtkInteractionStyle)
    9. #include
    10. #include
    11. #include
    12. #include //pcd 读写类相关的头文件。
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. using namespace pcl;
    19. using namespace pcl::io;
    20. using namespace std;
    21. int testpointcloudToPcd()
    22. {
    23. vtkObject::GlobalWarningDisplayOff();
    24. pcl::PointCloud::Ptr cloud_in(new pcl::PointCloud);
    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::Ptr cloud_out(new pcl::PointCloud);
    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 icp;
    51. icp.setInputSource(cloud_in);
    52. icp.setInputTarget(cloud_out);
    53. pcl::PointCloud 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 // for pcl::make_shared
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. using pcl::visualization::PointCloudColorHandlerGenericField;
    15. using pcl::visualization::PointCloudColorHandlerCustom;
    16. //convenient typedefs
    17. typedef pcl::PointXYZ PointT;
    18. typedef pcl::PointCloud PointCloud;
    19. typedef pcl::PointNormal PointNormalT;
    20. typedef pcl::PointCloud 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 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 src_h(cloud_src, 255, 0, 0);
    45. PointCloudColorHandlerCustom 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 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 norm_est;
    21. pcl::search::KdTree::Ptr tree(new pcl::search::KdTree());
    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 src_h(points_with_normals_src, 255, 0, 0);
    36. PointCloudColorHandlerCustom 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 // for pcl::make_shared
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. using pcl::visualization::PointCloudColorHandlerGenericField;
    15. using pcl::visualization::PointCloudColorHandlerCustom;
    16. //convenient typedefs
    17. typedef pcl::PointXYZ PointT;
    18. typedef pcl::PointCloud PointCloud;
    19. typedef pcl::PointNormal PointNormalT;
    20. typedef pcl::PointCloud PointCloudWithNormals;
    21. // Define a new point representation for < x, y, z, curvature >
    22. class MyPointRepresentation : public pcl::PointRepresentation < PointNormalT>
    23. {
    24. using pcl::PointRepresentation::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 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 norm_est;
    63. pcl::search::KdTree::Ptr tree(new pcl::search::KdTree());
    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 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 src_h(points_with_normals_src, 255, 0, 0);
    108. PointCloudColorHandlerCustom tgt_h(points_with_normals_tgt, 0, 255, 0);
    109. PointCloudColorHandlerCustom 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 // for pcl::make_shared
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. using pcl::visualization::PointCloudColorHandlerGenericField;
    15. using pcl::visualization::PointCloudColorHandlerCustom;
    16. //convenient typedefs
    17. typedef pcl::PointXYZ PointT;
    18. typedef pcl::PointCloud PointCloud;
    19. typedef pcl::PointNormal PointNormalT;
    20. typedef pcl::PointCloud PointCloudWithNormals;
    21. // Define a new point representation for < x, y, z, curvature >
    22. class MyPointRepresentation : public pcl::PointRepresentation < PointNormalT>
    23. {
    24. using pcl::PointRepresentation::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 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 norm_est;
    63. pcl::search::KdTree::Ptr tree(new pcl::search::KdTree());
    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 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 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 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 // for pcl::make_shared
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. using pcl::visualization::PointCloudColorHandlerGenericField;
    15. using pcl::visualization::PointCloudColorHandlerCustom;
    16. //convenient typedefs
    17. typedef pcl::PointXYZ PointT;
    18. typedef pcl::PointCloud PointCloud;
    19. typedef pcl::PointNormal PointNormalT;
    20. typedef pcl::PointCloud 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 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 src_h(cloud_src, 255, 0, 0);
    45. PointCloudColorHandlerCustom 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 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个点云数据做融合(相加),这样就可以实现一个拼接或者融合的功能,后续任务就可以基于这份包含更细致信息的点云做文章。

  • 相关阅读:
    外部访问win服务器的mysql数据库
    flink1.13.2版本的对应的hive的Hcatalog的使用记录
    为什么要使用elasticsearch
    React进阶之路(一)-- JSX基础、组件基础
    【微信小程序】flex布局
    云原生赋能智能网联汽车消息处理基础框架构建
    学生个人网页设计作品 HTML+CSS+JavaScript仿小米商城(8页) 学生个人网页模板 简单个人主页成品 个人网页制作 HTML学生个人网站作业设计
    用C语言API(常用)操作MySql数据库
    常见限流算法
    6143. 预算内的最多机器人数目--(每日一难phase2--day7)
  • 原文地址:https://blog.csdn.net/jiugeshao/article/details/126730727