1
//---------------------------------------------------------------------------
3
// Project: OpenWalnut ( http://www.openwalnut.org )
5
// Copyright 2009 OpenWalnut Community, BSV-Leipzig and CNCF-CBS
6
// For more information see http://www.openwalnut.org/copying
8
// This file is part of OpenWalnut.
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.
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.
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/>.
23
//---------------------------------------------------------------------------
30
#include "core/kernel/WKernel.h"
31
#include "core/dataHandler/WDataHandler.h"
32
#include "core/common/WPropertyHelper.h"
34
#include "WMAnisotropicFiltering.xpm"
35
#include "WMAnisotropicFiltering.h"
37
// This line is needed by the module loader to actually find your module.
38
W_LOADABLE_MODULE( WMAnisotropicFiltering )
40
WMAnisotropicFiltering::WMAnisotropicFiltering():
46
WMAnisotropicFiltering::~WMAnisotropicFiltering()
50
boost::shared_ptr< WModule > WMAnisotropicFiltering::factory() const
52
return boost::shared_ptr< WModule >( new WMAnisotropicFiltering() );
55
const std::string WMAnisotropicFiltering::getName() const
57
return "Anisotropic Filter";
60
const std::string WMAnisotropicFiltering::getDescription() const
62
return "Filters MRI data, preserving edges.";
65
const char** WMAnisotropicFiltering::getXPMIcon() const
67
return WMAnisotropicFiltering_xpm;
70
void WMAnisotropicFiltering::connectors()
72
m_input = boost::shared_ptr< WModuleInputData < WDataSetSingle > >(
73
new WModuleInputData< WDataSetSingle >( shared_from_this(), "in", "The input dataset." ) );
74
addConnector( m_input );
76
m_output = boost::shared_ptr< WModuleOutputData < WDataSetSingle > >(
77
new WModuleOutputData< WDataSetSingle >( shared_from_this(), "out", "The extracted image." ) );
78
addConnector( m_output );
80
WModule::connectors();
83
void WMAnisotropicFiltering::properties()
85
m_propCondition = boost::shared_ptr< WCondition >( new WCondition() );
87
m_iterations = m_properties->addProperty( "#Iterations", "Number of iterations.", 10, m_propCondition );
88
m_iterations->setMax( 1000 );
90
m_Kcoeff = m_properties->addProperty( "K", "The diffusion weighting coefficient. Increase this to better preserve edges.", 9.0, m_propCondition );
91
m_Kcoeff->setMin( 0.1 );
92
m_Kcoeff->setMax( 1000.0 );
94
m_delta = m_properties->addProperty( "delta", "The time step for integration.", 0.1, m_propCondition );
95
m_delta->setMax( 10.0 );
97
WModule::properties();
100
void WMAnisotropicFiltering::activate()
105
void WMAnisotropicFiltering::moduleMain()
107
m_moduleState.setResetable( true, true );
108
m_moduleState.add( m_input->getDataChangedCondition() );
109
m_moduleState.add( m_propCondition );
113
while( !m_shutdownFlag() )
115
m_moduleState.wait();
117
if( m_shutdownFlag() )
122
boost::shared_ptr< WDataSetSingle > newDataSet = m_input->getData();
123
bool dataChanged = ( m_dataSet != newDataSet );
124
bool dataValid = ( newDataSet );
128
if( dataChanged || m_iterations->changed() || m_Kcoeff->changed() )
130
m_dataSet = newDataSet;
131
WAssert( m_dataSet, "" );
132
WAssert( m_dataSet->getValueSet(), "" );
134
infoLog() << "Calculating.";
136
m_k = m_Kcoeff->get( true );
137
m_d = m_delta->get( true );
139
calcSmoothedImages( m_iterations->get( true ) );
141
infoLog() << "Calculation complete.";
146
debugLog() << "Shutting down...";
147
debugLog() << "Finished! Good Bye!";
150
void WMAnisotropicFiltering::calcSmoothedImages( int iterations )
155
std::size_t numImages = m_dataSet->getValueSet()->rawSize() / m_dataSet->getGrid()->size();
156
infoLog() << "Images: " << numImages;
158
boost::shared_ptr< std::vector< double > > smoothed( new std::vector< double >( m_dataSet->getValueSet()->rawSize() ) );
159
boost::shared_ptr< WGridRegular3D > grid = boost::shared_dynamic_cast< WGridRegular3D >( m_dataSet->getGrid() );
161
// fill in data from dataset
162
copyData( smoothed, grid );
164
// the 3 derivatives ( actually this is the gradient )
165
std::vector< double > deriv( 3 * m_dataSet->getGrid()->size() );
167
// the diffusion coeff
168
std::vector< double > coeff( m_dataSet->getGrid()->size() );
170
boost::shared_ptr< WProgress > prog( new WProgress( "Smoothing images", numImages ) );
171
m_progress->addSubProgress( prog );
173
for( std::size_t k = 0; k < numImages; ++k )
175
for( int i = 0; i < iterations; ++i )
177
calcDeriv( deriv, smoothed, grid, k, numImages );
178
if( m_iterations->changed() || m_Kcoeff->changed() || m_delta->changed() || m_dataSet != m_input->getData() )
184
calcCoeff( coeff, deriv, grid );
185
if( m_iterations->changed() || m_Kcoeff->changed() || m_delta->changed() || m_dataSet != m_input->getData() )
191
diffusion( deriv, coeff, smoothed, grid, k, numImages );
192
if( m_iterations->changed() || m_Kcoeff->changed() || m_delta->changed() || m_dataSet != m_input->getData() )
203
// create dataset and update connector
204
boost::shared_ptr< WValueSet< double > > vs( new WValueSet< double >(
205
m_dataSet->getValueSet()->order(),
206
m_dataSet->getValueSet()->dimension(),
209
boost::shared_ptr< WDataSetSingle > ds = m_dataSet->clone( vs );
211
m_output->updateData( ds );
214
std::size_t WMAnisotropicFiltering::coordsToIndex( boost::shared_ptr< WGridRegular3D > const& grid,
215
std::size_t x, std::size_t y, std::size_t z )
217
return x + y * grid->getNbCoordsX() + z * grid->getNbCoordsX() * grid->getNbCoordsY();
220
void WMAnisotropicFiltering::copyData( boost::shared_ptr< std::vector< double > >& smoothed, // NOLINT non-const ref
221
boost::shared_ptr< WGridRegular3D > const& /* grid */ )
223
for( std::size_t k = 0; k < m_dataSet->getValueSet()->rawSize(); ++k )
225
( *smoothed )[ k ] = m_dataSet->getValueSet()->getScalarDouble( k );
229
void WMAnisotropicFiltering::calcDeriv( std::vector< double >& deriv, // NOLINT non-const ref
230
boost::shared_ptr< std::vector< double > > const& smoothed,
231
boost::shared_ptr< WGridRegular3D > const& grid, std::size_t image, std::size_t numImages )
233
std::size_t s[] = { grid->getNbCoordsX(), grid->getNbCoordsY(), grid->getNbCoordsZ() };
234
double d[] = { fabs( grid->getOffsetX() ), fabs( grid->getOffsetY() ), fabs( grid->getOffsetZ() ) };
236
for( std::size_t x = 0; x < grid->getNbCoordsX(); ++x )
238
for( std::size_t y = 0; y < grid->getNbCoordsY(); ++y )
240
for( std::size_t z = 0; z < grid->getNbCoordsZ(); ++z )
242
double const& x1 = ( *smoothed )[ numImages * coordsToIndex( grid, ( x + 1 ) % s[ 0 ], y, z ) + image ];
243
double const& x2 = ( *smoothed )[ numImages * coordsToIndex( grid, ( x + s[ 0 ] - 1 ) % s[ 0 ], y, z ) + image ];
244
deriv[ 3 * coordsToIndex( grid, x, y, z ) + 0 ] = ( x1 - x2 ) / ( 2.0 * d[ 0 ] );
246
double const& y1 = ( *smoothed )[ numImages * coordsToIndex( grid, x, ( y + 1 ) % s[ 1 ], z ) + image ];
247
double const& y2 = ( *smoothed )[ numImages * coordsToIndex( grid, x, ( y + s[ 1 ] - 1 ) % s[ 1 ], z ) + image ];
248
deriv[ 3 * coordsToIndex( grid, x, y, z ) + 1 ] = ( y1 - y2 ) / ( 2.0 * d[ 1 ] );
250
double const& z1 = ( *smoothed )[ numImages * coordsToIndex( grid, x, y, ( z + 1 ) % s[ 2 ] ) + image ];
251
double const& z2 = ( *smoothed )[ numImages * coordsToIndex( grid, x, y, ( z + s[ 2 ] - 1 ) % s[ 2 ] ) + image ];
252
deriv[ 3 * coordsToIndex( grid, x, y, z ) + 2 ] = ( z1 - z2 ) / ( 2.0 * d[ 2 ] );
258
void WMAnisotropicFiltering::calcCoeff( std::vector< double >& coeff, // NOLINT non-const ref
259
std::vector< double > const& deriv,
260
boost::shared_ptr< WGridRegular3D > const& grid )
262
for( std::size_t x = 0; x < grid->getNbCoordsX(); ++x )
264
for( std::size_t y = 0; y < grid->getNbCoordsY(); ++y )
266
for( std::size_t z = 0; z < grid->getNbCoordsZ(); ++z )
268
// coeff = exp( -sqr( |I|/K ) )
269
double gradIAbsSquared = deriv[ 3 * coordsToIndex( grid, x, y, z ) + 0 ]
270
* deriv[ 3 * coordsToIndex( grid, x, y, z ) + 0 ]
271
+ deriv[ 3 * coordsToIndex( grid, x, y, z ) + 1 ]
272
* deriv[ 3 * coordsToIndex( grid, x, y, z ) + 1 ]
273
+ deriv[ 3 * coordsToIndex( grid, x, y, z ) + 2 ]
274
* deriv[ 3 * coordsToIndex( grid, x, y, z ) + 2 ];
275
coeff[ coordsToIndex( grid, x, y, z ) ] = 1.0 / exp( gradIAbsSquared / ( m_k * m_k ) );
281
void WMAnisotropicFiltering::diffusion( std::vector< double > const& deriv, std::vector< double > const& coeff,
282
boost::shared_ptr< std::vector< double > >& smoothed, // NOLINT non-const ref
283
boost::shared_ptr< WGridRegular3D > const& grid, std::size_t image, std::size_t numImages )
285
std::size_t s[] = { grid->getNbCoordsX(), grid->getNbCoordsY(), grid->getNbCoordsZ() };
286
double d[] = { fabs( grid->getOffsetX() ), fabs( grid->getOffsetY() ), fabs( grid->getOffsetZ() ) };
288
for( std::size_t x = 0; x < grid->getNbCoordsX(); ++x )
290
for( std::size_t y = 0; y < grid->getNbCoordsY(); ++y )
292
for( std::size_t z = 0; z < grid->getNbCoordsZ(); ++z )
294
// first deriv of the image intensity
295
double const& dIx = deriv[ 3 * coordsToIndex( grid, x, y, z ) + 0 ];
296
double const& dIy = deriv[ 3 * coordsToIndex( grid, x, y, z ) + 1 ];
297
double const& dIz = deriv[ 3 * coordsToIndex( grid, x, y, z ) + 2 ];
299
// first deriv of the diffusion coeff
300
double dcx = ( coeff[ coordsToIndex( grid, ( x + 1 ) % s[ 0 ], y, z ) ]
301
- coeff[ coordsToIndex( grid, ( x + s[ 0 ] - 1 ) % s[ 0 ], y, z ) ] )
303
double dcy = ( coeff[ coordsToIndex( grid, x, ( y + 1 ) % s[ 1 ], z ) ]
304
- coeff[ coordsToIndex( grid, x, ( y + s[ 1 ] - 1 ) % s[ 1 ], z ) ] )
306
double dcz = ( coeff[ coordsToIndex( grid, x, y, ( z + 1 ) % s[ 2 ] ) ]
307
- coeff[ coordsToIndex( grid, x, y, ( z + s[ 2 ] - 1 ) % s[ 2 ] ) ] )
311
double const& c = coeff[ coordsToIndex( grid, x, y, z ) ];
313
// 2nd derivatives in x, y, and z of the image intensity
314
double ddIxx = ( deriv[ 3 * coordsToIndex( grid, ( x + 1 ) % s[ 0 ], y, z ) + 0 ]
315
- deriv[ 3 * coordsToIndex( grid, ( x + s[ 0 ] - 1 ) % s[ 0 ], y, z ) + 0 ] )
317
double ddIyy = ( deriv[ 3 * coordsToIndex( grid, x, ( y + 1 ) % s[ 1 ], z ) + 1 ]
318
- deriv[ 3 * coordsToIndex( grid, x, ( y + s[ 1 ] - 1 ) % s[ 1 ], z ) + 1 ] )
320
double ddIzz = ( deriv[ 3 * coordsToIndex( grid, x, y, ( z + 1 ) % s[ 2 ] ) + 2 ]
321
- deriv[ 3 * coordsToIndex( grid, x, y, ( z + s[ 2 ] - 1 ) % s[ 2 ] ) + 2 ] )
324
// d * ( grad I * grad c + c * grad grad I )
325
( *smoothed )[ numImages * coordsToIndex( grid, x, y, z ) + image ] += m_d * ( dIx * dcx + dIy * dcy + dIz * dcz
326
+ c * ( ddIxx + ddIyy + ddIzz ) );