Commit 41b8f04c authored by aschwarzkopf's avatar aschwarzkopf

[ADD #360] Added prototypic module to remove tree structures.

 * This algorithm puts input point coulds to a voxel grid and applies the Principal
 * Component Analysis to each of these areas. It's calculated how isotropic voxels are.
 * Either planar voxels have the blue color and isotropic ones are red. There's a
 * feature to cut avay voxels from the output triangle mesh for the view. You can either
 * set the minimal point count per voxel or the quotient of the smallest Eigen value over
 * the biggest one as the maximal isotropic level criteria.
parent 9db2e499
......@@ -61,7 +61,7 @@ void WBuildingDetector::detectBuildings( boost::shared_ptr< WDataSetPoints > poi
projectDrawableAreas( zones2d->getRootNode(), minimalMaxima, targetShowables );
fetchBuildingVoxels( zones3d->getRootNode(), targetShowables, m_targetGrouped3d );
m_targetGrouped3d->groupNeighbourLeafs();
m_targetGrouped3d->groupNeighbourLeafsFromRoot();
//targetShowables->setExportElevationImageSettings( -16.0, 8.0 );
//targetShowables->exportElevationImage( "/home/renegade/Dokumente/Projekte/OpenWalnut@Eclipse/elevation images/targetShowables.bmp", 1 );
......
//---------------------------------------------------------------------------
//
// 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 "WMBuildingsDetectionByPCA.xpm"
#include "WMBuildingsDetectionByPCA.h"
#include "WPCADetector.h"
#include "../datastructures/octree/WOctree.h"
// This line is needed by the module loader to actually find your module.
//W_LOADABLE_MODULE( WMBuildingsDetectionByPCA )
//TODO(aschwarzkopf): Reenable above after solving the toolbox problem
WMBuildingsDetectionByPCA::WMBuildingsDetectionByPCA():
WModule(),
m_propCondition( new WCondition() )
{
}
WMBuildingsDetectionByPCA::~WMBuildingsDetectionByPCA()
{
}
boost::shared_ptr< WModule > WMBuildingsDetectionByPCA::factory() const
{
return boost::shared_ptr< WModule >( new WMBuildingsDetectionByPCA() );
}
const char** WMBuildingsDetectionByPCA::getXPMIcon() const
{
return WMBuildingsDetectionByPCA_xpm;
}
const std::string WMBuildingsDetectionByPCA::getName() const
{
return "Buildings Detection by PCA";
}
const std::string WMBuildingsDetectionByPCA::getDescription() const
{
return "Should draw values above some threshold.";
}
void WMBuildingsDetectionByPCA::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 WMBuildingsDetectionByPCA::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_showedIsotropicThresholdMin = m_properties->addProperty( "Eigen Value Quot. min.: ", "The minimal "
"that is displayed in the output triangle mesh using colors.", 0.0 );
m_showedIsotropicThresholdMin->setMin( 0.0 );
m_showedIsotropicThresholdMin->setMax( 0.998 );
m_showedIsotropicThresholdMax = m_properties->addProperty( "Eigen Value Quot. max.: ", "The maximal "
"that is displayed in the output triangle mesh using colors.", 1.0 );
m_showedIsotropicThresholdMax->setMin( 0.002 );
m_showedIsotropicThresholdMax->setMax( 1.0 );
m_maximalEigenValueQuotientToDraw = m_properties->addProperty( "Max. Eig. Quot. to draw: ",
"Maximal Eigen Value quotient of voxel's points to draw that area.", 1.0 );
m_maximalEigenValueQuotientToDraw->setMin( 0.0 );
m_maximalEigenValueQuotientToDraw->setMax( 1.0 );
m_minPointsPerVoxelToDraw = m_properties->addProperty( "Min. points per voxel to draw: ",
"The minimal points per voxel that enables an area to draw.", 1 );
m_minPointsPerVoxelToDraw->setMin( 1 );
WModule::properties();
}
void WMBuildingsDetectionByPCA::requirements()
{
}
void WMBuildingsDetectionByPCA::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();
m_showedIsotropicThresholdMax->setMin( m_showedIsotropicThresholdMin->get() + 0.002 );
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() ) );
WOctree* pcaAnalysis = new WOctree( m_detailDepthLabel->get(), new WPcaDetectOctNode() );
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() );
WPCADetector detector( pcaAnalysis, m_progressStatus );
detector.setDisplayedVarianceQuotientRange( m_showedIsotropicThresholdMin->get(), m_showedIsotropicThresholdMax->get() );
detector.setMaximalEigenValueQuotientToDraw( m_maximalEigenValueQuotientToDraw->get() );
detector.setMinPointsPerVoxelToDraw( m_minPointsPerVoxelToDraw->get() );
detector.analyze();
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 WMBuildingsDetectionByPCA::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 WMBUILDINGSDETECTIONBYPCA_H
#define WMBUILDINGSDETECTIONBYPCA_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 "../datastructures/octree/WOctree.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 that analyzes poin data whether it's planar or isotropic.
* Data is analyzed considering areas covered by voxels which get a threshold area how
* much isotropic they are. It's useful to watch where the area is planar or isotropic.
*/
class WMBuildingsDetectionByPCA: public WModule
{
public:
/**
* Starts the instance.
*/
WMBuildingsDetectionByPCA();
/**
* Destroys this module.
*/
virtual ~WMBuildingsDetectionByPCA();
/**
* 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;
/**
* Target triangle mesh to display isotropic threshold in voxels.
*/
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,
/**
* Minimal isotropic range for the display. This threshold is displayed using the
* blue color.
*/
WPropDouble m_showedIsotropicThresholdMin;
/**
* Maximal isotropic range for the display. This threshold is displayed using the
* red color.
*/
WPropDouble m_showedIsotropicThresholdMax;
/**
* Maximal isotropic level for drawing voxels. More exactly said: Smallest point
* distribution direction strength divided by the biggest one (Smallest Eigen Value
* divided by the biggest one).
*/
WPropDouble m_maximalEigenValueQuotientToDraw;
/**
* Minimal point amount per voxel to draw. Voxels below that amount aren't drawn.
*/
WPropInt m_minPointsPerVoxelToDraw;
/**
* Plugin progress status.
*/
boost::shared_ptr< WProgress > m_progressStatus;
};
#endif // WMBUILDINGSDETECTIONBYPCA_H
/* XPM */
static const char * WMBuildingsDetectionByPCA_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 "WPCADetector.h"
WPCADetector::WPCADetector( WOctree* analyzableOctree, boost::shared_ptr< WProgress > progressStatus )
{
m_analyzableOctree = analyzableOctree;
m_progressStatus = progressStatus;
}
WPCADetector::~WPCADetector()
{
}
void WPCADetector::setDisplayedVarianceQuotientRange( double showedIsotropicThresholdMin, double showedIsotropicThresholdMax )
{
m_showedisotropicThresholdMin = showedIsotropicThresholdMin;
m_showedisotropicThresholdMax = showedIsotropicThresholdMax;
}
void WPCADetector::setMaximalEigenValueQuotientToDraw( double maximalEigenValueQuotientToDraw )
{
m_maximalEigenValueQuotientToDraw = maximalEigenValueQuotientToDraw;
}
void WPCADetector::setMinPointsPerVoxelToDraw( size_t minPointsPerVoxelToDraw )
{
m_minPointsPerVoxelToDraw = minPointsPerVoxelToDraw;
}
void WPCADetector::analyze()
{
cout << "Total nodes in set: " << m_analyzableOctree->getRootNode()->getTotalNodeCount();
analyzeNode( ( WPcaDetectOctNode* )( m_analyzableOctree->getRootNode() ) );
}
void WPCADetector::analyzeNode( WPcaDetectOctNode* node )
{
m_progressStatus->increment( 1 );
if ( node->getRadius() <= m_analyzableOctree->getDetailLevel() )
{
if(node->getPointCount() >= 3 )
{
WPrincipalComponentAnalysis pca;
pca.analyzeData( node->getInputPoints() );
vector<double> variance = pca.getEigenValues();
if( variance[0] > 0.0 )
node->setEigenValueQuotient( variance[2] / variance[0] );
}
}
else
{
for ( int child = 0; child < 8; child++ )
if ( node->getChild( child ) != 0 )
analyzeNode( ( WPcaDetectOctNode* )( node->getChild( child ) ) );
}
}
boost::shared_ptr< WTriangleMesh > WPCADetector::getOutline()
{
boost::shared_ptr< WTriangleMesh > tmpMesh( new WTriangleMesh( 0, 0 ) );
drawNode( ( WPcaDetectOctNode* )( m_analyzableOctree->getRootNode() ), tmpMesh );
return tmpMesh;
}
void WPCADetector::drawNode( WPcaDetectOctNode* node, boost::shared_ptr< WTriangleMesh > outputMesh )
{
if ( node->getRadius() <= m_analyzableOctree->getDetailLevel() )
{
if( node->getEigenValueQuotient() > m_maximalEigenValueQuotientToDraw )
return;
if( node->getPointCount() < m_minPointsPerVoxelToDraw )
return;
drawLeafNode( node, outputMesh );
}
else
{
for ( int child = 0; child < 8; child++ )
if ( node->getChild( child ) != 0 )
drawNode( ( WPcaDetectOctNode* )(node->getChild( child ) ), outputMesh );
}
}
void WPCADetector::drawLeafNode( WPcaDetectOctNode* node, boost::shared_ptr< WTriangleMesh > outputMesh )
{
size_t index = outputMesh->vertSize();
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, calculateColorForNode( node ) );
}
// 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 );
}
osg::Vec4 WPCADetector::calculateColorForNode( WPcaDetectOctNode* node )
{
if( node-&g