+ add region growing, segmentation and ransac algorithms to Reen module

This commit is contained in:
wmayer 2016-03-02 15:51:26 +01:00
parent 1ec066553e
commit 8a76f2c13e
6 changed files with 421 additions and 0 deletions

View File

@ -44,7 +44,10 @@
#include "ApproxSurface.h"
#include "BSplineFitting.h"
#include "SurfaceTriangulation.h"
#include "RegionGrowing.h"
#include "SampleConsensus.h"
#if defined(HAVE_PCL_FILTERS)
#include <pcl/filters/passthrough.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/point_types.h>
#endif
@ -92,6 +95,16 @@ public:
"filterVoxelGrid(dim)."
);
#endif
#if defined(HAVE_PCL_SEGMENTATION)
add_keyword_method("regionGrowingSegmentation",&Module::regionGrowingSegmentation,
"regionGrowingSegmentation()."
);
#endif
#if defined(HAVE_PCL_SEGMENTATION)
add_keyword_method("sampleConsensus",&Module::sampleConsensus,
"sampleConsensus()."
);
#endif
initialize("This module is the ReverseEngineering module."); // register with Python
}
@ -572,6 +585,74 @@ Mesh.show(m)
return Py::asObject(new Points::PointsPy(points_sample));
}
#endif
#if defined(HAVE_PCL_SEGMENTATION)
Py::Object regionGrowingSegmentation(const Py::Tuple& args, const Py::Dict& kwds)
{
PyObject *pts;
PyObject *vec = 0;
int ksearch=5;
static char* kwds_segment[] = {"Points", "KSearch", "Normals", NULL};
if (!PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "O!|iO", kwds_segment,
&(Points::PointsPy::Type), &pts,
&ksearch, &vec))
throw Py::Exception();
Points::PointKernel* points = static_cast<Points::PointsPy*>(pts)->getPointKernelPtr();
std::list<std::vector<int> > clusters;
RegionGrowing segm(*points, clusters);
if (vec) {
Py::Sequence list(vec);
std::vector<Base::Vector3f> normals;
normals.reserve(list.size());
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
Base::Vector3d v = Py::Vector(*it).toVector();
normals.push_back(Base::convertTo<Base::Vector3f>(v));
}
segm.perform(normals);
}
else {
segm.perform(ksearch);
}
Py::List lists;
for (std::list<std::vector<int> >::iterator it = clusters.begin(); it != clusters.end(); ++it) {
Py::Tuple tuple(it->size());
for (std::size_t i = 0; i < it->size(); i++) {
tuple.setItem(i, Py::Long((*it)[i]));
}
lists.append(tuple);
}
return lists;
}
#endif
#if defined(HAVE_PCL_SEGMENTATION)
Py::Object sampleConsensus(const Py::Tuple& args, const Py::Dict& kwds)
{
PyObject *pts;
static char* kwds_sample[] = {"Points", NULL};
if (!PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "O!", kwds_sample,
&(Points::PointsPy::Type), &pts))
throw Py::Exception();
Points::PointKernel* points = static_cast<Points::PointsPy*>(pts)->getPointKernelPtr();
std::vector<float> parameters;
SampleConsensus sample(*points);
double probability = sample.perform(parameters);
Py::Dict dict;
Py::Tuple tuple(parameters.size());
for (std::size_t i = 0; i < parameters.size(); i++)
tuple.setItem(i, Py::Float(parameters[i]));
dict.setItem(Py::String("Probability"), Py::Float(probability));
return dict;
}
#endif
};
} // namespace Reen

View File

