OpenWalnut  1.5.0dev
WMDistanceMap.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 <memory>
27 #include <stdint.h>
28 #include <string>
29 #include <vector>
30 
31 #include "WMDistanceMap.h"
32 #include "WMDistanceMap.xpm"
33 #include "core/common/WAssert.h"
34 #include "core/common/WProgress.h"
35 #include "core/dataHandler/WGridRegular3D.h"
36 #include "core/dataHandler/WSubject.h"
37 #include "core/kernel/WKernel.h"
38 #include "core/kernel/WModuleFactory.h"
39 
40 // This line is needed by the module loader to actually find your module.
41 W_LOADABLE_MODULE( WMDistanceMap )
42 
44  WModule()
45 {
46  // WARNING: initializing connectors inside the constructor will lead to an exception.
47  // NOTE: Do not use the module factory inside this constructor. This will cause a dead lock as the module factory is locked
48  // during construction of this instance and can then not be used to create another instance (Isosurface in this case).
49 }
50 
52 {
53  // cleanup
55 }
56 
57 std::shared_ptr< WModule > WMDistanceMap::factory() const
58 {
59  return std::shared_ptr< WModule >( new WMDistanceMap() );
60 }
61 
62 const char** WMDistanceMap::getXPMIcon() const
63 {
64  return distancemap_xpm;
65 }
66 
67 
68 const std::string WMDistanceMap::getName() const
69 {
70  return "Distance Map";
71 }
72 
73 const std::string WMDistanceMap::getDescription() const
74 {
75  return "Computes a smoothed version of the dataset and a distance map on it.";
76 }
77 
79 {
80  // use the m_input "data changed" flag
81  m_moduleState.setResetable( true, true );
82  m_moduleState.add( m_input->getDataChangedCondition() );
83 
84  // signal ready state
85  ready();
86 
87  // loop until the module container requests the module to quit
88  while( !m_shutdownFlag() )
89  {
90  debugLog() << "Waiting ...";
92 
93  // woke up since the module is requested to finish?
94  if( m_shutdownFlag() )
95  {
96  break;
97  }
98 
99  // acquire data from the input connector
100  m_dataSet = m_input->getData();
101  if( !m_dataSet )
102  {
103  debugLog() << "Resetting output.";
104  m_output->reset();
105  continue;
106  }
107 
108  // found some data
109  debugLog() << "Data changed. Updating ...";
110  std::shared_ptr< WValueSet< float > > distanceMapValueSet = createOffset( m_dataSet );
111  m_distanceMapDataSet = std::shared_ptr< WDataSetScalar >( new WDataSetScalar( distanceMapValueSet, m_dataSet->getGrid() ) );
112 
113  WLogger::getLogger()->addLogMessage( "Done!", "Distance Map", LL_INFO );
114 
115  // update the output
116  m_output->updateData( m_distanceMapDataSet );
117  }
118 }
119 
121 {
122  // initialize connectors
123 
124  m_input = std::shared_ptr<WModuleInputData< WDataSetScalar > >(
125  new WModuleInputData< WDataSetScalar >( shared_from_this(),
126  "in", "Dataset to compute distance map for." )
127  );
128 
129  // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
131 
132  m_output = std::shared_ptr<WModuleOutputData< WDataSetScalar > >(
133  new WModuleOutputData< WDataSetScalar >( shared_from_this(),
134  "out", "Distance map for the input data set." )
135  );
136 
137  // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
139 
140  // call WModule's initialization
142 }
143 
145 {
147 }
148 
149 template< typename T > std::shared_ptr< WValueSet< float > > makeFloatValueSetHelper( std::shared_ptr< WValueSet< T > > inSet )
150 {
151  WAssert( inSet->dimension() == 1, "Works only for scalar data." );
152  WAssert( inSet->order() == 0, "Works only for scalar data." );
153 
154  std::shared_ptr< std::vector< float > > data( new std::vector< float >( inSet->size() ) );
155  for( unsigned int i = 0; i < inSet->size(); ++i )
156  {
157  ( *data )[i] = static_cast< float >( inSet->getScalar( i ) );
158  }
159 
160  std::shared_ptr< WValueSet< float > > outSet;
161  outSet = std::shared_ptr< WValueSet< float > >( new WValueSet< float >( ( *inSet ).order(), ( *inSet ).dimension(), data, W_DT_FLOAT ) );
162 
163  return outSet;
164 }
165 
166 std::shared_ptr< WValueSet< float > > makeFloatValueSet( std::shared_ptr< WValueSetBase > inSet )
167 {
168  WAssert( inSet->dimension() == 1, "Works only for scalar data." );
169  WAssert( inSet->order() == 0, "Works only for scalar data." );
170 
171  switch( inSet->getDataType() )
172  {
173  case W_DT_UNSIGNED_CHAR:
174  return makeFloatValueSetHelper( std::dynamic_pointer_cast< WValueSet< unsigned char > >( inSet ) );
175  break;
176  case W_DT_INT16:
177  return makeFloatValueSetHelper( std::dynamic_pointer_cast< WValueSet< int16_t > >( inSet ) );
178  break;
179  case W_DT_SIGNED_INT:
180  return makeFloatValueSetHelper( std::dynamic_pointer_cast< WValueSet< int32_t > >( inSet ) );
181  break;
182  case W_DT_FLOAT:
183  return std::dynamic_pointer_cast< WValueSet< float > >( inSet );
184  break;
185  default:
186  WAssert( false, "Unknow data type in makeFloatDataSet" );
187  }
188 
189  WAssert( false, "If this assertion is reached, the code above has to be fixed." );
190  return std::shared_ptr< WValueSet< float > >();
191 }
192 
193 std::shared_ptr< WValueSet< float > > WMDistanceMap::createOffset( std::shared_ptr< const WDataSetScalar > dataSet )
194 {
195  std::vector<float> floatDataset;
196 
197  // wiebel: I know that this is not the most speed and memory efficient way to deal with different data types.
198  // However, it seems the most feasible at the moment (2009-11-24).
199  std::shared_ptr< WValueSet< float > > valueSet = makeFloatValueSet( ( *dataSet ).getValueSet() );
200  WAssert( valueSet, "Works only for float data sets." );
201 
202  std::shared_ptr< WGridRegular3D > grid = std::dynamic_pointer_cast< WGridRegular3D >( ( *dataSet ).getGrid() );
203  WAssert( grid, "Works only for data on regular 3D grids." );
204 
205  int b, r, c, bb, rr, r0, b0, c0;
206  int i, istart, iend;
207  int nbands, nrows, ncols, npixels;
208  int d, d1, d2, cc1, cc2;
209  float u, dmin, dmax;
210  bool *srcpix;
211  double g, *array;
212 
213  nbands = grid->getNbCoordsZ();
214  nrows = grid->getNbCoordsY();
215  ncols = grid->getNbCoordsX();
216 
217  npixels = std::max( nbands, nrows );
218 
219  array = new double[npixels];
220 
221  npixels = nbands * nrows * ncols;
222 
223  floatDataset.resize( npixels );
224  for( int i = 0; i < npixels; ++i )
225  {
226  floatDataset[i] = 0.0;
227  }
228 
229  bool* bitmask = new bool[npixels];
230  for( int i = 0; i < npixels; ++i )
231  {
232  if( valueSet->getScalar( i ) < 0.01 )
233  {
234  bitmask[i] = true;
235  }
236  else
237  {
238  bitmask[i] = false;
239  }
240  }
241 
242  dmax = 999999999.0;
243 
244  // first pass
245 
246  std::shared_ptr< WProgress > progress1 = std::shared_ptr< WProgress >(
247  new WProgress( "Distance Map", nbands + nbands + nrows + nbands + nbands + nbands )
248  );
249  m_progress->addSubProgress( progress1 );
250  for( b = 0; b < nbands; ++b )
251  {
252  ++*progress1;
253  for( r = 0; r < nrows; ++r )
254  {
255  for( c = 0; c < ncols; ++c )
256  {
257  //if(VPixel(src,b,r,c,VBit) == 1)
258  if( bitmask[b * nrows * ncols + r * ncols + c] )
259  {
260  floatDataset[b * nrows * ncols + r * ncols + c] = 0;
261  continue;
262  }
263 
264  srcpix = bitmask + b * nrows * ncols + r * ncols + c;
265  cc1 = c;
266  while( cc1 < ncols && *srcpix++ == 0 )
267  cc1++;
268  d1 = ( cc1 >= ncols ? ncols : ( cc1 - c ) );
269 
270  srcpix = bitmask + b * nrows * ncols + r * ncols + c;
271  cc2 = c;
272  while( cc2 >= 0 && *srcpix-- == 0 )
273  cc2--;
274  d2 = ( cc2 <= 0 ? ncols : ( c - cc2 ) );
275 
276  if( d1 <= d2 )
277  {
278  d = d1;
279  c0 = cc1;
280  }
281  else
282  {
283  d = d2;
284  c0 = cc2;
285  }
286  floatDataset[b * nrows * ncols + r * ncols + c] = static_cast< float >( d * d );
287  }
288  }
289  }
290 
291  // second pass
292  for( b = 0; b < nbands; b++ )
293  {
294  ++*progress1;
295  for( c = 0; c < ncols; c++ )
296  {
297  for( r = 0; r < nrows; r++ )
298  array[r] = static_cast< double >( floatDataset[b * nrows * ncols + r * ncols + c] );
299 
300  for( r = 0; r < nrows; r++ )
301  {
302  if( bitmask[b * nrows * ncols + r * ncols + c] == 1 )
303  continue;
304 
305  dmin = dmax;
306  r0 = r;
307  g = sqrt( array[r] );
308  istart = r - static_cast< int >( g );
309  if( istart < 0 )
310  istart = 0;
311  iend = r + static_cast< int >( g + 1 );
312  if( iend >= nrows )
313  iend = nrows;
314 
315  for( rr = istart; rr < iend; rr++ )
316  {
317  u = array[rr] + ( r - rr ) * ( r - rr );
318  if( u < dmin )
319  {
320  dmin = u;
321  r0 = rr;
322  }
323  }
324  floatDataset[b * nrows * ncols + r * ncols + c] = dmin;
325  }
326  }
327  }
328 
329  // third pass
330  for( r = 0; r < nrows; r++ )
331  {
332  ++*progress1;
333  for( c = 0; c < ncols; c++ )
334  {
335  for( b = 0; b < nbands; b++ )
336  array[b] = static_cast< double >( floatDataset[b * nrows * ncols + r * ncols + c] );
337 
338  for( b = 0; b < nbands; b++ )
339  {
340  if( bitmask[b * nrows * ncols + r * ncols + c] == 1 )
341  continue;
342 
343  dmin = dmax;
344  b0 = b;
345 
346  g = sqrt( array[b] );
347  istart = b - static_cast< int >( g - 1 );
348  if( istart < 0 )
349  istart = 0;
350  iend = b + static_cast< int >( g + 1 );
351  if( iend >= nbands )
352  iend = nbands;
353 
354  for( bb = istart; bb < iend; bb++ )
355  {
356  u = array[bb] + ( b - bb ) * ( b - bb );
357  if( u < dmin )
358  {
359  dmin = u;
360  b0 = bb;
361  }
362  }
363  floatDataset[b * nrows * ncols + r * ncols + c] = dmin;
364  }
365  }
366  }
367 
368  delete[] array;
369 
370  float max = 0;
371  for( i = 0; i < npixels; ++i )
372  {
373  floatDataset[i] = sqrt( static_cast< double >( floatDataset[i] ) );
374  if( floatDataset[i] > max )
375  max = floatDataset[i];
376  }
377  for( i = 0; i < npixels; ++i )
378  {
379  floatDataset[i] = floatDataset[i] / max;
380  }
381 
382  // filter with gauss
383  // create the filter kernel
384  double sigma = 4;
385 
386  int dim = static_cast< int >( ( 3.0 * sigma + 1 ) );
387  int n = 2* dim + 1;
388  double step = 1;
389 
390  float* kernel = new float[n];
391 
392  double sum = 0;
393  double x = -static_cast< float >( dim );
394 
395  double uu;
396  for( int i = 0; i < n; ++i )
397  {
398  uu = xxgauss( x, sigma );
399  sum += uu;
400  kernel[i] = uu;
401  x += step;
402  }
403 
404  /* normalize */
405  for( int i = 0; i < n; ++i )
406  {
407  uu = kernel[i];
408  uu /= sum;
409  kernel[i] = uu;
410  }
411 
412  d = n / 2;
413  float* float_pp;
414  std::vector<float> tmp( npixels );
415  int c1, cc;
416 
417  for( int i = 0; i < npixels; ++i )
418  {
419  tmp[i] = 0.0;
420  }
421 
422  for( b = 0; b < nbands; ++b )
423  {
424  ++*progress1;
425  for( r = 0; r < nrows; ++r )
426  {
427  for( c = d; c < ncols - d; ++c )
428  {
429  float_pp = kernel;
430  sum = 0;
431  c0 = c - d;
432  c1 = c + d;
433  for( cc = c0; cc <= c1; cc++ )
434  {
435  x = floatDataset[b * nrows * ncols + r * ncols + cc];
436  sum += x * ( *float_pp++ );
437  }
438  tmp[b * nrows * ncols + r * ncols + c] = sum;
439  }
440  }
441  }
442  int r1;
443  for( b = 0; b < nbands; ++b )
444  {
445  ++*progress1;
446  for( r = d; r < nrows - d; ++r )
447  {
448  for( c = 0; c < ncols; ++c )
449  {
450  float_pp = kernel;
451  sum = 0;
452  r0 = r - d;
453  r1 = r + d;
454  for( rr = r0; rr <= r1; rr++ )
455  {
456  x = tmp[b * nrows * ncols + rr * ncols + c];
457  sum += x * ( *float_pp++ );
458  }
459  floatDataset[b * nrows * ncols + r * ncols + c] = sum;
460  }
461  }
462  }
463  int b1;
464  for( b = d; b < nbands - d; ++b )
465  {
466  ++*progress1;
467  for( r = 0; r < nrows; ++r )
468  {
469  for( c = 0; c < ncols; ++c )
470  {
471  float_pp = kernel;
472  sum = 0;
473  b0 = b - d;
474  b1 = b + d;
475  for( bb = b0; bb <= b1; bb++ )
476  {
477  x = floatDataset[bb * nrows * ncols + r * ncols + c];
478  sum += x * ( *float_pp++ );
479  }
480  tmp[b * nrows * ncols + r * ncols + c] = sum;
481  }
482  }
483  }
484  delete[] bitmask;
485  delete[] kernel;
486 
487  floatDataset = tmp;
488  std::shared_ptr< WValueSet< float > > resultValueSet;
489  resultValueSet = std::shared_ptr< WValueSet< float > >(
490  new WValueSet< float >( valueSet->order(), valueSet->dimension(),
491  std::shared_ptr< std::vector< float > >( new std::vector< float >( floatDataset ) ), W_DT_FLOAT ) );
492 
493  progress1->finish();
494 
495  return resultValueSet;
496 }
497 
498 double WMDistanceMap::xxgauss( double x, double sigma )
499 {
500  double y, z, a = 2.506628273;
501  z = x / sigma;
502  y = exp( -z * z * 0.5 ) / ( sigma * a );
503  return y;
504 }
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.
This data set type contains scalars as values.
void addLogMessage(std::string message, std::string source="", LogLevel level=LL_DEBUG)
Appends a log message to the logging queue.
Definition: WLogger.cpp:84
static WLogger * getLogger()
Returns pointer to the currently running logger instance.
Definition: WLogger.cpp:64
Computes a distance map from an anatomy dataset.
Definition: WMDistanceMap.h:41
std::shared_ptr< WDataSetScalar > m_dataSet
Source dataset.
virtual const std::string getDescription() const
Gives back a description of this module.
std::shared_ptr< WDataSetScalar > m_distanceMapDataSet
Target dataset.
std::shared_ptr< WModuleInputData< WDataSetScalar > > m_input
Input connector required by this module.
virtual void moduleMain()
Entry point after loading the module.
std::shared_ptr< WValueSet< float > > createOffset(std::shared_ptr< const WDataSetScalar > dataSet)
Function to create a distance map from Anatomy data set.
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...
double xxgauss(double x, double sigma)
Gauss function.
virtual const std::string getName() const
Gives back the name of this module.
virtual void connectors()
Initialize the connectors this module is using.
WMDistanceMap()
Standard constructor.
virtual void properties()
Initialize the properties for this module.
std::shared_ptr< WModuleOutputData< WDataSetScalar > > m_output
Connector to provide the distance map to other modules.
virtual const char ** getXPMIcon() const
Get the icon for this module in XPM format.
~WMDistanceMap()
Destructor.
Class offering an instantiate-able data connection between modules.
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 removeConnectors()
Removes all connectors properly.
Definition: WModule.cpp:194
void addConnector(std::shared_ptr< WModuleInputConnector > con)
Adds the specified connector to the list of inputs.
Definition: WModule.cpp:108
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
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
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
Base Class for all value set types.
Definition: WValueSet.h:47