MEPP2 Project
core.inl
Go to the documentation of this file.
1 // Copyright (c) 2012-2019 University of Lyon and CNRS (France).
2 // All rights reserved.
3 //
4 // This file is part of MEPP2; you can redistribute it and/or modify
5 // it under the terms of the GNU Lesser General Public License as
6 // published by the Free Software Foundation; either version 3 of
7 // the License, or (at your option) any later version.
8 //
9 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
10 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11 
12 // -------------------------------------------------------------------------------------
13 // Iterative weighted PCA for robust and edge-aware normal vector estimation
14 //--------------------------------------------------------------------------------------
15 // Julia Sanchez, Florence Denis, David Coeurjolly, Florent dupont, Laurent Trassoudaine, Paul Checchin
16 // Liris (Lyon), Institut Pascal (Clermont Ferrand)
17 // Région Auvergne Rhône Alpes ARC6
18 // Private use for reviewers only
19 // --------------------------------------------------------------------------------------
20 
21 
22 #if defined _MSC_VER
23 #pragma warning(push)
24 #pragma warning(disable: 4267 4244)
25 #endif
26 
27 //Extract neighbors
28 inline void CApp::selectNeighborsKnn(int N)
29 {
30  n_neigh_ = N;
31  std::vector<float> dis;
32  std::vector<int> neigh;
33 
34  int Required_neighbors_nbr = n_neigh_+1;
35  SearchFLANNTreeKnn(tree_, pt, neigh, dis, Required_neighbors_nbr);
36  neighborhood_.resize (n_neigh_,3);
37  std::vector<int> to_erase;
38 
39  for (size_t i = 1; i < neigh.size(); ++i)
40  {
41  if( dis[i] != 0)
42  neighborhood_.row(i-1) = pointcloud_->row(neigh[i]);
43  else
44  {
45  ++Required_neighbors_nbr;
46  SearchFLANNTreeKnn(tree_, pt, neigh, dis, Required_neighbors_nbr);
47  to_erase.push_back(i);
48  for(int k = to_erase.size()-1; k>=0; --k)
49  {
50  neigh.erase(neigh.begin() + to_erase[k]);
51  dis.erase(dis.begin() + to_erase[k]);
52  }
53  --i;
54  }
55  }
56  weights_.resize(neighborhood_.rows());
57  dist_.resize (neighborhood_.rows(), 3);
58  ComputeDist();
59  jamais_fait = 1;
60 }
61 
62 //Flann search (internally used in selectNeighborsKnn )
63 inline void CApp::SearchFLANNTreeKnn(flann::Index<flann::L2<float>>* index,
64  Eigen::Vector3f& input,
65  std::vector<int>& indices,
66  std::vector<float>& dists,
67  int nn)
68 {
69  int dim = input.size();
70 
71  std::vector<float> query;
72  query.resize(dim);
73  for (int i = 0; i < dim; i++)
74  query[i] = input(i);
75  flann::Matrix<float> query_mat(&query[0], 1, dim);
76 
77  indices.resize(nn);
78  dists.resize(nn);
79  flann::Matrix<int> indices_mat(&indices[0], 1, nn);
80  flann::Matrix<float> dists_mat(&dists[0], 1, nn);
81 
91  /*
92  size_t knnSearch(
93  const ElementType *query_point,
94  const size_t num_closest,
95  IndexType *out_indices,
96  DistanceType *out_distances_sq,
97  )
98  */
99 
100  index->knnSearch(query_mat, indices_mat, dists_mat, nn, flann::SearchParams(128));
101 }
102 
103 
104 //Fills dist_ with distances of the neighbors from current PCA reference point
105 inline void CApp::ComputeDist()
106 {
107  dist_ = neighborhood_ - Eigen::VectorXf::Ones(n_neigh_) * pt.transpose();
108 }
109 
110 //Computes 3rd eigen vector of a covariance matrix
111 inline Eigen::Vector3f CApp::getThirdEigenVector(Eigen::Matrix3f& C)
112 {
113  Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> es(C);
114  return es.eigenvectors().col(0);
115 }
116 
117 //first initialization with PCA + initialize mu_lim and tau
118 inline void CApp::init1()
119 {
120  //PCA
121  Eigen::MatrixXf centered_points (n_neigh_, 3);
122  Eigen::Vector3f mean_point = neighborhood_.colwise().mean();
123  centered_points = neighborhood_ - Eigen::VectorXf::Ones(n_neigh_)*(mean_point.transpose());
124 
125  Eigen::Matrix3f C = centered_points.transpose()*centered_points/n_neigh_;
127 
128  normalFirst0_ = new Eigen::Vector3f();
131  finalPos_ = pt;
132 
133  orient();
134 
135  //mu_lim and tau
136  float r = 0;
137  int N_boundary_neihborhood = (int)(0.2*neighborhood_.rows());
138  for(int i = 1; i<=N_boundary_neihborhood; ++i)
139  r += (neighborhood_.row(neighborhood_.rows()-i)-pt.transpose()).norm();
140  r /= N_boundary_neihborhood;
141  float Xmax = r*r/(2.0*curvature_);
142  float theta_m = 2*acos(1-Xmax/curvature_);
143  float mean;
144  float thresh;
145  if(abs(theta_m)>epsilon)
146  {
147  mean = 2*curvature_*sin(theta_m/2)/theta_m; // mean of distances to plane
148  thresh = sqrt((pow(curvature_,2)/2)*(1+(sin(theta_m)/theta_m)) - pow(mean,2));//sqrt( (1/theta_m)*( pow(curvature_,2)*( (theta_m/4) - (sin(theta_m)/4) ) - 2*mean*curvature_*sin(theta_m/2) + pow(mean,2)*theta_m/2 ) );
149  }
150  else
151  {
152  mean = 0;
153  thresh = 0;
154  }
155  float emax = Xmax+noise_/2;
156 
157  thresh_proj_ = (thresh + noise_);
158  limMuPos_ = emax*emax;
159 }
160 
161 inline void CApp::reinitFirst0()
162 {
164 }
165 
166 //second initialization -> perpendicular to edge and n01
167 inline void CApp::init2()
168 {
170  if(abs(normalFirst0_->dot(*normalFirst2_))<0.996)
171  {
172  Eigen::Vector3f edge_direction = normalFirst0_->cross(*normalFirst2_);
173  edge_direction /= edge_direction.norm();
174  normal = edge_direction.cross(*normalFirst2_);
175  normal /= normal.norm();
176  normalSecond0_ = new Eigen::Vector3f();
178  SuspectedOnEdge_ = 1;
179  }
180  else
181  {
182  SuspectedOnEdge_ = 0;
185  }
186 }
187 
188 //First weighting -> all weights in 1
189 inline void CApp::init_weight()
190 {
191  for (int i = 0; i<weights_.size(); ++i)
192  weights_[i] = 1;
193 }
194 
195 //Checks if point has neigborhood on edge (use tau)
196 inline bool CApp::isOnEdge()
197 {
198  Eigen::Vector3f pt_moy = Eigen::Vector3f::Zero();
199  for (int c = 0; c < n_neigh_; c++)
200  pt_moy += neighborhood_.row(c);
201 
202  pt_moy /= n_neigh_;
203 
204  float proj_moy = 0;
205  for (int c = 0; c < n_neigh_; c++)
206  proj_moy += pow(normal.dot(neighborhood_.row(c).transpose()-pt_moy),2);
207 
208  proj_moy /= n_neigh_;
209  proj_moy = sqrt(proj_moy);
210  return ( proj_moy>thresh_proj_ );
211 }
212 
213 //Actualizes weights
214 inline void CApp::ComputeWeights()
215 {
216  for (int c = 0; c < n_neigh_; c++)
217  weights_(c) = pow(mu_/(mu_+pow(normal.dot(dist_.row(c)),2)),2); //Scaled version of Geman McClure estimator
218 }
219 
220 //Compute maximal residual
221 inline float CApp::GetMaxError()
222 {
223  float er_max = 0;
224  float er_proj;
225  for (int c = 0; c < n_neigh_; c++)
226  {
227  er_proj = normal.dot(dist_.row(c));
228  if(abs(er_proj)>er_max)
229  er_max = abs(er_proj);
230  }
231  return er_max;
232 }
233 
234 //Rough estimation
235 inline void CApp::Optimize(bool first)
236 {
237  ComputeDist();
238 
239  if (first)
240  {
241  er_max = GetMaxError();
242  mu_ = pow(mu_max*er_max,2);
243  mu_ = std::max(mu_,limMuPos_);
244  }
245  else
246  {
247  std::vector<float> er_proj_squared(n_neigh_);
248  for (int c = 0; c < n_neigh_; c++)
249  er_proj_squared[c] = pow(normal.dot(dist_.row(c)),2);
250  std::sort(er_proj_squared.begin(), er_proj_squared.end());
251  mu_ = er_proj_squared[(int)(n_neigh_*mu_max2)];
252  mu_ = std::max(mu_,limMuPos_);
253 
254  mu_init2_ = mu_;
255  }
256 
257  int itr = 0;
258 
259  while(itr < itr_min || mu_ > limMuPos_)
260  {
261  if( mu_ > limMuPos_ && (itr % itr_per_mu) == 0)
262  mu_ /= divFact_;
263 
264  ComputeWeights();
265  Eigen::Matrix3f C = dist_.transpose()*weights_.asDiagonal()*dist_;// /weights_.sum();
266 
268  ++itr;
269  }
270 
271  if (first)
272  {
273  normalFirst1_ = new Eigen::Vector3f();
275  }
276  else
277  {
278  normalSecond1_ = new Eigen::Vector3f();
280  }
281 }
282 
283 //Refinement
284 inline void CApp::OptimizePos(bool first, float thresh_weight)
285 {
286  if(!first)
287  {
288  if(!isSecondOption())
289  {
292  return;
293  }
294  mu_ = 0.5*mu_init2_;
295  mu_ = std::max(mu_,limMuPos_);
296  }
297  else
298  {
299  mu_ = pow(0.5*er_max,2);
300  mu_ = std::max(mu_,limMuPos_);
301  }
302 
303  //-----------------------------------------------------------------------------------------
304  float sum_poids = 0;
305  float moy_proj = 0;
306 
307  int it = itr_per_mu*(int)(log(mu_/(limMuPos_) )/log(divFact_));
308 
309  if(it<itr_min)
310  it=itr_min;
311 
312  int itr = 0;
313 
314  while( itr< it)
315  {
316  if( mu_ > limMuPos_ && (itr % itr_per_mu) == 0)
317  mu_ /= divFact_;
318 
319  //actualize position of the PCA reference
320 
321  sum_poids = 0;
322  moy_proj = 0;
323 
324  for (int c = 0; c < n_neigh_; c++)
325  {
326  if(weights_(c) > thresh_weight)
327  {
328  sum_poids += weights_(c);
329  moy_proj += weights_(c)*normal.dot(dist_.row(c));
330  }
331  }
332  moy_proj /= sum_poids;
333 
334  pt = pt + moy_proj*normal;
335 
336  ComputeDist();
337  ComputeWeights();
338 
339  //actualize normal
340  Eigen::Matrix3f C = dist_.transpose()*weights_.asDiagonal()*dist_;
342 
343  ++itr;
344  }
345 
346  orient();
347 
348  if(first)
349  {
350  normalFirst2_ = new Eigen::Vector3f();
352  pointFirst_ = new Eigen::Vector3f();
353  *pointFirst_ = pt;
354 
356  }
357  else
358  {
359  normalSecond2_ = new Eigen::Vector3f();
361  pointSecond_ = new Eigen::Vector3f();
362  *pointSecond_ = pt;
364  select_normal();
365  }
366 }
367 
368 //orient normal to the exterior of the edge
369 inline void CApp::orient()
370 {
371  float moy_err = 0;
372  for (int c = 0; c < n_neigh_; c++)
373  moy_err += normal.dot(dist_.row(c));
374 
375  if(moy_err> epsilon)
376  normal = -normal;
377 }
378 
379 inline bool CApp::isSecondOption()
380 {
382 }
383 
384 inline void CApp::setRef( int ref)
385 {
386  ref_ = ref;
387  pt = pointcloud_->row(ref);
388  ptRef_ = pt;
389 }
390 
391 inline void CApp::reinitPoint()
392 {
393  setPoint(ptRef_);
394 }
395 
396 inline void CApp::evaluate(int *impact, float *mean, float weight_tresh)
397 {
398  float imp = 0;
399  for(int c = 0; c<n_neigh_; ++c)
400  {
401  if(weights_(c)>weight_tresh)
402  ++imp;
403  }
404 
405  *impact = imp;
406  *mean = (pt-ptRef_).dot(normal);
407 }
408 
409 inline void CApp::setPoint(Eigen::Vector3f point)
410 {
411  pt = point;
412  ComputeDist();
413 }
414 
415 //Check if result contains nan
416 inline bool CApp::isNan()
417 {
418  return (finalNormal_(0) != finalNormal_(0) || finalPos_(0) != finalPos_(0));
419 }
420 
421 inline void CApp::select_normal()
422 {
423  int min_points = (int)(min_points_fact*(float)neighborhood_.rows());
424  if( moyErrorFirst_<moyErrorSecond_ && impactFirst_>min_points )
425  {
428  }
429  else if(impactSecond_>min_points)
430  {
433  }
434  else if(impactFirst_>min_points)
435  {
438  }
440  {
443  }
444  else
445  {
448  }
449 }
450 
451 
452 #if defined _MSC_VER
453 #pragma warning(pop)
454 #endif
CApp::moyErrorSecond_
float moyErrorSecond_
Definition: core.h:244
CApp::GetMaxError
float GetMaxError()
Definition: core.inl:221
CApp::normalFirst2_
Eigen::Vector3f * normalFirst2_
Definition: core.h:222
CApp::jamais_fait
bool jamais_fait
Definition: core.h:245
CApp::isOnEdge
bool isOnEdge()
Definition: core.inl:196
CApp::OptimizePos
void OptimizePos(bool first, float thresh_weigh)
Definition: core.inl:284
CApp::Optimize
void Optimize(bool first)
Definition: core.inl:235
CApp::reinitFirst0
void reinitFirst0()
Definition: core.inl:161
CApp::tree_
flann::Index< flann::L2< float > > * tree_
Definition: core.h:213
CApp::dist_
Eigen::Matrix< float, Eigen::Dynamic, 3 > dist_
Definition: core.h:215
CApp::init2
void init2()
Definition: core.inl:167
CApp::isSecondOption
bool isSecondOption()
Definition: core.inl:379
FEVV::Math::Vector::Stats::mean
static ElementType mean(const ElementType v[DIM])
Definition: MatrixOperations.hpp:133
mu_max2
const float mu_max2
Definition: core.h:46
CApp::ptRef_
Eigen::Vector3f ptRef_
Definition: core.h:218
CApp::pointSecond_
Eigen::Vector3f * pointSecond_
Definition: core.h:227
likelihood_threshold
const float likelihood_threshold
Definition: core.h:60
CApp::mu_
float mu_
Definition: core.h:205
CApp::isNan
bool isNan()
Definition: core.inl:416
CApp::setRef
void setRef(int ref)
Definition: core.inl:384
CApp::normalSecond1_
Eigen::Vector3f * normalSecond1_
Definition: core.h:224
CApp::moyErrorFirst_
float moyErrorFirst_
Definition: core.h:243
CApp::n_neigh_
int n_neigh_
Definition: core.h:204
CApp::ComputeDist
void ComputeDist()
Definition: core.inl:105
itr_per_mu
const int itr_per_mu
Definition: core.h:58
CApp::noise_
float noise_
Definition: core.h:206
CApp::normalSecond2_
Eigen::Vector3f * normalSecond2_
Definition: core.h:225
CApp::normalFirst1_
Eigen::Vector3f * normalFirst1_
Definition: core.h:221
mu_max
const float mu_max
Definition: core.h:57
CApp::er_max
float er_max
Definition: core.h:246
CApp::setPoint
void setPoint(Eigen::Vector3f point)
Definition: core.inl:409
CApp::neighborhood_
Eigen::Matrix< float, Eigen::Dynamic, 3 > neighborhood_
Definition: core.h:214
CApp::SuspectedOnEdge_
bool SuspectedOnEdge_
Definition: core.h:200
CApp::finalPos_
Eigen::Vector3f finalPos_
Definition: core.h:197
CApp::normal
Eigen::Vector3f normal
Definition: core.h:199
CApp::curvature_
float curvature_
Definition: core.h:209
CApp::evaluate
void evaluate(int *impact, float *moyError, float impacter_weigh)
Definition: core.inl:396
FEVV::Operators::Geometry::acos
T acos(T cosine)
Safe call to the std::acos function.
Definition: AngleOperations.hpp:64
itr_min
const int itr_min
Definition: core.h:56
CApp::mu_init2_
float mu_init2_
Definition: core.h:247
CApp::pointcloud_
Eigen::Matrix< float, Eigen::Dynamic, 3 > * pointcloud_
Definition: core.h:212
CApp::ref_
int ref_
Definition: core.h:216
CApp::getThirdEigenVector
Eigen::Vector3f getThirdEigenVector(Eigen::Matrix3f &C)
Definition: core.inl:111
CApp::impactSecond_
int impactSecond_
Definition: core.h:242
CApp::limMuPos_
float limMuPos_
Definition: core.h:208
CApp::SearchFLANNTreeKnn
void SearchFLANNTreeKnn(flann::Index< flann::L2< float >> *index, Eigen::Vector3f &input, std::vector< int > &indices, std::vector< float > &dists, int nn)
Definition: core.inl:63
min_points_fact
const float min_points_fact
Definition: core.h:61
CApp::normalSecond0_
Eigen::Vector3f * normalSecond0_
Definition: core.h:223
CApp::reinitPoint
void reinitPoint()
Definition: core.inl:391
CApp::divFact_
float divFact_
Definition: core.h:210
thresh_weight
const float thresh_weight
Definition: core.h:62
CApp::impactFirst_
int impactFirst_
Definition: core.h:241
CApp::selectNeighborsKnn
void selectNeighborsKnn(int N)
Definition: core.inl:28
CApp::normalFirst0_
Eigen::Vector3f * normalFirst0_
Definition: core.h:220
CApp::weights_
Eigen::VectorXf weights_
Definition: core.h:230
CApp::orient
void orient()
Definition: core.inl:369
CApp::pt
Eigen::Vector3f pt
Definition: core.h:217
CApp::finalNormal_
Eigen::Vector3f finalNormal_
Definition: core.h:196
CApp::ComputeWeights
void ComputeWeights()
Definition: core.inl:214
CApp::select_normal
void select_normal()
Definition: core.inl:421
CApp::init1
void init1()
Definition: core.inl:118
CApp::init_weight
void init_weight()
Definition: core.inl:189
epsilon
const float epsilon
Definition: core.h:51
CApp::pointFirst_
Eigen::Vector3f * pointFirst_
Definition: core.h:226
CApp::thresh_proj_
float thresh_proj_
Definition: core.h:211