Point Cloud Library (PCL) 1.15.1-dev
Loading...
Searching...
No Matches
surfel_smoothing.hpp
1/*
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2011, Alexandru-Eugen Ichim
5 * Willow Garage, Inc
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * * Neither the name of Willow Garage, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * $Id$
36 */
37
38#ifndef PCL_SURFACE_IMPL_SURFEL_SMOOTHING_H_
39#define PCL_SURFACE_IMPL_SURFEL_SMOOTHING_H_
40
41#include <pcl/search/auto.h>
42#include <pcl/surface/surfel_smoothing.h>
44#include <pcl/console/print.h> // for PCL_ERROR, PCL_DEBUG
45
46//////////////////////////////////////////////////////////////////////////////////////////////
47template <typename PointT, typename PointNT> bool
49{
51 return false;
52
53 if (!normals_)
54 {
55 PCL_ERROR ("SurfelSmoothing: normal cloud not set\n");
56 return false;
57 }
58
59 if (input_->size () != normals_->size ())
60 {
61 PCL_ERROR ("SurfelSmoothing: number of input points different from the number of given normals\n");
62 return false;
63 }
64
65 // Initialize the spatial locator
66 if (!tree_)
67 {
68 tree_.reset (pcl::search::autoSelectMethod<PointT>(input_, false, pcl::search::Purpose::radius_search));
69 }
70
71 // create internal copies of the input - these will be modified
72 interm_cloud_ = PointCloudInPtr (new PointCloudIn (*input_));
73 interm_normals_ = NormalCloudPtr (new NormalCloud (*normals_));
74
75 return (true);
76}
77
78
79//////////////////////////////////////////////////////////////////////////////////////////////
80template <typename PointT, typename PointNT> float
82 NormalCloudPtr &output_normals)
83{
84// PCL_INFO ("SurfelSmoothing: cloud smoothing iteration starting ...\n");
85
86 output_positions = PointCloudInPtr (new PointCloudIn);
87 output_positions->points.resize (interm_cloud_->size ());
88 output_normals = NormalCloudPtr (new NormalCloud);
89 output_normals->points.resize (interm_cloud_->size ());
90
91 pcl::Indices nn_indices;
92 std::vector<float> nn_distances;
93
94 std::vector<float> diffs (interm_cloud_->size ());
95 float total_residual = 0.0f;
96
97 for (std::size_t i = 0; i < interm_cloud_->size (); ++i)
98 {
99 Eigen::Vector4f smoothed_point = Eigen::Vector4f::Zero ();
100 Eigen::Vector4f smoothed_normal = Eigen::Vector4f::Zero ();
101
102 // get neighbors
103 // @todo using 5x the scale for searching instead of all the points to avoid O(N^2)
104 tree_->radiusSearch ((*interm_cloud_)[i], 5*scale_, nn_indices, nn_distances);
105
106 float theta_normalization_factor = 0.0;
107 std::vector<float> theta (nn_indices.size ());
108 for (std::size_t nn_index_i = 0; nn_index_i < nn_indices.size (); ++nn_index_i)
109 {
110 float dist = pcl::squaredEuclideanDistance ((*interm_cloud_)[i], (*input_)[nn_indices[nn_index_i]]);//(*interm_cloud_)[nn_indices[nn_index_i]]);
111 float theta_i = std::exp ( (-1) * dist / scale_squared_);
112 theta_normalization_factor += theta_i;
113
114 smoothed_normal += theta_i * (*interm_normals_)[nn_indices[nn_index_i]].getNormalVector4fMap ();
115
116 theta[nn_index_i] = theta_i;
117 }
118
119 smoothed_normal /= theta_normalization_factor;
120 smoothed_normal(3) = 0.0f;
121 smoothed_normal.normalize ();
122
123
124 // find minimum along the normal
125 float e_residual;
126 smoothed_point = (*interm_cloud_)[i].getVector4fMap ();
127 while (true)
128 {
129 e_residual = 0.0f;
130 smoothed_point(3) = 0.0f;
131 for (std::size_t nn_index_i = 0; nn_index_i < nn_indices.size (); ++nn_index_i)
132 {
133 Eigen::Vector4f neighbor = (*input_)[nn_indices[nn_index_i]].getVector4fMap ();//(*interm_cloud_)[nn_indices[nn_index_i]].getVector4fMap ();
134 neighbor(3) = 0.0f;
135 float dot_product = smoothed_normal.dot (neighbor - smoothed_point);
136 e_residual += theta[nn_index_i] * dot_product;// * dot_product;
137 }
138 e_residual /= theta_normalization_factor;
139 if (e_residual < 1e-5) break;
140
141 smoothed_point += e_residual * smoothed_normal;
142 }
143
144 total_residual += e_residual;
145
146 (*output_positions)[i].getVector4fMap () = smoothed_point;
147 (*output_normals)[i].getNormalVector4fMap () = (*normals_)[i].getNormalVector4fMap ();//smoothed_normal;
148 }
149
150// std::cerr << "Total residual after iteration: " << total_residual << std::endl;
151// PCL_INFO("SurfelSmoothing done iteration\n");
152 return total_residual;
153}
154
155
156template <typename PointT, typename PointNT> void
158 PointT &output_point,
159 PointNT &output_normal)
160{
161 Eigen::Vector4f average_normal = Eigen::Vector4f::Zero ();
162 Eigen::Vector4f result_point = (*input_)[point_index].getVector4fMap ();
163 result_point(3) = 0.0f;
164
165 // @todo parameter
166 float error_residual_threshold_ = 1e-3f;
167 float error_residual = error_residual_threshold_ + 1;
168 float last_error_residual = error_residual + 100.0f;
169
170 pcl::Indices nn_indices;
171 std::vector<float> nn_distances;
172
173 int big_iterations = 0;
174 int max_big_iterations = 500;
175
176 while (std::fabs (error_residual) < std::fabs (last_error_residual) -error_residual_threshold_ &&
177 big_iterations < max_big_iterations)
178 {
179 average_normal = Eigen::Vector4f::Zero ();
180 big_iterations ++;
181 PointT aux_point; aux_point.x = result_point(0); aux_point.y = result_point(1); aux_point.z = result_point(2);
182 tree_->radiusSearch (aux_point, 5*scale_, nn_indices, nn_distances);
183
184 float theta_normalization_factor = 0.0;
185 std::vector<float> theta (nn_indices.size ());
186 for (std::size_t nn_index_i = 0; nn_index_i < nn_indices.size (); ++nn_index_i)
187 {
188 float dist = nn_distances[nn_index_i];
189 float theta_i = std::exp ( (-1) * dist / scale_squared_);
190 theta_normalization_factor += theta_i;
191
192 average_normal += theta_i * (*normals_)[nn_indices[nn_index_i]].getNormalVector4fMap ();
193 theta[nn_index_i] = theta_i;
194 }
195 average_normal /= theta_normalization_factor;
196 average_normal(3) = 0.0f;
197 average_normal.normalize ();
198
199 // find minimum along the normal
200 float e_residual_along_normal = 2, last_e_residual_along_normal = 3;
201 int small_iterations = 0;
202 int max_small_iterations = 10;
203 while ( std::fabs (e_residual_along_normal) < std::fabs (last_e_residual_along_normal) &&
204 small_iterations < max_small_iterations)
205 {
206 small_iterations ++;
207
208 e_residual_along_normal = 0.0f;
209 for (std::size_t nn_index_i = 0; nn_index_i < nn_indices.size (); ++nn_index_i)
210 {
211 Eigen::Vector4f neighbor = (*input_)[nn_indices[nn_index_i]].getVector4fMap ();
212 neighbor(3) = 0.0f;
213 float dot_product = average_normal.dot (neighbor - result_point);
214 e_residual_along_normal += theta[nn_index_i] * dot_product;
215 }
216 e_residual_along_normal /= theta_normalization_factor;
217 if (e_residual_along_normal < 1e-3) break;
218
219 result_point += e_residual_along_normal * average_normal;
220 }
221
222// if (small_iterations == max_small_iterations)
223// PCL_INFO ("passed the number of small iterations %d\n", small_iterations);
224
225 last_error_residual = error_residual;
226 error_residual = e_residual_along_normal;
227
228// PCL_INFO ("last %f current %f\n", last_error_residual, error_residual);
229 }
230
231 output_point.x = result_point(0);
232 output_point.y = result_point(1);
233 output_point.z = result_point(2);
234 output_normal = (*normals_)[point_index];
235
236 if (big_iterations == max_big_iterations)
237 PCL_DEBUG ("[pcl::SurfelSmoothing::smoothPoint] Passed the number of BIG iterations: %d\n", big_iterations);
238}
239
240
241//////////////////////////////////////////////////////////////////////////////////////////////
242template <typename PointT, typename PointNT> void
244 NormalCloudPtr &output_normals)
245{
246 if (!initCompute ())
247 {
248 PCL_ERROR ("[pcl::SurfelSmoothing::computeSmoothedCloud]: SurfelSmoothing not initialized properly, skipping computeSmoothedCloud ().\n");
249 return;
250 }
251
252 tree_->setInputCloud (input_);
253
254 output_positions->header = input_->header;
255 output_positions->height = input_->height;
256 output_positions->width = input_->width;
257
258 output_normals->header = input_->header;
259 output_normals->height = input_->height;
260 output_normals->width = input_->width;
261
262 output_positions->points.resize (input_->size ());
263 output_normals->points.resize (input_->size ());
264 for (std::size_t i = 0; i < input_->size (); ++i)
265 {
266 smoothPoint (i, (*output_positions)[i], (*output_normals)[i]);
267 }
268}
269
270//////////////////////////////////////////////////////////////////////////////////////////////
271template <typename PointT, typename PointNT> void
273 NormalCloudPtr &cloud2_normals,
274 pcl::IndicesPtr &output_features)
275{
276 if (interm_cloud_->size () != cloud2->size () ||
277 cloud2->size () != cloud2_normals->size ())
278 {
279 PCL_ERROR ("[pcl::SurfelSmoothing::extractSalientFeaturesBetweenScales]: Number of points in the clouds does not match.\n");
280 return;
281 }
282
283 std::vector<float> diffs (cloud2->size ());
284 for (std::size_t i = 0; i < cloud2->size (); ++i)
285 diffs[i] = (*cloud2_normals)[i].getNormalVector4fMap ().dot ((*cloud2)[i].getVector4fMap () -
286 (*interm_cloud_)[i].getVector4fMap ());
287
288 pcl::Indices nn_indices;
289 std::vector<float> nn_distances;
290
291 output_features->resize (cloud2->size ());
292 for (int point_i = 0; point_i < static_cast<int> (cloud2->size ()); ++point_i)
293 {
294 // Get neighbors
295 tree_->radiusSearch (point_i, scale_, nn_indices, nn_distances);
296
297 bool largest = true;
298 bool smallest = true;
299 for (const auto &nn_index : nn_indices)
300 {
301 if (diffs[point_i] < diffs[nn_index])
302 largest = false;
303 else
304 smallest = false;
305 }
306
307 if (largest || smallest)
308 (*output_features)[point_i] = point_i;
309 }
310}
311
312
313
314#define PCL_INSTANTIATE_SurfelSmoothing(PointT,PointNT) template class PCL_EXPORTS pcl::SurfelSmoothing<PointT, PointNT>;
315
316#endif /* PCL_SURFACE_IMPL_SURFEL_SMOOTHING_H_ */
PCL base class.
Definition pcl_base.h:70
typename pcl::PointCloud< PointNT >::Ptr NormalCloudPtr
pcl::PointCloud< PointT > PointCloudIn
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
Define standard C methods to do distance calculations.
@ radius_search
The search method will mainly be used for radiusSearch.
float squaredEuclideanDistance(const PointType1 &p1, const PointType2 &p2)
Calculate the squared euclidean distance between the two given points.
Definition distances.h:182
IndicesAllocator<> Indices
Type used for indices in PCL.
Definition types.h:133
shared_ptr< Indices > IndicesPtr
Definition pcl_base.h:58
A point structure representing Euclidean xyz coordinates, and the RGB color.