OpenWalnut  1.5.0dev
WMVoxelizer.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <algorithm>
26 #include <iomanip>
27 #include <list>
28 #include <memory>
29 #include <string>
30 #include <utility>
31 #include <vector>
32 
33 #include <osg/Depth>
34 #include <osg/Geode>
35 #include <osg/Geometry>
36 
37 #include "WBresenham.h"
38 #include "WBresenhamDBL.h"
39 #include "WCenterlineParameterization.h"
40 #include "WIntegrationParameterization.h"
41 #include "WMVoxelizer.h"
42 #include "WRasterAlgorithm.h"
43 #include "core/common/WColor.h"
44 #include "core/common/WLogger.h"
45 #include "core/common/WPropertyHelper.h"
46 #include "core/common/datastructures/WFiber.h"
47 #include "core/dataHandler/WDataSetFiberVector.h"
48 #include "core/dataHandler/WDataSetScalar.h"
49 #include "core/dataHandler/WGridTransformOrtho.h"
50 #include "core/dataHandler/WSubject.h"
51 #include "core/dataHandler/datastructures/WFiberCluster.h"
52 #include "core/graphicsEngine/WGEColormapping.h"
53 #include "core/graphicsEngine/WGEGeodeUtils.h"
54 #include "core/graphicsEngine/WGEGeometryUtils.h"
55 #include "core/graphicsEngine/WGEManagedGroupNode.h"
56 #include "core/graphicsEngine/WGEUtils.h"
57 #include "core/graphicsEngine/postprocessing/WGEPostprocessingNode.h"
58 #include "core/graphicsEngine/shaders/WGEPropertyUniform.h"
59 #include "core/graphicsEngine/shaders/WGEShaderDefineOptions.h"
60 #include "core/graphicsEngine/shaders/WGEShaderPropertyDefine.h"
61 #include "core/graphicsEngine/shaders/WGEShaderPropertyDefineOptions.h"
62 #include "core/kernel/WKernel.h"
63 #include "core/kernel/WModuleInputData.h"
64 
65 // This line is needed by the module loader to actually find your module.
66 W_LOADABLE_MODULE( WMVoxelizer )
67 
69  : WModule(),
70  m_fullUpdate( new WCondition() )
71 {
72 }
73 
75 {
76 }
77 
78 std::shared_ptr< WModule > WMVoxelizer::factory() const
79 {
80  return std::shared_ptr< WModule >( new WMVoxelizer() );
81 }
82 
84 {
85  m_antialiased = m_properties->addProperty( "Antialiasing", "Enable/disable antialiased rasterization of voxels.", true, m_fullUpdate );
86  m_voxelsPerUnit = m_properties->addProperty( "Voxels per Unit", "Specified the number of voxels per unit in the coordinate system. This "
87  "is useful to increase the resolution of the grid", 1.0, m_fullUpdate );
88 
89  m_renderingActive = m_properties->addProperty( "Rendering", "Enable/disable rendering of voxels.", false, m_fullUpdate );
90 
91  // for selecting the parameterization method
92  m_paramAlgoSelections = std::shared_ptr< WItemSelection >( new WItemSelection() );
93  m_paramAlgoSelections->addItem( "No Parameterization", "Disable parameterization." ); // NOTE: you can add XPM images here.
94  m_paramAlgoSelections->addItem( "By Longest Line", "Use the longest line and parameterize the bundle along it." );
95  m_paramAlgoSelections->addItem( "By Centerline", "Use the centerline and parameterize the bundle along it." );
96  m_paramAlgoSelections->addItem( "By Integration", "Integrate along the voxelized line." );
97  m_parameterAlgo = m_properties->addProperty( "Parameterization", "Select the parameterization algorithm.",
98  m_paramAlgoSelections->getSelectorFirst(), m_fullUpdate );
101 
102  // for selecting the rasterization method
103  std::shared_ptr< WItemSelection > rasterAlgos( new WItemSelection() );
104  rasterAlgos->addItem( "Bresenham", "Voxelization with 3D Bresenham" );
105  m_rasterAlgo = m_properties->addProperty( "Rasterization", "Which method for rasterizing the tracts", rasterAlgos->getSelectorFirst(),
106  m_fullUpdate );
109 
110  m_phongShading = m_properties->addProperty( "Phong shading", "If enabled, Phong shading gets applied on a per-pixel basis.", true );
111  m_colorMapping = m_properties->addProperty( "Colormapping", "If enabled, colormapping gets applied on a per-pixel basis.", false );
112 
114 }
115 
117 {
118  m_tractIC = WModuleInputData< const WDataSetFibers >::createAndAdd( shared_from_this(), "tractInput", "Deterministic tracts" );
119  m_clusterIC = WModuleInputData< const WFiberCluster >::createAndAdd( shared_from_this(), "clusterInput", "A subset (e.g. a cluster) of tracts" );
120  m_voxelizedOC = WModuleOutputData< WDataSetScalar >::createAndAdd( shared_from_this(), "voxelOutput", "The voxelized data set" );
121  m_paramOC = WModuleOutputData< WDataSetScalar >::createAndAdd( shared_from_this(), "parameterizationOutput",
122  "The parameter field for the voxelized fibers." );
123  WModule::connectors(); // call WModules initialization
124 }
125 
127 {
129  m_moduleState.add( m_tractIC->getDataChangedCondition() );
130  m_moduleState.add( m_clusterIC->getDataChangedCondition() );
132 
133  // create the post-processing node which actually does the nice stuff to the rendered image
134  osg::ref_ptr< WGEPostprocessingNode > postNode = new WGEPostprocessingNode(
135  WKernel::getRunningKernel()->getGraphicsEngine()->getViewer()->getCamera()
136  );
137  // provide the properties of the post-processor to the user
138  m_properties->addProperty( postNode->getProperties() );
139 
140  // create the root node containing everything
142 
143  // create sheader
144  osg::ref_ptr< WGEShader > shader( new WGEShader( "WMVoxelizer", m_localPath ) );
145  shader->addPreprocessor( WGEShaderPreprocessor::SPtr(
146  new WGEShaderPropertyDefineOptions< WPropBool >( m_phongShading, "PHONGSHADING_DISABLED", "PHONGSHADING_ENABLED" ) )
147  );
148  shader->addPreprocessor( WGEShaderPreprocessor::SPtr(
149  new WGEShaderPropertyDefineOptions< WPropBool >( m_colorMapping, "COLORMAPPING_DISABLED", "COLORMAPPING_ENABLED" ) )
150  );
151 
152  // apply colormapping
154 
155  // add it to postproc node and register shader
156  postNode->insert( m_rootNode, shader );
157 
158  // add to scene
159  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( postNode );
160 
161  ready();
162 
163  while( !m_shutdownFlag() ) // loop until the module container requests the module to quit
164  {
165  bool selectionPresent = ( m_clusterIC->getData() != NULL );
166 
167  if( !m_tractIC->getData() )
168  {
169  continue;
170  }
171 
172  size_t numTracts = ( selectionPresent ? m_clusterIC->getData()->size() : m_tractIC->getData()->size() );
173 
174  infoLog() << "Start voxelization with: " << numTracts << " tracts";
175 
176  boost::array< std::shared_ptr< WDataSetScalar >, 2 > result = generateDatasets( m_tractIC->getData(), m_clusterIC->getData() );
177 
178  if( !result.empty() )
179  {
180  m_voxelizedOC->updateData( result[0] );
181  if( result.size() == 2 ) // parameterized dataset available
182  {
183  m_paramOC->updateData( result[1] );
184  }
185 
186  m_rootNode->clear();
187  if( m_renderingActive->get() )
188  {
189  m_rootNode->insert( genDataSetGeode( result[0] ) );
190  }
191  }
192 
193  infoLog() << "Finished.";
194 
195  m_moduleState.wait(); // waits for firing of m_moduleState ( dataChanged, shutdown, etc. )
196  }
197 
198  // clean up scene
199  m_rootNode->clear();
200  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( postNode );
201 }
202 
203 std::shared_ptr< WGridRegular3D > WMVoxelizer::constructGrid( std::shared_ptr< const WDataSetFibers > tracts,
204  std::shared_ptr< const WFiberCluster > cluster ) const
205 {
206  WBoundingBox bb;
207  if( cluster )
208  {
209  bb = cluster->getBoundingBox();
210  }
211  else
212  {
213  bb = tracts->getBoundingBox();
214  }
215 
216  float nbVoxelsPerUnit = m_voxelsPerUnit->get( true );
217 
218  // TODO(math): remove hardcoded meta grid here.
219  // the "+1" in the following three statements is because there may be some more voxels
220  // The first and last voxel are only half sized! hence one more position is needed
221  size_t nbPosX = std::ceil( bb.xMax() - bb.xMin() ) + 1;
222  size_t nbPosY = std::ceil( bb.yMax() - bb.yMin() ) + 1;
223  size_t nbPosZ = std::ceil( bb.zMax() - bb.zMin() ) + 1;
224 
225  WMatrix< double > mat( 4, 4 );
226  mat.makeIdentity();
227  mat( 0, 0 ) = mat( 1, 1 ) = mat( 2, 2 ) = 1.0 / nbVoxelsPerUnit;
228  mat( 0, 3 ) = bb.getMin()[ 0 ];
229  mat( 1, 3 ) = bb.getMin()[ 1 ];
230  mat( 2, 3 ) = bb.getMin()[ 2 ];
231 
232  WGridTransformOrtho transform( mat );
233 
234  std::shared_ptr< WGridRegular3D > grid( new WGridRegular3D( nbVoxelsPerUnit * nbPosX,
235  nbVoxelsPerUnit * nbPosY,
236  nbVoxelsPerUnit * nbPosZ,
237  transform ) );
238  debugLog() << "Created grid of size: " << grid->size();
239  return grid;
240 }
241 
242 boost::array< std::shared_ptr< WDataSetScalar >, 2 > WMVoxelizer::generateDatasets(
243  std::shared_ptr< const WDataSetFibers > tracts,
244  std::shared_ptr< const WFiberCluster > cluster ) const
245 {
246  boost::array< std::shared_ptr< WDataSetScalar >, 2 > result; // unusable instances
247 
248  if( !tracts ) // mean while input connector has changed => abort
249  {
250  return result;
251  }
252 
253  std::shared_ptr< WGridRegular3D > grid = constructGrid( tracts, cluster );
254 
255  std::shared_ptr< WRasterAlgorithm > rasterAlgo;
256  std::string rasterName = m_rasterAlgo->get().at( 0 )->getName();
257  if( rasterName == "Bresenham" )
258  {
259  rasterAlgo = std::shared_ptr< WBresenham >( new WBresenham( grid, m_antialiased->get() ) );
260  }
261  else
262  {
263  errorLog() << "Invalid rasterization algorithm selected: " << rasterName << " aborting.";
264  return result;
265  }
266 
267  // decide which param algo to use:
268  std::shared_ptr< WRasterParameterization > paramAlgo;
269  std::string paramName = m_parameterAlgo->get( true ).at( 0 )->getName();
270  if( paramName == "By Longest Line" )
271  {
272  paramAlgo = std::shared_ptr< WRasterParameterization >( new WCenterlineParameterization( grid, longestLine( tracts, cluster ) ) );
273  }
274  else if( paramName == "By Centerline" )
275  {
276  paramAlgo = std::shared_ptr< WRasterParameterization >( new WCenterlineParameterization( grid, centerLine( tracts, cluster ) ) );
277  }
278  else if( paramName == "By Integration" )
279  {
280  paramAlgo = std::shared_ptr< WRasterParameterization >( new WIntegrationParameterization( grid ) );
281  }
282  debugLog() << paramName << " as parameterization method selected.";
283 
284  if( paramAlgo )
285  {
286  rasterAlgo->addParameterizationAlgorithm( paramAlgo );
287  }
288 
289  raster( rasterAlgo, tracts, cluster );
290 
291  result[0] = rasterAlgo->generateDataSet();
292 
293  if( paramAlgo )
294  {
295  result[1] = paramAlgo->getDataSet();
296  }
297 
298  return result;
299 }
300 
301 std::shared_ptr< WFiber > WMVoxelizer::longestLine( std::shared_ptr< const WDataSetFibers > tracts,
302  std::shared_ptr< const WFiberCluster > cluster ) const
303 {
304  if( cluster )
305  {
306  return cluster->getLongestLine();
307  }
308  return longestLine( tracts );
309 }
310 
311 std::shared_ptr< WFiber > WMVoxelizer::centerLine( std::shared_ptr< const WDataSetFibers > tracts,
312  std::shared_ptr< const WFiberCluster > cluster ) const
313 {
314  if( cluster )
315  {
316  return cluster->getCenterLine();
317  }
318  return centerLine( tracts );
319 }
320 
321 void WMVoxelizer::raster( std::shared_ptr< WRasterAlgorithm > algo, std::shared_ptr< const WDataSetFibers > tracts,
322  std::shared_ptr< const WFiberCluster > cluster ) const
323 {
324  // for each tract apply a call to algo->raster( tract );
325 
326  if( cluster )
327  {
328  std::shared_ptr< const WDataSetFiberVector > clusterTracts = cluster->getDataSetReference();
329  const std::list< size_t >& tractIDs = cluster->getIndices();
330  std::list< size_t >::const_iterator cit = tractIDs.begin();
331  for( cit = tractIDs.begin(); cit != tractIDs.end(); ++cit )
332  {
333  algo->raster( clusterTracts->at( *cit ) );
334  }
335  }
336  else
337  {
338  std::shared_ptr< WDataSetFiberVector > allTracts( new WDataSetFiberVector( tracts ) );
339  for( WDataSetFiberVector::const_iterator cit = allTracts->begin(); cit != allTracts->end(); ++cit )
340  {
341  algo->raster( *cit );
342  }
343  }
344 
345  algo->finished();
346 }
347 
348 osg::ref_ptr< osg::Node > WMVoxelizer::genDataSetGeode( std::shared_ptr< WDataSetScalar > dataset ) const
349 {
350  // set the scaling of the dataset. We assume a unit cube per voxel. But this might not be true:
351  WGridRegular3D::SPtr grid = std::dynamic_pointer_cast< WGridRegular3D >( dataset->getGrid() );
352  if( !grid )
353  {
354  errorLog() << "The dataset grid is not regular.";
355  return new osg::Node; // empty node
356  }
357  WPosition size( grid->getOffsetX(), grid->getOffsetY(), grid->getOffsetZ() );
358 
359  // add cubes to this geode
360  osg::ref_ptr< osg::Geode > geode( new osg::Geode );
361 
362  std::shared_ptr< WValueSet< double > > valueset = std::dynamic_pointer_cast< WValueSet< double > >( dataset->getValueSet() );
363  if( !valueset )
364  {
365  errorLog() << "The dataset does not contain a double valueset";
366  return new osg::Node; // empty node
367  }
368 
369  // create geometry for each voxel
370  osg::ref_ptr< osg::Geometry > geometry = osg::ref_ptr< osg::Geometry >( new osg::Geometry );
371  const std::vector< double >& values = *valueset->rawDataVectorPointer();
372  for( size_t i = 0; i < values.size(); ++i )
373  {
374  if( values[i] != 0.0 )
375  {
376  // collect data
377  WPosition pos = grid->getPosition( i );
378  double transparency = ( values[i] <= 1.0 ? values[i] : 1.0 );
379  WColor color( 1.0, 0.0, 0.0, transparency );
380 
381  // build cube
382  wge::createCube( geometry, pos, size, color );
383  }
384  }
385 
386  // done
387  geode->addDrawable( geometry );
388  return geode;
389 }
const vec_type & getMin() const
Gives the front lower left aka minimum corner.
Definition: WBoundingBox.h:302
Implements basic Bresenham algorithm for rasterization.
Definition: WBresenham.h:43
Stores the direction if a line in a separate dataset for each voxel.
virtual void wait() const
Wait for the condition.
void setResetable(bool resetable=true, bool autoReset=true)
Sets the resetable flag.
virtual void add(std::shared_ptr< WCondition > condition)
Adds another condition to the set of conditions to wait for.
Class to encapsulate boost::condition_variable_any.
Definition: WCondition.h:42
Represents a simple set of WFibers.
static void apply(osg::ref_ptr< osg::Node > node, WMatrix4d preTransform=WMatrix4d::identity(), osg::ref_ptr< WGEShader > shader=osg::ref_ptr< WGEShader >(), size_t startTexUnit=0)
Apply the colormapping to the specified node.
This class adds some convenience methods to WGEGroupNode.
This class enables you to add arbitrary nodes that get post-processed in screen space.
std::shared_ptr< WGEShaderPreprocessor > SPtr
Shared pointer for this class.
This is a WGEShaderDefineOptions class which additionally uses a property to automatically control th...
Class encapsulating the OSG Program class for a more convenient way of adding and modifying shader.
Definition: WGEShader.h:48
A grid that has parallelepiped cells which all have the same proportion.
std::shared_ptr< WGridRegular3DTemplate > SPtr
Convenience typedef for a std::shared_ptr< WGridRegular3DTemplate >.
Implements an orthogonal grid transformation.
Stores the direction if a line in a separate dataset for each voxel.
A class containing a list of named items.
static WKernel * getRunningKernel()
Returns pointer to the currently running kernel.
Definition: WKernel.cpp:117
std::shared_ptr< WGraphicsEngine > getGraphicsEngine() const
Returns pointer to currently running instance of graphics engine.
Definition: WKernel.cpp:122
Traces a given set of deterministic tracts as given by a dataset of deterministic tracts (optionally ...
Definition: WMVoxelizer.h:51
virtual std::shared_ptr< WModule > factory() const
Due to the prototype design pattern used to build modules, this method returns a new instance of this...
Definition: WMVoxelizer.cpp:78
WPropBool m_antialiased
Enable/disable anti-aliased rasterization of voxels.
Definition: WMVoxelizer.h:233
WPropBool m_colorMapping
add colormapping
Definition: WMVoxelizer.h:261
WMVoxelizer()
Default Constructor.
Definition: WMVoxelizer.cpp:68
WPropDouble m_voxelsPerUnit
The number of voxels per unit in the coordinate system.
Definition: WMVoxelizer.h:246
WPropBool m_phongShading
Add lighting to the scene.
Definition: WMVoxelizer.h:266
WPropSelection m_rasterAlgo
List for selecting the rasterization method.
Definition: WMVoxelizer.h:241
void raster(std::shared_ptr< WRasterAlgorithm > algo, std::shared_ptr< const WDataSetFibers > tracts, std::shared_ptr< const WFiberCluster > cluster) const
Performs rasterization with the given algorithm on either all tracts or only a subset if given.
std::shared_ptr< WModuleInputData< const WFiberCluster > > m_clusterIC
Input connector for an optional selection of some fibers in the fiber dataset via a cluster.
Definition: WMVoxelizer.h:205
WPropSelection m_parameterAlgo
The actually selected parameterization algorithm.
Definition: WMVoxelizer.h:256
std::shared_ptr< WFiber > longestLine(std::shared_ptr< const WDataSetFibers > tracts, std::shared_ptr< const WFiberCluster > cluster=std::shared_ptr< const WFiberCluster >()) const
Finds and returns a copy of the longest line (in term of #points) in the dataset, or in a subset of i...
std::shared_ptr< WModuleOutputData< WDataSetScalar > > m_paramOC
Output providing parameterization to other algorithms.
Definition: WMVoxelizer.h:216
std::shared_ptr< WGridRegular3D > constructGrid(std::shared_ptr< const WDataSetFibers > tracts, std::shared_ptr< const WFiberCluster > cluster) const
Constructs a grid out of the current tract dataset or out of a subset (selection) of this dataset.
osg::ref_ptr< WGEManagedGroupNode > m_rootNode
OSG root node for this module.
Definition: WMVoxelizer.h:226
std::shared_ptr< WItemSelection > m_paramAlgoSelections
The available parameterization algorithms.
Definition: WMVoxelizer.h:251
osg::ref_ptr< osg::Node > genDataSetGeode(std::shared_ptr< WDataSetScalar > dataset) const
Builds an OSG geode where all voxels inside the dataSet which are not zero are drawn as cuboids.
std::shared_ptr< WModuleOutputData< WDataSetScalar > > m_voxelizedOC
Output connector for a voxelized cluster.
Definition: WMVoxelizer.h:210
WPropBool m_renderingActive
Enable/disable rendering of voxels.
Definition: WMVoxelizer.h:234
virtual ~WMVoxelizer()
Default Destructor.
Definition: WMVoxelizer.cpp:74
virtual void properties()
Initialize the properties for this module.
Definition: WMVoxelizer.cpp:83
std::shared_ptr< WCondition > m_fullUpdate
module is performing an expensive update
Definition: WMVoxelizer.h:231
virtual void connectors()
Initialize the connectors this module is using.
virtual void moduleMain()
Entry point after loading the module.
std::shared_ptr< WFiber > centerLine(std::shared_ptr< const WDataSetFibers > tracts, std::shared_ptr< const WFiberCluster > cluster=std::shared_ptr< const WFiberCluster >()) const
Finds and returns a copy of the center line in the dataset, or in a subset of it specified by the giv...
boost::array< std::shared_ptr< WDataSetScalar >, 2 > generateDatasets(std::shared_ptr< const WDataSetFibers > tracts, std::shared_ptr< const WFiberCluster > cluster) const
Generates a intensity dataset where each tract is rasterized into.
std::shared_ptr< WModuleInputData< const WDataSetFibers > > m_tractIC
Input connector for a fiber dataset.
Definition: WMVoxelizer.h:200
WMatrix & makeIdentity()
Makes the matrix contain the identity matrix, i.e.
Definition: WMatrix.h:352
vector_type::const_iterator const_iterator
Compares to std::vector type.
Definition: WMixinVector.h:87
static PtrType createAndAdd(std::shared_ptr< WModule > module, std::string name="", std::string description="")
Convenience method to create a new instance of this in data connector with proper type and add it to ...
static PtrType createAndAdd(std::shared_ptr< WModule > module, std::string name="", std::string description="")
Convenience method to create a new instance of this out data connector with proper type and add it to...
Class representing a single module of OpenWalnut.
Definition: WModule.h:72
boost::filesystem::path m_localPath
The path where the module binary resides in.
Definition: WModule.h:734
virtual void properties()
Initialize properties in this function.
Definition: WModule.cpp:212
wlog::WStreamedLogger debugLog() const
Logger instance for comfortable debug logging.
Definition: WModule.cpp:575
std::shared_ptr< WProperties > m_properties
The property object for the module.
Definition: WModule.h:640
void ready()
Call this whenever your module is ready and can react on property changes.
Definition: WModule.cpp:505
WConditionSet m_moduleState
The internal state of the module.
Definition: WModule.h:703
wlog::WStreamedLogger errorLog() const
Logger instance for comfortable error logging.
Definition: WModule.cpp:570
WPropBool m_active
True whenever the module should be active.
Definition: WModule.h:723
wlog::WStreamedLogger infoLog() const
Logger instance for comfortable info logging.
Definition: WModule.cpp:565
virtual void connectors()
Initialize connectors in this function.
Definition: WModule.cpp:208
This only is a 3d double vector.
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
void addTo(WPropSelection prop)
Add the PC_NOTEMPTY constraint to the property.
void addTo(WPropSelection prop)
Add the PC_SELECTONLYONE constraint to the property.
void createCube(osg::ref_ptr< osg::Geometry > geometry, const WPosition &position, const WPosition &size, const WColor &color)
Create an arbitrary cube and insert it into the given geometry.