Commit df86ea5c authored by aschwarzkopf's avatar aschwarzkopf

[ADD #361] Added feature to delete small connected voxel groups

 * The algorithm is intended to grouup voxels that have surfaces with the same
 * normal vector. This feature helps to remove small groups. Obviously trees
 * by nature have points that lead the Principal Component Analysis to
 * surfaces that have very different Eigen Vectors of the smallest Eigen Value
 * that is the normal vector in the case of surfaces.
 *
 * Other feature: Removing voxels by a point count per voxel.
parent 7180d123
......@@ -111,6 +111,14 @@ void WMWallDetectionByPCA::properties()
m_showedVarianceQuotientMax->setMin( 0.0 );
m_showedVarianceQuotientMax->setMax( 1.0 );
m_minimalGroupSize = m_properties->addProperty( "Min. group size to draw: ",
"Groups below that node count aren't drawn.", 1 );
m_showedVarianceQuotientMax->setMin( 1 );
m_minimalPointsPerVoxel = m_properties->addProperty( "Min. points per voxel to draw: ",
"The minimal points per voxel that enables an area to draw.", 1 );
m_showedVarianceQuotientMax->setMin( 1 );
WModule::properties();
}
......@@ -165,8 +173,11 @@ void WMWallDetectionByPCA::moduleMain()
pcaAnalysis->setMaxIsotropicThresholdForVoxelMerge( m_showedVarianceQuotientMax->get() );
WPCAWallDetector detector( pcaAnalysis, m_progressStatus );
detector.setMinimalGroupSize( m_minimalGroupSize->get() );
detector.setMinimalPointsPerVoxel( m_minimalPointsPerVoxel->get() );
detector.analyze();
pcaAnalysis->groupNeighbourLeafsFromRoot();
pcaAnalysis->generateNodeCountsOfGroups();
m_outputTrimesh->updateData( detector.getOutline() );
m_progressStatus->finish();
......
......@@ -184,6 +184,16 @@ private:
* strength divided by the strongest. Nodes above that quotient aren't grouped.
*/
WPropDouble m_showedVarianceQuotientMax;
/**
* The minimal group size of nodes or its surface parts that makes voxels be drawn.
* Especially parts of buildings have bigger connected parts than e. g. trees.
*/
WPropInt m_minimalGroupSize;
/**
* Minimal allowed point count per voxel. Very small pixel counts don't make sense
* for the Principal Component Analysis.
*/
WPropInt m_minimalPointsPerVoxel;
/**
* Plugin progress status.
......
......@@ -34,6 +34,8 @@ WPCAWallDetector::WPCAWallDetector( WWallDetectOctree* analyzableOctree, boost::
WPCAWallDetector::~WPCAWallDetector()
{
m_minimalGroupSize = 1;
m_minimalPointsPerVoxel = 1;
}
void WPCAWallDetector::analyze()
{
......@@ -71,42 +73,15 @@ boost::shared_ptr< WTriangleMesh > WPCAWallDetector::getOutline()
void WPCAWallDetector::drawNode( WWallDetectOctNode* node, boost::shared_ptr< WTriangleMesh > outputMesh )
{
if ( node->getRadius() <= m_analyzableOctree->getDetailLevel() )
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 );
size_t groupSize = m_analyzableOctree->getNodeCountOfGroup( node->getGroupNr() );
if( groupSize < m_minimalGroupSize )
return;
if( node->getPointCount() < m_minimalPointsPerVoxel )
return;
drawLeavNode( node, outputMesh );
}
else
{
......@@ -115,3 +90,48 @@ void WPCAWallDetector::drawNode( WWallDetectOctNode* node, boost::shared_ptr< WT
drawNode( ( WWallDetectOctNode* )(node->getChild( child ) ), outputMesh );
}
}
void WPCAWallDetector::drawLeavNode( WWallDetectOctNode* node, boost::shared_ptr< WTriangleMesh > outputMesh )
{
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 );
}
void WPCAWallDetector::setMinimalGroupSize( double minimalGroupSize )
{
m_minimalGroupSize = minimalGroupSize;
}
void WPCAWallDetector::setMinimalPointsPerVoxel( double minimalPointsPerVoxel )
{
m_minimalPointsPerVoxel = minimalPointsPerVoxel;
}
......@@ -74,8 +74,26 @@ public:
* \param outputMesh Target triangle mesh.
*/
void drawNode( WWallDetectOctNode* node, boost::shared_ptr< WTriangleMesh > outputMesh );
/**
* Sets the minimal group size of nodes or its surface parts that makes voxels be
* drawn.Especially parts of buildings have bigger connected parts than e. g. trees.
* \param minimalGroupSize The minimal connected node count to put out.
*/
void setMinimalGroupSize( double minimalGroupSize );
/**
* Sets the minimal allowed point count per voxel. Very small pixel counts don't
* make sense for the Principal Component Analysis.
* \param minimalPointsPerVoxel The minimal point count per voxel to put them out.
*/
void setMinimalPointsPerVoxel( double minimalPointsPerVoxel );
private:
/**
* Draws a leaf node as a voxel on the output triangle mesh.
* \param node Leaf node to draw.
* \param outputMesh The output triangle mesh to draw a voxel.
*/
void drawLeavNode( WWallDetectOctNode* node, boost::shared_ptr< WTriangleMesh > outputMesh );
/**
* Input point data to be analyzed organized by voxels.
*/
......@@ -84,6 +102,16 @@ private:
* The assigned progress status.
*/
boost::shared_ptr< WProgress > m_progressStatus;
/**
* The minimal group size of nodes or its surface parts that makes voxels be drawn.
* Especially parts of buildings have bigger connected parts than e. g. trees.
*/
double m_minimalGroupSize;
/**
* Minimal allowed point count per voxel. Very small pixel counts don't make sense
* for the Principal Component Analysis.
*/
double m_minimalPointsPerVoxel;
};
#endif // WPCAWALLDETECTOR_H
......@@ -94,3 +94,34 @@ double WWallDetectOctree::getAngleOfTwoVectors( WVector3d vector1, WVector3d vec
return acos( sum ) * 90.0 / ANGLE_90_DEGREES;
}
const double WWallDetectOctree::ANGLE_90_DEGREES = asin( 1.0 );
size_t WWallDetectOctree::getNodeCountOfGroup( size_t groupNr )
{
if(groupNr >= m_nodeCountsOfGroups.size() )
return 0;
return m_nodeCountsOfGroups[groupNr];
}
void WWallDetectOctree::generateNodeCountsOfGroups()
{
m_nodeCountsOfGroups.reserve( 0 );
m_nodeCountsOfGroups.resize( 0 );
addGroupCountsFromNode( ( WWallDetectOctNode* )getRootNode() );
}
void WWallDetectOctree::addGroupCountsFromNode( WWallDetectOctNode* node )
{
if ( node->getRadius() <= getDetailLevel() )
{
if( node->hasGroup() == false )
return;
size_t groupNr = node->getGroupNr();
while( m_nodeCountsOfGroups.size() <= groupNr )
m_nodeCountsOfGroups.push_back( 0 );
m_nodeCountsOfGroups[groupNr]++;
}
else
{
for ( int child = 0; child < 8; child++ )
if ( node->getChild( child ) != 0 )
addGroupCountsFromNode( ( WWallDetectOctNode* )( node->getChild( child ) ) );
}
}
......@@ -76,6 +76,16 @@ public:
* \return Angle of the two vectors using the decree scale.
*/
static double getAngleOfTwoVectors( WVector3d vector1, WVector3d vector2 );
/**
* Returns how many nodes a group ID has.
* \param groupNr The group ID.
* \return Leaf node count of that croup.
*/
size_t getNodeCountOfGroup( size_t groupNr );
/**
* Counts The number of leaf nodes for each group.
*/
void generateNodeCountsOfGroups();
/**
* Radial amount of 90 degrees.
*/
......@@ -91,6 +101,12 @@ protected:
virtual vector<WOctNode*> getNeighborsOfNode( WOctNode* node );
private:
/**
* Adds a node and its children to the node counts for groups.
* \param node Node to analyze.
*/
void addGroupCountsFromNode( WWallDetectOctNode* node );
/**
* The maximal allowed angle between two node surface normal vectors. Nodes above
* that angle difference aren't grouped.
......@@ -101,6 +117,10 @@ private:
* strength divided by the strongest. Nodes above that quotient aren't grouped.
*/
double m_maxIsotropicThresholdForVoxelMerge;
/**
* Node counts for each connected group.
*/
vector<size_t> m_nodeCountsOfGroups;
};
#endif // WWALLDETECTOCTREE_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment