最佳PCL模板对齐设置

时间:2019-04-25 14:29:51

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

我有2个点云(以mm为单位),一个是从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)

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

2 个答案:

答案 0 :(得分:1)

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

一些例子:

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

答案 1 :(得分:1)

normal_radius _

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

min_sample_distance _

  • 主要是计算方面。采样距离越大,工作越快。
  • 如果太大,会降低对齐精度。

feature_radius _

  • 您需要考虑具有区分结构/形状的比例
  • 例如,使用面孔,特征半径大约是模型尺寸的1/10,我就获得了成功。

max_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);
}