【PCL】Failed to find match for field 'label'

本人尝试用以下代码从.pcd文件中读取点云数据:

PCLPointCloud2 cloud_blob;
PointCloud::Ptr cloud(new PointCloud());

Eigen::Vector4f origen;
Eigen::Quaternionf orientation;
if (pcl::io::loadPCDFile(filename, cloud_blob, origen, orientation) == -1)
{
    PCL_ERROR("Error loading point cloud file!");
    return;
}
else
{
    fromPCLPointCloud2(cloud_blob, *cloud);
    cout << "Loaded" << cloud->width * cloud->height << "data points from the PCD file:" << filename << endl;
}

其中pcd文件包含点云数据属性x,y,z,label,因此定义读取的点云数据PointType为PointXYZL。然而读取时报错“Failed to find match for field 'label'”。

报错提示从pcd文件中读取的点云对象包含正常的点个数(就是说点云可以说已经读取到对象中,只是没有正常解析出包含的x,y,z,label点云属性中的label属性。)。然后,我尝试debug。最终,从以下代码段:

fromPCLPointCloud2(cloud_blob, *cloud);

往内部调试,发现该函数负责将读取的cloud_blob对象映射到cloud点云指针(读者可能发现这里的点云读取方式和惯常的有所不同,这是因为笔者经过之前的探讨,发现被读取的pcd文件是0.7版本,而在此之前都是0.6版本pcd文件,这就导致用惯有的读取方式难以正确解析pcd文件,原因是0.7版本pcd文件包含相机原始的角度信息,因此多了一行文件头)。在fromPCLPointCloud2()函数内部,定义了一个由cloud_blob数据到cloud数据的Mapping:

【PCL】Failed to find match for field 'label'_第1张图片

可以简单理解,这里的createMapping函数利用传入的PCLPointCloud2类型的引用msg(也就是cloud_blob),构造属性域映射对象field_map,然后再进行数据转化。然后,进入createMapping函数体,进一步debug发现如下程序段:

struct FieldMapper
    {
      FieldMapper (const std::vector& fields,
                   std::vector& map)
        : fields_ (fields), map_ (map)
      {
      }

      template void
      operator () ()
      {
        BOOST_FOREACH (const pcl::PCLPointField& field, fields_)
        {
          if (FieldMatches()(field))
          {
            FieldMapping mapping;
            mapping.serialized_offset = field.offset;
            mapping.struct_offset = traits::offset::value;
            mapping.size = sizeof (typename traits::datatype::type);
            map_.push_back (mapping);
            return;
          }
        }
        // Disable thrown exception per #595: http://dev.pointclouds.org/issues/595
        PCL_WARN ("Failed to find match for field '%s'.\n", traits::name::value);
        //throw pcl::InvalidConversionException (ss.str ());
      }

      const std::vector& fields_;
      std::vector& map_;
    };

此处发现PCL_WARN,后面抛出的提示就是窗口报错“Failed to find match for field xx".此时情况已经比较明显,就是说在进行点云读取(这里的这种读取0.7版本pcd文件的方式和传统读取方式读取0.7版都会出现这个问题)时,内部模块进行点云属性域解析时,解析发生错误,从而抛出上述WARNING,最后导致点云数据的部分属性值不能正确使用。然后,更内部的原因和解决办法是什么呢?

【PCL】Failed to find match for field 'label'_第2张图片

进去FieldMatches,发现PCL内部通过上述模块判断field的各种属性是否满足要求,否则返回-1进一步抛出WARNINGS。上图注释的代码是调试用代码,通过这部分调试,笔者发现,本人读取的“label”属性的datatype是“5'\x5'”,类型,而traits::datatype::value是“6'\x6'”,也就是说读取的label值类型和PCL里PointXYZL要求的L类型不一致。

【PCL】Failed to find match for field 'label'_第3张图片

这里笔者卡住很久不知道这个5‘\x5’和6‘\x6’代表的含义,直到 查看traits命名空间源码,发现以下程序块包含的枚举类型:

【PCL】Failed to find match for field 'label'_第4张图片

其中,枚举第5号代表UINT32,枚举第6号代表FLOAT32。然后,笔者查看了PointXYZL类型的L的数据类型,要求的是uint32_t。然后笔者打开被读取的pcd文件,发现:

【PCL】Failed to find match for field 'label'_第5张图片

label域对应的TYPE为F,也就是pcl要求的label域值类型和实际的值类型不匹配,导致label域不能正确解析。随后,查询PCL官网,发现pcd文件规范:

【PCL】Failed to find match for field 'label'_第6张图片

可见,PCL要求的label属性值类型uint32在pcd文件中的TYPE应该是U而不能是I或者F(此处笔者尝试过修改为I,发现也不行).将PCD文件中TYPE最后一个字母从I改为U后,问题解决。

 

启示:

  pcd文件的属性域数值类型要与PointT要求的类型完全一致,不然就会出现“Failed to find match for field XX”的WARNING。此前在国内外网站搜索的类似问题的解答都没有涉及数据类型的问题。此处PO以作记录。

 

 

 

你可能感兴趣的:(PCL,PCL)