Esempio n. 1
0
File: io.cpp Progetto: FBIKKIBF/pcl
bool 
pcl::getEigenAsPointCloud (Eigen::MatrixXf &in, pcl::PCLPointCloud2 &out)
{
  // Get X-Y-Z indices
  int x_idx = getFieldIndex (out, "x");
  int y_idx = getFieldIndex (out, "y");
  int z_idx = getFieldIndex (out, "z");

  if (x_idx == -1 || y_idx == -1 || z_idx == -1)
  {
    PCL_ERROR ("Output dataset has no X-Y-Z coordinates set up as fields! Cannot convert from Eigen format.\n");
    return (false);
  }

  if (out.fields[x_idx].datatype != pcl::PCLPointField::FLOAT32 ||
      out.fields[y_idx].datatype != pcl::PCLPointField::FLOAT32 ||
      out.fields[z_idx].datatype != pcl::PCLPointField::FLOAT32)
  {
    PCL_ERROR ("X-Y-Z coordinates not floats. Currently only floats are supported.\n");
    return (false);
  }

  if (in.cols () != static_cast<int>(out.width * out.height))
  {
    PCL_ERROR ("Number of points in the point cloud differs from the Eigen matrix. Cannot continue.\n");
    return (false);
  }

  size_t npts = in.cols ();

  Eigen::Array4i xyz_offset (out.fields[x_idx].offset, out.fields[y_idx].offset, out.fields[z_idx].offset, 0);

  // Copy the input dataset into Eigen format
  for (size_t i = 0; i < npts; ++i)
  {
     // Unoptimized memcpys: assume fields x, y, z are in random order
     memcpy (&out.data[xyz_offset[0]], &in (0, i), sizeof (float));
     memcpy (&out.data[xyz_offset[1]], &in (1, i), sizeof (float));
     memcpy (&out.data[xyz_offset[2]], &in (2, i), sizeof (float));

     xyz_offset += out.point_step;
  }

  return (true);
}
Esempio n. 2
0
void
pcl::getMinMax3D (const sensor_msgs::PointCloud2ConstPtr &cloud, int x_idx, int y_idx, int z_idx,
                  Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt)
{
  // @todo fix this
  if (cloud->fields[x_idx].datatype != sensor_msgs::PointField::FLOAT32 || 
      cloud->fields[y_idx].datatype != sensor_msgs::PointField::FLOAT32 ||
      cloud->fields[z_idx].datatype != sensor_msgs::PointField::FLOAT32)
  {
    PCL_ERROR ("[pcl::getMinMax3D] XYZ dimensions are not float type!\n");
    return;
  }

  Eigen::Array4f min_p, max_p;
  min_p.setConstant (FLT_MAX);
  max_p.setConstant (-FLT_MAX);

  int nr_points = cloud->width * cloud->height;

  Eigen::Array4f pt = Eigen::Array4f::Zero ();
  Eigen::Array4i xyz_offset (cloud->fields[x_idx].offset, cloud->fields[y_idx].offset, cloud->fields[z_idx].offset, 0);

  for (int cp = 0; cp < nr_points; ++cp)
  {
    // Unoptimized memcpys: assume fields x, y, z are in random order
    memcpy (&pt[0], &cloud->data[xyz_offset[0]], sizeof (float));
    memcpy (&pt[1], &cloud->data[xyz_offset[1]], sizeof (float));
    memcpy (&pt[2], &cloud->data[xyz_offset[2]], sizeof (float));
    // Check if the point is invalid
    if (!pcl_isfinite (pt[0]) || 
        !pcl_isfinite (pt[1]) || 
        !pcl_isfinite (pt[2]))
    {
      xyz_offset += cloud->point_step;
      continue;
    }
    xyz_offset += cloud->point_step;
    min_p = (min_p.min) (pt);
    max_p = (max_p.max) (pt);
  }
  min_pt = min_p;
  max_pt = max_p;
}
Esempio n. 3
0
File: io.cpp Progetto: FBIKKIBF/pcl
bool
pcl::getPointCloudAsEigen (const pcl::PCLPointCloud2 &in, Eigen::MatrixXf &out)
{
  // Get X-Y-Z indices
  int x_idx = getFieldIndex (in, "x");
  int y_idx = getFieldIndex (in, "y");
  int z_idx = getFieldIndex (in, "z");

  if (x_idx == -1 || y_idx == -1 || z_idx == -1)
  {
    PCL_ERROR ("Input dataset has no X-Y-Z coordinates! Cannot convert to Eigen format.\n");
    return (false);
  }

  if (in.fields[x_idx].datatype != pcl::PCLPointField::FLOAT32 ||
      in.fields[y_idx].datatype != pcl::PCLPointField::FLOAT32 ||
      in.fields[z_idx].datatype != pcl::PCLPointField::FLOAT32)
  {
    PCL_ERROR ("X-Y-Z coordinates not floats. Currently only floats are supported.\n");
    return (false);
  }

  size_t npts = in.width * in.height;
  out = Eigen::MatrixXf::Ones (4, npts);

  Eigen::Array4i xyz_offset (in.fields[x_idx].offset, in.fields[y_idx].offset, in.fields[z_idx].offset, 0);

  // Copy the input dataset into Eigen format
  for (size_t i = 0; i < npts; ++i)
  {
     // Unoptimized memcpys: assume fields x, y, z are in random order
     memcpy (&out (0, i), &in.data[xyz_offset[0]], sizeof (float));
     memcpy (&out (1, i), &in.data[xyz_offset[1]], sizeof (float));
     memcpy (&out (2, i), &in.data[xyz_offset[2]], sizeof (float));

     xyz_offset += in.point_step;
  }

  return (true);
}
Esempio n. 4
0
void
pcl::getMinMax3D (const sensor_msgs::PointCloud2ConstPtr &cloud, int x_idx, int y_idx, int z_idx,
                  const std::string &distance_field_name, float min_distance, float max_distance,
                  Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt, bool limit_negative)
{
  // @todo fix this
  if (cloud->fields[x_idx].datatype != sensor_msgs::PointField::FLOAT32 || 
      cloud->fields[y_idx].datatype != sensor_msgs::PointField::FLOAT32 ||
      cloud->fields[z_idx].datatype != sensor_msgs::PointField::FLOAT32)
  {
    PCL_ERROR ("[pcl::getMinMax3D] XYZ dimensions are not float type!\n");
    return;
  }

  Eigen::Array4f min_p, max_p;
  min_p.setConstant (FLT_MAX);
  max_p.setConstant (-FLT_MAX);

  // Get the distance field index
  int distance_idx = pcl::getFieldIndex (*cloud, distance_field_name);

  // @todo fix this
  if (cloud->fields[distance_idx].datatype != sensor_msgs::PointField::FLOAT32)
  {
    PCL_ERROR ("[pcl::getMinMax3D] Filtering dimensions is not float type!\n");
    return;
  }

  int nr_points = cloud->width * cloud->height;

  Eigen::Array4f pt = Eigen::Array4f::Zero ();
  Eigen::Array4i xyz_offset (cloud->fields[x_idx].offset,
                             cloud->fields[y_idx].offset,
                             cloud->fields[z_idx].offset,
                             0);
  float distance_value = 0;
  for (int cp = 0; cp < nr_points; ++cp)
  {
    int point_offset = cp * cloud->point_step;

    // Get the distance value
    memcpy (&distance_value, &cloud->data[point_offset + cloud->fields[distance_idx].offset], sizeof (float));

    if (limit_negative)
    {
      // Use a threshold for cutting out points which inside the interval
      if ((distance_value < max_distance) && (distance_value > min_distance))
      {
        xyz_offset += cloud->point_step;
        continue;
      }
    }
    else
    {
      // Use a threshold for cutting out points which are too close/far away
      if ((distance_value > max_distance) || (distance_value < min_distance))
      {
        xyz_offset += cloud->point_step;
        continue;
      }
    }

    // Unoptimized memcpys: assume fields x, y, z are in random order
    memcpy (&pt[0], &cloud->data[xyz_offset[0]], sizeof (float));
    memcpy (&pt[1], &cloud->data[xyz_offset[1]], sizeof (float));
    memcpy (&pt[2], &cloud->data[xyz_offset[2]], sizeof (float));
    // Check if the point is invalid
    if (!pcl_isfinite (pt[0]) || 
        !pcl_isfinite (pt[1]) || 
        !pcl_isfinite (pt[2]))
    {
      xyz_offset += cloud->point_step;
      continue;
    }
    xyz_offset += cloud->point_step;
    min_p = (min_p.min) (pt);
    max_p = (max_p.max) (pt);
  }
  min_pt = min_p;
  max_pt = max_p;
}
Esempio n. 5
0
void
pcl::VoxelGrid<sensor_msgs::PointCloud2>::applyFilter (PointCloud2 &output)
{
  // If fields x/y/z are not present, we cannot downsample
  if (x_idx_ == -1 || y_idx_ == -1 || z_idx_ == -1)
  {
    PCL_ERROR ("[pcl::%s::applyFilter] Input dataset doesn't have x-y-z coordinates!\n", getClassName ().c_str ());
    output.width = output.height = 0;
    output.data.clear ();
    return;
  }
  int nr_points  = input_->width * input_->height;

  // Copy the header (and thus the frame_id) + allocate enough space for points
  output.height         = 1;                    // downsampling breaks the organized structure
  if (downsample_all_data_)
  {
    output.fields       = input_->fields;
    output.point_step   = input_->point_step;
  }
  else
  {
    output.fields.resize (4);

    output.fields[0] = input_->fields[x_idx_];
    output.fields[0].offset = 0;

    output.fields[1] = input_->fields[y_idx_];
    output.fields[1].offset = 4;

    output.fields[2] = input_->fields[z_idx_];
    output.fields[2].offset = 8;

    output.fields[3].name = "rgba";
    output.fields[3].offset = 12;
    output.fields[3].datatype = sensor_msgs::PointField::FLOAT32;

    output.point_step = 16;
  }
  output.is_bigendian = input_->is_bigendian;
  output.row_step     = input_->row_step;
  output.is_dense     = true;                 // we filter out invalid points

  Eigen::Vector4f min_p, max_p;
  // Get the minimum and maximum dimensions
  if (!filter_field_name_.empty ()) // If we don't want to process the entire cloud...
    getMinMax3D (input_, x_idx_, y_idx_, z_idx_, filter_field_name_, filter_limit_min_, filter_limit_max_, min_p, max_p, filter_limit_negative_);
  else
    getMinMax3D (input_, x_idx_, y_idx_, z_idx_, min_p, max_p);

  // Compute the minimum and maximum bounding box values
  min_b_[0] = (int)(floor (min_p[0] * inverse_leaf_size_[0]));
  max_b_[0] = (int)(floor (max_p[0] * inverse_leaf_size_[0]));
  min_b_[1] = (int)(floor (min_p[1] * inverse_leaf_size_[1]));
  max_b_[1] = (int)(floor (max_p[1] * inverse_leaf_size_[1]));
  min_b_[2] = (int)(floor (min_p[2] * inverse_leaf_size_[2]));
  max_b_[2] = (int)(floor (max_p[2] * inverse_leaf_size_[2]));
//  min_b_ = (min_p.array () * inverse_leaf_size_).cast<int> ();
//  max_b_ = (max_p.array () * inverse_leaf_size_).cast<int> ();

  // Compute the number of divisions needed along all axis
  div_b_ = max_b_ - min_b_ + Eigen::Vector4i::Ones ();
  div_b_[3] = 0;

  // Clear the leaves
  leaves_.clear ();

  // Create the first xyz_offset, and set up the division multiplier
  Eigen::Array4i xyz_offset (input_->fields[x_idx_].offset,
                             input_->fields[y_idx_].offset,
                             input_->fields[z_idx_].offset,
                             0);
  divb_mul_ = Eigen::Vector4i (1, div_b_[0], div_b_[0] * div_b_[1], 0);
  Eigen::Vector4f pt  = Eigen::Vector4f::Zero ();

  int centroid_size = 4;
  if (downsample_all_data_)
    centroid_size = input_->fields.size ();

  int rgba_index = -1;

  // ---[ RGB special case
  // if the data contains "rgba" or "rgb", add an extra field for r/g/b in centroid
  for (int d = 0; d < centroid_size; ++d)
  {
    if (input_->fields[d].name == std::string("rgba") || input_->fields[d].name == std::string("rgb"))
    {
      rgba_index = d;
      centroid_size += 3;
      break;
    }
  }

  Eigen::Vector4i ijk = Eigen::Vector4i::Zero ();
  // If we don't want to process the entire cloud, but rather filter points far away from the viewpoint first...
  if (!filter_field_name_.empty ())
  {
    // Get the distance field index
    int distance_idx = pcl::getFieldIndex (*input_, filter_field_name_);

    // @todo fixme
    if (input_->fields[distance_idx].datatype != sensor_msgs::PointField::FLOAT32)
    {
      PCL_ERROR ("[pcl::%s::applyFilter] Distance filtering requested, but distances are not float/double in the dataset! Only FLOAT32/FLOAT64 distances are supported right now.\n", getClassName ().c_str ());
      output.width = output.height = 0;
      output.data.clear ();
      return;
    }

    // First pass: go over all points and insert them into the right leaf
    float distance_value = 0;
    for (int cp = 0; cp < nr_points; ++cp)
    {
      int point_offset = cp * input_->point_step;
      // Get the distance value
      memcpy (&distance_value, &input_->data[point_offset + input_->fields[distance_idx].offset], sizeof (float));

      if (filter_limit_negative_)
      {
        // Use a threshold for cutting out points which inside the interval
        if (distance_value < filter_limit_max_ && distance_value > filter_limit_min_)
        {
          xyz_offset += input_->point_step;
          continue;
        }
      }
      else
      {
        // Use a threshold for cutting out points which are too close/far away
        if (distance_value > filter_limit_max_ || distance_value < filter_limit_min_)
        {
          xyz_offset += input_->point_step;
          continue;
        }
      }

      // Unoptimized memcpys: assume fields x, y, z are in random order
      memcpy (&pt[0], &input_->data[xyz_offset[0]], sizeof (float));
      memcpy (&pt[1], &input_->data[xyz_offset[1]], sizeof (float));
      memcpy (&pt[2], &input_->data[xyz_offset[2]], sizeof (float));

      // Check if the point is invalid
      if (!pcl_isfinite (pt[0]) || 
          !pcl_isfinite (pt[1]) || 
          !pcl_isfinite (pt[2]))
      {
        xyz_offset += input_->point_step;
        continue;
      }

      ijk[0] = (int)(floor (pt[0] * inverse_leaf_size_[0]));
      ijk[1] = (int)(floor (pt[1] * inverse_leaf_size_[1]));
      ijk[2] = (int)(floor (pt[2] * inverse_leaf_size_[2]));
      // Compute the centroid leaf index
      int idx = (ijk - min_b_).dot (divb_mul_);
      //int idx = (((pt.array () * inverse_leaf_size_).cast<int> ()).matrix () - min_b_).dot (divb_mul_);
      Leaf& leaf = leaves_[idx];

      if (leaf.nr_points == 0)
      {
        leaf.centroid.resize (centroid_size);
        leaf.centroid.setZero ();
      }

      // Do we need to process all the fields?
      if (!downsample_all_data_)
      {
        leaf.centroid.head<4> () += pt;
      }
      else
      {
        Eigen::VectorXf centroid = Eigen::VectorXf::Zero (centroid_size);
        // ---[ RGB special case
        // fill in extra r/g/b centroid field
        if (rgba_index >= 0)
        {
          pcl::RGB rgb;
          memcpy (&rgb, &input_->data[point_offset + input_->fields[rgba_index].offset], sizeof (RGB));
          centroid[centroid_size-3] = rgb.r;
          centroid[centroid_size-2] = rgb.g;
          centroid[centroid_size-1] = rgb.b;
        }
        // Copy all the fields
        for (unsigned int d = 0; d < input_->fields.size (); ++d)
          memcpy (&centroid[d], &input_->data[point_offset + input_->fields[d].offset], field_sizes_[d]);
        leaf.centroid += centroid;
      }
      ++leaf.nr_points;

      xyz_offset += input_->point_step;
    }
  }
  // No distance filtering, process all data
  else
  {
    // First pass: go over all points and insert them into the right leaf
    for (int cp = 0; cp < nr_points; ++cp)
    {
      // Unoptimized memcpys: assume fields x, y, z are in random order
      memcpy (&pt[0], &input_->data[xyz_offset[0]], sizeof (float));
      memcpy (&pt[1], &input_->data[xyz_offset[1]], sizeof (float));
      memcpy (&pt[2], &input_->data[xyz_offset[2]], sizeof (float));

      // Check if the point is invalid
      if (!pcl_isfinite (pt[0]) || 
          !pcl_isfinite (pt[1]) || 
          !pcl_isfinite (pt[2]))
      {
        xyz_offset += input_->point_step;
        continue;
      }

      ijk[0] = (int)(floor (pt[0] * inverse_leaf_size_[0]));
      ijk[1] = (int)(floor (pt[1] * inverse_leaf_size_[1]));
      ijk[2] = (int)(floor (pt[2] * inverse_leaf_size_[2]));
      // Compute the centroid leaf index
      int idx = (ijk - min_b_).dot (divb_mul_);
      //int idx = (((pt.array () * inverse_leaf_size_).cast<int> ()).matrix () - min_b_).dot (divb_mul_);
      Leaf& leaf = leaves_[idx];

      if (leaf.nr_points == 0)
      {
        leaf.centroid.resize (centroid_size);
        leaf.centroid.setZero ();
      }

      // Do we need to process all the fields?
      if (!downsample_all_data_)
        leaf.centroid.head<4> () += pt;
      else
      {
        Eigen::VectorXf centroid = Eigen::VectorXf::Zero (centroid_size);
        int point_offset = cp * input_->point_step;
        // ---[ RGB special case
        // fill extra r/g/b centroid field
        if (rgba_index >= 0)
        {
          pcl::RGB rgb;
          memcpy (&rgb, &input_->data[point_offset + input_->fields[rgba_index].offset], sizeof (RGB));
          centroid[centroid_size-3] = rgb.r;
          centroid[centroid_size-2] = rgb.g;
          centroid[centroid_size-1] = rgb.b;
        }
        // Copy all the fields
        for (unsigned int d = 0; d < input_->fields.size(); ++d)
          memcpy (&centroid[d], &input_->data[point_offset + input_->fields[d].offset], 
                  field_sizes_[d]);

        leaf.centroid += centroid;
      }
      ++leaf.nr_points;

      xyz_offset += input_->point_step;
    }
  }

  // Second pass: go over all leaves and compute centroids
  int nr_p = 0;
  // If we downsample each field, the {x,y,z}_idx_ offsets should correspond in input_ and output
  if (downsample_all_data_)
    xyz_offset = Eigen::Array4i (output.fields[x_idx_].offset,
                                 output.fields[y_idx_].offset,
                                 output.fields[z_idx_].offset,
                                 0);
  else
    // If not, we must have created a new xyzw cloud
    xyz_offset = Eigen::Array4i (0, 4, 8, 12);

  Eigen::VectorXf centroid;
  output.width = leaves_.size ();
  output.row_step = output.point_step * output.width;
  output.data.resize (output.width * output.point_step);

  if (save_leaf_layout_)
    leaf_layout_.resize (div_b_[0] * div_b_[1] * div_b_[2], -1);

  int cp = 0;
  for (boost::unordered_map<size_t, Leaf>::const_iterator it = leaves_.begin (); it != leaves_.end (); ++it)
  {
    // Save leaf layout information for fast access to cells relative to current position
    if (save_leaf_layout_)
      leaf_layout_[it->first] = cp++;

    // Normalize the centroid
    const Leaf& leaf = it->second;
    centroid = leaf.centroid / leaf.nr_points;

    // Do we need to process all the fields?
    if (!downsample_all_data_)
    {
      // Copy the data
      memcpy (&output.data[xyz_offset[0]], &centroid[0], sizeof (float));
      memcpy (&output.data[xyz_offset[1]], &centroid[1], sizeof (float));
      memcpy (&output.data[xyz_offset[2]], &centroid[2], sizeof (float));
      xyz_offset += output.point_step;
    }
    else
    {
      int point_offset = nr_p * output.point_step;
      // Copy all the fields
      for (size_t d = 0; d < output.fields.size (); ++d)
        memcpy (&output.data[point_offset + output.fields[d].offset], &centroid[d], field_sizes_[d]);

      // ---[ RGB special case
      // full extra r/g/b centroid field
      if (rgba_index >= 0) 
      {
        float r = centroid[centroid_size-3], g = centroid[centroid_size-2], b = centroid[centroid_size-1];
        int rgb = ((int)r) << 16 | ((int)g) << 8 | ((int)b);
        memcpy (&output.data[point_offset + output.fields[rgba_index].offset], &rgb, sizeof(float));
      }
    }
    ++nr_p;
  }
}
Esempio n. 6
0
void
pcl::PassThrough<pcl::PCLPointCloud2>::applyFilter (PCLPointCloud2 &output)
{
  if (!input_)
  {
    PCL_ERROR ("[pcl::%s::applyFilter] Input dataset not given!\n", getClassName ().c_str ());
    output.width = output.height = 0;
    output.data.clear ();
    return;
  }

  // If fields x/y/z are not present, we cannot filter
  if (x_idx_ == -1 || y_idx_ == -1 || z_idx_ == -1)
  {
    PCL_ERROR ("[pcl::%s::applyFilter] Input dataset doesn't have x-y-z coordinates!\n", getClassName ().c_str ());
    output.width = output.height = 0;
    output.data.clear ();
    return;
  }

  int nr_points = input_->width * input_->height;

  // Check if we're going to keep the organized structure of the cloud or not
  if (keep_organized_)
  {
    if (filter_field_name_.empty ())
    {
      // Silly - if no filtering is actually done, and we want to keep the data organized, 
      // just copy everything. Any optimizations that can be done here???
      output = *input_;
      return;
    }

    output.width = input_->width;
    output.height = input_->height;
    // Check what the user value is: if !finite, set is_dense to false, true otherwise
    if (!pcl_isfinite (user_filter_value_))
      output.is_dense = false;
    else
      output.is_dense = input_->is_dense;
  }
  else
  {
    // Copy the header (and thus the frame_id) + allocate enough space for points
    output.height = 1; // filtering breaks the organized structure
    // Because we're doing explit checks for isfinite, is_dense = true
    output.is_dense = true;
  }
  output.row_step = input_->row_step;
  output.point_step = input_->point_step;
  output.is_bigendian = input_->is_bigendian;
  output.data.resize (input_->data.size ());

  removed_indices_->resize (input_->data.size ());

  int nr_p = 0;
  int nr_removed_p = 0;
  // Create the first xyz_offset
  Eigen::Array4i xyz_offset (input_->fields[x_idx_].offset, input_->fields[y_idx_].offset,
                             input_->fields[z_idx_].offset, 0);

  Eigen::Vector4f pt = Eigen::Vector4f::Zero ();
  // If we don't want to process the entire cloud, but rather filter points far away from the viewpoint first...
  if (!filter_field_name_.empty ())
  {
    // Get the distance field index
    int distance_idx = pcl::getFieldIndex (*input_, filter_field_name_);
    if (distance_idx == -1)
    {
      PCL_WARN ("[pcl::%s::applyFilter] Invalid filter field name. Index is %d.\n", getClassName ().c_str (), distance_idx);
      output.width = output.height = 0;
      output.data.clear ();
      return;
    }

    // @todo fixme
    if (input_->fields[distance_idx].datatype != pcl::PCLPointField::FLOAT32)
    {
      PCL_ERROR ("[pcl::%s::downsample] Distance filtering requested, but distances are not float/double in the dataset! Only FLOAT32/FLOAT64 distances are supported right now.\n", getClassName ().c_str ());
      output.width = output.height = 0;
      output.data.clear ();
      return;
    }

    float badpt = std::numeric_limits<float>::quiet_NaN ();
    // Check whether we need to store filtered valued in place
    if (keep_organized_)
    {
      float distance_value = 0;
      // Go over all points
      for (int cp = 0; cp < nr_points; ++cp, xyz_offset += input_->point_step)
      {
        // Copy all the fields
        memcpy (&output.data[cp * output.point_step], &input_->data[cp * output.point_step], output.point_step);

        // Get the distance value
        memcpy (&distance_value, &input_->data[cp * input_->point_step + input_->fields[distance_idx].offset],
                sizeof (float));

        if (filter_limit_negative_)
        {
          // Use a threshold for cutting out points which inside the interval
          if ((distance_value < filter_limit_max_) && (distance_value > filter_limit_min_))
          {
            // Unoptimized memcpys: assume fields x, y, z are in random order
            memcpy (&output.data[xyz_offset[0]], &badpt, sizeof (float));
            memcpy (&output.data[xyz_offset[1]], &badpt, sizeof (float));
            memcpy (&output.data[xyz_offset[2]], &badpt, sizeof (float));
            continue;
          }
          else
          {
            if (extract_removed_indices_)
              (*removed_indices_)[nr_removed_p++] = cp;
          }
        }
        else
        {
          // Use a threshold for cutting out points which are too close/far away
          if ((distance_value > filter_limit_max_) || (distance_value < filter_limit_min_))
          {
            // Unoptimized memcpys: assume fields x, y, z are in random order
            memcpy (&output.data[xyz_offset[0]], &badpt, sizeof (float));
            memcpy (&output.data[xyz_offset[1]], &badpt, sizeof (float));
            memcpy (&output.data[xyz_offset[2]], &badpt, sizeof (float));
            continue;
          }
          else
          {
            if (extract_removed_indices_)
              (*removed_indices_)[nr_removed_p++] = cp;
          }
        }
      }
    }
    // Remove filtered points
    else
    {
      // Go over all points
      float distance_value = 0;
      for (int cp = 0; cp < nr_points; ++cp, xyz_offset += input_->point_step)
      {
        // Get the distance value
        memcpy (&distance_value, &input_->data[cp * input_->point_step + input_->fields[distance_idx].offset],
                sizeof(float));

        // Remove NAN/INF/-INF values. We expect passthrough to output clean valid data.
        if (!pcl_isfinite (distance_value))
        {
          if (extract_removed_indices_)
            (*removed_indices_)[nr_removed_p++] = cp;
          continue;
        }

        if (filter_limit_negative_)
        {
          // Use a threshold for cutting out points which inside the interval
          if (distance_value < filter_limit_max_ && distance_value > filter_limit_min_)
          {
            if (extract_removed_indices_)
            {
              (*removed_indices_)[nr_removed_p] = cp;
              nr_removed_p++;
            }
            continue;
          }
        }
        else
        {
          // Use a threshold for cutting out points which are too close/far away
          if (distance_value > filter_limit_max_ || distance_value < filter_limit_min_)
          {
            if (extract_removed_indices_)
            {
              (*removed_indices_)[nr_removed_p] = cp;
              nr_removed_p++;
            }
            continue;
          }
        }

        // Unoptimized memcpys: assume fields x, y, z are in random order
        memcpy (&pt[0], &input_->data[xyz_offset[0]], sizeof(float));
        memcpy (&pt[1], &input_->data[xyz_offset[1]], sizeof(float));
        memcpy (&pt[2], &input_->data[xyz_offset[2]], sizeof(float));

        // Check if the point is invalid
        if (!pcl_isfinite (pt[0]) || !pcl_isfinite (pt[1]) || !pcl_isfinite (pt[2]))
        {
          if (extract_removed_indices_)
          {
            (*removed_indices_)[nr_removed_p] = cp;
            nr_removed_p++;
          }
          continue;
        }

        // Copy all the fields
        memcpy (&output.data[nr_p * output.point_step], &input_->data[cp * output.point_step], output.point_step);
        nr_p++;
      }
      output.width = nr_p;
    } // !keep_organized_
  }
  // No distance filtering, process all data. No need to check for is_organized here as we did it above
  else
  {
    for (int cp = 0; cp < nr_points; ++cp, xyz_offset += input_->point_step)
    {
      // Unoptimized memcpys: assume fields x, y, z are in random order
      memcpy (&pt[0], &input_->data[xyz_offset[0]], sizeof(float));
      memcpy (&pt[1], &input_->data[xyz_offset[1]], sizeof(float));
      memcpy (&pt[2], &input_->data[xyz_offset[2]], sizeof(float));

      // Check if the point is invalid
      if (!pcl_isfinite (pt[0]) || !pcl_isfinite (pt[1]) || !pcl_isfinite (pt[2]))
      {
        if (extract_removed_indices_)
        {
          (*removed_indices_)[nr_removed_p] = cp;
          nr_removed_p++;
        }
        continue;
      }

      // Copy all the fields
      memcpy (&output.data[nr_p * output.point_step], &input_->data[cp * output.point_step], output.point_step);
      nr_p++;
    }
    output.width = nr_p;
  }

  output.row_step = output.point_step * output.width;
  output.data.resize (output.width * output.height * output.point_step);

  removed_indices_->resize (nr_removed_p);
}
Esempio n. 7
0
int
pcl::io::mesh2vtk (const pcl::PolygonMesh& mesh, vtkSmartPointer<vtkPolyData>& poly_data)
{
  unsigned int nr_points = mesh.cloud.width * mesh.cloud.height;
  unsigned int nr_polygons = static_cast<unsigned int> (mesh.polygons.size ());

  // reset vtkPolyData object
  poly_data = vtkSmartPointer<vtkPolyData>::New (); // OR poly_data->Reset();
  vtkSmartPointer<vtkPoints> vtk_mesh_points = vtkSmartPointer<vtkPoints>::New ();
  vtkSmartPointer<vtkCellArray> vtk_mesh_polygons = vtkSmartPointer<vtkCellArray>::New ();
  poly_data->SetPoints (vtk_mesh_points);

  // get field indices for x, y, z (as well as rgb and/or rgba)
  int idx_x = -1, idx_y = -1, idx_z = -1, idx_rgb = -1, idx_rgba = -1, idx_normal_x = -1, idx_normal_y = -1, idx_normal_z = -1;
  for (int d = 0; d < static_cast<int> (mesh.cloud.fields.size ()); ++d)
  {
    if (mesh.cloud.fields[d].name == "x") idx_x = d;
    else if (mesh.cloud.fields[d].name == "y") idx_y = d;
    else if (mesh.cloud.fields[d].name == "z") idx_z = d;
    else if (mesh.cloud.fields[d].name == "rgb") idx_rgb = d;
    else if (mesh.cloud.fields[d].name == "rgba") idx_rgba = d;
    else if (mesh.cloud.fields[d].name == "normal_x") idx_normal_x = d;
    else if (mesh.cloud.fields[d].name == "normal_y") idx_normal_y = d;
    else if (mesh.cloud.fields[d].name == "normal_z") idx_normal_z = d;
  }
  if ( ( idx_x == -1 ) || ( idx_y == -1 ) || ( idx_z == -1 ) )
    nr_points = 0;

  // copy point data
  vtk_mesh_points->SetNumberOfPoints (nr_points);
  if (nr_points > 0)
  {
    Eigen::Vector4f pt = Eigen::Vector4f::Zero ();
    Eigen::Array4i xyz_offset (mesh.cloud.fields[idx_x].offset, mesh.cloud.fields[idx_y].offset, mesh.cloud.fields[idx_z].offset, 0);
    for (vtkIdType cp = 0; cp < static_cast<vtkIdType> (nr_points); ++cp, xyz_offset += mesh.cloud.point_step)
    {
      memcpy(&pt[0], &mesh.cloud.data[xyz_offset[0]], sizeof (float));
      memcpy(&pt[1], &mesh.cloud.data[xyz_offset[1]], sizeof (float));
      memcpy(&pt[2], &mesh.cloud.data[xyz_offset[2]], sizeof (float));
      vtk_mesh_points->InsertPoint (cp, pt[0], pt[1], pt[2]);
    }
  }

  // copy polygon data
  if (nr_polygons > 0)
  {
    for (unsigned int i = 0; i < nr_polygons; i++)
    {
      unsigned int nr_points_in_polygon = static_cast<unsigned int> (mesh.polygons[i].vertices.size ());
      vtk_mesh_polygons->InsertNextCell (nr_points_in_polygon);
      for (unsigned int j = 0; j < nr_points_in_polygon; j++)
        vtk_mesh_polygons->InsertCellPoint (mesh.polygons[i].vertices[j]);
    }
    poly_data->SetPolys (vtk_mesh_polygons);
  }

  // copy color information
  if (idx_rgb != -1 || idx_rgba != -1)
  {
    vtkSmartPointer<vtkUnsignedCharArray> colors = vtkSmartPointer<vtkUnsignedCharArray>::New ();
    colors->SetNumberOfComponents (3);
    colors->SetName ("Colors");
    pcl::RGB rgb;
    int offset = (idx_rgb != -1) ? mesh.cloud.fields[idx_rgb].offset : mesh.cloud.fields[idx_rgba].offset;
    for (vtkIdType cp = 0; cp < nr_points; ++cp)
    {
      memcpy (&rgb, &mesh.cloud.data[cp * mesh.cloud.point_step + offset], sizeof (RGB));
      const unsigned char color[3] = {rgb.r, rgb.g, rgb.b};
      colors->InsertNextTupleValue (color);
    }
    poly_data->GetPointData ()->SetScalars (colors);
  }

  // copy normal information
  if (( idx_normal_x != -1 ) && ( idx_normal_y != -1 ) && ( idx_normal_z != -1 ))
  {
    vtkSmartPointer<vtkFloatArray> normals = vtkSmartPointer<vtkFloatArray>::New ();
    normals->SetNumberOfComponents (3);
    float nx = 0.0f, ny = 0.0f, nz = 0.0f;
    for (vtkIdType cp = 0; cp < nr_points; ++cp)
    {
      memcpy (&nx, &mesh.cloud.data[cp*mesh.cloud.point_step+mesh.cloud.fields[idx_normal_x].offset], sizeof (float));
      memcpy (&ny, &mesh.cloud.data[cp*mesh.cloud.point_step+mesh.cloud.fields[idx_normal_y].offset], sizeof (float));
      memcpy (&nz, &mesh.cloud.data[cp*mesh.cloud.point_step+mesh.cloud.fields[idx_normal_z].offset], sizeof (float));
      const float normal[3] = {nx, ny, nz};
      normals->InsertNextTupleValue (normal);
    }
    poly_data->GetPointData()->SetNormals (normals);
  }

  if (poly_data->GetPoints () == NULL)
    return (0);
  return (static_cast<int> (poly_data->GetPoints ()->GetNumberOfPoints ()));
}
Esempio n. 8
0
void 
transformPointCloud (const Eigen::Matrix4f &transform, const sensor_msgs::PointCloud2 &in,
                     sensor_msgs::PointCloud2 &out)
{
  // Get X-Y-Z indices
  int x_idx = pcl::getFieldIndex (in, "x");
  int y_idx = pcl::getFieldIndex (in, "y");
  int z_idx = pcl::getFieldIndex (in, "z");

  if (x_idx == -1 || y_idx == -1 || z_idx == -1)
  {
    ROS_ERROR ("Input dataset has no X-Y-Z coordinates! Cannot convert to Eigen format.");
    return;
  }

  if (in.fields[x_idx].datatype != sensor_msgs::PointField::FLOAT32 || 
      in.fields[y_idx].datatype != sensor_msgs::PointField::FLOAT32 || 
      in.fields[z_idx].datatype != sensor_msgs::PointField::FLOAT32)
  {
    ROS_ERROR ("X-Y-Z coordinates not floats. Currently only floats are supported.");
    return;
  }

  // Check if distance is available
  int dist_idx = pcl::getFieldIndex (in, "distance");

  // Copy the other data
  if (&in != &out)
  {
    out.header = in.header;
    out.height = in.height;
    out.width  = in.width;
    out.fields = in.fields;
    out.is_bigendian = in.is_bigendian;
    out.point_step   = in.point_step;
    out.row_step     = in.row_step;
    out.is_dense     = in.is_dense;
    out.data.resize (in.data.size ());
    // Copy everything as it's faster than copying individual elements
    memcpy (&out.data[0], &in.data[0], in.data.size ());
  }

  Eigen::Array4i xyz_offset (in.fields[x_idx].offset, in.fields[y_idx].offset, in.fields[z_idx].offset, 0);

  for (size_t i = 0; i < in.width * in.height; ++i)
  {
    Eigen::Vector4f pt (*(float*)&in.data[xyz_offset[0]], *(float*)&in.data[xyz_offset[1]], *(float*)&in.data[xyz_offset[2]], 1);
    Eigen::Vector4f pt_out;
    
    bool max_range_point = false;
    int distance_ptr_offset = i*in.point_step + in.fields[dist_idx].offset;
    float* distance_ptr = (dist_idx < 0 ? NULL : (float*)(&in.data[distance_ptr_offset]));
    if (!std::isfinite (pt[0]) || !std::isfinite (pt[1]) || !std::isfinite (pt[2]))
    {
      if (distance_ptr==NULL || !std::isfinite(*distance_ptr))  // Invalid point
      {
        pt_out = pt;
      }
      else  // max range point
      {
        pt[0] = *distance_ptr;  // Replace x with the x value saved in distance
        pt_out = transform * pt;
        max_range_point = true;
        //std::cout << pt[0]<<","<<pt[1]<<","<<pt[2]<<" => "<<pt_out[0]<<","<<pt_out[1]<<","<<pt_out[2]<<"\n";
      }
    }
    else
    {
      pt_out = transform * pt;
    }

    if (max_range_point)
    {
      // Save x value in distance again
      *(float*)(&out.data[distance_ptr_offset]) = pt_out[0];
      pt_out[0] = std::numeric_limits<float>::quiet_NaN();
    }

    memcpy (&out.data[xyz_offset[0]], &pt_out[0], sizeof (float));
    memcpy (&out.data[xyz_offset[1]], &pt_out[1], sizeof (float));
    memcpy (&out.data[xyz_offset[2]], &pt_out[2], sizeof (float));
  
    
    xyz_offset += in.point_step;
  }

  // Check if the viewpoint information is present
  int vp_idx = pcl::getFieldIndex (in, "vp_x");
  if (vp_idx != -1)
  {
    // Transform the viewpoint info too
    for (size_t i = 0; i < out.width * out.height; ++i)
    {
      float *pstep = (float*)&out.data[i * out.point_step + out.fields[vp_idx].offset];
      // Assume vp_x, vp_y, vp_z are consecutive
      Eigen::Vector4f vp_in (pstep[0], pstep[1], pstep[2], 1);
      Eigen::Vector4f vp_out = transform * vp_in;

      pstep[0] = vp_out[0];
      pstep[1] = vp_out[1];
      pstep[2] = vp_out[2];
    }
  }
}
Esempio n. 9
0
void
pcl::VoxelGrid<sensor_msgs::PointCloud2>::applyFilter (PointCloud2 &output)
{
    // If fields x/y/z are not present, we cannot downsample
    if (x_idx_ == -1 || y_idx_ == -1 || z_idx_ == -1)
    {
        PCL_ERROR ("[pcl::%s::applyFilter] Input dataset doesn't have x-y-z coordinates!\n", getClassName ().c_str ());
        output.width = output.height = 0;
        output.data.clear ();
        return;
    }
    int nr_points  = input_->width * input_->height;

    // Copy the header (and thus the frame_id) + allocate enough space for points
    output.height         = 1;                    // downsampling breaks the organized structure
    if (downsample_all_data_)
    {
        output.fields       = input_->fields;
        output.point_step   = input_->point_step;
    }
    else
    {
        output.fields.resize (4);

        output.fields[0] = input_->fields[x_idx_];
        output.fields[0].offset = 0;

        output.fields[1] = input_->fields[y_idx_];
        output.fields[1].offset = 4;

        output.fields[2] = input_->fields[z_idx_];
        output.fields[2].offset = 8;

        output.fields[3].name = "rgba";
        output.fields[3].offset = 12;
        output.fields[3].datatype = sensor_msgs::PointField::FLOAT32;

        output.point_step = 16;
    }
    output.is_bigendian = input_->is_bigendian;
    output.row_step     = input_->row_step;
    output.is_dense     = true;                 // we filter out invalid points

    Eigen::Vector4f min_p, max_p;
    // Get the minimum and maximum dimensions
    if (!filter_field_name_.empty ()) // If we don't want to process the entire cloud...
        getMinMax3D (input_, x_idx_, y_idx_, z_idx_, filter_field_name_,
                     static_cast<float> (filter_limit_min_),
                     static_cast<float> (filter_limit_max_), min_p, max_p, filter_limit_negative_);
    else
        getMinMax3D (input_, x_idx_, y_idx_, z_idx_, min_p, max_p);

    // Compute the minimum and maximum bounding box values
    min_b_[0] = static_cast<int> (floor (min_p[0] * inverse_leaf_size_[0]));
    max_b_[0] = static_cast<int> (floor (max_p[0] * inverse_leaf_size_[0]));
    min_b_[1] = static_cast<int> (floor (min_p[1] * inverse_leaf_size_[1]));
    max_b_[1] = static_cast<int> (floor (max_p[1] * inverse_leaf_size_[1]));
    min_b_[2] = static_cast<int> (floor (min_p[2] * inverse_leaf_size_[2]));
    max_b_[2] = static_cast<int> (floor (max_p[2] * inverse_leaf_size_[2]));

    // Compute the number of divisions needed along all axis
    div_b_ = max_b_ - min_b_ + Eigen::Vector4i::Ones ();
    div_b_[3] = 0;

    std::vector<cloud_point_index_idx> index_vector;
    index_vector.reserve (nr_points);

    // Create the first xyz_offset, and set up the division multiplier
    Eigen::Array4i xyz_offset (input_->fields[x_idx_].offset,
                               input_->fields[y_idx_].offset,
                               input_->fields[z_idx_].offset,
                               0);
    divb_mul_ = Eigen::Vector4i (1, div_b_[0], div_b_[0] * div_b_[1], 0);
    Eigen::Vector4f pt  = Eigen::Vector4f::Zero ();

    int centroid_size = 4;
    if (downsample_all_data_)
        centroid_size = static_cast<int> (input_->fields.size ());

    int rgba_index = -1;

    // ---[ RGB special case
    // if the data contains "rgba" or "rgb", add an extra field for r/g/b in centroid
    for (int d = 0; d < centroid_size; ++d)
    {
        if (input_->fields[d].name == std::string ("rgba") || input_->fields[d].name == std::string ("rgb"))
        {
            rgba_index = d;
            centroid_size += 3;
            break;
        }
    }

    // If we don't want to process the entire cloud, but rather filter points far away from the viewpoint first...
    if (!filter_field_name_.empty ())
    {
        // Get the distance field index
        int distance_idx = pcl::getFieldIndex (*input_, filter_field_name_);

        // @todo fixme
        if (input_->fields[distance_idx].datatype != sensor_msgs::PointField::FLOAT32)
        {
            PCL_ERROR ("[pcl::%s::applyFilter] Distance filtering requested, but distances are not float/double in the dataset! Only FLOAT32/FLOAT64 distances are supported right now.\n", getClassName ().c_str ());
            output.width = output.height = 0;
            output.data.clear ();
            return;
        }

        // First pass: go over all points and insert them into the index_vector vector
        // with calculated idx. Points with the same idx value will contribute to the
        // same point of resulting CloudPoint
        float distance_value = 0;
        for (int cp = 0; cp < nr_points; ++cp)
        {
            int point_offset = cp * input_->point_step;
            // Get the distance value
            memcpy (&distance_value, &input_->data[point_offset + input_->fields[distance_idx].offset], sizeof (float));

            if (filter_limit_negative_)
            {
                // Use a threshold for cutting out points which inside the interval
                if (distance_value < filter_limit_max_ && distance_value > filter_limit_min_)
                {
                    xyz_offset += input_->point_step;
                    continue;
                }
            }
            else
            {
                // Use a threshold for cutting out points which are too close/far away
                if (distance_value > filter_limit_max_ || distance_value < filter_limit_min_)
                {
                    xyz_offset += input_->point_step;
                    continue;
                }
            }

            // Unoptimized memcpys: assume fields x, y, z are in random order
            memcpy (&pt[0], &input_->data[xyz_offset[0]], sizeof (float));
            memcpy (&pt[1], &input_->data[xyz_offset[1]], sizeof (float));
            memcpy (&pt[2], &input_->data[xyz_offset[2]], sizeof (float));

            // Check if the point is invalid
            if (!pcl_isfinite (pt[0]) ||
                    !pcl_isfinite (pt[1]) ||
                    !pcl_isfinite (pt[2]))
            {
                xyz_offset += input_->point_step;
                continue;
            }

            int ijk0 = static_cast<int> (floor (pt[0] * inverse_leaf_size_[0]) - min_b_[0]);
            int ijk1 = static_cast<int> (floor (pt[1] * inverse_leaf_size_[1]) - min_b_[1]);
            int ijk2 = static_cast<int> (floor (pt[2] * inverse_leaf_size_[2]) - min_b_[2]);
            // Compute the centroid leaf index
            int idx = ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
            index_vector.push_back (cloud_point_index_idx (idx, cp));

            xyz_offset += input_->point_step;
        }
    }
    // No distance filtering, process all data
    else
    {
        // First pass: go over all points and insert them into the right leaf
        for (int cp = 0; cp < nr_points; ++cp)
        {
            // Unoptimized memcpys: assume fields x, y, z are in random order
            memcpy (&pt[0], &input_->data[xyz_offset[0]], sizeof (float));
            memcpy (&pt[1], &input_->data[xyz_offset[1]], sizeof (float));
            memcpy (&pt[2], &input_->data[xyz_offset[2]], sizeof (float));

            // Check if the point is invalid
            if (!pcl_isfinite (pt[0]) ||
                    !pcl_isfinite (pt[1]) ||
                    !pcl_isfinite (pt[2]))
            {
                xyz_offset += input_->point_step;
                continue;
            }

            int ijk0 = static_cast<int> (floor (pt[0] * inverse_leaf_size_[0]) - min_b_[0]);
            int ijk1 = static_cast<int> (floor (pt[1] * inverse_leaf_size_[1]) - min_b_[1]);
            int ijk2 = static_cast<int> (floor (pt[2] * inverse_leaf_size_[2]) - min_b_[2]);
            // Compute the centroid leaf index
            int idx = ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
            index_vector.push_back (cloud_point_index_idx (idx, cp));
            xyz_offset += input_->point_step;
        }
    }

    // Second pass: sort the index_vector vector using value representing target cell as index
    // in effect all points belonging to the same output cell will be next to each other
    std::sort (index_vector.begin (), index_vector.end (), std::less<cloud_point_index_idx> ());

    // Third pass: count output cells
    // we need to skip all the same, adjacenent idx values
    unsigned int total=0;
    unsigned int index=0;
    while (index < index_vector.size ())
    {
        unsigned int i = index + 1;
        while (i < index_vector.size () && index_vector[i].idx == index_vector[index].idx)
            ++i;
        ++total;
        index = i;
    }

    // Fourth pass: compute centroids, insert them into their final position
    output.width = total;
    output.row_step = output.point_step * output.width;
    output.data.resize (output.width * output.point_step);

    if (save_leaf_layout_)
    {
        try
        {
            leaf_layout_.resize (div_b_[0]*div_b_[1]*div_b_[2], -1);
        }
        catch (std::bad_alloc&)
        {
            throw PCLException("VoxelGrid bin size is too low; impossible to allocate memory for layout",
                               "voxel_grid.cpp", "applyFilter");
        }
        catch (std::length_error&)
        {
            throw PCLException("VoxelGrid bin size is too low; impossible to allocate memory for layout",
                               "voxel_grid.cpp", "applyFilter");
        }
    }

    // If we downsample each field, the {x,y,z}_idx_ offsets should correspond in input_ and output
    if (downsample_all_data_)
        xyz_offset = Eigen::Array4i (output.fields[x_idx_].offset,
                                     output.fields[y_idx_].offset,
                                     output.fields[z_idx_].offset,
                                     0);
    else
        // If not, we must have created a new xyzw cloud
        xyz_offset = Eigen::Array4i (0, 4, 8, 12);

    index=0;
    Eigen::VectorXf centroid = Eigen::VectorXf::Zero (centroid_size);
    Eigen::VectorXf temporary = Eigen::VectorXf::Zero (centroid_size);

    for (unsigned int cp = 0; cp < index_vector.size ();)
    {
        int point_offset = index_vector[cp].cloud_point_index * input_->point_step;
        // Do we need to process all the fields?
        if (!downsample_all_data_)
        {
            memcpy (&pt[0], &input_->data[point_offset+input_->fields[x_idx_].offset], sizeof (float));
            memcpy (&pt[1], &input_->data[point_offset+input_->fields[y_idx_].offset], sizeof (float));
            memcpy (&pt[2], &input_->data[point_offset+input_->fields[z_idx_].offset], sizeof (float));
            centroid[0] = pt[0];
            centroid[1] = pt[1];
            centroid[2] = pt[2];
            centroid[3] = 0;
        }
        else
        {
            // ---[ RGB special case
            // fill extra r/g/b centroid field
            if (rgba_index >= 0)
            {
                pcl::RGB rgb;
                memcpy (&rgb, &input_->data[point_offset + input_->fields[rgba_index].offset], sizeof (RGB));
                centroid[centroid_size-3] = rgb.r;
                centroid[centroid_size-2] = rgb.g;
                centroid[centroid_size-1] = rgb.b;
            }
            // Copy all the fields
            for (unsigned int d = 0; d < input_->fields.size (); ++d)
                memcpy (&centroid[d], &input_->data[point_offset + input_->fields[d].offset], field_sizes_[d]);
        }

        unsigned int i = cp + 1;
        while (i < index_vector.size () && index_vector[i].idx == index_vector[cp].idx)
        {
            int point_offset = index_vector[i].cloud_point_index * input_->point_step;
            if (!downsample_all_data_)
            {
                memcpy (&pt[0], &input_->data[point_offset+input_->fields[x_idx_].offset], sizeof (float));
                memcpy (&pt[1], &input_->data[point_offset+input_->fields[y_idx_].offset], sizeof (float));
                memcpy (&pt[2], &input_->data[point_offset+input_->fields[z_idx_].offset], sizeof (float));
                centroid[0] += pt[0];
                centroid[1] += pt[1];
                centroid[2] += pt[2];
            }
            else
            {
                // ---[ RGB special case
                // fill extra r/g/b centroid field
                if (rgba_index >= 0)
                {
                    pcl::RGB rgb;
                    memcpy (&rgb, &input_->data[point_offset + input_->fields[rgba_index].offset], sizeof (RGB));
                    temporary[centroid_size-3] = rgb.r;
                    temporary[centroid_size-2] = rgb.g;
                    temporary[centroid_size-1] = rgb.b;
                }
                // Copy all the fields
                for (unsigned int d = 0; d < input_->fields.size (); ++d)
                    memcpy (&temporary[d], &input_->data[point_offset + input_->fields[d].offset], field_sizes_[d]);
                centroid+=temporary;
            }
            ++i;
        }

        // Save leaf layout information for fast access to cells relative to current position
        if (save_leaf_layout_)
            leaf_layout_[index_vector[cp].idx] = index;

        // Normalize the centroid
        centroid /= static_cast<float> (i - cp);

        // Do we need to process all the fields?
        if (!downsample_all_data_)
        {
            // Copy the data
            memcpy (&output.data[xyz_offset[0]], &centroid[0], sizeof (float));
            memcpy (&output.data[xyz_offset[1]], &centroid[1], sizeof (float));
            memcpy (&output.data[xyz_offset[2]], &centroid[2], sizeof (float));
            xyz_offset += output.point_step;
        }
        else
        {
            int point_offset = index * output.point_step;
            // Copy all the fields
            for (size_t d = 0; d < output.fields.size (); ++d)
                memcpy (&output.data[point_offset + output.fields[d].offset], &centroid[d], field_sizes_[d]);

            // ---[ RGB special case
            // full extra r/g/b centroid field
            if (rgba_index >= 0)
            {
                float r = centroid[centroid_size-3], g = centroid[centroid_size-2], b = centroid[centroid_size-1];
                int rgb = (static_cast<int> (r) << 16) | (static_cast<int> (g) << 8) | static_cast<int> (b);
                memcpy (&output.data[point_offset + output.fields[rgba_index].offset], &rgb, sizeof (float));
            }
        }
        cp = i;
        ++index;
    }
}