Open
Description
The CropHull algorithm works well when you want to crop points outside the hull, either in 2d or 3d but it doesn't work when you want to crop points inside the hull in 3d (but it works in 2d).
Code copied from crop_hull.hpp:
202 if (crop_outside_ && (crossings[0]&1) + (crossings[1]&1) + (crossings[2]&1) > 1)
203 output.push_back (input_->points[(*indices_)[index]]);
204 else if (!crop_outside_)
205 output.push_back (input_->points[(*indices_)[index]]);
This is clearly wrong. The condition checking if the point is inside or outside the hull is not being checked when crop_outside is false, which means every point is being pushed back to the output if the option to crop inside is selected.
Your Environment
- Operating System and version: Debian GNU/Linux 8 (jessie) 64-bit
- Compiler: GCC
- PCL Version: 1.7.1
Expected Behavior
The filter method should filter points as told by the documentation.
Current Behavior
The filter method is not filtering points inside the hull in a 3d (the default) dimensionality.
Possible Solution
Possible solution:
202 bool isPointInsideHull = (crossings[0]&1) + (crossings[1]&1) + (crossings[2]&1) > 1
203 if ((crop_outside_ && isPointInsideHull) || (!crop_outside_ && !isPointInsideHull))
204 output.push_back (input_->points[(*indices_)[index]]);
Code to Reproduce
#include <iostream>
#include <pcl/common/common.h>
#include <pcl-1.7/pcl/point_types.h>
#include <pcl-1.7/pcl/point_cloud.h>
#include <pcl/filters/crop_hull.h>
#include <pcl/surface/convex_hull.h>
#include <boost/shared_ptr.hpp>
int main(int argc, char **argv)
{
typedef pcl::PointCloud<pcl::PointXYZ> PointCloud;
pcl::CropHull<pcl::PointXYZ> cropHullFilter;
boost::shared_ptr<PointCloud> hullCloud(new PointCloud());
boost::shared_ptr<PointCloud> hullPoints(new PointCloud());
std::vector<pcl::Vertices> hullPolygons;
hullCloud->clear();
{
pcl::PointXYZ p;
p.x = -1;
p.y = -1;
p.z = -1;
hullCloud->push_back(p);
p.z = 1;
hullCloud->push_back(p);
}
{
pcl::PointXYZ p;
p.x = -1;
p.y = 1;
p.z = -1;
hullCloud->push_back(p);
p.z = 1;
hullCloud->push_back(p);
}
{
pcl::PointXYZ p;
p.x = 1;
p.y = 1;
p.z = -1;
hullCloud->push_back(p);
p.z = 1;
hullCloud->push_back(p);
}
{
pcl::PointXYZ p;
p.x = 1;
p.y = -1;
p.z = -1;
hullCloud->push_back(p);
p.z = 1;
hullCloud->push_back(p);
}
// setup hull filter
pcl::ConvexHull<pcl::PointXYZ> cHull;
cHull.setInputCloud(hullCloud);
cHull.reconstruct(*hullPoints, hullPolygons);
cropHullFilter.setHullIndices(hullPolygons);
cropHullFilter.setHullCloud(hullPoints);
//cropHullFilter.setDim(2); // if you uncomment this, it will work
cropHullFilter.setCropOutside(false); // this will remove points inside the hull
// create point cloud
boost::shared_ptr<PointCloud> pc(new PointCloud());
// a point inside the hull
{
pcl::PointXYZ p;
p.x = 0;
p.y = 0;
p.z = 0;
pc->push_back(p);
}
// and a point outside the hull
{
pcl::PointXYZ p;
p.x = 10;
p.y = 10;
p.z = 10;
pc->push_back(p);
}
for(size_t i=0; i < pc->size(); ++i)
{
std::cout << (*pc)[i] << std::endl;
}
//filter points
std::cout << "Point cloud: " << std::endl;
cropHullFilter.setInputCloud(pc);
boost::shared_ptr<PointCloud> filtered(new PointCloud());
cropHullFilter.filter(*filtered);
std::cout << "Filtered point cloud: " << std::endl;
for(size_t i=0; i < filtered->size(); ++i)
{
std::cout << (*filtered)[i] << std::endl;
}
return 0;
}