OpenWalnut  1.5.0dev
WMGaussFiltering.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 <cmath>
26 #include <fstream>
27 #include <iostream>
28 #include <memory>
29 #include <stdint.h>
30 #include <string>
31 #include <vector>
32 
33 #include "WMGaussFiltering.h"
34 #include "WMGaussFiltering.xpm"
35 #include "core/common/WAssert.h"
36 #include "core/common/WProgress.h"
37 #include "core/common/WStringUtils.h"
38 #include "core/dataHandler/WGridRegular3D.h"
39 #include "core/kernel/WKernel.h"
40 
41 // This line is needed by the module loader to actually find your module.
42 W_LOADABLE_MODULE( WMGaussFiltering )
43 
45  WModule()
46 {
47  // WARNING: initializing connectors inside the constructor will lead to an exception.
48  // Implement WModule::initializeConnectors instead.
49 }
50 
52 {
53  // cleanup
55 }
56 
57 std::shared_ptr< WModule > WMGaussFiltering::factory() const
58 {
59  return std::shared_ptr< WModule >( new WMGaussFiltering() );
60 }
61 
62 const char** WMGaussFiltering::getXPMIcon() const
63 {
64  return gaussfiltering_xpm;
65 }
66 
67 const std::string WMGaussFiltering::getName() const
68 {
69  return "Gauss Filtering";
70 }
71 
72 const std::string WMGaussFiltering::getDescription() const
73 {
74  return "Runs a discretized Gauss filter as mask over a simple scalar field.";
75 }
76 
77 size_t getId( size_t xDim, size_t yDim, size_t /*zDim*/, size_t x, size_t y, size_t z, size_t offset = 0, size_t elements = 1 )
78 {
79  return offset + ( elements * ( z * xDim * yDim + y * xDim + x ) );
80 }
81 
82 double mask( size_t i, size_t j, size_t k )
83 {
84  WAssert( i < 3, "Index larger than two where [0,1,2] is expected." );
85  WAssert( j < 3, "Index larger than two where [0,1,2] is expected." );
86  WAssert( k < 3, "Index larger than two where [0,1,2] is expected." );
87  double maskEntries[3][3][3] = { // NOLINT
88  { { 0, 1, 0 }, { 1, 2, 1 }, { 0, 1, 0 } }, // NOLINT
89  { { 1, 2, 1 }, { 2, 4, 2 }, { 1, 2, 1 } }, // NOLINT
90  { { 0, 1, 0 }, { 1, 2, 1 }, { 0, 1, 0 } } }; // NOLINT
91  return maskEntries[i][j][k];
92 }
93 
94 template<typename T> double WMGaussFiltering::filterAtPosition(
95  std::shared_ptr<WValueSet<T> > vals, size_t nX, size_t nY, size_t nZ,
96  size_t x, size_t y, size_t z, size_t offset )
97 {
98  double filtered = 0;
99  double maskSum = 0;
100  size_t filterSize = 3;
101  for( size_t k = 0; k < filterSize; ++k )
102  {
103  for( size_t j = 0; j < filterSize; ++j )
104  {
105  for( size_t i = 0; i < filterSize; ++i )
106  {
107  filtered += mask( i, j, k ) * vals->getScalar(
108  getId( nX, nY, nZ, x - 1 + i, y - 1 + j, z - 1 + k, offset, vals->elementsPerValue() ) );
109  maskSum += mask( i, j, k );
110  }
111  }
112  }
113  filtered /= maskSum;
114 
115  return filtered;
116 }
117 
118 template< typename T >
119 std::vector<double> WMGaussFiltering::filterField( std::shared_ptr< WValueSet< T > > vals, std::shared_ptr<WGridRegular3D> grid,
120  std::shared_ptr< WProgress > prog )
121 {
122  size_t nX = grid->getNbCoordsX();
123  size_t nY = grid->getNbCoordsY();
124  size_t nZ = grid->getNbCoordsZ();
125 
126  if( m_3DMaskMode->get( true ) )
127  {
128  std::vector<double> newVals( vals->elementsPerValue() * nX * nY * nZ, 0. );
129 
130  for( size_t z = 1; z < nZ - 1; z++ )
131  {
132  ++*prog;
133  for( size_t y = 1; y < nY - 1; y++ )
134  {
135  for( size_t x = 1; x < nX - 1; x++ )
136  {
137  for( size_t offset = 0; offset < vals->elementsPerValue(); ++offset )
138  {
139  newVals[getId( nX, nY, nZ, x, y, z, offset, vals->elementsPerValue() )] =
140  filterAtPosition( vals, nX, nY, nZ, x, y, z, offset );
141  }
142  }
143  }
144  }
145  return newVals;
146  }
147  else
148  {
149  std::vector<double> newVals1( vals->elementsPerValue() * nX * nY * nZ, 0. );
150  std::vector<double> newVals2( vals->elementsPerValue() * nX * nY * nZ, 0. );
151 
152  filterField1D( &newVals1, vals, prog, nX, nY, nZ, 1, nX, nX*nY ); // run in X direction
153  filterField1D( &newVals2, newVals1, prog, nY, nX, nZ, nX, 1, nX*nY ); // run in Y direction
154  filterField1D( &newVals1, newVals2, prog, nZ, nX, nY, nX*nY, 1, nX ); // run in Z direction
155 
156  return newVals1;
157  }
158 }
159 
160 template< typename T >
161 void WMGaussFiltering::filterField1D( std::vector<double>* newVals,
162  std::shared_ptr< WValueSet< T > > vals,
163  std::shared_ptr< WProgress > prog,
164  size_t nX, size_t nY, size_t nZ, size_t dx, size_t dy, size_t dz )
165 {
166  for( size_t z = 1; z < nZ - 1; ++z )
167  {
168  ++*prog;
169  for( size_t y = 1; y < nY - 1; ++y )
170  {
171  for( size_t x = 1; x < nX - 1; ++x )
172  {
173  size_t id = x*dx + y*dy + z*dz;
174  ( *newVals )[ id ] =
175  0.25 * ( vals->getScalar( id - dx ) + 2. * vals->getScalar( id ) + vals->getScalar( id + dx ) );
176  }
177  }
178  }
179 }
180 
181 template< typename T >
182 void WMGaussFiltering::filterField1D( std::vector<T>* newVals,
183  const std::vector<T>& vals,
184  std::shared_ptr< WProgress > prog,
185  size_t nX, size_t nY, size_t nZ, size_t dx, size_t dy, size_t dz )
186 {
187  for( size_t z = 1; z < nZ - 1; ++z )
188  {
189  ++*prog;
190  for( size_t y = 1; y < nY - 1; ++y )
191  {
192  for( size_t x = 1; x < nX - 1; ++x )
193  {
194  size_t id = x*dx + y*dy + z*dz;
195  ( *newVals )[ id ] =
196  0.25 * ( vals[ id - dx ] + 2. * vals[ id ] + vals[ id + dx ] );
197  }
198  }
199  }
200 }
201 
202 template< typename T >
203 std::shared_ptr< WValueSet< double > > WMGaussFiltering::iterativeFilterField( std::shared_ptr< WValueSet< T > > vals, unsigned int iterations )
204 {
205  // the grid used
206  std::shared_ptr<WGridRegular3D> grid = std::dynamic_pointer_cast< WGridRegular3D >( m_dataSet->getGrid() );
207  WAssert( grid, "Grid is not of type WGridRegular3D." );
208 
209  // use a custom progress combiner
210  std::shared_ptr< WProgress > prog;
211 
212  if( m_3DMaskMode->get() )
213  {
214  prog = std::shared_ptr< WProgress >(
215  new WProgress( "Gauss Filter Iteration", iterations * grid->getNbCoordsZ() ) );
216  }
217  else
218  {
219  prog = std::shared_ptr< WProgress >(
220  new WProgress( "Gauss Filter Iteration", 3 * iterations * grid->getNbCoordsZ() ) );
221  }
222  m_progress->addSubProgress( prog );
223 
224  // iterate filter, apply at least once
225  std::shared_ptr< WValueSet< double > > valueSet = std::shared_ptr< WValueSet< double > >(
226  new WValueSet<double> ( vals->order(), vals->dimension(),
227  std::shared_ptr< std::vector< double > >( new std::vector< double >( filterField( vals, grid, prog ) ) ),
228  W_DT_DOUBLE )
229  );
230  for( unsigned int i = 1; i < iterations; ++i ) // this only runs if iter > 1
231  {
232  valueSet = std::shared_ptr< WValueSet< double > >(
233  new WValueSet<double> ( valueSet->order(), valueSet->dimension(),
234  std::shared_ptr< std::vector< double > >( new std::vector< double >( filterField( valueSet, grid, prog ) ) ),
235  W_DT_DOUBLE )
236  );
237  }
238 
239  prog->finish();
240 
241  return valueSet;
242 }
243 
245 {
246  // let the main loop awake if the data changes or the properties changed.
247  m_moduleState.setResetable( true, true );
248  m_moduleState.add( m_input->getDataChangedCondition() );
250 
251  // signal ready state
252  ready();
253 
254  // the number of iterations
255  unsigned int iterations = 1;
256 
257  // loop until the module container requests the module to quit
258  while( !m_shutdownFlag() )
259  {
260  // Now, the moduleState variable comes into play. The module can wait for the condition, which gets fired whenever the input receives data
261  // or an property changes. The main loop now waits until something happens.
262  debugLog() << "Waiting ...";
264 
265  // woke up since the module is requested to finish
266  if( m_shutdownFlag() )
267  {
268  break;
269  }
270 
271  // has the data changed?
272  std::shared_ptr< WDataSetScalar > newDataSet = m_input->getData();
273  bool dataChanged = ( m_dataSet != newDataSet );
274  if( dataChanged || !m_dataSet )
275  // this condition will become true whenever the new data is different from the current one or our actual data is NULL. This handles all
276  // cases.
277  {
278  // The data is different. Copy it to our internal data variable:
279  debugLog() << "Received Data.";
280  m_dataSet = newDataSet;
281 
282  // invalid data
283  if( !m_dataSet )
284  {
285  debugLog() << "Resetting output.";
286  m_output->reset();
287  // NOTE: m_dataSet is already reset
288  continue;
289  }
290  }
291 
292  // m_iterations changed
293  if( m_iterations->changed() )
294  {
295  // a changed number of iteration also requires recalculation
296  iterations = m_iterations->get( true );
297  dataChanged = ( iterations >= 1 );
298  }
299 
300  if( m_3DMaskMode->changed() )
301  {
302  dataChanged = true;
303  }
304 
305  if( dataChanged )
306  {
307  std::shared_ptr< WValueSet< double > > newValueSet;
308 
309  switch( ( *m_dataSet ).getValueSet()->getDataType() )
310  {
311  case W_DT_UNSIGNED_CHAR:
312  {
313  std::shared_ptr<WValueSet<unsigned char> > vals;
314  vals = std::dynamic_pointer_cast<WValueSet<unsigned char> >( ( *m_dataSet ).getValueSet() );
315  WAssert( vals, "Data type and data type indicator must fit." );
316  newValueSet = iterativeFilterField( vals, iterations );
317  break;
318  }
319  case W_DT_INT16:
320  {
321  std::shared_ptr<WValueSet<int16_t> > vals;
322  vals = std::dynamic_pointer_cast<WValueSet<int16_t> >( ( *m_dataSet ).getValueSet() );
323  WAssert( vals, "Data type and data type indicator must fit." );
324  newValueSet = iterativeFilterField( vals, iterations );
325  break;
326  }
327  case W_DT_UINT16:
328  {
329  std::shared_ptr<WValueSet<uint16_t> > vals;
330  vals = std::dynamic_pointer_cast<WValueSet<uint16_t> >( ( *m_dataSet ).getValueSet() );
331  WAssert( vals, "Data type and data type indicator must fit." );
332  newValueSet = iterativeFilterField( vals, iterations );
333  break;
334  }
335  case W_DT_SIGNED_INT:
336  {
337  std::shared_ptr<WValueSet<int32_t> > vals;
338  vals = std::dynamic_pointer_cast<WValueSet<int32_t> >( ( *m_dataSet ).getValueSet() );
339  WAssert( vals, "Data type and data type indicator must fit." );
340  newValueSet = iterativeFilterField( vals, iterations );
341  break;
342  }
343  case W_DT_FLOAT:
344  {
345  std::shared_ptr<WValueSet<float> > vals;
346  vals = std::dynamic_pointer_cast<WValueSet<float> >( ( *m_dataSet ).getValueSet() );
347  WAssert( vals, "Data type and data type indicator must fit." );
348  newValueSet = iterativeFilterField( vals, iterations );
349  break;
350  }
351  case W_DT_DOUBLE:
352  {
353  std::shared_ptr<WValueSet<double> > vals;
354  vals = std::dynamic_pointer_cast<WValueSet<double> >( ( *m_dataSet ).getValueSet() );
355  WAssert( vals, "Data type and data type indicator must fit." );
356  newValueSet = iterativeFilterField( vals, iterations );
357  break;
358  }
359  default:
360  WAssert( false, "Unknown data type in Gauss Filtering module" );
361  }
362 
363  m_output->updateData( std::shared_ptr<WDataSetScalar>( new WDataSetScalar( newValueSet, m_dataSet->getGrid() ) ) );
364  }
365 
366  // if the number of iterations is 0 -> simply set the input as output
367  if( iterations == 0 )
368  {
369  m_output->updateData( m_dataSet );
370  }
371  }
372 }
373 
375 {
376  // initialize connectors
377  m_input = std::shared_ptr<WModuleInputData<WDataSetScalar> >(
378  new WModuleInputData<WDataSetScalar> ( shared_from_this(), "in",
379  "The dataset to filter" ) );
380 
381  // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
383 
384  // initialize connectors
385  m_output = std::shared_ptr<WModuleOutputData<WDataSetScalar> >(
386  new WModuleOutputData<WDataSetScalar> ( shared_from_this(), "out",
387  "The filtered data set." ) );
388 
389  // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
391 
392  // call WModules initialization
394 }
395 
397 {
398  m_propCondition = std::shared_ptr< WCondition >( new WCondition() );
399 
400  m_iterations = m_properties->addProperty( "Iterations", "How often should the filter be applied.", 1, m_propCondition );
401  m_iterations->setMin( 0 );
402  m_iterations->setMax( 100 );
403 
404  m_3DMaskMode = m_properties->addProperty( "Filter 3D", "Filter with a 3D mask instead of three 1D masks.", false, m_propCondition );
405 
407 }
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
This data set type contains scalars as values.
Gauss filtering for WDataSetScalar.
std::shared_ptr< WDataSetScalar > m_dataSet
Pointer providing access to the treated data set in the whole module.
double filterAtPosition(std::shared_ptr< WValueSet< T > > vals, size_t nX, size_t nY, size_t nZ, size_t x, size_t y, size_t z, size_t offset)
Simple convolution using a small gauss-like mask.
virtual void moduleMain()
Entry point after loading the module.
virtual void properties()
Initialize the properties for this module.
~WMGaussFiltering()
Destructor.
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...
std::shared_ptr< WModuleInputData< WDataSetScalar > > m_input
Input connector required by this module.
std::shared_ptr< WModuleOutputData< WDataSetScalar > > m_output
The only output of this filter module.
void filterField1D(std::vector< T > *newVals, const std::vector< T > &vals, std::shared_ptr< WProgress > prog, size_t Nx, size_t Ny, size_t Nz, size_t dx, size_t dy, size_t dz)
Run the 1D Gaussian filter over the field.
std::vector< double > filterField(std::shared_ptr< WValueSet< T > > vals, std::shared_ptr< WGridRegular3D > grid, std::shared_ptr< WProgress > prog)
Run the filter over the field.
std::shared_ptr< WValueSet< double > > iterativeFilterField(std::shared_ptr< WValueSet< T > > vals, unsigned int iterations)
Run the filter iteratively over the field.
virtual const std::string getDescription() const
Gives back a description of this module.
WPropBool m_3DMaskMode
1D or 3D filtering flag
virtual void connectors()
Initialize the connectors this module is using.
virtual const char ** getXPMIcon() const
Get the icon for this module in XPM format.
WMGaussFiltering()
Standard constructor.
std::shared_ptr< WCondition > m_propCondition
A condition used to notify about changes in several properties.
virtual const std::string getName() const
Gives back the name of this module.
WPropInt m_iterations
The number of iterations to use for filtering.
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
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
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