PanoramaNormals.cpp
Go to the documentation of this file.
1 
29 
31 #include "lvr2/geometry/Normal.hpp"
32 #include "lvr2/io/Progress.hpp"
33 #include "lvr2/io/Timestamp.hpp"
34 
35 #include <Eigen/Dense>
36 
37 #include <iostream>
38 #include <iterator>
39 #include <algorithm>
40 
41 #include <gsl/gsl_math.h>
42 #include <gsl/gsl_eigen.h>
43 
44 using std::cout;
45 using std::endl;
46 
47 namespace lvr2
48 {
49 
50 using Vec = BaseVector<float>;
51 
53  : m_mti(mti)
54 {
55  m_buffer = mti->pointBuffer();
56 }
57 
59 {
60  // Create new point buffer and tmp storages
61  PointBufferPtr out_buffer(new PointBuffer);
62  vector<float> pts;
63  vector<float> normals;
64 
65  // Get input buffer's points
66  PointBufferPtr in_buffer = m_mti->pointBuffer();
67  size_t w_color;
68  size_t n_inPoints = in_buffer->numPoints();
69  floatArr in_points = in_buffer->getPointArray();
70  ucharArr in_colors = in_buffer->getColorArray(w_color);
71 
72  // Reserve memory for output buffers (we need a deep copy)
73  floatArr p_arr(new float[n_inPoints * 3]);
74  floatArr n_arr(new float[n_inPoints * 3]);
75  ucharArr c_arr;
76  if(in_buffer->hasColors())
77  {
78  c_arr = ucharArr(new unsigned char[n_inPoints * 3]);
79  }
80 
81  // Get panorama
84 
85  // If the desired neighborhood is larger than 2 x 2 pixels
86  // compute offsets for i und j dimension of the image.
87  int di = 2;
88  if(width > 2)
89  {
90  di = width / 2;
91  }
92 
93 
94  int dj = 2;
95  if(height > 2)
96  {
97  dj = height / 2;
98  }
99 
100  // Compute normals
101  // Create progress output
102  string comment = timestamp.getElapsedTime() + "Computing normals ";
103  ProgressBar progress(mat.pixels.size(), comment);
104 
105 
106 
107  for(size_t i = 0; i < mat.pixels.size(); i++)
108  {
109  #pragma omp parallel for
110  for(size_t j = 0; j < mat.pixels[i].size(); j++)
111  {
112  // Check if image entry is empty
113  if(mat.pixels[i][j].size() == 0)
114  {
115  continue;
116  }
117 
118  // Collect 'neighboring' points
119  vector<ModelToImage::PanoramaPoint> nb;
120 
121  // The points at the current position are part of the neighborhood
122  std::copy(mat.pixels[i][j].begin(), mat.pixels[i][j].end(), std::back_inserter(nb));
123 
124  for(int off_i = -di; off_i <= di; off_i++)
125  {
126  for(int off_j = -dj; off_j <= dj; off_j++)
127  {
128  int p_i = i + off_i;
129  int p_j = j + off_j;
130 
131 
132  if(p_i >= 0 && p_i < mat.pixels.size() &&
133  p_j >= 0 && p_j < mat.pixels[i].size())
134  {
135  // We only save the first point as representative
136  // because using all points from list will likely
137  // result in undesirable configurations for local
138  // normal estimation
139  if(mat.pixels[p_i][p_j].size() > 0)
140  {
141  nb.push_back(mat.pixels[p_i][p_j][0]);
142  }
143  }
144  }
145  }
146 
147  // Compute normal if more than three neighbors where found
148  if(nb.size() > 3)
149  {
150 
151 
152  // Compute mean
153  Vec mean;
154  for(int i = 0; i < nb.size(); i++)
155  {
156  // Determine position of geometry in point array
157  size_t index = nb[i].index * 3;
158 
159  // Get point coordinates
160  Vec neighbor(in_points[index],
161  in_points[index + 1],
162  in_points[index + 2]);
163 
164  // Add to mean
165  mean.x += neighbor.x;
166  mean.y += neighbor.y;
167  mean.z += neighbor.z;
168  }
169  mean.x /= nb.size();
170  mean.y /= nb.size();
171  mean.z /= nb.size();
172 
173  // Calculate covariance
174  double covariance[9] = {0};
175 
176  for(int i = 0; i < nb.size(); i++)
177  {
178  size_t index = nb[i].index * 3;
179 
180  Vec pt(in_points[index ] - mean.x,
181  in_points[index + 1] - mean.y,
182  in_points[index + 3] - mean.z);
183 
184  covariance[4] += pt.y * pt.y;
185  covariance[7] += pt.y * pt.z;
186  covariance[8] += pt.z * pt.z;
187 
188  pt.x *= pt.x;
189  pt.y *= pt.x;
190  pt.z *= pt.x;
191 
192  covariance[0] += pt.x;
193  covariance[1] += pt.y;
194  covariance[6] += pt.z;
195 
196  }
197 
198  covariance[3] = covariance[1];
199  covariance[2] = covariance[6];
200  covariance[5] = covariance[7];
201 
202  for(int i = 0; i < 9; i++)
203  {
204  covariance[i] /= nb.size();
205  }
206 
207  // Compute eigenvalues and eigenvectors using GSL
208  gsl_matrix_view m = gsl_matrix_view_array(covariance, 3, 3);
209  gsl_matrix* evec = gsl_matrix_alloc(3, 3);
210  gsl_vector* eval = gsl_vector_alloc(3);
211 
212 
213  gsl_eigen_symmv_workspace * w = gsl_eigen_symmv_alloc (3);
214  gsl_eigen_symmv (&m.matrix, eval, evec, w);
215 
216  gsl_eigen_symmv_free (w);
217  gsl_eigen_symmv_sort (eval, evec, GSL_EIGEN_SORT_ABS_ASC);
218 
219  gsl_vector_view evec_0 = gsl_matrix_column(evec, 0);
220  float nx = gsl_vector_get(&evec_0.vector, 0);
221  float ny = gsl_vector_get(&evec_0.vector, 1);
222  float nz = gsl_vector_get(&evec_0.vector, 2);
223 
224  // Flip normals towards reference point
225  Normal<float> nn(nx, ny, nz);
226  Vec center(0, 0, 0);
227 
228  size_t index = mat.pixels[i][j][0].index * 3;
229  Vec p1 = center - Vec(in_points[index], in_points[index + 1], in_points[index + 2]);
230 
231  if(Normal<float>(p1) * nn < 0)
232  {
233  nx *= -1;
234  ny *= -1;
235  nz *= -1;
236  }
237 
238  for(size_t k = 0; k < mat.pixels[i][j].size(); k++)
239  {
240  // Assign the same normal to all points
241  // behind this pixel to preserve the complete
242  // point cloud
243  size_t index = mat.pixels[i][j][k].index * 3;
244  size_t color_index = mat.pixels[i][j][k].index * w_color;
245 
246  // Copy point and normal to target buffer
247  p_arr[index ] = in_points[index];
248  p_arr[index + 1] = in_points[index + 1];
249  p_arr[index + 2] = in_points[index + 2];
250 
251  if(in_buffer->hasColors())
252  {
253  c_arr[index ] = in_colors[color_index];
254  c_arr[index + 1] = in_colors[color_index + 1];
255  c_arr[index + 2] = in_colors[color_index + 2];
256  }
257 
258  if(!interpolate)
259  {
260  n_arr[index ] = nx;
261  n_arr[index + 1] = ny;
262  n_arr[index + 2] = nz;
263  }
264  }
265  }
266  }
267  ++progress;
268  }
269  cout << endl;
270 
271 // if(interpolate)
272 // {
273 // cout << timestamp << " Interpolating normals" << endl;
274 // for(size_t i = 0; i < mat.pixels.size(); i++)
275 // {
276 // for(size_t j = 0; j < mat.pixels[i].size(); j++)
277 // {
278 // float x = 0.0f;
279 // float y = 0.0f;
280 // float z = 0.0f;
281 // int np = 0;
282 // for(int off_i = -di; off_i <= di; off_i++)
283 // {
284 // for(int off_j = -dj; off_j <= dj; off_j++)
285 // {
286 // int p_i = i + off_i;
287 // int p_j = j + off_j;
288 
289 
290 // if(p_i >= 0 && p_i < mat.pixels.size() &&
291 // p_j >= 0 && p_j < mat.pixels[i].size())
292 // {
293 // for(size_t k = 0; k < mat.pixels[p_i][p_j].size(); k++)
294 // {
295 // size_t index = mat.pixels[p_i][p_j][k].index;
296 // x += in_points[index];
297 // y += in_points[index + 1];
298 // z += in_points[index + 2];
299 // np++;
300 // }
301 // }
302 // }
303 // }
304 // if(np > 3) // Same condition as above
305 // {
306 // x /= np;
307 // y /= np;
308 // z /= np;
309 // normals.push_back(x);
310 // normals.push_back(y);
311 // normals.push_back(z);
312 // }
313 
314 // }
315 // }
316 
317 // cout << normals.size() << " " << pts.size() << endl;
318 // }
319 
320  cout << timestamp << "Finished normal estimation" << endl;
321 
322  if(in_buffer->hasColors())
323  {
324  out_buffer->setColorArray(c_arr, n_inPoints);
325  }
326  out_buffer->setPointArray(p_arr, n_inPoints);
327  out_buffer->setNormalArray(n_arr, n_inPoints);
328 
329  return out_buffer;
330 }
331 
332 } // namespace lvr2
lvr2::floatArr
boost::shared_array< float > floatArr
Definition: DataStruct.hpp:133
lvr2::ProgressBar
Definition: Progress.hpp:68
BaseVector.hpp
lvr2::BaseVector< float >
lvr2::Vec
BaseVector< float > Vec
Definition: TexturedMesh.hpp:44
lvr2::PanoramaNormals::computeNormals
PointBufferPtr computeNormals(int with, int height, bool interpolate)
Definition: PanoramaNormals.cpp:58
lvr2::ModelToImage::PLI::pixels
vector< vector< vector< PanoramaPoint > > > pixels
Definition: ModelToImage.hpp:87
lvr2::PointBufferPtr
std::shared_ptr< PointBuffer > PointBufferPtr
Definition: PointBuffer.hpp:130
lvr2::PointBuffer
A class to handle point information with an arbitrarily large number of attribute channels....
Definition: PointBuffer.hpp:51
lvr2::Timestamp::getElapsedTime
string getElapsedTime() const
Returns a string representation of the current timer value.
Definition: Timestamp.cpp:136
lvr2::BaseVector::x
CoordT x
Definition: BaseVector.hpp:65
lvr2::ModelToImage::PLI
Image with list of projected points at each pixel.
Definition: ModelToImage.hpp:85
lvr2::PanoramaNormals::m_buffer
PointBufferPtr m_buffer
Definition: PanoramaNormals.hpp:51
psimpl::math::interpolate
OutputIterator interpolate(InputIterator p1, InputIterator p2, float fraction, OutputIterator result)
Peforms linear interpolation between two points.
Definition: psimpl.h:260
PanoramaNormals.hpp
lvr2::Normal< float >
lvr2::BaseVector::y
CoordT y
Definition: BaseVector.hpp:66
lvr2::timestamp
static Timestamp timestamp
A global time stamp object for program runtime measurement.
Definition: Timestamp.hpp:116
Progress.hpp
Vec
BaseVector< float > Vec
Definition: src/tools/lvr2_cuda_normals/Main.cpp:57
lvr2::ModelToImage
The ModelToImage class provides methods to re-project 3D laser scans to image planes.
Definition: ModelToImage.hpp:55
lvr2::BaseVector::z
CoordT z
Definition: BaseVector.hpp:67
lvr2::ModelToImage::pointBuffer
PointBufferPtr pointBuffer()
Retruns the point buffer.
Definition: ModelToImage.hpp:186
lvr2::ucharArr
boost::shared_array< unsigned char > ucharArr
Definition: DataStruct.hpp:137
lvr2
Definition: BaseBufferManipulators.hpp:39
Timestamp.hpp
lvr2::PanoramaNormals::PanoramaNormals
PanoramaNormals(ModelToImage *mti)
Definition: PanoramaNormals.cpp:52
lvr2::ModelToImage::computeDepthListMatrix
void computeDepthListMatrix(DepthListMatrix &mat)
Computes a DepthListMatrix, i.e., an image matrix where each entry holds a vector of all points that ...
Definition: ModelToImage.cpp:91
Normal.hpp
lvr2::PanoramaNormals::m_mti
ModelToImage * m_mti
Definition: PanoramaNormals.hpp:50


lvr2
Author(s): Thomas Wiemann , Sebastian Pütz , Alexander Mock , Lars Kiesow , Lukas Kalbertodt , Tristan Igelbrink , Johan M. von Behren , Dominik Feldschnieders , Alexander Löhr
autogenerated on Wed Mar 2 2022 00:37:24