@ -16,6 +16,14 @@ if (PCL_FILTERS_FOUND AND PCL_FEATURES_FOUND)
add_definitions(-DHAVE_PCL_FILTERS)
endif ()
if (PCL_SEGMENTATION_FOUND AND PCL_FEATURES_FOUND)
add_definitions(-DHAVE_PCL_SEGMENTATION)
endif ()
if (PCL_SAMPLE_CONSENSUS_FOUND)
add_definitions(-DHAVE_PCL_SAMPLE_CONSENSUS)
endif ()
include_directories(
${CMAKE_SOURCE_DIR}/src
${Boost_INCLUDE_DIRS}
@ -42,6 +50,8 @@ set(Reen_LIBS
${PCL_FILTERS_LIBRARIES}
${PCL_SEARCH_LIBRARIES}
${PCL_SURFACE_LIBRARIES}
${PCL_SEGMENTATION_LIBRARIES}
${PCL_SAMPLE_CONSENSUS_LIBRARIES}
${QT_QTCORE_LIBRARY}
)
@ -51,6 +61,10 @@ SET(Reen_SRCS
ApproxSurface.h
BSplineFitting.cpp
BSplineFitting.h
RegionGrowing.cpp
RegionGrowing.h
SampleConsensus.cpp
SampleConsensus.h
SurfaceTriangulation.cpp
SurfaceTriangulation.h
PreCompiled.cpp

View File

@ -0,0 +1,147 @@
/***************************************************************************
* Copyright (c) 2016 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#include "RegionGrowing.h"
#include <Mod/Points/App/Points.h>
#include <Base/Exception.h>
#if defined(HAVE_PCL_FILTERS)
#include <pcl/filters/passthrough.h>
#include <pcl/point_types.h>
#endif
#if defined(HAVE_PCL_SEGMENTATION)
#include <pcl/search/search.h>
#include <pcl/search/kdtree.h>
#include <pcl/features/normal_3d.h>
#include <pcl/segmentation/region_growing.h>
#include <pcl/filters/extract_indices.h>
using namespace std;
using namespace Reen;
using pcl::PointXYZ;
using pcl::PointNormal;
using pcl::PointCloud;
RegionGrowing::RegionGrowing(const Points::PointKernel& pts, std::list<std::vector<int> >& clusters)
: myPoints(pts)
, myClusters(clusters)
{
}
void RegionGrowing::perform(int ksearch)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
cloud->reserve(myPoints.size());
for (Points::PointKernel::const_iterator it = myPoints.begin(); it != myPoints.end(); ++it) {
cloud->push_back(pcl::PointXYZ(it->x, it->y, it->z));
}
//normal estimation
pcl::search::Search<pcl::PointXYZ>::Ptr tree = boost::shared_ptr<pcl::search::Search<pcl::PointXYZ> > (new pcl::search::KdTree<pcl::PointXYZ>);
pcl::PointCloud <pcl::Normal>::Ptr normals (new pcl::PointCloud <pcl::Normal>);
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimator;
normal_estimator.setSearchMethod (tree);
normal_estimator.setInputCloud (cloud);
normal_estimator.setKSearch (ksearch);
normal_estimator.compute (*normals);
// pass through
pcl::IndicesPtr indices (new std::vector <int>);
pcl::PassThrough<pcl::PointXYZ> pass;
pass.setInputCloud (cloud);
pass.setFilterFieldName ("z");
pass.setFilterLimits (0.0, 1.0);
pass.filter (*indices);
pcl::RegionGrowing<pcl::PointXYZ, pcl::Normal> reg;
reg.setMinClusterSize (50);
reg.setMaxClusterSize (1000000);
reg.setSearchMethod (tree);
reg.setNumberOfNeighbours (30);
reg.setInputCloud (cloud);
//reg.setIndices (indices);
reg.setInputNormals (normals);
reg.setSmoothnessThreshold (3.0 / 180.0 * M_PI);
reg.setCurvatureThreshold (1.0);
std::vector <pcl::PointIndices> clusters;
reg.extract (clusters);
for (std::vector<pcl::PointIndices>::iterator it = clusters.begin (); it != clusters.end (); ++it) {
myClusters.push_back(std::vector<int>());
myClusters.back().swap(it->indices);
}
}
void RegionGrowing::perform(const std::vector<Base::Vector3f>& myNormals)
{
if (myPoints.size() != myNormals.size())
throw Base::RuntimeError("Number of points doesn't match with number of normals");
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
cloud->reserve(myPoints.size());
for (Points::PointKernel::const_iterator it = myPoints.begin(); it != myPoints.end(); ++it) {
cloud->push_back(pcl::PointXYZ(it->x, it->y, it->z));
}
pcl::search::Search<pcl::PointXYZ>::Ptr tree = boost::shared_ptr<pcl::search::Search<pcl::PointXYZ> > (new pcl::search::KdTree<pcl::PointXYZ>);
tree->setInputCloud (cloud);
pcl::PointCloud <pcl::Normal>::Ptr normals (new pcl::PointCloud <pcl::Normal>);
normals->reserve(myNormals.size());
for (std::vector<Base::Vector3f>::const_iterator it = myNormals.begin(); it != myNormals.end(); ++it) {
normals->push_back(pcl::Normal(it->x, it->y, it->z));
}
// pass through
pcl::IndicesPtr indices (new std::vector <int>);
pcl::PassThrough<pcl::PointXYZ> pass;
pass.setInputCloud (cloud);
pass.setFilterFieldName ("z");
pass.setFilterLimits (0.0, 1.0);
pass.filter (*indices);
pcl::RegionGrowing<pcl::PointXYZ, pcl::Normal> reg;
reg.setMinClusterSize (50);
reg.setMaxClusterSize (1000000);
reg.setSearchMethod (tree);
reg.setNumberOfNeighbours (30);
reg.setInputCloud (cloud);
//reg.setIndices (indices);
reg.setInputNormals (normals);
reg.setSmoothnessThreshold (3.0 / 180.0 * M_PI);
reg.setCurvatureThreshold (1.0);
std::vector <pcl::PointIndices> clusters;
reg.extract (clusters);
for (std::vector<pcl::PointIndices>::iterator it = clusters.begin (); it != clusters.end (); ++it) {
myClusters.push_back(std::vector<int>());
myClusters.back().swap(it->indices);
}
}
#endif // HAVE_PCL_SEGMENTATION

View File

@ -0,0 +1,56 @@
/***************************************************************************
* Copyright (c) 2016 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef REEN_REGIONGROWING_H
#define REEN_REGIONGROWING_H
#include <Base/Vector3D.h>
#include <vector>
#include <list>
namespace Points {class PointKernel;}
namespace Reen {
class RegionGrowing
{
public:
RegionGrowing(const Points::PointKernel&, std::list<std::vector<int> >&);
/** \brief Set the number of k nearest neighbors to use for the normal estimation.
* \param[in] k the number of k-nearest neighbors
*/
void perform(int ksearch);
/** \brief Pass the normals to the points given in the constructor.
* \param[in] normals the normals to the given points.
*/
void perform(const std::vector<Base::Vector3f>& normals);
private:
const Points::PointKernel& myPoints;
std::list<std::vector<int> >& myClusters;
};
} // namespace Reen
#endif // REEN_REGIONGROWING_H

