template<typename PointT, typename PointNT, typename PointLT> void
pcl::OrganizedMultiPlaneSegmentation<PointT, PointNT, PointLT>::segment (std::vector<ModelCoefficients>& model_coefficients, 
                                                                         std::vector<PointIndices>& inlier_indices,
                                                                         std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> >& centroids,
                                                                         std::vector <Eigen::Matrix3f, Eigen::aligned_allocator<Eigen::Matrix3f> >& covariances,
                                                                         pcl::PointCloud<PointLT>& labels,
                                                                         std::vector<pcl::PointIndices>& label_indices)
{
  if (!initCompute ())
    return;

  // Check that we got the same number of points and normals
  if (static_cast<int> (normals_->points.size ()) != static_cast<int> (input_->points.size ()))
  {
    PCL_ERROR ("[pcl::%s::segment] Number of points in input cloud (%zu) and normal cloud (%zu) do not match!\n",
               getClassName ().c_str (), input_->points.size (),
               normals_->points.size ());
    return;
  }

  // Check that the cloud is organized
  if (!input_->isOrganized ())
  {
    PCL_ERROR ("[pcl::%s::segment] Organized point cloud is required for this plane extraction method!\n",
               getClassName ().c_str ());
    return;
  }

  // Calculate range part of planes' hessian normal form
  std::vector<float> plane_d (input_->points.size ());
  
  for (unsigned int i = 0; i < input_->size (); ++i)
    plane_d[i] = input_->points[i].getVector3fMap ().dot (normals_->points[i].getNormalVector3fMap ());
  
  // Make a comparator
  //PlaneCoefficientComparator<PointT,PointNT> plane_comparator (plane_d);
  compare_->setPlaneCoeffD (plane_d);
  compare_->setInputCloud (input_);
  compare_->setInputNormals (normals_);
  compare_->setAngularThreshold (static_cast<float> (angular_threshold_));
  compare_->setDistanceThreshold (static_cast<float> (distance_threshold_), true);

  // Set up the output
  OrganizedConnectedComponentSegmentation<PointT,pcl::Label> connected_component (compare_);
  connected_component.setInputCloud (input_);
  connected_component.segment (labels, label_indices);

  Eigen::Vector4f clust_centroid = Eigen::Vector4f::Zero ();
  Eigen::Vector4f vp = Eigen::Vector4f::Zero ();
  Eigen::Matrix3f clust_cov;
  pcl::ModelCoefficients model;
  model.values.resize (4);

  // Fit Planes to each cluster
  for (size_t i = 0; i < label_indices.size (); i++)
  {
    if (static_cast<unsigned> (label_indices[i].indices.size ()) > min_inliers_)
    {
      pcl::computeMeanAndCovarianceMatrix (*input_, label_indices[i].indices, clust_cov, clust_centroid);
      Eigen::Vector4f plane_params;
      
      EIGEN_ALIGN16 Eigen::Vector3f::Scalar eigen_value;
      EIGEN_ALIGN16 Eigen::Vector3f eigen_vector;
      pcl::eigen33 (clust_cov, eigen_value, eigen_vector);
      plane_params[0] = eigen_vector[0];
      plane_params[1] = eigen_vector[1];
      plane_params[2] = eigen_vector[2];
      plane_params[3] = 0;
      plane_params[3] = -1 * plane_params.dot (clust_centroid);

      vp -= clust_centroid;
      float cos_theta = vp.dot (plane_params);
      if (cos_theta < 0)
      {
        plane_params *= -1;
        plane_params[3] = 0;
        plane_params[3] = -1 * plane_params.dot (clust_centroid);
      }
      
      // Compute the curvature surface change
      float curvature;
      float eig_sum = clust_cov.coeff (0) + clust_cov.coeff (4) + clust_cov.coeff (8);
      if (eig_sum != 0)
        curvature = fabsf (eigen_value / eig_sum);
      else
        curvature = 0;

      if (curvature < maximum_curvature_)
      {
        model.values[0] = plane_params[0];
        model.values[1] = plane_params[1];
        model.values[2] = plane_params[2];
        model.values[3] = plane_params[3];
        model_coefficients.push_back (model);
        inlier_indices.push_back (label_indices[i]);
        centroids.push_back (clust_centroid);
        covariances.push_back (clust_cov);
      }
    }
  }
  deinitCompute ();
}
Beispiel #2
0
IntersectType clipPoly2D(const Points2D& points,
	const Line2<typename points_adaptor<Points2D>::scalar>& plane,
	std::list<ClippedPoly<typename points_adaptor<Points2D>::scalar> >& result,
	detail::ClippingContext<typename points_adaptor<Points2D>::scalar>* ctxt)
{
	typedef points_adaptor<Points2D> 					Adaptor;
	typedef typename Adaptor::scalar					T;
	typedef typename Adaptor::elem_type					point_type;
	typedef typename Adaptor::const_elem_ref			const_point_ref;
	typedef ClippedPoly<T> 								polyclip_type;
	typedef typename polyclip_type::intersection		polyclip_intersection;

	typedef std::multimap<T, unsigned int>							onplane_lookup;
	typedef boost::unordered_multimap<unsigned int, unsigned int>	edge_lookup;
	typedef boost::unordered_set<unsigned int>						visited_verts_set;
	typedef boost::unordered_map<unsigned int, unsigned int>		shared_verts_map;

	Adaptor a(points);

	unsigned int npoints = a.size();
	assert(a.size() > 2);

	static const unsigned int shared_offset = std::numeric_limits<unsigned int>::max()/2;
	bool shared_vert_check = (npoints > 4);
	visited_verts_set visited_verts;
	shared_verts_map shared_vert_remap;

	unsigned int index1, index2;
	index1 = a.index(0);
	if(shared_vert_check)
		visited_verts.insert(index1);

	std::vector<polyclip_intersection> onplanePoints;
	std::vector<unsigned int> insidePoints;

	polyclip_intersection edgeInt;
	point_type line_dir = plane.dir();
	bool anyPtOutside = false;
	bool ptInsideNext;
	bool ptInside = (ctxt)? ctxt->isPointInside(index1) : plane.isRight(a[0]);

	onplane_lookup intersectionsOut, intersectionsIn;
	edge_lookup edges(npoints);

	// do the clip. Note that onplane points are indexed as i+npoints and are adjusted after
	for(unsigned int i=0; i<npoints; ++i, ptInside=ptInsideNext, index1=index2)
	{
		unsigned int j = (i+1) % npoints;
		const_point_ref pt_i = a[i];
		const_point_ref pt_j = a[j];

		index2 = a.index(j);
		anyPtOutside |= !ptInside;
		ptInsideNext = (ctxt)? ctxt->isPointInside(index2) : plane.isRight(pt_j);

		if((j>0) && shared_vert_check && !visited_verts.insert(index2).second)
		{
			unsigned int alias_index = shared_offset + shared_vert_remap.size();
			shared_vert_remap.insert(shared_verts_map::value_type(alias_index, index2));
			index2 = alias_index;
		}

		if(ptInsideNext != ptInside)
		{
			// calc edge intersection with line
			edgeInt.m_point1 = index1;
			edgeInt.m_point2 = index2;
			plane.intersect(pt_i, pt_j, edgeInt.m_u);

			// if the edge is almost exactly parallel to the plane it is possible to
			// get a spurious value due to float-pt inaccuracy - solve the prob in double
			if((edgeInt.m_u <= 0) || (edgeInt.m_u >= 1))
			{
				if(boost::is_same<T,double>::value)
					edgeInt.m_u = std::min(std::max(edgeInt.m_u, T(0.0)), T(1.0));
				else
				{
					Line2<double> plane_d(plane);
					Imath::V2d ptd_i(pt_i);
					Imath::V2d ptd_j(pt_j);
					double u;
					plane_d.intersect(ptd_i, ptd_j, u);
					u = std::min(std::max(u, 0.0), 1.0);
					edgeInt.m_u = static_cast<T>(u);
				}
			}

			// sort intersection wrt line dir
			point_type pt_int = pt_i + (pt_j-pt_i)*edgeInt.m_u;
			T dist = pt_int.dot(line_dir);

			unsigned int vert_int = onplanePoints.size() + npoints;
			onplanePoints.push_back(edgeInt);

			if(ptInside)
				intersectionsOut.insert(typename onplane_lookup::value_type(dist, vert_int));
			else
				intersectionsIn.insert(typename onplane_lookup::value_type(dist, vert_int));

			if(ptInside)
			{
				unsigned int vert1 = insidePoints.size();
				unsigned int vert2 = vert_int;
				insidePoints.push_back(index1);
				edges.insert(edge_lookup::value_type(vert1, vert2));
			}
			else
			{
				unsigned int vert1 = vert_int;
				unsigned int vert2 = (j==0)? 0 : insidePoints.size();
				edges.insert(edge_lookup::value_type(vert1, vert2));
			}
		}
		else if(ptInside)
		{
			unsigned int vert1 = insidePoints.size();
			unsigned int vert2 = (j==0)? 0 : vert1+1;
			insidePoints.push_back(index1);
			edges.insert(edge_lookup::value_type(vert1, vert2));
		}
	}

	if(insidePoints.empty())
		return INTERSECT_OUTSIDE;

	if(!anyPtOutside)
	{
		// poly is completely inside
		result.push_back(polyclip_type());
		polyclip_type& pclip = result.back();
		pclip.makeInside(points);
		if(ctxt)
			pclip.m_polyId = ctxt->m_currentPolyId;

		return INTERSECT_INSIDE;
	}

	assert(!intersectionsOut.empty());
	assert(intersectionsOut.size() == intersectionsIn.size());

	// turn each pair of intersections into an edge
	while(!intersectionsOut.empty())
	{
		typename onplane_lookup::iterator itOut = intersectionsOut.begin();
		typename onplane_lookup::iterator itIn = intersectionsIn.begin();
		edges.insert(edge_lookup::value_type(itOut->second, itIn->second));
		intersectionsOut.erase(itOut);
		intersectionsIn.erase(itIn);
	}

	// find each closed loop within edges and return as poly
	while(!edges.empty())
	{
		result.push_back(polyclip_type());
		polyclip_type& pclip = result.back();
		pclip.m_vertices.reserve(edges.size());
		if(ctxt)
			pclip.m_polyId = -std::abs(ctxt->m_currentPolyId);

		edge_lookup::iterator it = edges.begin();
		unsigned int first_vert = it->first;

		while(it != edges.end())
		{
			unsigned int vert = it->first;
			if(vert >= npoints)
			{
				pclip.m_vertices.push_back(pclip.m_onplanePoints.size() + npoints);
				pclip.m_onplanePoints.push_back(onplanePoints[vert - npoints]);
			}
			else
			{
				pclip.m_vertices.push_back(pclip.m_insidePoints.size());
				pclip.m_insidePoints.push_back(insidePoints[vert]);
			}

			unsigned int next_vert = it->second;
			edges.erase(it);
			it = edges.find(next_vert);
		}

		// remap shared verts, if any
		if(shared_vert_check && !shared_vert_remap.empty())
		{
			for(unsigned int i=0; i<pclip.m_insidePoints.size(); ++i)
			{
				unsigned int vert = pclip.m_insidePoints[i];
				if(vert >= shared_offset)
				{
					assert(shared_vert_remap.find(vert) != shared_vert_remap.end());
					pclip.m_insidePoints[i] = shared_vert_remap.find(vert)->second;
				}
			}

			for(unsigned int i=0; i<pclip.m_onplanePoints.size(); ++i)
			{
				polyclip_intersection& is = pclip.m_onplanePoints[i];
				if(is.m_point1 >= shared_offset)
				{
					assert(shared_vert_remap.find(is.m_point1) != shared_vert_remap.end());
					is.m_point1 = shared_vert_remap.find(is.m_point1)->second;
				}
				if(is.m_point2 >= shared_offset)
				{
					assert(shared_vert_remap.find(is.m_point2) != shared_vert_remap.end());
					is.m_point2 = shared_vert_remap.find(is.m_point2)->second;
				}
			}
		}

		// remap verts so that onplane verts are correctly offset by inside pt count
		assert(pclip.m_vertices.size() > 2);
		unsigned int adjust = npoints - pclip.m_insidePoints.size();
		for(unsigned int i=0; i<pclip.m_vertices.size(); ++i)
		{
			if(pclip.m_vertices[i] >= npoints)
				pclip.m_vertices[i] -= adjust;
		}
	}

	return INTERSECT_INTERSECTS;
}