【问题标题】:Optimal PCL Template Alignment setup最佳 PCL 模板对齐设置
【发布时间】:2019-04-25 14:29:50
【问题描述】:

我有 2 个点云(以毫米为单位),一个是从 stl 对象(99999 个点)采样的“网格”,第二个是 3D cam 拍摄的该对象的点云(大约 30841 个点)。我正在使用此 PCL 教程的代码进行模板匹配:http://pointclouds.org/documentation/tutorials/template_alignment.php。之后,我使用 PCL ICP 代码进行最终对齐。但是我仍然从模板对齐中得到了相当糟糕的初步猜测。 (例如,没有轮换,半场比赛,...)

我尝试从以下位置更改设置:

normal_radius_(0.02f)
feature_radius_(0.02f)
min_sample_distance_(0.05f)
max_correspondence_distance_(0.01f * 0.01f)
nr_iterations_(50)

到这个:

normal_radius_(2.0f)
feature_radius_(2.0f)
min_sample_distance_(0.5f)
max_correspondence_distance_(1.0f * 1.0f)
nr_iterations_(1000)

有人可以给我一些提示如何改进此代码吗?谢谢!

【问题讨论】:

    标签: c++ point-cloud-library template-matching


    【解决方案1】:

    分辨率相关的参数也应该相对于点云的分辨率进行设置。 依赖于对象大小的参数也应该根据对象的大小进行设置。

    一些例子:

    • normal_radius: 4-8 * <resolution>
      要计算良好法线,底层表面必须有足够的点来表示稳定的表面。如果您的单位在mm,那么您选择的半径为2mm,这太小了。
    • feature_radius: 1-2 * <normal_radius>
      计算特征法线一样。
    • max_correspondence_distance: 您将此值设置为1mm*1mm,这意味着,对应关系只能与1mm 分开才能归类为对应关系。在这里使用与对象大小相关的值很重要。你应该问自己,“我的对象和参考之间允许的最大距离是多少,这样我的对象仍然是匹配的?”如果你在比较人脸,你应该使用一些centimeters,例如1cm-5cm,因为脸比较小。但是,假设您想比较像建筑物这样的大物体。在那里,您可以使用高达 1m 的值。
    • min_sample_distance: 这里几乎与max_correspondence_distance 相同。您应该问自己,“一个样本与另一个样本的距离应该是多少?”。值越小,您获得的样本就越多。同样,选择一个值是对象大小的一小部分,但还要考虑它不应小于云的分辨率。你把它设置为0.5mm,太小了。
    • nr_iterations: 通常不那么重要,但100-500 之间的值是合理的。

    【讨论】:

      【解决方案2】:

      normal_radius_

      • 根据您的云的密度进行选择(您希望它足够大以捕获环境中的足够个点 - 如果太小,法线会很嘈杂,直至完全垃圾或失败计算)
      • 考虑云的平滑度(您希望它足够小,以便将本地环境近似为平面是正确的 - 如果它太大,则法线将过于平滑并忽略小细节)

      min_sample_distance_

      • 主要是计算方面。采样距离越大,工作速度越快。
      • 如果它太大,则会降低对齐的准确性。

      feature_radius_

      • 您需要考虑您的判别结构/形状的规模
      • 以人脸为例,我已经成功地将特征半径约为模型大小的 1/10。

      ma​​x_correspondence_distance_

      • 取决于您的起始条件 - 2 个对应点可以有多远。使用一些启发式方法提供初始猜测可以帮助您减少此参数,并提高性能和结果。
      • 请注意,这是平方距离

      在您的情况下(同一对象的两个云),如果您的云具有法线,则可以在完全不使用 SampleConsensusInitialAlignment 的情况下实现良好的初始猜测。只需对齐两朵云的平均法线。您可以将以下方法应用于您的两个云,以将它们置于“标准化”位置和方向:

      void ToOrigin(pcl::PointCloud<pcl::PointXYZINormal>::Ptr cloud, Eigen::Affine3f & transformation, Eigen::Vector3f up, float resolution)
      {
          // Calc Origin
      
          pcl::PointXYZINormal origin;
          auto size = cloud->points.size();
          for (auto pointItr = cloud->begin(); pointItr != cloud->end(); pointItr++)
          {
              origin.getArray3fMap() += pointItr->getArray3fMap() / size;
              origin.getNormalVector3fMap() += pointItr->getNormalVector3fMap();
          }
          origin.getNormalVector3fMap().normalize();
      
          // Calc Transformation  
      
          auto proj = origin.getNormalVector3fMap().dot(up) * origin.getNormalVector3fMap();
      
          // the direction that will be rotated to y_axis
          // (the part of "up" that is perpendicular to the cloud normal)
          auto y_direction = (up - proj).normalized();
      
          // the direction that will be rotated to z_axis
          auto z_direction = origin.getNormalVector3fMap();   
      
          // the point that will be shifted to origin (0,0,0)
          auto center = origin.getArray3fMap();               
      
          pcl::getTransformationFromTwoUnitVectorsAndOrigin(y_direction, z_direction, center, transformation);
      
          // Transform
      
          pcl::PointCloud<pcl::PointXYZINormal> cloud_tmp;
          pcl::transformPointCloudWithNormals(*cloud, cloud_tmp, transformation);
          pcl::copyPointCloud(cloud_tmp, *cloud);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-04-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多