Commit 7180d123 authored by aschwarzkopf's avatar aschwarzkopf

[ADD 361] Prototypic surface detection OpenWalnut module

 * The new module firstly puts point data into a voxel grid. For each of these areas
 * the Principal Component Analysis is run. For each voxel the Eigen Vector of the
 * smallest Eigen Value is taken. In the case of surface kins data it's the normal
 * vector. In the last steps voxels with the similar vector are grouped.
 * Currently the region growing often bleeds over through many surfaces.
parent 41b8f04c
......@@ -31,10 +31,12 @@
#include <core/kernel/WModule.h>
#include "buildingsDetection/WMBuildingsDetection.h"
#include "buildingsDetectionByPCA/WMBuildingsDetectionByPCA.h"
#include "elevationImageExport/WMElevationImageExport.h"
#include "pointsCutOutliers/WMPointsCutOutliers.h"
#include "pointsGroupSelector/WMPointsGroupSelector.h"
#include "readLAS/WMReadLAS.h"
#include "wallDetectionByPCA/WMWallDetectionByPCA.h"
// #include "WToolkit.h"
......@@ -51,10 +53,12 @@
extern "C" void WLoadModule( WModuleList& m ) // NOLINT
{
m.push_back( boost::shared_ptr< WModule >( new WMBuildingsDetection ) );
m.push_back( boost::shared_ptr< WModule >( new WMBuildingsDetectionByPCA ) );
m.push_back( boost::shared_ptr< WModule >( new WMElevationImageExport ) );
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 WMWallDetectionByPCA ) );
}
/**
......
//---------------------------------------------------------------------------
//
// 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 <string>
#include <fstream> // std::ifstream
#include <iostream> // std::cout
#include <vector>
#include <osg/Geometry>
#include "core/kernel/WModule.h"
#include "core/dataHandler/WDataSetScalar.h"
#include "core/graphicsEngine/callbacks/WGELinearTranslationCallback.h"
#include "core/graphicsEngine/shaders/WGEPropertyUniform.h"
#include "core/graphicsEngine/shaders/WGEShader.h"
#include "core/graphicsEngine/WGEGeodeUtils.h"
#include "core/graphicsEngine/WGEManagedGroupNode.h"
#include "core/kernel/WKernel.h"
#include "core/kernel/WModuleInputData.h"
#include "WMWallDetectionByPCA.xpm"
#include "WMWallDetectionByPCA.h"
#include "WPCAWallDetector.h"
// This line is needed by the module loader to actually find your module.
//W_LOADABLE_MODULE( WMWallDetectionByPCA )
//TODO(aschwarzkopf): Reenable above after solving the toolbox problem
WMWallDetectionByPCA::WMWallDetectionByPCA():
WModule(),
m_propCondition( new WCondition() )
{
}
WMWallDetectionByPCA::~WMWallDetectionByPCA()
{
}
boost::shared_ptr< WModule > WMWallDetectionByPCA::factory() const
{
return boost::shared_ptr< WModule >( new WMWallDetectionByPCA() );
}
const char** WMWallDetectionByPCA::getXPMIcon() const
{
return WMWallDetectionByPCA_xpm;
}
const std::string WMWallDetectionByPCA::getName() const
{
return "Wall Detection by PCA";
}
const std::string WMWallDetectionByPCA::getDescription() const
{
return "Should draw values above some threshold.";
}
void WMWallDetectionByPCA::connectors()
{
m_input = WModuleInputData< WDataSetPoints >::createAndAdd( shared_from_this(), "input", "The mesh to display" );
m_outputTrimesh = boost::shared_ptr< WModuleOutputData< WTriangleMesh > >(
new WModuleOutputData< WTriangleMesh >( shared_from_this(), "Variance intensity", "The loaded mesh." ) );
addConnector( m_outputTrimesh );
// addConnector( m_buildings );
WModule::connectors();
}
void WMWallDetectionByPCA::properties()
{
// ---> Put the code for your properties here. See "src/modules/template/" for an extensively documented example.
m_reloadData = m_properties->addProperty( "Reload data:", "Execute", WPVBaseTypes::PV_TRIGGER_READY, m_propCondition );
m_detailDepth = m_properties->addProperty( "Detail Depth 2^n m: ", "Resulting 2^n meters detail "
"depth for the octree search tree.", 0 );
m_detailDepth->setMin( -3 );
m_detailDepth->setMax( 4 );
m_detailDepthLabel = m_properties->addProperty( "Detail Depth meters: ", "Resulting detail depth "
"in meters for the octree search tree.", 1.0 );
m_detailDepthLabel->setPurpose( PV_PURPOSE_INFORMATION );
m_wallMaxAngleToNeighborVoxel = m_properties->addProperty( "Wall - max angle to voxel: ", "The maximal "
"angle between two connected voxels to detect as a single wall.", 5.0 );
m_wallMaxAngleToNeighborVoxel->setMin( 0.0 );
m_wallMaxAngleToNeighborVoxel->setMax( 45.0 );
m_showedVarianceQuotientMax = m_properties->addProperty( "Variance - Quotient max.: ", "The maximal "
"that is displayed in the output triangle mesh using colors.", 0.5 );
m_showedVarianceQuotientMax->setMin( 0.0 );
m_showedVarianceQuotientMax->setMax( 1.0 );
WModule::properties();
}
void WMWallDetectionByPCA::requirements()
{
}
void WMWallDetectionByPCA::moduleMain()
{
infoLog() << "Thrsholding example main routine started";
// get notified about data changes
m_moduleState.setResetable( true, true );
m_moduleState.add( m_input->getDataChangedCondition() );
m_moduleState.add( m_propCondition );
ready();
// graphics setup
m_rootNode = osg::ref_ptr< WGEManagedGroupNode >( new WGEManagedGroupNode( m_active ) );
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_rootNode );
// main loop
while( !m_shutdownFlag() )
{
//infoLog() << "Waiting ...";
m_moduleState.wait();
boost::shared_ptr< WDataSetPoints > points = m_input->getData();
// std::cout << "Execute cycle\r\n";
if ( points )
{
WDataSetPoints::VertexArray inputVerts = points->getVertices();
size_t count = inputVerts->size()/3;
setProgressSettings( count );
m_detailDepthLabel->set( pow( 2.0, m_detailDepth->get() ) );
WWallDetectOctree* pcaAnalysis = new WWallDetectOctree( m_detailDepthLabel->get() );
pcaAnalysis->setWallMaxAngleToNeighborVoxel( m_wallMaxAngleToNeighborVoxel->get() );
boost::shared_ptr< WTriangleMesh > tmpMesh( new WTriangleMesh( 0, 0 ) );
for ( size_t vertex = 0; vertex < count; vertex++)
{
m_progressStatus->increment( 1 );
float x = inputVerts->at( vertex*3 );
float y = inputVerts->at( vertex*3+1 );
float z = inputVerts->at( vertex*3+2 );
pcaAnalysis->registerPoint( x, y, z );
}
setProgressSettings( pcaAnalysis->getRootNode()->getTotalNodeCount() );
pcaAnalysis->setMaxIsotropicThresholdForVoxelMerge( m_showedVarianceQuotientMax->get() );
WPCAWallDetector detector( pcaAnalysis, m_progressStatus );
detector.analyze();
pcaAnalysis->groupNeighbourLeafsFromRoot();
m_outputTrimesh->updateData( detector.getOutline() );
m_progressStatus->finish();
}
m_reloadData->set( WPVBaseTypes::PV_TRIGGER_READY, true );
m_reloadData->get( true );
// woke up since the module is requested to finish?
if ( m_shutdownFlag() )
{
break;
}
boost::shared_ptr< WDataSetPoints > points2 = m_input->getData();
if ( !points2 )
{
continue;
}
// ---> Insert code doing the real stuff here
}
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_rootNode );
}
void WMWallDetectionByPCA::setProgressSettings( size_t steps )
{
m_progress->removeSubProgress( m_progressStatus );
std::string headerText = "Loading data";
m_progressStatus = boost::shared_ptr< WProgress >( new WProgress( headerText, steps ) );
m_progress->addSubProgress( m_progressStatus );
}
//---------------------------------------------------------------------------
//
// 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 WMWALLDETECTIONBYPCA_H
#define WMWALLDETECTIONBYPCA_H
#include <liblas/liblas.hpp>
#include <string>
#include <vector>
#include <fstream> // std::ifstream
#include <iostream> // std::cout
#include "core/kernel/WModule.h"
#include "core/graphicsEngine/WGEManagedGroupNode.h"
#include "core/graphicsEngine/shaders/WGEShader.h"
#include "core/graphicsEngine/WTriangleMesh.h"
#include <osg/ShapeDrawable>
#include <osg/Geode>
#include "core/dataHandler/WDataSetPoints.h"
#include "structure/WWallDetectOctree.h"
#include "../datastructures/quadtree/WQuadTree.h"
#include "../datastructures/WDataSetPointsGrouped.h"
//!.Unnecessary imports
#include "core/common/WItemSelection.h"
#include "core/common/WItemSelector.h"
#include "core/kernel/WModuleOutputData.h"
#include <osg/Group>
#include <osg/Material>
#include <osg/StateAttribute>
#include "core/kernel/WKernel.h"
#include "core/common/exceptions/WFileNotFound.h"
#include "core/common/WColor.h"
#include "core/common/WPathHelper.h"
#include "core/common/WPropertyHelper.h"
#include "core/common/WItemSelectionItem.h"
#include "core/common/WItemSelectionItemTyped.h"
#include "core/graphicsEngine/WGEUtils.h"
#include "core/graphicsEngine/WGERequirement.h"
// forward declarations to reduce compile dependencies
template< class T > class WModuleInputData;
class WDataSetScalar;
class WGEManagedGroupNode;
/**
* OpenWalnut plugin for detecting plain surfaces, mainly walls and roofs.
*/
class WMWallDetectionByPCA: public WModule
{
public:
WMWallDetectionByPCA();
/**
* Destroys this module.
*/
virtual ~WMWallDetectionByPCA();
/**
* Gives back the name of this module.
* \return the module's name.
*/
virtual const std::string getName() const;
/**
* Gives back a description of this module.
* \return description to module.
*/
virtual const std::string getDescription() const;
/**
* Due to the prototype design pattern used to build modules, this method returns a
* new instance of this method. NOTE: it should never be initialized or modified in
* some other way. A simple new instance is required.
* \return the prototype used to create every module in OpenWalnut.
*/
virtual boost::shared_ptr< WModule > factory() const;
/**
* Get the icon for this module in XPM format.
* \return The icon.
*/
virtual const char** getXPMIcon() const;
protected:
/**
* Entry point after loading the module. Runs in separate thread.
*/
virtual void moduleMain();
/**
*Initialize the connectors this module is using.
*/
virtual void connectors();
/**
* Initialize the properties for this module.
*/
virtual void properties();
/**
* Initialize requirements for this module.
*/
virtual void requirements();
private:
/**
* Initializes progress bar settings.
* \param steps Points count as reference to the progress bar.
*/
void setProgressSettings( size_t steps );
/**
* Determines the resolution of the smallest octree nodes in 2^n meters. The smallest
* radius equals to its result.
*/
WPropInt m_detailDepth;
/**
* WDataSetPoints data input (proposed for LiDAR data).
*/
boost::shared_ptr< WModuleInputData< WDataSetPoints > > m_input;
/**
* The output triangle mesh that is proposed to show surface node groups.
*/
boost::shared_ptr< WModuleOutputData< WTriangleMesh > > m_outputTrimesh;
/**
* The OSG root node for this module. All other geodes or OSG nodes will be attached
* on this single node.
*/
osg::ref_ptr< WGEManagedGroupNode > m_rootNode;
/**
* Needed for recreating the geometry, incase when resolution changes.
*/
boost::shared_ptr< WCondition > m_propCondition;
/**
* Determines the resolution of smallest octree nodes. Their radius equal that value.
*/
WPropDouble m_detailDepthLabel;
WPropTrigger m_reloadData; //!< This property triggers the actual reading,
/**
* The maximal allowed angle between two node surface normal vectors. Nodes above
* that angle difference aren't grouped.
*/
WPropDouble m_wallMaxAngleToNeighborVoxel;
/**
* The biggest allowed value consisting of that: Weakest point distribution vector
* strength divided by the strongest. Nodes above that quotient aren't grouped.
*/
WPropDouble m_showedVarianceQuotientMax;
/**
* Plugin progress status.
*/
boost::shared_ptr< WProgress > m_progressStatus;
};
#endif // WMWALLDETECTIONBYPCA_H
/* XPM */
static const char * WMWallDetectionByPCA_xpm[] = {
"32 32 5 1",
" c #FFFFFF",
". c #3E3E3E",
"+ c #000000",
"@ c #000063",
"# c #808080",
" ",
" ",
" ",
" ",
" ",
"............. ..............",
" +. .+ ",
" + . . + ",
" + . . + ",
" + . . + ",
" + . . + ",
" + . . + ",
" + . . + ",
"........ @. .@ .........",
" . @ . . @ . ",
" . . . . ",
" @@ @@ . @ . . @ . @@ @@ @",
" .@ @. .@ @. ",
" . @ . # . @ . ",
" . . . . ",
" @@ @@ . @ + # + @ . @@ @@ @",
" .@ + # + @. ",
" . + + . ",
" . + + . ",
" @@ @@ . + # + . @@ @@ @",
" . + # + . ",
" .+ +. ",
"........+ +.........",
" # ",
" # ",
" # ",
"### ### ### ### ### ### "};
//---------------------------------------------------------------------------
//
// 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 <iostream>
#include <vector>
#include "WPCAWallDetector.h"
WPCAWallDetector::WPCAWallDetector( WWallDetectOctree* analyzableOctree, boost::shared_ptr< WProgress > progressStatus )
{
m_analyzableOctree = analyzableOctree;
m_progressStatus = progressStatus;
}
WPCAWallDetector::~WPCAWallDetector()
{
}
void WPCAWallDetector::analyze()
{
cout << "Total nodes in set: " << m_analyzableOctree->getRootNode()->getTotalNodeCount();
analyzeNode( ( WWallDetectOctNode* )( m_analyzableOctree->getRootNode() ) );
}
void WPCAWallDetector::analyzeNode( WWallDetectOctNode* node )
{
m_progressStatus->increment( 1 );
if ( node->getRadius() <= m_analyzableOctree->getDetailLevel() )
{
if(node->getPointCount() >= 3 )
{
WPrincipalComponentAnalysis pca;
pca.analyzeData( node->getInputPoints() );
node->setNormalVector( pca.getDirections()[2] );
vector<double> variance = pca.getEigenValues();
double quotient = variance[0] > 0.0 ?variance[2] / variance[0] :1.0;
node->setIsotropicThreshold( quotient );
}
}
else
{
for ( int child = 0; child < 8; child++ )
if ( node->getChild( child ) != 0 )
analyzeNode( ( WWallDetectOctNode* )( node->getChild( child ) ) );
}
}
boost::shared_ptr< WTriangleMesh > WPCAWallDetector::getOutline()
{
boost::shared_ptr< WTriangleMesh > tmpMesh( new WTriangleMesh( 0, 0 ) );
drawNode( ( WWallDetectOctNode* )( m_analyzableOctree->getRootNode() ), tmpMesh );
return tmpMesh;
}
void WPCAWallDetector::drawNode( WWallDetectOctNode* node, boost::shared_ptr< WTriangleMesh > outputMesh )
{
if ( node->getRadius() <= m_analyzableOctree->getDetailLevel() )
{
size_t index = outputMesh->vertSize();
osg::Vec4 color = osg::Vec4(
WOctree::calcColor( node->getGroupNr(), 0 ),
WOctree::calcColor( node->getGroupNr(), 1 ),
WOctree::calcColor( node->getGroupNr(), 2 ), 1.0 );
for( size_t vertex = 0; vertex <= 8; vertex++ )
{
double iX = vertex % 2;
double iY = ( vertex / 2 ) % 2;
double iZ = ( vertex / 4 ) % 2;
double x = node->getCenter( 0 ) + node->getRadius() * ( iX * 2.0 - 1.0 );
double y = node->getCenter( 1 ) + node->getRadius() * ( iY * 2.0 - 1.0 );
double z = node->getCenter( 2 ) + node->getRadius() * ( iZ * 2.0 - 1.0 );
outputMesh->addVertex( x, y, z );
outputMesh->setVertexColor( index+vertex, color );
}
// Z = 0
outputMesh->addTriangle( index + 0, index + 2, index + 1 );
outputMesh->addTriangle( index + 3, index + 1, index + 2 );
// X = 0
outputMesh->addTriangle( index + 0, index + 4, index + 2 );
outputMesh->addTriangle( index + 4, index + 6, index + 2 );
// Y = 0
outputMesh->addTriangle( index + 0, index + 1, index + 4 );
outputMesh->addTriangle( index + 1, index + 5, index + 4 );
// Z = 1
outputMesh->addTriangle( index + 4, index + 5, index + 6 );
outputMesh->addTriangle( index + 5, index + 7, index + 6 );
// X = 1
outputMesh->addTriangle( index + 1, index + 3, index + 5 );
outputMesh->addTriangle( index + 3, index + 7, index + 5 );
// Y = 1
outputMesh->addTriangle( index + 2, index + 6, index + 3 );
outputMesh->addTriangle( index + 6, index + 7, index + 3 );
}
else
{
for ( int child = 0; child < 8; child++ )
if ( node->getChild( child ) != 0 )
drawNode( ( WWallDetectOctNode* )(node->getChild( child ) ), outputMesh );
}
}
//---------------------------------------------------------------------------
//
// 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 WPCAWALLDETECTOR_H
#define WPCAWALLDETECTOR_H
#include <math.h>
#include <vector>
#include "core/graphicsEngine/WTriangleMesh.h"
#include "core/dataHandler/WDataSetPoints.h"
#include "../datastructures/quadtree/WQuadNode.h"
#include "../datastructures/quadtree/WQuadTree.h"
#include "structure/WWallDetectOctree.h"
#include "structure/WWallDetectOctNode.h"
#include "core/common/math/PrincipalComponentAnalsis/WPrincipalComponentAnalysis.h"
#include "core/common/WProgress.h"