Commit c2b92c4b authored by Andreas Schwarzkopf's avatar Andreas Schwarzkopf

[ADD ##368] Surface detection using the Region Growing Segmentation of the Point Cloud Library

 * Currently the module Surface detection by PCL only gives the ability to detect
 * surfaces using point clouds (WDataSetPoints) what is a method of a fair quality.
 *
 * Some few changes across other modules:
 *   - Improvement on the octree neighbor search algorithm. Now you can look for
 *     neighbors using the neighborship of 6, 18 or 26
 *   - Very first steps on the surface detection algorithm "An adaptive approach for the
 *     segmentation and extraction of planar and linear/cylindrical features from laser
 *     scanning data" of Lari/Habib (2014).
 *   - Added an unidimensional kd tree structures with some processing methods such as
 *     looking for nearest nghbors.
parent ca452e19
......@@ -5,4 +5,8 @@ This toolbox is a collection of modules for dealing with LiDAR data. More inform
This toolbox is currently under development by
- Andreas Schwarzkopf
- Alexander Wiebel
\ No newline at end of file
- Alexander Wiebel
Requirements:
- libLAS (http://www.liblas.org/ or packages liblas-dev and liblas-c-dev)
- Point Cloud Library (http://pointclouds.org/)
\ No newline at end of file
......@@ -15,4 +15,4 @@
#VERSION=1.2.0
#VERSION=1.2.0+hgX -> replaces the X with the current revision number
#VERSUIB=1.2.0+hg1234 -> here, revision number was set by the build scripts for example.
VERSION=0.0.2+hgX
VERSION=0.0.3+hgX
......@@ -59,6 +59,20 @@ INCLUDE( OpenWalnut )
# IMPORTANT: NEVER add any commands bore the line INCLUDE( OpenWalnut ). This might cause problems!
# -----------------------------------------------------------------------------------------------------------------------------------------------
# Add Point Cloud Library for Nearest Neighbor Search
# -----------------------------------------------------------------------------------------------------------------------------------------------
# Code has been written with PCL v1.5
# FIND_PACKAGE( PCL 1.5 REQUIRED COMPONENTS common kdtree registration )
FIND_PACKAGE( PCL REQUIRED COMPONENTS common kdtree search registration segmentation )
INCLUDE_DIRECTORIES( ${PCL_INCLUDE_DIRS} )
LINK_DIRECTORIES( ${PCL_LIBRARY_DIRS} )
ADD_DEFINITIONS( ${PCL_DEFINITIONS} )
LIST( APPEND ADDITIONAL_LIBS ${PCL_SEGMENTATION_LIBRARIES};)
# ---------------------------------------------------------------------------------------------------------------------------------------------------
#
# Setup all modules
......@@ -73,10 +87,10 @@ INCLUDE( OpenWalnut )
# Please see the documentation of SETUP_MODULE as it shows how to add custom dependencies (third-party libs)
SETUP_MODULE(
${PROJECT_NAME} # use project name as module(-toolbox) name
"." # where to find the sources
"liblas.so" # no additonal dependencies
"" # no sources to exclude
${PROJECT_NAME} # use project name as module(-toolbox) name
"." # where to find the sources
"liblas.so;${ADDITIONAL_LIBS}" # no additonal dependencies
"" # no sources to exclude
)
# Tell CMake that we want to use the WToolboxVersion header in our Modules. It gets created automatically if you keep this line.
......
......@@ -37,6 +37,8 @@
#include "pointsCutOutliers/WMPointsCutOutliers.h"
#include "pointsGroupSelector/WMPointsGroupSelector.h"
#include "readLAS/WMReadLAS.h"
#include "surfaceDetectionByLari/WMSurfaceDetectionByLari.h"
#include "surfaceDetectionByPCL/WMSurfaceDetectionByPCL.h"
#include "wallDetectionByPCA/WMWallDetectionByPCA.h"
// #include "WToolkit.h"
......@@ -60,6 +62,8 @@ extern "C" void WLoadModule( WModuleList& m ) // NOLINT
m.push_back( boost::shared_ptr< WModule >( new WMPointsCutOutliers ) );
m.push_back( boost::shared_ptr< WModule >( new WMPointsGroupSelector ) );
m.push_back( boost::shared_ptr< WModule >( new WMReadLAS ) );
m.push_back( boost::shared_ptr< WModule >( new WMSurfaceDetectionByLari ) );
m.push_back( boost::shared_ptr< WModule >( new WMSurfaceDetectionByPCL ) );
m.push_back( boost::shared_ptr< WModule >( new WMWallDetectionByPCA ) );
}
......
This diff is collapsed.
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV-Leipzig and CNCF-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WKDTREEND_H
#define WKDTREEND_H
#include <vector>
#include <algorithm>
using std::vector;
using std::size_t;
using std::cout;
using std::endl;
/**
* This is a unidimensional kd tree compound. It is proposed not only to work with two
* or three dimensional kd trees but also with a single or more than three dimensions.
*/
class WKdTreeND
{
public:
WKdTreeND();
/**
* Instantiates a kd tree of a arbitrary dimension count.
* \param dimensions The dimension count of the kd tree.
*/
explicit WKdTreeND( size_t dimensions );
virtual ~WKdTreeND();
/**
* Adds points to the kd tree. It's better to add all the points into an empty tree.
* The tree is compatible to add one by one point but it will result a heavily
* unbalanced binary tree inside adding a larger amount of points.
* \param addables Points to add.
*/
void add( vector<vector<double> >* addables );
/**
* Says whether a kd tree node can be split or not. Firstly the method to determine
* the splitting dimension should be executed. A true value is returned if the
* calculated splitting dimension is within the total dimensions count.
* \return The kd tree node can be split or not.
*/
bool canSplit();
/**
* Fetches all the points from a kd tree node into a list.
* \param targetPointSet Target point list to put points to.
*/
void fetchPoints( vector<vector<double> >* targetPointSet );
// double getAreaMin(size_t dimension); //TODO(aschwarzkopf): Consider to purge in future
// double getAreaMax(size_t dimension); //TODO(aschwarzkopf): Consider to purge in future
/**
* Returns all the leaf nodes of the kd tree.
* \return All the leaf nodes of the kd tree.
*/
vector<WKdTreeND*>* getAllLeafNodes();
/**
* Returns the dimension count of the kd tree.
* \return The dimension count of the kd tree.
*/
size_t getDimensions();
// bool getHasBoundMin(size_t dimension); //TODO(aschwarzkopf): Consider to purge in future
// bool getHasBoundMax(size_t dimension); //TODO(aschwarzkopf): Consider to purge in future
/**
* Returns the child node that lies on the lower scale across the splitting
* dimension.
* \return The child node that lies on the lower scale across the splitting
* dimension.
*/
WKdTreeND* getLowerChild();
/**
* Returns the child node that lies on the higher scale across the splitting
* dimension.
* \return The child node that lies on the higher scale across the splitting
* dimension.
*/
WKdTreeND* getHigherChild();
/**
* Returns the points that are registered to the kd tree node. Usually all the
* poinnts have the same coordinate if nodes are subdivided to the lowest point
* count and no points of the same coordinates exist. Only leaf nodes can have and
* return points.
* \return The points of a kd tree node.
*/
vector<vector<double> >* getNodePoints();
/**
* Returns the dimension across which the current node is split.
* \return The dimension across which the current node is split.
*/
size_t getSplittingDimension();
/**
* Returns the splitting position of the splitted dimension.
* \return The splitting position of the splitted dimension.
*/
double getSplittingPosition();
protected:
/**
* Returns a new instance of the kd tree. You should overwrite this method when you
* derive your own class from this so that the kd tree can instantiate new objects
* of your type.
* \param dimensions The dimensions count of the new node.
* \return A new kd tree node instance of your node type.
*/
virtual WKdTreeND* getNewInstance( size_t dimensions );
private:
/**
* This method is used by the method to add new points. It puts points either to the
* node of the lower or higher position across the splitting dimension. The method is
* executed after the splitting dimension and position are calculated.
* \param newPoints Points to append to child nodes.
*/
void addPointsToChildren( vector<vector<double> >* newPoints );
/**
* Calculates the splitting position between the two child nodes. It calculates the
* median of all input points across the splitting dimension between two children.
* Always check out the splitting dimension before that.
* \param points Input points to calculate the median across the splitted dimension.
*/
void calculateSplittingPosition( vector<vector<double> >* points );
/**
* Determines the new splitting dimension between two child nodes. Afterwards the
* splitting position can be calculated across that dimension after executing that
* method.
* \param inputPoints Input points to analyse the most optimal splitting dimension.
* \return The kd tree node can be split or not.
*/
bool determineNewSplittingDimension( vector<vector<double> >* inputPoints );
/**
* Fetches all kd tree leaf nodes into a node list.
* \param targetNodeList The target list where leaf nodes are put.
*/
void fetchAllLeafNodes( vector<WKdTreeND*>* targetNodeList );
/**
* Tells whether a kd tree node has a parent or not.
* \return The node has a parent or not.
*/
bool hasParent();
/**
* Initializes newly created child kd tree nodes.
*/
void initSubNodes();
//void clearPointVector(vector<vector<double> >* deletables); //TODO(aschwarzkopf): Consider to purge in future
//TODO(aschwarzkopf): There are implementations with only 4 members!
/**
* The splitting dimension of the parent kd tree node. It is considered to determine
* the splitting dimension of the current kd tree node.
*/
size_t m_parentSplittingDimension; //ggf. wegschmeißen
//TODO(aschwarzkopf): Ggf. Sinn: Nicht bis ins Letzte unterteilen, ggf. nur über einem Threshold
/**
* The kd tree node child which is on the lower position across the splitting
* dimension.
*/
WKdTreeND* m_lowerChild;
/**
* The kd tree node child which is on the higher position across the splitting
* dimension.
*/
WKdTreeND* m_higherChild;
/**
* The dimension count of the kd tree.
*/
size_t m_dimensions; //TODO(aschwarzkopf): Consider whether you need it.
/**
* Children of a kd tree node are separated by a plane. The splitting dimension axis * is perpendicular to that.
*/
size_t m_splittingDimension;
/**
* Children of a kd tree node are separated by a plane. The splitting dimension axis * is perpendicular to that. This position variable is the intersection between this
* plane and axis.
*/
double m_splittingPosition;
/**
* Points of same coordinates can be added or not.
*/
bool m_allowDoubles; //TODO(aschwarzkopf): Still neither used nor implemented
/**
* Points covered by a kd tree node.
*/
vector<vector<double> >* m_points;
// vector<double> areaMin; //TODO(aschwarzkopf): Decide later whether to keep or not: It can be easily purged.
// vector<double> areaMax; //TODO(aschwarzkopf): Decide later whether to keep or not: It can be easily purged.
// vector<double> hasBoundMin; //TODO(aschwarzkopf): Decide later whether to keep or not: It can be easily purged.
// vector<double> hasBoundMax; //TODO(aschwarzkopf): Decide later whether to keep or not: It can be easily purged.
};
#endif // WKDTREEND_H
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV-Leipzig and CNCF-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include <vector>
#include "WPointDistance.h"
WPointDistance::WPointDistance()
{
m_pointDistance = 0;
}
WPointDistance::WPointDistance( vector<double> sourcePoint, vector<double> comparedPoint )
{
m_comparedCoordinate = comparedPoint;
m_pointDistance = getPointDistance( sourcePoint, comparedPoint );
}
WPointDistance::~WPointDistance()
{
}
vector<double> WPointDistance::getComparedCoordinate()
{
return m_comparedCoordinate;
}
double WPointDistance::getDistance()
{
return m_pointDistance;
}
double WPointDistance::getPointDistance( vector<double> point1, vector<double> point2 )
{ //TODO(aschwarzkopf): Not verified that the euclidian distance is calculated right also for points above 3 dimensions.
double distance = 0;
for( size_t index = 0; index < point1.size() && index < point2.size(); index++ )
{
double coord1 = point1[index];
double coord2 = point2[index];
distance += pow( coord1 - coord2, 2 );
}
return pow( distance, 0.5 );
}
bool WPointDistance::operator<( WPointDistance const& right ) const
{
return m_pointDistance < right.m_pointDistance;
}
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV-Leipzig and CNCF-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WPOINTDISTANCE_H
#define WPOINTDISTANCE_H
#include <math.h>
#include <iostream>
#include <vector>
using std::vector;
/**
* Object that pairs a coordinate with a distance information. It has also an operator
* that allows to use std::sort to sort coordinates by the ascending distance. The
* coordinates have the vector type because the class is used paired with the kd tree
* which is unidimensional.
*/
class WPointDistance
{
public:
/**
* Sets up the object without filling parameters.
*/
WPointDistance();
/**
* Instantiates the coordinate distance pair filling all necessary parameters.
* \param sourcePoint Reference point used to calculate the distance. Its
* coordinate isn't stored.
* \param comparedPoint The second point that is used to calculate the distance
* between. The object stores its coordinates by that.
*/
WPointDistance( vector<double> sourcePoint, vector<double> comparedPoint );
/**
* Object destructor
*/
virtual ~WPointDistance();
/**
* Returns the coordinate of the point compared to the reference.
* \return The compared point coordinate.
*/
vector<double> getComparedCoordinate();
/**
* Returns the distance between the reference point and the compared one.
* \return The distance between the two instantiated points using the constructor.
*/
double getDistance();
/**
* Static method that calculates the euclidian distance between two arbitrary
* unidimensional points.
* \param point1 First point for calculating the distance.
* \param point2 Second point for calculating the distance.
* \return Euclidian distance between that two points.
*/
static double getPointDistance( vector<double> point1, vector<double> point2 );
/**
* Operator for sorting a vector<WPointDistance> using std::sort.
* \param right The right compared object to this one.
* \return The distance of this object is smaller than the right one or not.
*/
bool operator<( WPointDistance const& right ) const;
/**
* The euclidian distance between the two points instantiated using the constructor.
*/
double m_pointDistance;
/**
* The unidimensional coordinate of the compared point instantiated using the
* constructor.
*/
vector<double> m_comparedCoordinate;
};
#endif // WPOINTDISTANCE_H
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV-Leipzig and CNCF-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include <algorithm>
#include <vector>
#include "WPointSearcher.h"
WPointSearcher::WPointSearcher()
{
m_distanceSteps = 4;
m_examinedKdTree = 0;
m_maxResultPointCount = 50;
m_maxSearchDistance = 0.5;
}
WPointSearcher::~WPointSearcher()
{
m_searchedPoint.resize( 0 );
m_searchedPoint.reserve( 0 );
}
vector<WPosition>* WPointSearcher::convertToPointSet( vector<WPointDistance>* pointDistances )
{
vector<WPosition>* pointSet = new vector<WPosition>();
for( size_t index = 0; index < pointDistances->size(); index++ )
{
vector<double> coordinate = pointDistances->at( index ).getComparedCoordinate();
if( coordinate.size() == 3 )
pointSet->push_back( WPosition( coordinate[0], coordinate[1], coordinate[2] ) );
}
return pointSet;
}
vector<WPointDistance>* WPointSearcher::getNearestPoints()
{
vector<WPointDistance>* nearestPoints = new vector<WPointDistance>();
double index = 1;
for( index = 1; index <= m_distanceSteps
&& nearestPoints->size() < m_maxResultPointCount; index++ )
{
nearestPoints->resize( 0 );
nearestPoints->reserve( 0 );
double maxDistance = m_maxSearchDistance * pow( 2.0, - ( double )m_distanceSteps + ( double )index );
fetchNearestPoints( m_examinedKdTree, nearestPoints, maxDistance );
//cout << "Attempt at max distance: " << maxDistance << " size = " << nearestPoints->size() << endl;
}
std::sort( nearestPoints->begin(), nearestPoints->end() );
//cout << "Found " << nearestPoints->size() << " Neighbors on index " << (index - 1)
// << " with maximal disstance " << nearestPoints->at(nearestPoints->size() - 1).getDistance() << endl;
if( nearestPoints->size() > m_maxResultPointCount )
{
nearestPoints->resize( m_maxResultPointCount );
nearestPoints->reserve( m_maxResultPointCount );
}
return nearestPoints;
}
void WPointSearcher::setExaminedKdTree( WKdTreeND* kdTree )
{
m_examinedKdTree = kdTree;
}
void WPointSearcher::setSearchedPoint( vector<double> searchedPoint )
{
m_searchedPoint = searchedPoint;
}
void WPointSearcher::setMaxSearchDistance( double distance )
{
m_maxSearchDistance = distance;
}
void WPointSearcher::setMaxResultPointCount( size_t maxPointCount )
{
m_maxResultPointCount = maxPointCount;
}
void WPointSearcher::fetchNearestPoints( WKdTreeND* currentNode, vector<WPointDistance>* targetPoints, double maxDistance )
{
vector<vector<double> >* nodePoints = currentNode->getNodePoints();
WKdTreeND* lowerChild = currentNode->getLowerChild();
WKdTreeND* higherChild = currentNode->getHigherChild();
if( nodePoints->size() > 0 && lowerChild == 0 && higherChild == 0)
{
for( size_t index = 0; index < nodePoints->size(); index++ )
{
vector<double> point = nodePoints->at( index );
if( WPointDistance::getPointDistance( m_searchedPoint, point ) <= maxDistance )
targetPoints->push_back( WPointDistance( m_searchedPoint, point ) );
}
}
else
{
if( nodePoints->size() == 0 && lowerChild != 0 && higherChild != 0 )
{
double splittingPosition = currentNode->getSplittingPosition();
double pointCoord = m_searchedPoint.at( currentNode->getSplittingDimension() );
if( pointCoord < splittingPosition + maxDistance )
fetchNearestPoints( currentNode->getLowerChild(), targetPoints, maxDistance );
if( pointCoord > splittingPosition - maxDistance )
fetchNearestPoints( currentNode->getHigherChild(), targetPoints, maxDistance );
}
else
{
cout << "!!!UNKNOWN EXCEPTION!!! - getting nearest points" << endl;
}
}
}
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV-Leipzig and CNCF-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WPOINTSEARCHER_H
#define WPOINTSEARCHER_H
#include <iostream>
#include <vector>
#include "WPointDistance.h"
#include "WKdTreeND.h"
#include "core/common/math/linearAlgebra/WPosition.h"
using std::cout;
using std::endl;
using std::vector;
/**
* Instance that searchs for particular points within a kd tree. Currently it looks for
* ones within a radius and a maximal point count. This type is proposed to be suitable
* for unidimensional coordinate systems.
*/
class WPointSearcher
{
public:
/**
* Instantiates the points searcher.
*/
WPointSearcher();
/**
* Destroys the points searcher