Exemple #1
0
//////////////////////////////////////////////////////////////////////////////////////////////
// Compute a local Reference Frame for a 3D feature; the output is stored in the "rf" matrix
template<typename PointInT, typename PointOutT> float
pcl::SHOTLocalReferenceFrameEstimation<PointInT, PointOutT>::getLocalRF (const int& current_point_idx, Eigen::Matrix3f &rf)
{
  const Eigen::Vector4f& central_point = (*input_)[current_point_idx].getVector4fMap ();
  std::vector<int> n_indices;
  std::vector<float> n_sqr_distances;

  searchForNeighbors (current_point_idx, search_parameter_, n_indices, n_sqr_distances);

  Eigen::Matrix<double, Eigen::Dynamic, 4> vij (n_indices.size (), 4);

  Eigen::Matrix3d cov_m = Eigen::Matrix3d::Zero ();

  double distance = 0.0;
  double sum = 0.0;

  int valid_nn_points = 0;

  for (size_t i_idx = 0; i_idx < n_indices.size (); ++i_idx)
  {
    Eigen::Vector4f pt = surface_->points[n_indices[i_idx]].getVector4fMap ();
    if (pt.head<3> () == central_point.head<3> ())
		  continue;

    // Difference between current point and origin
    vij.row (valid_nn_points) = (pt - central_point).cast<double> ();
    vij (valid_nn_points, 3) = 0;

    distance = search_parameter_ - sqrt (n_sqr_distances[i_idx]);

    // Multiply vij * vij'
    cov_m += distance * (vij.row (valid_nn_points).head<3> ().transpose () * vij.row (valid_nn_points).head<3> ());

    sum += distance;
    valid_nn_points++;
  }

  if (valid_nn_points < 5)
  {
    //PCL_ERROR ("[pcl::%s::getLocalRF] Warning! Neighborhood has less than 5 vertexes. Aborting Local RF computation of feature point (%lf, %lf, %lf)\n", "SHOTLocalReferenceFrameEstimation", central_point[0], central_point[1], central_point[2]);
    rf.setConstant (std::numeric_limits<float>::quiet_NaN ());

    return (std::numeric_limits<float>::max ());
  }

  cov_m /= sum;

  Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> solver (cov_m);

  const double& e1c = solver.eigenvalues ()[0];
  const double& e2c = solver.eigenvalues ()[1];
  const double& e3c = solver.eigenvalues ()[2];

  if (!pcl_isfinite (e1c) || !pcl_isfinite (e2c) || !pcl_isfinite (e3c))
  {
    //PCL_ERROR ("[pcl::%s::getLocalRF] Warning! Eigenvectors are NaN. Aborting Local RF computation of feature point (%lf, %lf, %lf)\n", "SHOTLocalReferenceFrameEstimation", central_point[0], central_point[1], central_point[2]);
    rf.setConstant (std::numeric_limits<float>::quiet_NaN ());

    return (std::numeric_limits<float>::max ());
  }

  // Disambiguation
  Eigen::Vector4d v1 = Eigen::Vector4d::Zero ();
  Eigen::Vector4d v3 = Eigen::Vector4d::Zero ();
  v1.head<3> () = solver.eigenvectors ().col (2);
  v3.head<3> () = solver.eigenvectors ().col (0);

  int plusNormal = 0, plusTangentDirection1=0;
  for (int ne = 0; ne < valid_nn_points; ne++)
  {
    double dp = vij.row (ne).dot (v1);
    if (dp >= 0)
      plusTangentDirection1++;

    dp = vij.row (ne).dot (v3);
    if (dp >= 0)
      plusNormal++;
  }

  //TANGENT
  plusTangentDirection1 = 2*plusTangentDirection1 - valid_nn_points;
  if (plusTangentDirection1 == 0)
  {
		int points = 5; //std::min(valid_nn_points*2/2+1, 11);
		int medianIndex = valid_nn_points/2;

		for (int i = -points/2; i <= points/2; i++)
			if ( vij.row (medianIndex - i).dot (v1) > 0)
				plusTangentDirection1 ++;

		if (plusTangentDirection1 < points/2+1)
			v1 *= - 1;
	} else if (plusTangentDirection1 < 0)
    v1 *= - 1;

  //Normal
  plusNormal = 2*plusNormal - valid_nn_points;
  if (plusNormal == 0)
  {
		int points = 5; //std::min(valid_nn_points*2/2+1, 11);
		int medianIndex = valid_nn_points/2;

		for (int i = -points/2; i <= points/2; i++)
			if ( vij.row (medianIndex - i).dot (v3) > 0)
				plusNormal ++;

		if (plusNormal < points/2+1)
			v3 *= - 1;
	} else if (plusNormal < 0)
    v3 *= - 1;

  rf.row (0) = v1.head<3> ().cast<float> ();
  rf.row (2) = v3.head<3> ().cast<float> ();
  rf.row (1) = rf.row (2).cross (rf.row (0));

  return (0.0f);
}
Exemple #2
0
template<typename PointInT, typename PointNT, typename PointOutT> float
pcl::BOARDLocalReferenceFrameEstimation<PointInT, PointNT, PointOutT>::computePointLRF (const int &index,
                                                                                        Eigen::Matrix3f &lrf)
{
  //find Z axis

  //extract support points for Rz radius
  std::vector<int> neighbours_indices;
  std::vector<float> neighbours_distances;
  int n_neighbours = this->searchForNeighbors (index, search_parameter_, neighbours_indices, neighbours_distances);

  //check if there are enough neighbor points, otherwise compute a random X axis and use normal as Z axis
  if (n_neighbours < 6)
  {
    //PCL_WARN(
    //    "[pcl::%s::computePointLRF] Warning! Neighborhood has less than 6 vertices. Aborting description of point with index %d\n",
    //    getClassName().c_str(), index);

    //setting lrf to NaN
    lrf.setConstant (std::numeric_limits<float>::quiet_NaN ());

    return (std::numeric_limits<float>::max ());
  }

  //copy neighbours coordinates into eigen matrix
  Eigen::Matrix<float, Eigen::Dynamic, 3> neigh_points_mat (n_neighbours, 3);
  for (int i = 0; i < n_neighbours; ++i)
  {
    neigh_points_mat.row (i) = (*surface_)[neighbours_indices[i]].getVector3fMap ();
  }

  Eigen::Vector3f x_axis, y_axis;
  //plane fitting to find direction of Z axis
  Eigen::Vector3f fitted_normal; //z_axis
  Eigen::Vector3f centroid;
  planeFitting (neigh_points_mat, centroid, fitted_normal);

  //disambiguate Z axis with normal mean
  normalDisambiguation (*normals_, neighbours_indices, fitted_normal);

  //setting LRF Z axis
  lrf.row (2).matrix () = fitted_normal;

  /////////////////////////////////////////////////////////////////////////////////////////
  //find X axis

  //extract support points for Rx radius
  if (tangent_radius_ != 0.0f && search_parameter_ != tangent_radius_)
  {
    n_neighbours = this->searchForNeighbors (index, tangent_radius_, neighbours_indices, neighbours_distances);
  }

  //find point with the "most different" normal (with respect to fittedNormal)

  float min_normal_cos = std::numeric_limits<float>::max ();
  int min_normal_index = -1;

  bool margin_point_found = false;
  Eigen::Vector3f best_margin_point;
  bool best_point_found_on_margins = false;

  float radius2 = tangent_radius_ * tangent_radius_;

  float margin_distance2 = margin_thresh_ * margin_thresh_ * radius2;

  float max_boundary_angle = 0;

  if (find_holes_)
  {
    randomOrthogonalAxis (fitted_normal, x_axis);

    lrf.row (0).matrix () = x_axis;

    for (int i = 0; i < check_margin_array_size_; i++)
    {
      check_margin_array_[i] = false;
      margin_array_min_angle_[i] = std::numeric_limits<float>::max ();
      margin_array_max_angle_[i] = -std::numeric_limits<float>::max ();
      margin_array_min_angle_normal_[i] = -1.0;
      margin_array_max_angle_normal_[i] = -1.0;
    }
    max_boundary_angle = (2 * static_cast<float> (M_PI)) / static_cast<float> (check_margin_array_size_);
  }

  for (int curr_neigh = 0; curr_neigh < n_neighbours; ++curr_neigh)
  {
    const int& curr_neigh_idx = neighbours_indices[curr_neigh];
    const float& neigh_distance_sqr = neighbours_distances[curr_neigh];
    if (neigh_distance_sqr <= margin_distance2)
    {
      continue;
    }

    //point normalIndex is inside the ring between marginThresh and Radius
    margin_point_found = true;

    Eigen::Vector3f normal_mean = normals_->at (curr_neigh_idx).getNormalVector3fMap ();

    float normal_cos = fitted_normal.dot (normal_mean);
    if (normal_cos < min_normal_cos)
    {
      min_normal_index = curr_neigh_idx;
      min_normal_cos = normal_cos;
      best_point_found_on_margins = false;
    }

    if (find_holes_)
    {
      //find angle with respect to random axis previously calculated
      Eigen::Vector3f indicating_normal_vect;
      directedOrthogonalAxis (fitted_normal, input_->at (index).getVector3fMap (),
                              surface_->at (curr_neigh_idx).getVector3fMap (), indicating_normal_vect);
      float angle = getAngleBetweenUnitVectors (x_axis, indicating_normal_vect, fitted_normal);

      int check_margin_array_idx = std::min (static_cast<int> (floor (angle / max_boundary_angle)), check_margin_array_size_ - 1);
      check_margin_array_[check_margin_array_idx] = true;

      if (angle < margin_array_min_angle_[check_margin_array_idx])
      {
        margin_array_min_angle_[check_margin_array_idx] = angle;
        margin_array_min_angle_normal_[check_margin_array_idx] = normal_cos;
      }
      if (angle > margin_array_max_angle_[check_margin_array_idx])
      {
        margin_array_max_angle_[check_margin_array_idx] = angle;
        margin_array_max_angle_normal_[check_margin_array_idx] = normal_cos;
      }
    }

  } //for each neighbor

  if (!margin_point_found)
  {
    //find among points with neighDistance <= marginThresh*radius
    for (int curr_neigh = 0; curr_neigh < n_neighbours; curr_neigh++)
    {
      const int& curr_neigh_idx = neighbours_indices[curr_neigh];
      const float& neigh_distance_sqr = neighbours_distances[curr_neigh];

      if (neigh_distance_sqr > margin_distance2)
        continue;

      Eigen::Vector3f normal_mean = normals_->at (curr_neigh_idx).getNormalVector3fMap ();

      float normal_cos = fitted_normal.dot (normal_mean);

      if (normal_cos < min_normal_cos)
      {
        min_normal_index = curr_neigh_idx;
        min_normal_cos = normal_cos;
      }
    }//for each neighbor

    // Check if we are not in a degenerate case (all the neighboring normals are NaNs)
    if (min_normal_index == -1)
    {
      lrf.setConstant (std::numeric_limits<float>::quiet_NaN ());
      return (std::numeric_limits<float>::max ());
    }
    //find orthogonal axis directed to minNormalIndex point projection on plane with fittedNormal as axis
    directedOrthogonalAxis (fitted_normal, input_->at (index).getVector3fMap (),
                            surface_->at (min_normal_index).getVector3fMap (), x_axis);
    y_axis = fitted_normal.cross (x_axis);

    lrf.row (0).matrix () = x_axis;
    lrf.row (1).matrix () = y_axis;
    //z axis already set


    return (min_normal_cos);
  }

  if (!find_holes_)
  {
    if (best_point_found_on_margins)
    {
      //if most inclined normal is on support margin
      directedOrthogonalAxis (fitted_normal, input_->at (index).getVector3fMap (), best_margin_point, x_axis);
      y_axis = fitted_normal.cross (x_axis);

      lrf.row (0).matrix () = x_axis;
      lrf.row (1).matrix () = y_axis;
      //z axis already set

      return (min_normal_cos);
    }

    // Check if we are not in a degenerate case (all the neighboring normals are NaNs)
    if (min_normal_index == -1)
    {
      lrf.setConstant (std::numeric_limits<float>::quiet_NaN ());
      return (std::numeric_limits<float>::max ());
    }

    directedOrthogonalAxis (fitted_normal, input_->at (index).getVector3fMap (),
                            surface_->at (min_normal_index).getVector3fMap (), x_axis);
    y_axis = fitted_normal.cross (x_axis);

    lrf.row (0).matrix () = x_axis;
    lrf.row (1).matrix () = y_axis;
    //z axis already set

    return (min_normal_cos);
  }// if(!find_holes_)

  //check if there is at least a hole
  bool is_hole_present = false;
  for (int i = 0; i < check_margin_array_size_; i++)
  {
    if (!check_margin_array_[i])
    {
      is_hole_present = true;
      break;
    }
  }

  if (!is_hole_present)
  {
    if (best_point_found_on_margins)
    {
      //if most inclined normal is on support margin
      directedOrthogonalAxis (fitted_normal, input_->at (index).getVector3fMap (), best_margin_point, x_axis);
      y_axis = fitted_normal.cross (x_axis);

      lrf.row (0).matrix () = x_axis;
      lrf.row (1).matrix () = y_axis;
      //z axis already set

      return (min_normal_cos);
    }

    // Check if we are not in a degenerate case (all the neighboring normals are NaNs)
    if (min_normal_index == -1)
    {
      lrf.setConstant (std::numeric_limits<float>::quiet_NaN ());
      return (std::numeric_limits<float>::max ());
    }

    //find orthogonal axis directed to minNormalIndex point projection on plane with fittedNormal as axis
    directedOrthogonalAxis (fitted_normal, input_->at (index).getVector3fMap (),
                            surface_->at (min_normal_index).getVector3fMap (), x_axis);
    y_axis = fitted_normal.cross (x_axis);

    lrf.row (0).matrix () = x_axis;
    lrf.row (1).matrix () = y_axis;
    //z axis already set

    return (min_normal_cos);
  }//if (!is_hole_present)

  //case hole found
  //find missing region
  float angle = 0.0;
  int hole_end;
  int hole_first;

  //find first no border pie
  int first_no_border = -1;
  if (check_margin_array_[check_margin_array_size_ - 1])
  {
    first_no_border = 0;
  }
  else
  {
    for (int i = 0; i < check_margin_array_size_; i++)
    {
      if (check_margin_array_[i])
      {
        first_no_border = i;
        break;
      }
    }
  }

  //float steep_prob = 0.0;
  float max_hole_prob = -std::numeric_limits<float>::max ();

  //find holes
  for (int ch = first_no_border; ch < check_margin_array_size_; ch++)
  {
    if (!check_margin_array_[ch])
    {
      //border beginning found
      hole_first = ch;
      hole_end = hole_first + 1;
      while (!check_margin_array_[hole_end % check_margin_array_size_])
      {
        ++hole_end;
      }
      //border end found, find angle

      if ((hole_end - hole_first) > 0)
      {
        //check if hole can be a shapeness hole
        int previous_hole = (((hole_first - 1) < 0) ? (hole_first - 1) + check_margin_array_size_ : (hole_first - 1))
            % check_margin_array_size_;
        int following_hole = (hole_end) % check_margin_array_size_;
        float normal_begin = margin_array_max_angle_normal_[previous_hole];
        float normal_end = margin_array_min_angle_normal_[following_hole];
        normal_begin -= min_normal_cos;
        normal_end -= min_normal_cos;
        normal_begin = normal_begin / (1.0f - min_normal_cos);
        normal_end = normal_end / (1.0f - min_normal_cos);
        normal_begin = 1.0f - normal_begin;
        normal_end = 1.0f - normal_end;

        //evaluate P(Hole);
        float hole_width = 0.0f;
        if (following_hole < previous_hole)
        {
          hole_width = margin_array_min_angle_[following_hole] + 2 * static_cast<float> (M_PI)
              - margin_array_max_angle_[previous_hole];
        }
        else
        {
          hole_width = margin_array_min_angle_[following_hole] - margin_array_max_angle_[previous_hole];
        }
        float hole_prob = hole_width / (2 * static_cast<float> (M_PI));

        //evaluate P(zmin|Hole)
        float steep_prob = (normal_end + normal_begin) / 2.0f;

        //check hole prob and after that, check steepThresh

        if (hole_prob > hole_size_prob_thresh_)
        {
          if (steep_prob > steep_thresh_)
          {
            if (hole_prob > max_hole_prob)
            {
              max_hole_prob = hole_prob;

              float angle_weight = ((normal_end - normal_begin) + 1.0f) / 2.0f;
              if (following_hole < previous_hole)
              {
                angle = margin_array_max_angle_[previous_hole] + (margin_array_min_angle_[following_hole] + 2
                    * static_cast<float> (M_PI) - margin_array_max_angle_[previous_hole]) * angle_weight;
              }
              else
              {
                angle = margin_array_max_angle_[previous_hole] + (margin_array_min_angle_[following_hole]
                    - margin_array_max_angle_[previous_hole]) * angle_weight;
              }
            }
          }
        }
      } //(hole_end-hole_first) > 0

      if (hole_end >= check_margin_array_size_)
      {
        break;
      }
      else
      {
        ch = hole_end - 1;
      }
    }
  }

  if (max_hole_prob > -std::numeric_limits<float>::max ())
  {
    //hole found
    Eigen::AngleAxisf rotation = Eigen::AngleAxisf (angle, fitted_normal);
    x_axis = rotation * x_axis;

    min_normal_cos -= 10.0f;
  }
  else
  {
    if (best_point_found_on_margins)
    {
      //if most inclined normal is on support margin
      directedOrthogonalAxis (fitted_normal, input_->at (index).getVector3fMap (), best_margin_point, x_axis);
    }
    else
    {
      // Check if we are not in a degenerate case (all the neighboring normals are NaNs)
      if (min_normal_index == -1)
      {
        lrf.setConstant (std::numeric_limits<float>::quiet_NaN ());
        return (std::numeric_limits<float>::max ());
      }

      //find orthogonal axis directed to minNormalIndex point projection on plane with fittedNormal as axis
      directedOrthogonalAxis (fitted_normal, input_->at (index).getVector3fMap (),
                              surface_->at (min_normal_index).getVector3fMap (), x_axis);
    }
  }

  y_axis = fitted_normal.cross (x_axis);

  lrf.row (0).matrix () = x_axis;
  lrf.row (1).matrix () = y_axis;
  //z axis already set

  return (min_normal_cos);
}