grasp
minBoundBox.cpp
1 /* Copyright: (C) 2014 iCub Facility - Istituto Italiano di Tecnologia
2  * Authors: Ilaria Gori
3  * email: ilaria.gori@iit.it
4  * Permission is granted to copy, distribute, and/or modify this program
5  * under the terms of the GNU General Public License, version 2 or any
6  * later version published by the Free Software Foundation.
7  *
8  * A copy of the license can be found in the file LICENSE located in the
9  * root directory.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14  * Public License for more details
15 */
16 
17 #include <iCub/data3D/private/helpers.h>
18 #include <iCub/data3D/minBoundBox.h>
19 
20 using namespace std;
21 using namespace yarp::sig;
22 using namespace yarp::os;
23 using namespace yarp::math;
24 using namespace iCub::data3D;
25 
26 /************************************************************************/
27 void buildRotMat2(const double &theta,yarp::sig::Matrix &rot)
28 {
29  rot.resize(2,2);
30  rot(0,0)=cos(theta);
31  rot(0,1)=sin(theta);
32  rot(1,0)=-sin(theta);
33  rot(1,1)=cos(theta);
34 }
35 
36 /************************************************************************/
37 void buildRotMat3(const double &alpha,const double &beta,const double &gamma,yarp::sig::Matrix &rot)
38 {
39  rot.resize(3,3);
40  rot(0,0)=cos(beta)*cos(gamma);
41  rot(0,1)=-cos(beta)*sin(gamma);
42  rot(0,2)=sin(beta);
43  rot(1,0)=sin(alpha)*sin(beta)*cos(gamma)+cos(alpha)*sin(gamma);
44  rot(1,1)=-sin(alpha)*sin(beta)*sin(gamma)+cos(alpha)*cos(gamma);
45  rot(1,2)=-sin(alpha)*cos(beta);
46  rot(2,0)=-cos(alpha)*sin(beta)*cos(gamma)+sin(alpha)*sin(gamma);
47  rot(2,1)=cos(alpha)*sin(beta)*sin(gamma)+sin(alpha)*cos(gamma);
48  rot(2,2)=cos(alpha)*cos(beta);
49 }
50 
51 /************************************************************************/
52 void findRotation2D(const Matrix &xy, Matrix &rot2)
53 {
54  yarp::sig::Vector edgeangles;
55  double met=1000000;
56  for (int j=0; j<xy.rows()-1; j++)
57  {
58  double val=atan2(xy(j+1,1)-xy(j,1),xy(j+1,0)-xy(j,0));
59  bool contain=false;
60  for (int k=0; k<edgeangles.size(); k++)
61  {
62  if (edgeangles[k]==Helpers::mod(val,M_PI/2))
63  {
64  contain=true;
65  break;
66  }
67  }
68  if (!contain)
69  {
70  edgeangles.push_back(Helpers::mod(val,M_PI/2));
71  Matrix rot_i;
72  buildRotMat2(-Helpers::mod(val,M_PI/2),rot_i);
73  Matrix xyr=xy*rot_i;
74  yarp::sig::Vector minimum;
75  Helpers::min(xyr,minimum);
76  yarp::sig::Vector maximum;
77  Helpers::max(xyr,maximum);
78  yarp::sig::Vector diff=maximum-minimum;
79  double prod=diff[0]*diff[1];
80  if (prod<met)
81  {
82  met=prod;
83  rot2=rot_i;
84  }
85  }
86  }
87 }
88 
89 /************************************************************************/
90 void findRotation(const Matrix &xyz_i, Matrix &rot2)
91 {
92  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_on_plane(new pcl::PointCloud<pcl::PointXYZ>);
93 
94  for (int j=0; j<xyz_i.rows(); j++)
95  {
96  pcl::PointXYZ point;
97  point.x=xyz_i(j,0);
98  point.y=xyz_i(j,1);
99  point.y=xyz_i(j,2);
100  cloud_on_plane->push_back(point);
101  }
102 
103  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_hull2D (new pcl::PointCloud<pcl::PointXYZ>);
104  pcl::ConvexHull<pcl::PointXYZ> chull2D;
105  chull2D.setInputCloud (cloud_on_plane);
106  chull2D.setDimension(2);
107  chull2D.reconstruct (*cloud_hull2D);
108 
109  Matrix xy(cloud_hull2D->size(),2);
110  for (int j=0; j<cloud_hull2D->size()-1; j++)
111  {
112  xy(j,0)=cloud_hull2D->at(j).x;
113  xy(j,1)=cloud_hull2D->at(j).y;
114  }
115 
116  findRotation2D(xy,rot2);
117 }
118 
119 /************************************************************************/
120 void assignCorners(const Matrix &minmax, Matrix &cornerpoints)
121 {
122  cornerpoints(0,0)=minmax(0,0);
123  cornerpoints(0,1)=minmax(0,1);
124  cornerpoints(0,2)=minmax(0,2);
125  cornerpoints(1,0)=minmax(1,0);
126  cornerpoints(1,1)=minmax(0,1);
127  cornerpoints(1,2)=minmax(0,2);
128  cornerpoints(2,0)=minmax(1,0);
129  cornerpoints(2,1)=minmax(1,1);
130  cornerpoints(2,2)=minmax(0,2);
131  cornerpoints(3,0)=minmax(0,0);
132  cornerpoints(3,1)=minmax(1,1);
133  cornerpoints(3,2)=minmax(0,2);
134  cornerpoints(4,0)=minmax(0,0);
135  cornerpoints(4,1)=minmax(0,1);
136  cornerpoints(4,2)=minmax(1,2);
137  cornerpoints(5,0)=minmax(1,0);
138  cornerpoints(5,1)=minmax(0,1);
139  cornerpoints(5,2)=minmax(1,2);
140  cornerpoints(6,0)=minmax(1,0);
141  cornerpoints(6,1)=minmax(1,1);
142  cornerpoints(6,2)=minmax(1,2);
143  cornerpoints(7,0)=minmax(0,0);
144  cornerpoints(7,1)=minmax(1,1);
145  cornerpoints(7,2)=minmax(1,2);
146 }
147 
148 /************************************************************************/
149 void eulerAngles(const std::vector<yarp::sig::Vector> &edges1,const std::vector<yarp::sig::Vector> &edges2,const std::vector<yarp::sig::Vector> &crossProduct,yarp::sig::Vector &alpha,yarp::sig::Vector &beta,yarp::sig::Vector &gamma)
150 {
151  double singamma;
152  alpha.resize(crossProduct.size(),0.0);
153  beta.resize(crossProduct.size(),0.0);
154  gamma.resize(crossProduct.size(),0.0);
155  for (int i=0; i<crossProduct.size(); i++)
156  {
157  double value=crossProduct.at(i)[0];
158  beta[i]=asin(std::min(abs(value),1.0)*Helpers::sign(value));
159  if (value==1.0)
160  alpha[i]=asin(Helpers::sign(edges2.at(i)[2])*std::min(1.0,abs(edges2.at(i)[2])));
161  else
162  {
163  double tmp=crossProduct.at(i)[2]/cos(beta[i]);
164  alpha[i]=acos(Helpers::sign(tmp)*std::min(1.0,abs(tmp)));
165  if (Helpers::sign(crossProduct.at(i)[1])!=Helpers::sign(-sin(alpha[i])*cos(beta[i])))
166  alpha[i]=-alpha[i];
167  singamma=-edges2.at(i)[0]/cos(beta[i]);
168  if (edges1.at(i)[0]>=0)
169  gamma[i]=asin(Helpers::sign(singamma)*std::min(1.0,abs(singamma)));
170  else
171  gamma[i]=-M_PI-asin(Helpers::sign(singamma)*std::min(1.0,abs(singamma)));
172  }
173  }
174 }
175 
176 /************************************************************************/
177 void retrieveEdges2(const yarp::sig::Vector &vx, const yarp::sig::Vector &vy, const yarp::sig::Vector &vz, const std::vector<yarp::sig::Vector> &edges1, std::vector<yarp::sig::Vector> &edges)
178 {
179  for (int i=0; i<vx.size(); i++)
180  {
181  yarp::sig::Vector vect(3);
182  vect[0]=vx[i];
183  vect[1]=vy[i];
184  vect[2]=vz[i];
185  double dotprod=dot(edges1.at(i),vect);
186  vect=vect-dotprod*edges1.at(i);
187  double normvect=norm(vect);
188  vect=vect/normvect;
189  edges.push_back(vect);
190  }
191 }
192 
193 /************************************************************************/
194 void retrieveEdges(const yarp::sig::Vector &vx, const yarp::sig::Vector &vy, const yarp::sig::Vector &vz, std::vector<yarp::sig::Vector> &edges)
195 {
196  yarp::sig::Vector vxSquare=vx*vx;
197  yarp::sig::Vector vySquare=vy*vy;
198  yarp::sig::Vector vzSquare=vz*vz;
199  yarp::sig::Vector sum=vxSquare+vySquare+vzSquare;
200 
201  for (int i=0; i<sum.size(); i++)
202  {
203  yarp::sig::Vector vect(3);
204  vect[0]=vx[i]/(sqrt(sum[i]));
205  vect[1]=vy[i]/(sqrt(sum[i]));
206  vect[2]=vz[i]/(sqrt(sum[i]));
207  edges.push_back(vect);
208  }
209 }
210 
211 /************************************************************************/
212 BoundingBox MinimumBoundingBox::getMinimumBoundingBox(pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud)
213 {
214  BoundingBox bb;
215  std::vector< pcl::Vertices > polygons;
216  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_hull (new pcl::PointCloud<pcl::PointXYZRGB>);
217  pcl::ConvexHull<pcl::PointXYZRGB> chull;
218  chull.setInputCloud (cloud);
219  chull.setDimension(3);
220  chull.reconstruct (*cloud_hull,polygons);
221 
222  yarp::sig::Vector x1;
223  yarp::sig::Vector x2;
224  yarp::sig::Vector x3;
225  yarp::sig::Vector y1;
226  yarp::sig::Vector y2;
227  yarp::sig::Vector y3;
228  yarp::sig::Vector z1;
229  yarp::sig::Vector z2;
230  yarp::sig::Vector z3;
231 
232  for (int i=0; i<polygons.size(); i++)
233  {
234  pcl::Vertices vertex=polygons.at(i);
235  x1.push_back(cloud_hull->at(vertex.vertices[0]).x);
236  x2.push_back(cloud_hull->at(vertex.vertices[1]).x);
237  x3.push_back(cloud_hull->at(vertex.vertices[2]).x);
238  y1.push_back(cloud_hull->at(vertex.vertices[0]).y);
239  y2.push_back(cloud_hull->at(vertex.vertices[1]).y);
240  y3.push_back(cloud_hull->at(vertex.vertices[2]).y);
241  z1.push_back(cloud_hull->at(vertex.vertices[0]).z);
242  z2.push_back(cloud_hull->at(vertex.vertices[1]).z);
243  z3.push_back(cloud_hull->at(vertex.vertices[2]).z);
244  }
245 
246  Matrix pointCloud(cloud_hull->size(),3);
247  for (int i=0; i<cloud_hull->size(); i++)
248  {
249  pointCloud(i,0)=cloud_hull->at(i).x;
250  pointCloud(i,1)=cloud_hull->at(i).y;
251  pointCloud(i,2)=cloud_hull->at(i).z;
252  }
253 
254  yarp::sig::Vector v1x=x2-x1;
255  yarp::sig::Vector v1y=y2-y1;
256  yarp::sig::Vector v1z=z2-z1;
257  std::vector<yarp::sig::Vector> edges1;
258 
259  retrieveEdges(v1x,v1y,v1z,edges1);
260 
261  yarp::sig::Vector v2x=x3-x1;
262  yarp::sig::Vector v2y=y3-y1;
263  yarp::sig::Vector v2z=z3-z1;
264  std::vector<yarp::sig::Vector> edges2;
265 
266  retrieveEdges2(v2x,v2y,v2z,edges1,edges2);
267 
268  std::vector<yarp::sig::Vector> crossProduct;
269  for (int i=0; i<edges1.size(); i++)
270  {
271  yarp::sig::Vector vect=cross(edges1.at(i),edges2.at(i));
272  crossProduct.push_back(vect);
273  }
274 
275  yarp::sig::Vector alpha;
276  yarp::sig::Vector beta;
277  yarp::sig::Vector gamma;
278  eulerAngles(edges1, edges2, crossProduct, alpha, beta, gamma);
279 
280  Matrix minmax(2,3);
281  double minVol=100000;
282  Matrix rot2;
283 
284  for (int i=0; i<alpha.size(); i++)
285  {
286  Matrix rot;
287  buildRotMat3(alpha[i],beta[i],gamma[i],rot);
288  Matrix xyz_i=pointCloud*rot;
289  findRotation(xyz_i,rot2);
290 
291  Matrix rot3dim=eye(3,3);
292  rot3dim.setSubmatrix(rot2,0,0);
293  Matrix rotation=rot*rot3dim;
294 
295  xyz_i=pointCloud*rotation;
296  yarp::sig::Vector minimum;
297  Helpers::min(xyz_i,minimum);
298  yarp::sig::Vector maximum;
299  Helpers::max(xyz_i,maximum);
300  yarp::sig::Vector h=maximum-minimum;
301 
302  double prod=h[0]*h[1]*h[2];
303  if (prod<minVol)
304  {
305  minVol=prod;
306  bb.setOrientation(rotation);
307  minmax.setRow(0,minimum);
308  minmax.setRow(1,maximum);
309  }
310  }
311  Matrix cornerpointsTmp(8,3);
312  assignCorners(minmax,cornerpointsTmp);
313  Matrix cornerpoints=cornerpointsTmp*(bb.getOrientation().transposed());
314 
315  std::vector<iCub::data3D::PointXYZ> corners;
316  for (unsigned int i=0; i<cornerpoints.rows(); i++)
317  corners.push_back(PointXYZ(cornerpoints(i,0),cornerpoints(i,1),cornerpoints(i,2)));
318 
319  bb.setCorners(corners);
320  return bb;
321 }
322 
The Definition of the BoundingBox class.
Definition: boundingBox.h:61
yarp::sig::Matrix getOrientation()
Return the orientation of the Box3D structure.
Definition: boundingBox.cpp:59
void setCorners(const std::vector< iCub::data3D::PointXYZ > &corners)
Set the corners of the bounding box.
Definition: boundingBox.cpp:53
void setOrientation(const yarp::sig::Matrix &orientation)
Modify the orientation of the bounding box.
Definition: boundingBox.cpp:65