38 #ifndef PCL_SURFACE_IMPL_SURFEL_SMOOTHING_H_
39 #define PCL_SURFACE_IMPL_SURFEL_SMOOTHING_H_
41 #include <pcl/search/organized.h>
42 #include <pcl/search/kdtree.h>
43 #include <pcl/surface/surfel_smoothing.h>
45 #include <pcl/console/print.h>
48 template <
typename Po
intT,
typename Po
intNT>
bool
56 PCL_ERROR (
"SurfelSmoothing: normal cloud not set\n");
60 if (input_->size () != normals_->size ())
62 PCL_ERROR (
"SurfelSmoothing: number of input points different from the number of given normals\n");
69 if (input_->isOrganized ())
84 template <
typename Po
intT,
typename Po
intNT>
float
91 output_positions->points.resize (interm_cloud_->size ());
93 output_normals->points.resize (interm_cloud_->size ());
96 std::vector<float> nn_distances;
98 std::vector<float> diffs (interm_cloud_->size ());
99 float total_residual = 0.0f;
101 for (std::size_t i = 0; i < interm_cloud_->size (); ++i)
103 Eigen::Vector4f smoothed_point = Eigen::Vector4f::Zero ();
104 Eigen::Vector4f smoothed_normal = Eigen::Vector4f::Zero ();
108 tree_->radiusSearch ((*interm_cloud_)[i], 5*scale_, nn_indices, nn_distances);
110 float theta_normalization_factor = 0.0;
111 std::vector<float> theta (nn_indices.size ());
112 for (std::size_t nn_index_i = 0; nn_index_i < nn_indices.size (); ++nn_index_i)
115 float theta_i = std::exp ( (-1) * dist / scale_squared_);
116 theta_normalization_factor += theta_i;
118 smoothed_normal += theta_i * (*interm_normals_)[nn_indices[nn_index_i]].getNormalVector4fMap ();
120 theta[nn_index_i] = theta_i;
123 smoothed_normal /= theta_normalization_factor;
124 smoothed_normal(3) = 0.0f;
125 smoothed_normal.normalize ();
130 smoothed_point = (*interm_cloud_)[i].getVector4fMap ();
134 smoothed_point(3) = 0.0f;
135 for (std::size_t nn_index_i = 0; nn_index_i < nn_indices.size (); ++nn_index_i)
137 Eigen::Vector4f neighbor = (*input_)[nn_indices[nn_index_i]].getVector4fMap ();
139 float dot_product = smoothed_normal.dot (neighbor - smoothed_point);
140 e_residual += theta[nn_index_i] * dot_product;
142 e_residual /= theta_normalization_factor;
143 if (e_residual < 1e-5)
break;
145 smoothed_point += e_residual * smoothed_normal;
148 total_residual += e_residual;
150 (*output_positions)[i].getVector4fMap () = smoothed_point;
151 (*output_normals)[i].getNormalVector4fMap () = (*normals_)[i].getNormalVector4fMap ();
156 return total_residual;
160 template <
typename Po
intT,
typename Po
intNT>
void
163 PointNT &output_normal)
165 Eigen::Vector4f average_normal = Eigen::Vector4f::Zero ();
166 Eigen::Vector4f result_point = (*input_)[point_index].getVector4fMap ();
167 result_point(3) = 0.0f;
170 float error_residual_threshold_ = 1e-3f;
171 float error_residual = error_residual_threshold_ + 1;
172 float last_error_residual = error_residual + 100.0f;
175 std::vector<float> nn_distances;
177 int big_iterations = 0;
178 int max_big_iterations = 500;
180 while (std::fabs (error_residual) < std::fabs (last_error_residual) -error_residual_threshold_ &&
181 big_iterations < max_big_iterations)
183 average_normal = Eigen::Vector4f::Zero ();
185 PointT aux_point; aux_point.x = result_point(0); aux_point.y = result_point(1); aux_point.z = result_point(2);
186 tree_->radiusSearch (aux_point, 5*scale_, nn_indices, nn_distances);
188 float theta_normalization_factor = 0.0;
189 std::vector<float> theta (nn_indices.size ());
190 for (std::size_t nn_index_i = 0; nn_index_i < nn_indices.size (); ++nn_index_i)
192 float dist = nn_distances[nn_index_i];
193 float theta_i = std::exp ( (-1) * dist / scale_squared_);
194 theta_normalization_factor += theta_i;
196 average_normal += theta_i * (*normals_)[nn_indices[nn_index_i]].getNormalVector4fMap ();
197 theta[nn_index_i] = theta_i;
199 average_normal /= theta_normalization_factor;
200 average_normal(3) = 0.0f;
201 average_normal.normalize ();
204 float e_residual_along_normal = 2, last_e_residual_along_normal = 3;
205 int small_iterations = 0;
206 int max_small_iterations = 10;
207 while ( std::fabs (e_residual_along_normal) < std::fabs (last_e_residual_along_normal) &&
208 small_iterations < max_small_iterations)
212 e_residual_along_normal = 0.0f;
213 for (std::size_t nn_index_i = 0; nn_index_i < nn_indices.size (); ++nn_index_i)
215 Eigen::Vector4f neighbor = (*input_)[nn_indices[nn_index_i]].getVector4fMap ();
217 float dot_product = average_normal.dot (neighbor - result_point);
218 e_residual_along_normal += theta[nn_index_i] * dot_product;
220 e_residual_along_normal /= theta_normalization_factor;
221 if (e_residual_along_normal < 1e-3)
break;
223 result_point += e_residual_along_normal * average_normal;
229 last_error_residual = error_residual;
230 error_residual = e_residual_along_normal;
235 output_point.x = result_point(0);
236 output_point.y = result_point(1);
237 output_point.z = result_point(2);
238 output_normal = (*normals_)[point_index];
240 if (big_iterations == max_big_iterations)
241 PCL_DEBUG (
"[pcl::SurfelSmoothing::smoothPoint] Passed the number of BIG iterations: %d\n", big_iterations);
246 template <
typename Po
intT,
typename Po
intNT>
void
252 PCL_ERROR (
"[pcl::SurfelSmoothing::computeSmoothedCloud]: SurfelSmoothing not initialized properly, skipping computeSmoothedCloud ().\n");
256 tree_->setInputCloud (input_);
258 output_positions->header = input_->header;
259 output_positions->height = input_->height;
260 output_positions->width = input_->width;
262 output_normals->header = input_->header;
263 output_normals->height = input_->height;
264 output_normals->width = input_->width;
266 output_positions->points.resize (input_->size ());
267 output_normals->points.resize (input_->size ());
268 for (std::size_t i = 0; i < input_->size (); ++i)
270 smoothPoint (i, (*output_positions)[i], (*output_normals)[i]);
275 template <
typename Po
intT,
typename Po
intNT>
void
280 if (interm_cloud_->size () != cloud2->size () ||
281 cloud2->size () != cloud2_normals->size ())
283 PCL_ERROR (
"[pcl::SurfelSmoothing::extractSalientFeaturesBetweenScales]: Number of points in the clouds does not match.\n");
287 std::vector<float> diffs (cloud2->size ());
288 for (std::size_t i = 0; i < cloud2->size (); ++i)
289 diffs[i] = (*cloud2_normals)[i].getNormalVector4fMap ().dot ((*cloud2)[i].getVector4fMap () -
290 (*interm_cloud_)[i].getVector4fMap ());
293 std::vector<float> nn_distances;
295 output_features->resize (cloud2->size ());
296 for (
int point_i = 0; point_i < static_cast<int> (cloud2->size ()); ++point_i)
299 tree_->radiusSearch (point_i, scale_, nn_indices, nn_distances);
302 bool smallest =
true;
303 for (
const auto &nn_index : nn_indices)
305 if (diffs[point_i] < diffs[nn_index])
311 if (largest || smallest)
312 (*output_features)[point_i] = point_i;
318 #define PCL_INSTANTIATE_SurfelSmoothing(PointT,PointNT) template class PCL_EXPORTS pcl::SurfelSmoothing<PointT, PointNT>;
PointCloud represents the base class in PCL for storing collections of 3D points.
typename pcl::PointCloud< PointNT >::Ptr NormalCloudPtr
void extractSalientFeaturesBetweenScales(PointCloudInPtr &cloud2, NormalCloudPtr &cloud2_normals, pcl::IndicesPtr &output_features)
float smoothCloudIteration(PointCloudInPtr &output_positions, NormalCloudPtr &output_normals)
void smoothPoint(std::size_t &point_index, PointT &output_point, PointNT &output_normal)
void computeSmoothedCloud(PointCloudInPtr &output_positions, NormalCloudPtr &output_normals)
typename pcl::PointCloud< PointT >::Ptr PointCloudInPtr
search::KdTree is a wrapper class which inherits the pcl::KdTree class for performing search function...
OrganizedNeighbor is a class for optimized nearest neighbor search in organized projectable point clo...
Define standard C methods to do distance calculations.
float squaredEuclideanDistance(const PointType1 &p1, const PointType2 &p2)
Calculate the squared euclidean distance between the two given points.
IndicesAllocator<> Indices
Type used for indices in PCL.
shared_ptr< Indices > IndicesPtr
A point structure representing Euclidean xyz coordinates, and the RGB color.