OpenWalnut  1.5.0dev
WMDeterministicFTMori.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 <memory>
26 #include <sstream>
27 #include <string>
28 #include <vector>
29 
30 #include "WMDeterministicFTMori.h"
31 #include "WMDeterministicFTMori.xpm"
32 #include "core/common/WAssert.h"
33 #include "core/common/math/WLinearAlgebraFunctions.h"
34 #include "core/common/math/WTensorFunctions.h"
35 #include "core/common/math/WTensorSym.h"
36 #include "core/dataHandler/WDataSetFiberVector.h"
37 #include "core/dataHandler/WDataSetSingle.h"
38 #include "core/dataHandler/WGridRegular3D.h"
39 #include "core/dataHandler/WValueSet.h"
40 #include "core/dataHandler/io/WWriterFiberVTK.h"
41 #include "core/kernel/WModuleInputData.h"
42 #include "core/kernel/WModuleOutputData.h"
43 
44 // This line is needed by the module loader to actually find your module.
45 W_LOADABLE_MODULE( WMDeterministicFTMori )
46 
48  : WModule(),
49  m_dataSet(),
50  m_fiberSet(),
51  m_eigenField(),
52  m_eigenOperationFloat(),
53  m_eigenOperationDouble(),
54  m_eigenPool()
55 {
56 }
57 
59 {
60 }
61 
62 std::shared_ptr< WModule > WMDeterministicFTMori::factory() const
63 {
64  return std::shared_ptr< WModule >( new WMDeterministicFTMori() );
65 }
66 
68 {
69  return moriTracking_xpm;
70 }
71 
72 const std::string WMDeterministicFTMori::getName() const
73 {
74  return "Mori Det. Tracking";
75 }
76 
77 const std::string WMDeterministicFTMori::getDescription() const
78 {
79  return "Implements the simple deterministic fibertracking algorithm by Mori et al.";
80 }
81 
83 {
84  m_moduleState.setResetable( true, true );
85  m_moduleState.add( m_input->getDataChangedCondition() );
87 
88  ready();
89 
90  while( !m_shutdownFlag() )
91  {
92  debugLog() << "Waiting.";
94  if( m_shutdownFlag() )
95  {
96  break;
97  }
98 
99  if( m_trackingPool && m_trackingPool->status() == W_THREADS_FINISHED )
100  {
102  m_fiberAccu.clear();
103  m_currentProgress->finish();
104  debugLog() << "Tracking done.";
105  // forward result
106  m_output->updateData( m_fiberSet );
107  m_trackingPool = std::shared_ptr< TrackingFuncType >();
108  }
109 
110  std::shared_ptr< WDataSetSingle > inData = m_input->getData();
111  bool dataChanged = ( m_dataSet != inData );
112  if( dataChanged || !m_dataSet )
113  {
114  m_dataSet = inData;
115  if( !m_dataSet )
116  {
117  continue;
118  }
119  }
120 
121  if( dataChanged && m_dataSet )
122  {
124  // start the eigenvector computation
125  // when the computation finishes, we'll be notified by the threadspool's
126  // threadsDoneCondition
127  resetProgress( m_dataSet->getValueSet()->size() );
128  m_eigenPool->run();
129  debugLog() << "Running computation of eigenvectors.";
130  }
131  else if( m_eigenPool && m_eigenPool->status() == W_THREADS_FINISHED )
132  {
133  // the computation of the eigenvectors has finished
134  // we have a new eigenvectorfield
135  m_currentProgress->finish();
137 
138  if( m_dataSet->getValueSet()->getDataType() == W_DT_DOUBLE )
139  {
140  m_eigenField = m_eigenOperationDouble->getResult();
141  }
142  else
143  {
144  m_eigenField = m_eigenOperationFloat->getResult();
145  }
146 
147  m_eigenPool = std::shared_ptr< WThreadedFunctionBase >();
148  debugLog() << "Eigenvectors computed.";
149 
150  m_currentMinFA = m_minFA->get( true );
151  m_currentMinPoints = static_cast< std::size_t >( m_minPoints->get( true ) );
152  m_currentMinCos = m_minCos->get( true );
153 
154  // perform the actual tracking
155  resetTracking();
156  resetProgress( m_dataSet->getValueSet()->size() );
157  m_trackingPool->run();
158  debugLog() << "Running tracking function.";
159  }
160  else if( !m_eigenPool && ( m_minFA->changed() || m_minPoints->changed() || m_minCos->changed() ) )
161  {
162  m_currentMinFA = m_minFA->get( true );
163  m_currentMinPoints = static_cast< std::size_t >( m_minPoints->get( true ) );
164  m_currentMinCos = m_minCos->get( true );
165 
166  // if there are no new eigenvectors or datasets,
167  // restart the tracking, as there are changes to the parameters
168  resetTracking();
169  std::shared_ptr< WGridRegular3D > g( std::dynamic_pointer_cast< WGridRegular3D >( m_eigenField->getGrid() ) );
170  std::size_t todo = ( g->getNbCoordsX() - 2 ) * ( g->getNbCoordsY() - 2 ) * ( g->getNbCoordsZ() - 2 );
171  resetProgress( todo );
172  m_trackingPool->run();
173  debugLog() << "Running tracking function.";
174  }
175  }
176 
177  // module shutdown
178  debugLog() << "Shutting down module.";
179  if( m_eigenPool )
180  {
181  if( m_eigenPool->status() == W_THREADS_RUNNING || m_eigenPool->status() == W_THREADS_STOP_REQUESTED )
182  {
183  m_eigenPool->stop();
184  m_eigenPool->wait();
185  debugLog() << "Aborting computation of eigenvalues because the module was ordered to shut down.";
186  }
187  }
188  if( m_trackingPool )
189  {
190  if( m_trackingPool->status() == W_THREADS_RUNNING || m_trackingPool->status() == W_THREADS_STOP_REQUESTED )
191  {
192  m_trackingPool->stop();
193  m_trackingPool->wait();
194  debugLog() << "Aborting fiber tracking because the module was ordered to shut down.";
195  }
196  }
197 }
198 
200 {
201  m_output = std::shared_ptr< WModuleOutputData< WDataSetFibers > >( new WModuleOutputData< WDataSetFibers >( shared_from_this(),
202  "det FT Mori output fibers", "A set of fibers extracted from the input set." )
203  );
204 
205  m_input = std::shared_ptr< WModuleInputData< WDataSetSingle > >( new WModuleInputData< WDataSetSingle >( shared_from_this(),
206  "det FT Mori input tensor field", "An input set of 2nd-order tensors on a regular 3d-grid." )
207  );
208 
211 
213 }
214 
216 {
217  m_propCondition = std::shared_ptr< WCondition >( new WCondition() );
218 
219  m_minFA = m_properties->addProperty( "Min. FA", "The fractional anisotropy threshold value needed by "
220  "Mori's fiber tracking algorithm.", 0.2, m_propCondition );
221  m_minFA->setMax( 1.0 );
222  m_minFA->setMin( 0.0 );
223 
224  m_minPoints = m_properties->addProperty( "Min. points", "The minimum number of points per fiber.", 30, m_propCondition );
225  m_minPoints->setMax( 100 );
226  m_minPoints->setMin( 1 );
227 
228  m_minCos = m_properties->addProperty( "Min. cosine", "Minimum cosine of the angle between two"
229  " adjacent fiber segments.", 0.80, m_propCondition );
230  m_minCos->setMax( 1.0 );
231  m_minCos->setMin( 0.0 );
232 
234 }
235 
237 {
239 }
240 
242 {
243  // check if we need to stop the currently running eigencomputation
244  if( m_eigenPool )
245  {
246  debugLog() << "Stopping eigencomputation.";
247  WThreadedFunctionStatus s = m_eigenPool->status();
248  if( s != W_THREADS_FINISHED && s != W_THREADS_ABORTED )
249  {
250  m_eigenPool->stop();
251  m_eigenPool->wait();
252  s = m_eigenPool->status();
253  WAssert( s == W_THREADS_FINISHED || s == W_THREADS_ABORTED, "" );
254  }
255  m_moduleState.remove( m_eigenPool->getThreadsDoneCondition() );
256  }
257  // the threadpool should have finished computing by now
258 
259  m_eigenOperationFloat = std::shared_ptr< TPVOFloat >();
260  m_eigenOperationDouble = std::shared_ptr< TPVODouble >();
261 
262  // create a new one
263  if( m_dataSet->getValueSet()->getDataType() == W_DT_DOUBLE )
264  {
265  m_eigenOperationDouble = std::shared_ptr< TPVODouble >( new TPVODouble( m_dataSet,
266  boost::bind( &WMDeterministicFTMori::eigenFuncDouble, this, boost::placeholders::_1 ) ) );
267  m_eigenPool = std::shared_ptr< WThreadedFunctionBase >( new EigenFunctionTypeDouble( WM_MORI_NUM_CORES, m_eigenOperationDouble ) );
268  m_moduleState.add( m_eigenPool->getThreadsDoneCondition() );
269  }
270  else if( m_dataSet->getValueSet()->getDataType() == W_DT_FLOAT )
271  {
272  m_eigenOperationFloat = std::shared_ptr< TPVOFloat >( new TPVOFloat( m_dataSet,
273  boost::bind( &WMDeterministicFTMori::eigenFuncFloat, this, boost::placeholders::_1 ) ) );
274  m_eigenPool = std::shared_ptr< WThreadedFunctionBase >( new EigenFunctionTypeFloat( WM_MORI_NUM_CORES, m_eigenOperationFloat ) );
275  m_moduleState.add( m_eigenPool->getThreadsDoneCondition() );
276  }
277  else
278  {
279  errorLog() << "Input data does not contain floating point values, skipping.";
280  m_eigenPool = std::shared_ptr< WThreadedFunctionBase >();
281  }
282 }
283 
285 {
286  // check if we need to stop the currently running tracking
287  if( m_trackingPool )
288  {
289  debugLog() << "Stopping tracking.";
290  WThreadedFunctionStatus s = m_trackingPool->status();
291  if( s != W_THREADS_FINISHED && s != W_THREADS_ABORTED )
292  {
293  m_trackingPool->stop();
294  m_trackingPool->wait();
295  s = m_trackingPool->status();
296  WAssert( s == W_THREADS_FINISHED || s == W_THREADS_ABORTED, "" );
297  }
298  m_moduleState.remove( m_trackingPool->getThreadsDoneCondition() );
299  }
300  // the threadpool should have finished computing by now
301 
302  m_fiberAccu.clear();
303 
304  // create a new one
305  std::shared_ptr< Tracking > t( new Tracking( m_eigenField,
306  boost::bind( &This::getEigenDirection, this, boost::placeholders::_1, boost::placeholders::_2 ),
308  boost::placeholders::_1,
309  boost::placeholders::_2,
310  boost::placeholders::_3 ),
311  boost::bind( &This::fiberVis, this, boost::placeholders::_1 ),
312  boost::bind( &This::pointVis, this, boost::placeholders::_1 ) ) );
313  m_trackingPool = std::shared_ptr< TrackingFuncType >( new TrackingFuncType( WM_MORI_NUM_CORES, t ) );
314  m_moduleState.add( m_trackingPool->getThreadsDoneCondition() );
315 }
316 
317 WVector3d WMDeterministicFTMori::getEigenDirection( std::shared_ptr< WDataSetSingle const > ds,
319 {
320  WAssert( ds, "" );
321  WAssert( ds->getGrid(), "" );
322  WAssert( ds->getValueSet(), "" );
323  std::shared_ptr< WGridRegular3D > g = std::dynamic_pointer_cast< WGridRegular3D >( ds->getGrid() );
324  int i = g->getVoxelNum( j.first );
325  WAssert( i != -1, "" );
326  std::shared_ptr< WValueSet< double > > vs = std::dynamic_pointer_cast< WValueSet< double > >( ds->getValueSet() );
327  WAssert( vs, "" );
328  if( vs->rawData()[ 4 * i + 3 ] < m_currentMinFA )
329  {
330  return WVector3d( 0.0, 0.0, 0.0 );
331  }
332  else
333  {
334  WVector3d v;
335  v[ 0 ] = vs->rawData()[ 4 * i + 0 ];
336  v[ 1 ] = vs->rawData()[ 4 * i + 1 ];
337  v[ 2 ] = vs->rawData()[ 4 * i + 2 ];
338  v = normalize( v );
339  if( length( j.second ) == 0 )
340  {
341  return v;
342  }
343  else if( dot( v, j.second ) > m_currentMinCos )
344  {
345  return v;
346  }
347  else if( dot( j.second, v * -1.0 ) > m_currentMinCos )
348  {
349  return v * -1.0;
350  }
351  else
352  {
353  return WVector3d( 0.0, 0.0, 0.0 );
354  }
355  }
356 }
357 
359 {
360  if( f.size() >= m_currentMinPoints )
361  {
362  m_fiberAccu.add( f );
363  }
365 }
366 
368 {
369 }
370 
371 boost::array< double, 4 > const WMDeterministicFTMori::computeFaAndEigenVec( WTensorSym< 2, 3, double > const& m ) const
372 {
373  boost::array< double, 4 > a;
374 
375  RealEigenSystem eigenSys;
376  std::vector< double > ev( 3 );
377  std::vector< WVector3d > t( 3 );
378 
379  // calc eigenvectors
380  jacobiEigenvector3D( m, &eigenSys );
381 
382  // find the eigenvector with largest absolute eigenvalue
383  int u = 0;
384  double h = 0.0;
385  for( int n = 0; n < 3; ++n )
386  {
387  if( fabs( eigenSys[ n ].first ) > h )
388  {
389  h = fabs( eigenSys[ n ].first );
390  u = n;
391  }
392  }
393 
394  // copy them to the output
395  a[ 0 ] = eigenSys[ u ].second[ 0 ];
396  a[ 1 ] = eigenSys[ u ].second[ 1 ];
397  a[ 2 ] = eigenSys[ u ].second[ 2 ];
398 
399  // calc fa
400  double d = eigenSys[ 0 ].first * eigenSys[ 0 ].first + eigenSys[ 1 ].first * eigenSys[ 1 ].first + eigenSys[ 2 ].first * eigenSys[ 2 ].first;
401  if( fabs( d ) == 0.0 )
402  {
403  a[ 3 ] = 0.0;
404  }
405  else
406  {
407  double trace = ( eigenSys[ 0 ].first + eigenSys[ 1 ].first + eigenSys[ 2 ].first ) / 3;
408  a[ 3 ] = sqrt( 1.5 * ( ( eigenSys[ 0 ].first - trace ) * ( eigenSys[ 0 ].first - trace )
409  + ( eigenSys[ 1 ].first - trace ) * ( eigenSys[ 1 ].first - trace )
410  + ( eigenSys[ 2 ].first - trace ) * ( eigenSys[ 2 ].first - trace ) ) / d );
411  }
412 
413  return a;
414 }
415 
417 {
419  m( 0, 0 ) = static_cast< double >( input[ 0 ] );
420  m( 0, 1 ) = static_cast< double >( input[ 1 ] );
421  m( 0, 2 ) = static_cast< double >( input[ 2 ] );
422  m( 1, 1 ) = static_cast< double >( input[ 3 ] );
423  m( 1, 2 ) = static_cast< double >( input[ 4 ] );
424  m( 2, 2 ) = static_cast< double >( input[ 5 ] );
425 
427 
428  return computeFaAndEigenVec( m );
429 }
430 
432 {
434  m( 0, 0 ) = static_cast< double >( input[ 0 ] );
435  m( 0, 1 ) = static_cast< double >( input[ 1 ] );
436  m( 0, 2 ) = static_cast< double >( input[ 2 ] );
437  m( 1, 1 ) = static_cast< double >( input[ 3 ] );
438  m( 1, 2 ) = static_cast< double >( input[ 4 ] );
439  m( 2, 2 ) = static_cast< double >( input[ 5 ] );
440 
442 
443  return computeFaAndEigenVec( m );
444 }
445 
446 void WMDeterministicFTMori::resetProgress( std::size_t todo )
447 {
448  if( m_currentProgress )
449  {
450  m_currentProgress->finish();
451  }
452  m_currentProgress = std::shared_ptr< WProgress >( new WProgress( "det Mori FT", todo ) );
453  m_progress->addSubProgress( m_currentProgress );
454 }
virtual void wait() const
Wait for the condition.
void setResetable(bool resetable=true, bool autoReset=true)
Sets the resetable flag.
virtual void remove(std::shared_ptr< WCondition > condition)
Removes the specified condition.
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
void add(std::vector< WVector3d > const &in)
Add a fiber to the dataset.
std::shared_ptr< WDataSetFibers > buildDataSet()
Return the dataset that has been accumulated to this point and start a new dataset.
void clear()
Clears all data.
This module implements the simple fiber tracking algorithm by Mori et al.
wtracking::WThreadedTrackingFunction Tracking
the threaded tracking functor
WThreadedFunction< TPVOFloat > EigenFunctionTypeFloat
the thread pool type for the eigencomputation (float input)
std::shared_ptr< WThreadedFunctionBase > m_eigenPool
The threadpool for the eigenvector and fa computations.
std::shared_ptr< WDataSetSingle > m_dataSet
A pointer to the input tensor dataset.
virtual const char ** getXPMIcon() const
Get the icon for this module in XPM format.
WPropDouble m_minCos
The minimum cosine property.
WVector3d getEigenDirection(std::shared_ptr< WDataSetSingle const > ds, wtracking::WTrackingUtility::JobType const &j)
Calculate the direction of the eigenvector with largest magnitude.
boost::array< double, 4 > const computeFaAndEigenVec(WTensorSym< 2, 3, double > const &m) const
The function that does the actual fa and eigenvector computations.
virtual void moduleMain()
The worker function, runs in its own thread.
std::shared_ptr< TPVODouble > m_eigenOperationDouble
the functor used for the calculation of the eigenvectors
WMDeterministicFTMori()
Standard Constructor.
WThreadedPerVoxelOperation< float, 6, double, 4 > TPVOFloat
the threaded per-voxel function for the eigenvector computation (float input)
WThreadedPerVoxelOperation< double, 6, double, 4 > TPVODouble
the threaded per-voxel function for the eigenvector computation (double input)
virtual void properties()
Initialize the module's properties.
TPVODouble::OutTransmitType const eigenFuncDouble(TPVODouble::TransmitType const &input)
The function that computes the eigenvectors from the input tensor field.
virtual const std::string getName() const
Return the name of this module.
WFiberAccumulator m_fiberAccu
The fiber accumulator.
virtual ~WMDeterministicFTMori()
Destructor.
virtual void activate()
Callback.
void resetTracking()
Reset the tracking function and abort the current one, if there is a current one.
double m_currentMinFA
The current minimum FA property.
void pointVis(WVector3d const &)
The point visitor.
WPropDouble m_minFA
The minimum FA property.
double m_currentMinCos
The current minimum cosine property.
std::vector< WVector3d > FiberType
the fiber type
virtual void connectors()
Initialize the module's connectors.
std::size_t m_currentMinPoints
The current minimum number of points property.
std::shared_ptr< TrackingFuncType > m_trackingPool
The threadpool for the tracking.
virtual std::shared_ptr< WModule > factory() const
Returns a new instance of this module.
std::shared_ptr< WModuleOutputData< WDataSetFibers > > m_output
The output Connector.
std::shared_ptr< WCondition > m_propCondition
A condition for property changes.
std::shared_ptr< WProgress > m_currentProgress
the object that keeps track of the current progress
WPropInt m_minPoints
The minimum number of points property.
TPVOFloat::OutTransmitType const eigenFuncFloat(TPVOFloat::TransmitType const &input)
The function that computes the eigenvectors from the input tensor field.
void fiberVis(FiberType const &f)
The fiber visitor.
std::shared_ptr< WDataSetFibers > m_fiberSet
The output dataset. Stores all fibers extracted from the input tensor field.
std::shared_ptr< TPVOFloat > m_eigenOperationFloat
the functor used for the calculation of the eigenvectors
void resetProgress(std::size_t todo)
Resets the current progress to 0.
std::shared_ptr< WModuleInputData< WDataSetSingle > > m_input
The input Connector.
WThreadedFunction< TPVODouble > EigenFunctionTypeDouble
the thread pool type for the eigencomputation (double input)
virtual const std::string getDescription() const
Return the description of this module.
std::shared_ptr< WDataSetSingle > m_eigenField
Stores eigenvectors and fractional anisotropy of the input dataset.
WThreadedFunction< Tracking > TrackingFuncType
the tracking threadpool
void resetEigenFunction()
Resets the threaded function/threadpool.
Class offering an instantiate-able data connection between modules.
Class representing a single module of OpenWalnut.
Definition: WModule.h:72
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
void addConnector(std::shared_ptr< WModuleInputConnector > con)
Adds the specified connector to the list of inputs.
Definition: WModule.cpp:108
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
virtual void activate()
Callback for m_active.
Definition: WModule.cpp:220
std::shared_ptr< WProgressCombiner > m_progress
Progress indicator used as parent for all progress' of this module.
Definition: WModule.h:652
virtual void connectors()
Initialize connectors in this function.
Definition: WModule.cpp:208
Class managing progress inside of modules.
Definition: WProgress.h:42
Implements a symmetric tensor that has the same number of components in every direction.
Definition: WTensorSym.h:73
boost::array< Output_T, numOutputs > OutTransmitType
the output type for the per-voxel operation
ValueSetType::SubArray const TransmitType
the input type for the per-voxel operation
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
std::pair< WVector3d, WVector3d > JobType
define a job type for tracking algorithms
static bool followToNextVoxel(DataSetPtr dataset, JobType &job, DirFunc const &dirFunc)
A function that follows a direction until leaving the current voxel.