superquadric-model
superquadric.cpp
1 /*
2  * Copyright (C) 2015 iCub Facility - Istituto Italiano di Tecnologia
3  * Author: Giulia Vezzani
4  * email: giulia.vezzani@iit.it
5  * Permission is granted to copy, distribute, and/or modify this program
6  * under the terms of the GNU General Public License, version 2 or any
7  * later version published by the Free Software Foundation.
8  *
9  * A copy of the license can be found at
10  * http://www.robotcub.org/icub/license/gpl.txt
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15  * Public License for more details
16 */
17 
18 #include <csignal>
19 #include <cmath>
20 #include <limits>
21 #include <algorithm>
22 #include <sstream>
23 #include <fstream>
24 #include <iomanip>
25 
26 #include <yarp/math/Math.h>
27 #include <yarp/math/SVD.h>
28 
29 using namespace std;
30 using namespace yarp::os;
31 using namespace yarp::sig;
32 using namespace yarp::math;
33 
34 #include "superquadric.h"
35 
36 /****************************************************************/
38 {
39  points_downsampled.clear();
40  aux_objvalue=0.0;
41 }
42 
43 /****************************************************************/
44 void SuperQuadric_NLP::setPoints(const deque<Vector> &point_cloud, const int &optimizer_points)
45 {
46  if (point_cloud.size()<optimizer_points)
47  {
48  for (size_t i=0;i<point_cloud.size();i++)
49  {
50  points_downsampled.push_back(point_cloud[i].subVector(0,2));
51  }
52  }
53  else
54  {
55  int count=point_cloud.size()/optimizer_points;
56 
57  for (size_t i=0; i<point_cloud.size(); i+=count)
58  {
59  points_downsampled.push_back(point_cloud[i].subVector(0,2));
60  }
61  }
62 
63  yInfo("[Superquadric]: points actually used for modeling: %lu ",points_downsampled.size());
64 
65  x0.resize(11,0.0);
66  computeX0(x0, points_downsampled);
67 }
68 
69 /****************************************************************/
70 bool SuperQuadric_NLP::get_nlp_info(Ipopt::Index &n, Ipopt::Index &m,Ipopt::Index &nnz_jac_g,
71  Ipopt::Index &nnz_h_lag, Ipopt::TNLP::IndexStyleEnum &index_style)
72 {
73  n=11;
74  m=nnz_jac_g=nnz_h_lag=0;
75  index_style=TNLP::C_STYLE;
76  x_v.resize(n,0.0);
77 
78  return true;
79 }
80 
81 /****************************************************************/
83 {
84  if (bounds_automatic==true)
85  {
86  bounds(0,1)=x0[0]*2.0;
87  bounds(1,1)=x0[1]*2.0;
88  bounds(2,1)=x0[2]*2.0;
89 
90  bounds(0,0)=0.001;
91  bounds(1,0)=0.001;
92  bounds(2,0)=0.001;
93 
94  bounds(5,0)=x0[5]-bounds(0,1);
95  bounds(6,0)=x0[6]-bounds(1,1);
96  bounds(7,0)=x0[7]-bounds(2,1);
97  bounds(5,1)=x0[5]+bounds(0,1);
98  bounds(6,1)=x0[6]+bounds(1,1);
99  bounds(7,1)=x0[7]+bounds(2,1);
100  }
101 
102  bounds(8,0)=0;
103  bounds(9,0)=0;
104  bounds(10,0)=0;
105  bounds(8,1)=2*M_PI;
106  bounds(9,1)=M_PI;
107  bounds(10,1)=2*M_PI;
108 }
109 
110 /****************************************************************/
111 bool SuperQuadric_NLP::get_bounds_info(Ipopt::Index n, Ipopt::Number *x_l, Ipopt::Number *x_u,
112  Ipopt::Index m, Ipopt::Number *g_l, Ipopt::Number *g_u)
113 {
114  computeBounds();
115 
116  for (Ipopt::Index i=0; i<n; i++)
117  {
118  x_l[i]=bounds(i,0);
119  x_u[i]=bounds(i,1);
120  }
121 
122  return true;
123 }
124 
125 /****************************************************************/
126  bool SuperQuadric_NLP::get_starting_point(Ipopt::Index n, bool init_x, Ipopt::Number *x,
127  bool init_z, Ipopt::Number *z_L, Ipopt::Number *z_U,
128  Ipopt::Index m, bool init_lambda, Ipopt::Number *lambda)
129  {
130  for (Ipopt::Index i=0;i<n;i++)
131  {
132  x[i]=x0[i];
133  }
134  return true;
135  }
136 
137  /****************************************************************/
138  bool SuperQuadric_NLP::eval_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x,
139  Ipopt::Number &obj_value)
140  {
141  F(x,points_downsampled, new_x);
142  obj_value=aux_objvalue;
143  return true;
144  }
145 
146  /****************************************************************/
147  void SuperQuadric_NLP::F(const Ipopt::Number *x, deque<Vector> &points, bool &new_x)
148  {
149  if (new_x)
150  {
151  double value=0.0;
152 
153  Vector euler(3,0.0);
154  euler[0]=x[8];
155  euler[1]=x[9];
156  euler[2]=x[10];
157  Matrix R=euler2dcm(euler);
158 
159  for(size_t i=0;i<points.size();i++)
160  {
161  double tmp=pow(f(x,R,points[i]),x[3])-1;
162  value+=tmp*tmp;
163  }
164  value*=x[0]*x[1]*x[2]/points.size();
165  aux_objvalue=value;
166  }
167  }
168 
169  /****************************************************************/
170  double SuperQuadric_NLP::f(const Ipopt::Number *x, const Matrix &R,
171  const Vector &point_cloud)
172  {
173  double num1 = R(0, 0)*point_cloud[0] + R(0, 1)*point_cloud[1] + R(0, 2)*point_cloud[2] - x[5] * R(0, 0) - x[6] * R(0, 1) - x[7] * R(0, 2);
174  double num2 = R(1, 0)*point_cloud[0] + R(1, 1)*point_cloud[1] + R(1, 2)*point_cloud[2] - x[5] * R(1, 0) - x[6] * R(1, 1) - x[7] * R(1, 2);
175  double num3 = R(2, 0)*point_cloud[0] + R(2, 1)*point_cloud[1] + R(2, 2)*point_cloud[2] - x[5] * R(2, 0) - x[6] * R(2, 1) - x[7] * R(2, 2);
176  double tmp = pow(abs(num1 / x[0]), 2.0 / x[4]) + pow(abs(num2 / x[1]), 2.0 / x[4]);
177  return pow(abs(tmp), x[4] / x[3]) + pow(abs(num3 / x[2]), (2.0 / x[3]));
178  }
179 
180  /****************************************************************/
181  double SuperQuadric_NLP::F_v(const Vector &x, const deque<Vector> &points)
182  {
183  double value=0.0;
184 
185  Vector euler(3,0.0);
186  euler[0]=x[8];
187  euler[1]=x[9];
188  euler[2]=x[10];
189  Matrix R=euler2dcm(euler);
190 
191  for (size_t i=0;i<points.size();i++)
192  {
193  double tmp=pow(f_v(x,R,points[i]),x[3])-1;
194  value+=tmp*tmp;
195  }
196 
197  value*=x[0]*x[1]*x[2]/points.size();
198  return value;
199  }
200 
201  /****************************************************************/
202  double SuperQuadric_NLP::f_v(const Vector &x, const Matrix &R,
203  const Vector &point_cloud)
204  {
205  double num1 = R(0, 0)*point_cloud[0] + R(0, 1)*point_cloud[1] + R(0, 2)*point_cloud[2] - x[5] * R(0, 0) - x[6] * R(0, 1) - x[7] * R(0, 2);
206  double num2 = R(1, 0)*point_cloud[0] + R(1, 1)*point_cloud[1] + R(1, 2)*point_cloud[2] - x[5] * R(1, 0) - x[6] * R(1, 1) - x[7] * R(1, 2);
207  double num3 = R(2, 0)*point_cloud[0] + R(2, 1)*point_cloud[1] + R(2, 2)*point_cloud[2] - x[5] * R(2, 0) - x[6] * R(2, 1) - x[7] * R(2, 2);
208  double tmp = pow(abs(num1 / x[0]), 2.0 / x[4]) + pow(abs(num2 / x[1]), 2.0 / x[4]);
209  return pow(abs(tmp), x[4] / x[3]) + pow(abs(num3 / x[2]), (2.0 / x[3]));
210  }
211 
212  /****************************************************************/
213  bool SuperQuadric_NLP::eval_grad_f(Ipopt::Index n, const Ipopt::Number* x, bool new_x,
214  Ipopt::Number *grad_f)
215  {
216  Vector x_tmp(n,0.0);
217  double grad_p, grad_n;
218  double eps=1e-8;
219 
220  for (Ipopt::Index j=0;j<n;j++)
221  x_tmp[j]=x[j];
222 
223  for (Ipopt::Index j=0;j<n;j++)
224  {
225  x_tmp[j]+=eps;
226 
227  grad_p=F_v(x_tmp,points_downsampled);
228 
229  x_tmp[j]-=eps;
230 
231  grad_n=F_v(x_tmp,points_downsampled);
232 
233  grad_f[j]=(grad_p-grad_n)/(2.0*eps);
234  }
235 
236  return true;
237  }
238 
239  /****************************************************************/
240  bool SuperQuadric_NLP::eval_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x,
241  Ipopt::Index m, Ipopt::Number *g)
242  {
243  return false;
244  }
245 
246  /****************************************************************/
247  bool SuperQuadric_NLP::eval_jac_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x,
248  Ipopt::Index m, Ipopt::Index nele_jac, Ipopt::Index *iRow,
249  Ipopt::Index *jCol, Ipopt::Number *values)
250  {
251  return false;
252  }
253 
254 /****************************************************************/
255 void SuperQuadric_NLP::configure(ResourceFinder *rf, bool b_automatic, const string &object_class)
256 {
257  bounds.resize(11,2);
258 
259  bounds_automatic=b_automatic;
260  obj_class=object_class;
261 
262  readMatrix("bounds_"+object_class,bounds, 11, rf);
263 }
264 
265 /****************************************************************/
266 void SuperQuadric_NLP::computeX0(Vector &x0, deque<Vector> &point_cloud)
267 {
268  x0[3]=1.0;
269  x0[4]=1.0;
270  x0[5]=0.0;
271  x0[6]=0.0;
272  x0[7]=0.0;
273 
274  for (size_t i=0; i<point_cloud.size();i++)
275  {
276  Vector &point=point_cloud[i];
277  x0[5]+=point[0];
278  x0[6]+=point[1];
279  x0[7]+=point[2];
280  }
281 
282  x0[5]/=point_cloud.size();
283  x0[6]/=point_cloud.size();
284  x0[7]/=point_cloud.size();
285 
286  computeInitialOrientation(x0,point_cloud);
287 
288  Matrix bounding_box(3,2);
289  bounding_box=computeBoundingBox(point_cloud,x0);
290 
291  x0[0]=(-bounding_box(0,0)+bounding_box(0,1))/2;
292  x0[1]=(-bounding_box(1,0)+bounding_box(1,1))/2;
293  x0[2]=(-bounding_box(2,0)+bounding_box(2,1))/2;
294 }
295 
296 /****************************************************************/
297 void SuperQuadric_NLP::computeInitialOrientation(Vector &x0,deque<Vector> &point_cloud)
298 {
299  Matrix M=zeros(3,3);
300  Matrix R(3,3);
301  Matrix u(3,3);
302  Matrix v(3,3);
303 
304  Vector s(3,0.0);
305  Vector n(3,0.0);
306  Vector o(3,0.0);
307  Vector a(3,0.0);
308 
309  for (size_t i=0;i<point_cloud.size(); i++)
310  {
311  Vector &point=point_cloud[i];
312  M(0,0)= M(0,0) + (point[1]-x0[6])*(point[1]-x0[6]) + (point[2]-x0[7])*(point[2]-x0[7]);
313  M(0,1)= M(0,1) - (point[1]-x0[6])*(point[0]-x0[5]);
314  M(0,2)= M(0,2) - (point[2]-x0[7])*(point[0]-x0[5]);
315  M(1,1)= M(1,1) + (point[0]-x0[5])*(point[0]-x0[5]) + (point[2]-x0[7])*(point[2]-x0[7]);
316  M(2,2)= M(2,2) + (point[1]-x0[6])*(point[1]-x0[6]) + (point[0]-x0[5])*(point[0]-x0[5]);
317  M(1,2)= M(1,2) - (point[2]-x0[7])*(point[1]-x0[6]);
318  }
319 
320  M(0,0)= M(0,0)/point_cloud.size();
321  M(0,1)= M(0,1)/point_cloud.size();
322  M(0,2)= M(0,2)/point_cloud.size();
323  M(1,1)= M(1,1)/point_cloud.size();
324  M(2,2)= M(2,2)/point_cloud.size();
325  M(1,2)= M(1,2)/point_cloud.size();
326 
327  M(1,0)= M(0,1);
328  M(2,0)= M(0,2);
329  M(2,1)= M(1,2);
330 
331  SVDJacobi(M,u,s,v);
332  n=u.getCol(0);
333  o=u.getCol(1);
334  a=u.getCol(2);
335 
336  R.setCol(0,n);
337  R.setCol(1,o);
338  R.setCol(2,a);
339 
340  x0.setSubvector(8,dcm2euler(R));
341 }
342 
343 /****************************************************************/
344 Matrix SuperQuadric_NLP::computeBoundingBox(deque<Vector> &points, const Vector &x0)
345 {
346  Matrix BB(3,2);
347  Matrix R3(3,3);
348 
349  R3=euler2dcm(x0.subVector(8,10)).submatrix(0,2,0,2);
350 
351  Vector point(3,0.0);
352  point=R3.transposed()*points[0];
353 
354  BB(0,0)=point[0];
355  BB(1,0)=point[1];
356  BB(2,0)=point[2];
357  BB(0,1)=point[0];
358  BB(1,1)=point[1];
359  BB(2,1)=point[2];
360 
361  for (size_t i=0; i<points.size();i++)
362  {
363  Vector &pnt=points[i];
364  point=R3.transposed()*pnt;
365  if(BB(0,0)>point[0])
366  BB(0,0)=point[0];
367 
368  if(BB(0,1)<point[0])
369  BB(0,1)=point[0];
370 
371  if(BB(1,0)>point[1])
372  BB(1,0)=point[1];
373 
374  if(BB(1,1)<point[1])
375  BB(1,1)=point[1];
376 
377  if(BB(2,0)>point[2])
378  BB(2,0)=point[2];
379 
380  if(BB(2,1)<point[2])
381  BB(2,1)=point[2];
382  }
383 
384  return BB;
385 }
386 
387 /****************************************************************/
388 bool SuperQuadric_NLP::readMatrix(const string &tag, Matrix &matrix, const int &dimension, ResourceFinder *rf)
389 {
390  string tag_x=tag+"_x";
391  string tag_y=tag+"_y";
392  bool check_x;
393 
394  if (tag=="x0")
395  {
396  if (Bottle *b=rf->find(tag.c_str()).asList())
397  {
398  Vector col;
399  if (b->size()>=dimension)
400  {
401  for(int i=0; i<b->size();i++)
402  col.push_back(b->get(i).asDouble());
403 
404  matrix.setCol(0, col);
405  }
406  return true;
407  }
408  }
409  else
410  {
411  if (tag=="bounds_"+obj_class)
412  {
413  tag_x=tag+"_l";
414  tag_y=tag+"_u";
415  }
416 
417  if (Bottle *b=rf->find(tag_x.c_str()).asList())
418  {
419  Vector col;
420  if (b->size()>=dimension)
421  {
422  for(int i=0; i<b->size();i++)
423  col.push_back(b->get(i).asDouble());
424 
425  matrix.setCol(0, col);
426  }
427  check_x=true;
428 
429  }
430 
431  if (Bottle *b=rf->find(tag_y.c_str()).asList())
432  {
433  Vector col;
434  if (b->size()>=dimension)
435  {
436  for (int i=0; i<b->size();i++)
437  col.push_back(b->get(i).asDouble());
438  matrix.setCol(1, col);
439  }
440 
441  if (check_x==true)
442  return true;
443  }
444 
445  }
446  return false;
447 }
448 
449 /****************************************************************/
450 void SuperQuadric_NLP::finalize_solution(Ipopt::SolverReturn status, Ipopt::Index n,
451  const Ipopt::Number *x, const Ipopt::Number *z_L,
452  const Ipopt::Number *z_U, Ipopt::Index m,
453  const Ipopt::Number *g, const Ipopt::Number *lambda,
454  Ipopt::Number obj_value, const Ipopt::IpoptData *ip_data,
455  Ipopt::IpoptCalculatedQuantities *ip_cq)
456 {
457  solution.resize(n);
458  for (Ipopt::Index i=0; i<n; i++)
459  solution[i]=x[i];
460 }
461 
462 /****************************************************************/
464 {
465  return solution;
466 }
467 
468 
double f_v(const yarp::sig::Vector &x, const yarp::sig::Matrix &R, const yarp::sig::Vector &point_cloud)
Auxiliary function for computing cost function of the nonlinear problem to be solved with ipopt...
void computeBounds()
Compute bounds variable from the point cloud for speeding up optimization.
void F(const Ipopt::Number *x, std::deque< yarp::sig::Vector > &points, bool &new_x)
Auxiliary function for computing cost function of the nonlinear problem to be solved with ipopt...
bool get_starting_point(Ipopt::Index n, bool init_x, Ipopt::Number *x, bool init_z, Ipopt::Number *z_L, Ipopt::Number *z_U, Ipopt::Index m, bool init_lambda, Ipopt::Number *lambda)
Get the starting point for the nonlinear problem to be solved with ipopt.
bool eval_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Number &obj_value)
Cost function of the nonlinear problem to be solved with ipopt.
bool get_bounds_info(Ipopt::Index n, Ipopt::Number *x_l, Ipopt::Number *x_u, Ipopt::Index m, Ipopt::Number *g_l, Ipopt::Number *g_u)
Get variable bounds for the nonlinear problem to be solved with ipopt.
void setPoints(const std::deque< yarp::sig::Vector > &point_cloud, const int &optimizer_points)
Set point to be used for superquadric estimation.
void computeInitialOrientation(yarp::sig::Vector &x0, std::deque< yarp::sig::Vector > &point_cloud)
Compute initial superquadric orientation from the point cloud.
bool eval_grad_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Number *grad_f)
Gradient of the cost function of the nonlinear problem.
yarp::sig::Vector get_result() const
Extract the solution.
bool readMatrix(const std::string &tag, yarp::sig::Matrix &matrix, const int &dimension, yarp::os::ResourceFinder *rf)
Function for reading matrices from config files.
double f(const Ipopt::Number *x, const yarp::sig::Matrix &R, const yarp::sig::Vector &point_cloud)
Auxiliary function for computing cost function of the nonlinear problem to be solved with ipopt...
yarp::sig::Matrix computeBoundingBox(std::deque< yarp::sig::Vector > &points, const yarp::sig::Vector &x0)
Compute bounding box from the point cloud.
void configure(yarp::os::ResourceFinder *rf, bool bounds_aut, const std::string &object_class)
Configure function.
void computeX0(yarp::sig::Vector &x0, std::deque< yarp::sig::Vector > &point_cloud)
Compute a good starting point for the nonlinear problem.
bool get_nlp_info(Ipopt::Index &n, Ipopt::Index &m, Ipopt::Index &nnz_jac_g, Ipopt::Index &nnz_h_lag, Ipopt::TNLP::IndexStyleEnum &index_style)
Get info for the nonlinear problem to be solved with ipopt.
void finalize_solution(Ipopt::SolverReturn status, Ipopt::Index n, const Ipopt::Number *x, const Ipopt::Number *z_L, const Ipopt::Number *z_U, Ipopt::Index m, const Ipopt::Number *g, const Ipopt::Number *lambda, Ipopt::Number obj_value, const Ipopt::IpoptData *ip_data, Ipopt::IpoptCalculatedQuantities *ip_cq)
Finalize the solution.
bool eval_jac_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Index m, Ipopt::Index nele_jac, Ipopt::Index *iRow, Ipopt::Index *jCol, Ipopt::Number *values)
Jacobian of the constraints of the nonlinear problem.
bool eval_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Index m, Ipopt::Number *g)
Constraints of the nonlinear problem.
void init()
Init function.
double F_v(const yarp::sig::Vector &x, const std::deque< yarp::sig::Vector > &points)
Auxiliary function for computing the gradient of cost function of the nonlinear problem.