View File

@ -0,0 +1,76 @@
/***************************************************************************
* Copyright (c) 2016 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#include "SampleConsensus.h"
#include <Mod/Points/App/Points.h>
#include <Base/Exception.h>
#if defined(HAVE_PCL_SAMPLE_CONSENSUS)
#include <pcl/point_types.h>
#include <pcl/sample_consensus/ransac.h>
#include <pcl/sample_consensus/sac_model_plane.h>
using namespace std;
using namespace Reen;
using pcl::PointXYZ;
using pcl::PointNormal;
using pcl::PointCloud;
SampleConsensus::SampleConsensus(const Points::PointKernel& pts)
: myPoints(pts)
{
}
double SampleConsensus::perform(std::vector<float>& parameters)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
cloud->reserve(myPoints.size());
for (Points::PointKernel::const_iterator it = myPoints.begin(); it != myPoints.end(); ++it) {
cloud->push_back(pcl::PointXYZ(it->x, it->y, it->z));
}
cloud->width = int (cloud->points.size ());
cloud->height = 1;
cloud->is_dense = true;
// created RandomSampleConsensus object and compute the appropriated model
pcl::SampleConsensusModelPlane<pcl::PointXYZ>::Ptr
model_p (new pcl::SampleConsensusModelPlane<pcl::PointXYZ> (cloud));
pcl::RandomSampleConsensus<pcl::PointXYZ> ransac (model_p);
ransac.setDistanceThreshold (.01);
ransac.computeModel();
//ransac.getInliers(inliers);
//ransac.getModel (model);
Eigen::VectorXf model_p_coefficients;
ransac.getModelCoefficients (model_p_coefficients);
for (int i=0; i<model_p_coefficients.size(); i++)
parameters.push_back(model_p_coefficients[i]);
return ransac.getProbability();
}
#endif // HAVE_PCL_SAMPLE_CONSENSUS

View File

@ -0,0 +1,47 @@
/***************************************************************************
* Copyright (c) 2016 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef REEN_SAMPLECONSENSUS_H
#define REEN_SAMPLECONSENSUS_H
#include <Base/Vector3D.h>
#include <vector>
namespace Points {class PointKernel;}
namespace Reen {
class SampleConsensus
{
public:
SampleConsensus(const Points::PointKernel&);
double perform(std::vector<float>& parameters);
private:
const Points::PointKernel& myPoints;
};
} // namespace Reen
#endif // REEN_SAMPLECONSENSUS_H