PCL - MLS code study - RANDOM_UNIFORM_DENSITY up sampling method

Keywords: C++ PCL

PCL - MLS code study (XIII) - RANDOM_UNIFORM_DENSITY up sampling method

preface

stay PCL - MLS code study (XI) - computeMLSPointNormal function NONE and sample have been introduced in_ LOCAL_ Sampling method on plane. This chapter mainly introduces random, which was omitted before_ UNIFORM_ Density up sampling method.

Member variable

protected member variable:

/** \brief Parameter that specifies the desired number of points within the search radius
  * \note Used only in the case of RANDOM_UNIFORM_DENSITY upsampling
  */
int desired_num_points_in_radius_;

desired_num_points_in_radius_ Specifies the number of points to reach within the search radius.

private member variable:

/** \brief Random number generator algorithm. */
mutable std::mt19937 rng_;

/** \brief Random number generator using an uniform distribution of floats
  * \note Used only in the case of RANDOM_UNIFORM_DENSITY upsampling
  */
std::unique_ptr<std::uniform_real_distribution<>> rng_uniform_distribution_;

std::mt19937 is a new type of random number generator, which can generate high-quality random numbers. std::uniform_real_distribution means that the random number distribution we want is uniform. Their detailed introduction can be referred to Teaching of C++11 built-in random number function library: random random number generator and probability distribution.

getter & setter

/** \brief Set the parameter that specifies the desired number of points within the search radius
  * \note Used only in the case of RANDOM_UNIFORM_DENSITY upsampling
  * \param[in] desired_num_points_in_radius the desired number of points in the output cloud in a sphere of
  * radius \ref search_radius_ around each point
  */
inline void
setPointDensity (int desired_num_points_in_radius) { desired_num_points_in_radius_ = desired_num_points_in_radius; }


/** \brief Get the parameter that specifies the desired number of points within the search radius
  * \note Used only in the case of RANDOM_UNIFORM_DENSITY upsampling
  */
inline int
getPointDensity () const { return (desired_num_points_in_radius_); }

The above two functions are desired_ num_ points_ in_ Setters and getter s of radius member variables.

process function

//
template <typename PointInT, typename PointOutT> void
pcl::MovingLeastSquares<PointInT, PointOutT>::process (PointCloudOut &output)
{
  //...

  //If you use upsampling methods other than NONE, you have to initialize the required member variables
  switch (upsample_method_)
  {
    // Initialize random number generator if necessary
    case (RANDOM_UNIFORM_DENSITY):
    {
      std::random_device rd;
      rng_.seed (rd());
      //Generate a number evenly and randomly within (- search_radius_ / 2.0,search_radius_ / 2.0)
      const double tmp = search_radius_ / 2.0;
      rng_uniform_distribution_.reset (new std::uniform_real_distribution<> (-tmp, tmp));

      break;
    }
    case (VOXEL_GRID_DILATION):
    case (DISTINCT_CLOUD):
    {
      //...
    }
    default:
      break;
  }
  //...

  // Perform the actual surface reconstruction
  performProcessing (output);

  //...
}

Initializes member variables rng#. Then initialize rng_uniform_distribution_, Let it randomly and evenly generate floating-point numbers in the range of [- search_radius_ / 2.0, search_radius_ / 2.0]. I don't know why the value range here is not [- search_radius, search_radius].

You can see that the performProcessing function is called at the end of the process function. In the performProcessing function, the computeMLSPointNormal function is further called.

template <typename PointInT, typename PointOutT> void
pcl::MovingLeastSquares<PointInT, PointOutT>::performProcessing (PointCloudOut &output)
{
  // ...
  for (int cp = 0; cp < static_cast<int> (indices_->size ()); ++cp)
  {
    // ...

    // Get the initial estimates of point positions and their neighborhoods
    if (searchForNeighbors ((*indices_)[cp], nn_indices, nn_sqr_dists))
    {
      // Check the number of nearest neighbors for normal estimation (and later for polynomial fit as well)
      if (nn_indices.size () >= 3)
      {
        // ...
        computeMLSPointNormal (index, nn_indices, projected_points, projected_points_normals, *corresponding_input_indices_, mls_results_[mls_result_index]);
      }
    }
  }

  //...
}

computeMLSPointNormal function

In the computeMLSPointNormal function, the number of target points for upsampling will be calculated as num first_ points_ to_ Add, and then rng_ And rng_uniform_distribution_ Generate points within the range, project the points, and then call addProjectedPointNormal function to add the projection points to the output point cloud.

The computeMLSPointNormal function is followed by random_ UNIFORM_ The relevant parts of the sampling method on density are as follows:

case (RANDOM_UNIFORM_DENSITY):
{

First, calculate the number of points to be filled in:

// Compute the local point density and add more samples if necessary
//Why divide the radius by two?
//Why not desired_num_points_in_radius_-nn_indices.size ()
//desired_num_points_in_radius and nn_indices common radius
const int num_points_to_add = static_cast<int> (std::floor (desired_num_points_in_radius_ / 2.0 / static_cast<double> (nn_indices.size ())));

==Why divide, not subtract== The following is the author's guess: suppose that each point will become x points after upper sampling, so the radius is nn_indices.size() points will become NN_ Indexes. Size() multiply by X points. If x is taken as desired_num_points_in_radius_/ nn_ Indexes. Size(), then the number of points in the search radius will be approximately equal to desired after upsampling_ num_ points_ in_ radius_. What is / 2.0 in the code for?

If upsampling is not required, query_ After point projection, add it to projected_ In the points data structure:

// Just add the query point, because the density is good
if (num_points_to_add <= 0)
{
  // Just add the current point
  const MLSResult::MLSProjectionResults proj = mls_result.projectQueryPoint (projection_method_, nr_coeff_);
  addProjectedPointNormal (index, proj.point, proj.normal, mls_result.curvature, projected_points, projected_points_normals, corresponding_input_indices);
}

If upper sampling is required, query_ A point is randomly generated within the range of [- search_radius_ / 2.0, search_radius_ / 2.0] near point, projected onto a surface or plane, and finally added to the projected point_ points,projected_points_ In data structures such as normals.

else
{
  // Sample the local plane
  for (int num_added = 0; num_added < num_points_to_add;)
  {
    //Generate a number evenly and randomly within (- search_radius_ / 2.0,search_radius_ / 2.0)
    const double u = (*rng_uniform_distribution_) (rng_);
    const double v = (*rng_uniform_distribution_) (rng_);

    // Check if inside circle; if not, try another coin flip
    // If "search_radius/2" is taken as the radius, then this sentence is reasonable
    // After continue here, the bottom "num_added + +" will be skipped
    if (u * u + v * v > search_radius_ * search_radius_ / 4)
      continue;

    MLSResult::MLSProjectionResults proj;
    //Why not do the same check as projectPointSimpleToPolynomialSurface:
    //if (order > 1 && c_vec.size () >= (order + 1) * (order + 2) / 2 && std::isfinite (c_vec[0]))
    if (order_ > 1 && mls_result.num_neighbors >= 5 * nr_coeff_)
      proj = mls_result.projectPointSimpleToPolynomialSurface (u, v);
    else
      proj = mls_result.projectPointToMLSPlane (u, v);

    addProjectedPointNormal (index, proj.point, proj.normal, mls_result.curvature, projected_points, projected_points_normals, corresponding_input_indices);

    num_added++;
  }
}
break;

Upsampling results

Figure 1 shows the original point cloud, and Figure 2 shows the point cloud after up sampling.

Posted by neroag on Mon, 13 Sep 2021 16:34:30 -0700