Point Cloud Library (PCL)  1.8.1-dev
extract_polygonal_prism_data.hpp
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2010, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the copyright holder(s) nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * $Id$
35  *
36  */
37 
38 #ifndef PCL_SEGMENTATION_IMPL_EXTRACT_POLYGONAL_PRISM_DATA_H_
39 #define PCL_SEGMENTATION_IMPL_EXTRACT_POLYGONAL_PRISM_DATA_H_
40 
41 #include <pcl/segmentation/extract_polygonal_prism_data.h>
42 #include <pcl/common/centroid.h>
43 #include <pcl/common/eigen.h>
44 
45 //////////////////////////////////////////////////////////////////////////
46 template <typename PointT> bool
48 {
49  // Compute the plane coefficients
50  Eigen::Vector4f model_coefficients;
51  EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix;
52  Eigen::Vector4f xyz_centroid;
53 
54  computeMeanAndCovarianceMatrix (polygon, covariance_matrix, xyz_centroid);
55 
56  // Compute the model coefficients
57  EIGEN_ALIGN16 Eigen::Vector3f::Scalar eigen_value;
58  EIGEN_ALIGN16 Eigen::Vector3f eigen_vector;
59  eigen33 (covariance_matrix, eigen_value, eigen_vector);
60 
61  model_coefficients[0] = eigen_vector [0];
62  model_coefficients[1] = eigen_vector [1];
63  model_coefficients[2] = eigen_vector [2];
64  model_coefficients[3] = 0;
65 
66  // Hessian form (D = nc . p_plane (centroid here) + p)
67  model_coefficients[3] = -1 * model_coefficients.dot (xyz_centroid);
68 
69  float distance_to_plane = model_coefficients[0] * point.x +
70  model_coefficients[1] * point.y +
71  model_coefficients[2] * point.z +
72  model_coefficients[3];
73  PointT ppoint;
74  // Calculate the projection of the point on the plane
75  ppoint.x = point.x - distance_to_plane * model_coefficients[0];
76  ppoint.y = point.y - distance_to_plane * model_coefficients[1];
77  ppoint.z = point.z - distance_to_plane * model_coefficients[2];
78 
79  // Create a X-Y projected representation for within bounds polygonal checking
80  int k0, k1, k2;
81  // Determine the best plane to project points onto
82  k0 = (fabs (model_coefficients[0] ) > fabs (model_coefficients[1])) ? 0 : 1;
83  k0 = (fabs (model_coefficients[k0]) > fabs (model_coefficients[2])) ? k0 : 2;
84  k1 = (k0 + 1) % 3;
85  k2 = (k0 + 2) % 3;
86  // Project the convex hull
87  pcl::PointCloud<PointT> xy_polygon;
88  xy_polygon.points.resize (polygon.points.size ());
89  for (size_t i = 0; i < polygon.points.size (); ++i)
90  {
91  Eigen::Vector4f pt (polygon.points[i].x, polygon.points[i].y, polygon.points[i].z, 0);
92  xy_polygon.points[i].x = pt[k1];
93  xy_polygon.points[i].y = pt[k2];
94  xy_polygon.points[i].z = 0;
95  }
96  PointT xy_point;
97  xy_point.z = 0;
98  Eigen::Vector4f pt (ppoint.x, ppoint.y, ppoint.z, 0);
99  xy_point.x = pt[k1];
100  xy_point.y = pt[k2];
101 
102  return (pcl::isXYPointIn2DXYPolygon (xy_point, xy_polygon));
103 }
104 
105 //////////////////////////////////////////////////////////////////////////
106 template <typename PointT> bool
108 {
109  bool in_poly = false;
110  double x1, x2, y1, y2;
111 
112  int nr_poly_points = static_cast<int> (polygon.points.size ());
113  // start with the last point to make the check last point<->first point the first one
114  double xold = polygon.points[nr_poly_points - 1].x;
115  double yold = polygon.points[nr_poly_points - 1].y;
116  for (int i = 0; i < nr_poly_points; i++)
117  {
118  double xnew = polygon.points[i].x;
119  double ynew = polygon.points[i].y;
120  if (xnew > xold)
121  {
122  x1 = xold;
123  x2 = xnew;
124  y1 = yold;
125  y2 = ynew;
126  }
127  else
128  {
129  x1 = xnew;
130  x2 = xold;
131  y1 = ynew;
132  y2 = yold;
133  }
134 
135  if ( (xnew < point.x) == (point.x <= xold) && (point.y - y1) * (x2 - x1) < (y2 - y1) * (point.x - x1) )
136  {
137  in_poly = !in_poly;
138  }
139  xold = xnew;
140  yold = ynew;
141  }
142 
143  return (in_poly);
144 }
145 
146 //////////////////////////////////////////////////////////////////////////
147 template <typename PointT> void
149 {
150  output.header = input_->header;
151 
152  if (!initCompute ())
153  {
154  output.indices.clear ();
155  return;
156  }
157 
158  if (static_cast<int> (planar_hull_->points.size ()) < min_pts_hull_)
159  {
160  PCL_ERROR ("[pcl::%s::segment] Not enough points (%lu) in the hull!\n", getClassName ().c_str (), planar_hull_->points.size ());
161  output.indices.clear ();
162  return;
163  }
164 
165  // Compute the plane coefficients
166  Eigen::Vector4f model_coefficients;
167  EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix;
168  Eigen::Vector4f xyz_centroid;
169 
170  computeMeanAndCovarianceMatrix (*planar_hull_, covariance_matrix, xyz_centroid);
171 
172  // Compute the model coefficients
173  EIGEN_ALIGN16 Eigen::Vector3f::Scalar eigen_value;
174  EIGEN_ALIGN16 Eigen::Vector3f eigen_vector;
175  eigen33 (covariance_matrix, eigen_value, eigen_vector);
176 
177  model_coefficients[0] = eigen_vector [0];
178  model_coefficients[1] = eigen_vector [1];
179  model_coefficients[2] = eigen_vector [2];
180  model_coefficients[3] = 0;
181 
182  // Hessian form (D = nc . p_plane (centroid here) + p)
183  model_coefficients[3] = -1 * model_coefficients.dot (xyz_centroid);
184 
185  // Need to flip the plane normal towards the viewpoint
186  Eigen::Vector4f vp (vpx_, vpy_, vpz_, 0);
187  // See if we need to flip any plane normals
188  vp -= planar_hull_->points[0].getVector4fMap ();
189  vp[3] = 0;
190  // Dot product between the (viewpoint - point) and the plane normal
191  float cos_theta = vp.dot (model_coefficients);
192  // Flip the plane normal
193  if (cos_theta < 0)
194  {
195  model_coefficients *= -1;
196  model_coefficients[3] = 0;
197  // Hessian form (D = nc . p_plane (centroid here) + p)
198  model_coefficients[3] = -1 * (model_coefficients.dot (planar_hull_->points[0].getVector4fMap ()));
199  }
200 
201  // Project all points
202  PointCloud projected_points;
203  SampleConsensusModelPlane<PointT> sacmodel (input_);
204  sacmodel.projectPoints (*indices_, model_coefficients, projected_points, false);
205 
206  // Create a X-Y projected representation for within bounds polygonal checking
207  int k0, k1, k2;
208  // Determine the best plane to project points onto
209  k0 = (fabs (model_coefficients[0] ) > fabs (model_coefficients[1])) ? 0 : 1;
210  k0 = (fabs (model_coefficients[k0]) > fabs (model_coefficients[2])) ? k0 : 2;
211  k1 = (k0 + 1) % 3;
212  k2 = (k0 + 2) % 3;
213  // Project the convex hull
214  pcl::PointCloud<PointT> polygon;
215  polygon.points.resize (planar_hull_->points.size ());
216  for (size_t i = 0; i < planar_hull_->points.size (); ++i)
217  {
218  Eigen::Vector4f pt (planar_hull_->points[i].x, planar_hull_->points[i].y, planar_hull_->points[i].z, 0);
219  polygon.points[i].x = pt[k1];
220  polygon.points[i].y = pt[k2];
221  polygon.points[i].z = 0;
222  }
223 
224  PointT pt_xy;
225  pt_xy.z = 0;
226 
227  output.indices.resize (indices_->size ());
228  int l = 0;
229  for (size_t i = 0; i < projected_points.points.size (); ++i)
230  {
231  // Check the distance to the user imposed limits from the table planar model
232  double distance = pointToPlaneDistanceSigned (input_->points[(*indices_)[i]], model_coefficients);
233  if (distance < height_limit_min_ || distance > height_limit_max_)
234  continue;
235 
236  // Check what points are inside the hull
237  Eigen::Vector4f pt (projected_points.points[i].x,
238  projected_points.points[i].y,
239  projected_points.points[i].z, 0);
240  pt_xy.x = pt[k1];
241  pt_xy.y = pt[k2];
242 
243  if (!pcl::isXYPointIn2DXYPolygon (pt_xy, polygon))
244  continue;
245 
246  output.indices[l++] = (*indices_)[i];
247  }
248  output.indices.resize (l);
249 
250  deinitCompute ();
251 }
252 
253 #define PCL_INSTANTIATE_ExtractPolygonalPrismData(T) template class PCL_EXPORTS pcl::ExtractPolygonalPrismData<T>;
254 #define PCL_INSTANTIATE_isPointIn2DPolygon(T) template bool PCL_EXPORTS pcl::isPointIn2DPolygon<T>(const T&, const pcl::PointCloud<T> &);
255 #define PCL_INSTANTIATE_isXYPointIn2DXYPolygon(T) template bool PCL_EXPORTS pcl::isXYPointIn2DXYPolygon<T>(const T &, const pcl::PointCloud<T> &);
256 
257 #endif // PCL_SEGMENTATION_IMPL_EXTRACT_POLYGONAL_PRISM_DATA_H_
258 
double pointToPlaneDistanceSigned(const Point &p, double a, double b, double c, double d)
Get the distance from a point to a plane (signed) defined by ax+by+cz+d=0.
struct pcl::PointXYZIEdge EIGEN_ALIGN16
unsigned int computeMeanAndCovarianceMatrix(const pcl::PointCloud< PointT > &cloud, Eigen::Matrix< Scalar, 3, 3 > &covariance_matrix, Eigen::Matrix< Scalar, 4, 1 > &centroid)
Compute the normalized 3x3 covariance matrix and the centroid of a given set of points in a single lo...
Definition: centroid.hpp:489
std::vector< int > indices
Definition: PointIndices.h:19
std::vector< PointT, Eigen::aligned_allocator< PointT > > points
The point data.
Definition: point_cloud.h:410
void projectPoints(const std::vector< int > &inliers, const Eigen::VectorXf &model_coefficients, PointCloud &projected_points, bool copy_data_fields=true)
Create a new point cloud with inliers projected onto the plane model.
::pcl::PCLHeader header
Definition: PointIndices.h:17
void eigen33(const Matrix &mat, typename Matrix::Scalar &eigenvalue, Vector &eigenvector)
determines the eigenvector and eigenvalue of the smallest eigenvalue of the symmetric positive semi d...
Definition: eigen.hpp:251
A point structure representing Euclidean xyz coordinates, and the RGB color.
SampleConsensusModelPlane defines a model for 3D plane segmentation.
bool isPointIn2DPolygon(const PointT &point, const pcl::PointCloud< PointT > &polygon)
General purpose method for checking if a 3D point is inside or outside a given 2D polygon...
void segment(PointIndices &output)
Cluster extraction in a PointCloud given by <setInputCloud (), setIndices ()>
bool isXYPointIn2DXYPolygon(const PointT &point, const pcl::PointCloud< PointT > &polygon)
Check if a 2d point (X and Y coordinates considered only!) is inside or outside a given polygon...