OpenWalnut  1.5.0dev
WMWriteNIfTI.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 <utility>
32 #include <vector>
33 
34 #include <nifti1_io.h> // NOLINT: brainlint thinks this is C System Header
35 
36 #include "WMWriteNIfTI.h"
37 #include "core/common/WAssert.h"
38 #include "core/common/WPathHelper.h"
39 #include "core/common/WStringUtils.h"
40 #include "core/dataHandler/WDataSetRawHARDI.h"
41 #include "core/dataHandler/WGridRegular3D.h"
42 #include "core/kernel/WKernel.h"
43 #include "core/kernel/WModule.h"
44 
46  WModule()
47 {
48  // WARNING: initializing connectors inside the constructor will lead to an exception.
49  // Implement WModule::initializeConnectors instead.
50 }
51 
53 {
54  // cleanup
56 }
57 
58 std::shared_ptr< WModule > WMWriteNIfTI::factory() const
59 {
60  return std::shared_ptr< WModule >( new WMWriteNIfTI() );
61 }
62 
63 const char** WMWriteNIfTI::getXPMIcon() const
64 {
65  static const char * disc_xpm[] =
66  {
67  "16 16 7 1", " c None", ". c #000080", "+ c #000000", "@ c #FFFF00", "# c #E0E0E0",
68  "$ c #FFFFFF", "% c #C0C0C0", "..+++++++++++..+", "..@@@@@@@@@@@..+", "..###########..+",
69  "..$$$$$$$$$$$..+", "..###########..+", "..$$$$$$$$$$$..+", "..###########..+", "..$$$$$$$$$$$..+",
70  "...............+", "....%%%%%%%....+", "....%..%%%%....+", "....%..%%%%....+", "....%..%%%%....+",
71  "....%..%%%%....+", "+...%%%%%%%....+", "++++++++++++++++"
72  };
73  return disc_xpm;
74 }
75 
76 const std::string WMWriteNIfTI::getName() const
77 {
78  return "Write NIfTI";
79 }
80 
81 const std::string WMWriteNIfTI::getDescription() const
82 {
83  return "Writes a data set to a NIfTI file.";
84 }
85 
87 {
88  // use the m_input "data changed" flag
89  m_moduleState.setResetable( true, true );
90  m_moduleState.add( m_input->getDataChangedCondition() );
91  m_moduleState.add( m_saveTriggerProp->getCondition() );
92 
93  // signal ready state
94  ready();
95 
96  // loop until the module container requests the module to quit
97  while( !m_shutdownFlag() )
98  {
99  debugLog() << "Waiting for data ...";
100 
102 
103  // acquire data from the input connector
104  m_dataSet = m_input->getData();
105  if( !m_dataSet )
106  {
107  continue;
108  }
110  {
111  writeToFile();
112  m_saveTriggerProp->set( WPVBaseTypes::PV_TRIGGER_READY, false ); // reset button to save again
113  }
114  }
115 }
116 
118 {
119  m_input = WModuleInputData< WDataSetSingle >::createAndAdd( shared_from_this(), "in", "The dataset to filter" );
120 
122 }
123 
125 {
126  m_filename = m_properties->addProperty( "Filename", "Filename where to write the NIfTI file to.", WPathHelper::getAppPath() );
127  m_saveTriggerProp = m_properties->addProperty( "Do save", "Press!", WPVBaseTypes::PV_TRIGGER_READY );
128 
130 }
131 
132 template< typename T > void WMWriteNIfTI::castData( void*& returnData )
133 {
134  // cast valueset
135  std::shared_ptr< WValueSetBase > valsB = ( *m_dataSet ).getValueSet();
136  std::shared_ptr< WValueSet< T > > vals = std::dynamic_pointer_cast< WValueSet< T > >( ( *m_dataSet ).getValueSet() );
137  WAssert( vals, "Seems that value set type is not yet supported." );
138  const size_t vDim = vals->dimension();
139  // cast grid
140  std::shared_ptr< WGridRegular3D > grid = std::dynamic_pointer_cast< WGridRegular3D >( m_dataSet->getGrid() );
141  const size_t countVoxels = grid->getNbCoordsX() * grid->getNbCoordsY() * grid->getNbCoordsZ();
142  WAssert( grid, "Seems that grid is of wrong type." );
143 
144  // copy data
145  T* data = new T[vals->rawSize()];
146  for( size_t i = 0; i < countVoxels; ++i )
147  {
148  for( size_t j = 0; j < vDim; ++j )
149  {
150  data[( j * countVoxels ) + i] = static_cast< T > ( vals->getScalar( i * vDim + j ) );
151  }
152  }
153  returnData = static_cast< void* > ( data );
154 }
155 
157 {
158  infoLog() << "Writing Data to " << m_filename->get().string();
159  nifti_image *outField = nifti_simple_init_nim();
160 
161  std::shared_ptr< WGridRegular3D > grid = std::dynamic_pointer_cast< WGridRegular3D >( m_dataSet->getGrid() );
162  WAssert( grid, "Seems that grid is of wrong type." );
163 
164  size_t nbValues = ( *m_dataSet ).getValueSet()->size();
165 
166  outField->nx = grid->getNbCoordsX();
167  outField->ny = grid->getNbCoordsY();
168  outField->nz = grid->getNbCoordsZ();
169  WAssert( grid->getNbCoordsX() * grid->getNbCoordsY() * grid->getNbCoordsZ() == nbValues,
170  "Overall size incompatible with size in axis directions." );
171 
172  outField->nvox = nbValues*m_dataSet->getValueSet()->dimension();
173 
174  outField->dx = grid->getOffsetX();
175  outField->dy = grid->getOffsetY();
176  outField->dz = grid->getOffsetZ();
177 
178  outField->nifti_type = 1; // 1==NIFTI-1 (1 file)
179 
180  outField->freq_dim = 1;
181  outField->phase_dim = 2;
182  outField->slice_dim = 3;
183 
184  outField->qform_code = 1;
185  outField->sform_code = 1;
186 
187  // TODO(philips): solve ticket 334
188  // set time dimension to 1
189  // wrong, according to nifti specs
190  outField->nt = m_dataSet->getValueSet()->dimension();
191  outField->dim[0] = 4;
192  // right, according to nifti specs
193 
194  // wrong, according to nifti specs
195  outField->ndim = 4;
196  // right, according to nifti specs
197  std::string description = m_dataSet->getName();
198  // a description max. 80 char
199  description.copy( outField->descrip, 80 );
200 
201  WMatrix< double > matrix = grid->getTransformationMatrix();
202  for( size_t i = 0; i < 4; ++i )
203  {
204  for( size_t j = 0; j < 4; ++j )
205  {
206  outField->qto_xyz.m[i][j] = matrix( i, j );
207  outField->sto_xyz.m[i][j] = matrix( i, j );
208  }
209  }
210 
211  {
212  float dx, dy, dz;
213  nifti_mat44_to_quatern( outField->qto_xyz, &( outField->quatern_b ),
214  &( outField->quatern_c ), &( outField->quatern_d ),
215  &( outField->qoffset_x ), &( outField->qoffset_y ),
216  &( outField->qoffset_z ),
217  &dx, &dy, &dz,
218  &( outField->qfac ) );
219  }
220 
221  outField->qto_ijk = nifti_mat44_inverse( outField->qto_xyz );
222  outField->sto_ijk = nifti_mat44_inverse( outField->sto_xyz );
223 
224  void* data = 0;
225  switch( ( *m_dataSet ).getValueSet()->getDataType() )
226  {
227  case W_DT_DOUBLE:
228  outField->datatype = DT_DOUBLE;
229  castData< double > ( data );
230  outField->nbyper = 8;
231  break;
232  case W_DT_FLOAT:
233  outField->datatype = DT_FLOAT;
234  castData< float > ( data );
235  outField->nbyper = 4;
236  break;
237  case W_DT_UNSIGNED_CHAR:
238  outField->datatype = DT_UNSIGNED_CHAR;
239  castData< uint8_t > ( data );
240  outField->nbyper = 1;
241  break;
242  case W_DT_INT8:
243  outField->datatype = DT_INT8;
244  castData< int8_t > ( data );
245  outField->nbyper = 1;
246  break;
247  case W_DT_UINT16:
248  outField->datatype = DT_UINT16;
249  castData< uint16_t > ( data );
250  outField->nbyper = 2;
251  break;
252  case W_DT_INT16:
253  outField->datatype = DT_INT16;
254  castData< int16_t > ( data );
255  outField->nbyper = 2;
256  break;
257  case W_DT_UINT32:
258  outField->datatype = DT_UINT32;
259  castData< uint32_t > ( data );
260  outField->nbyper = 4;
261  break;
262  case W_DT_SIGNED_INT:
263  outField->datatype = DT_SIGNED_INT;
264  castData< int32_t > ( data );
265  outField->nbyper = 4;
266  break;
267  default:
268  WAssert( false, "Data set type not yet supported." );
269  }
270  outField->data = data;
271 
272  std::string s = m_filename->get().string();
273  if( nifti_set_filenames( outField, s.c_str(), 0, 1 ) )
274  {
275  throw WException( std::string( "NIfTI filename Problem" ) );
276  }
277 
278  nifti_image_write( outField );
279 
280  std::shared_ptr< WDataSetRawHARDI > h = std::dynamic_pointer_cast< WDataSetRawHARDI >( m_dataSet );
281  if( h )
282  {
283  std::fstream f( ( s + ".bvec" ).c_str(), std::ios_base::out );
284  for( std::size_t i = 0; i < 3; ++i )
285  {
286  for( std::size_t k = 0; k < h->getNumberOfMeasurements(); ++k )
287  {
288  f << h->getGradient( k )[ i ] << " ";
289  }
290  f << std::endl;
291  }
292  f.close();
293  }
294 
295  nifti_image_free( outField );
296  infoLog() << "Writing data completed.";
297 }
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.
Basic exception handler.
Definition: WException.h:39
~WMWriteNIfTI()
Destructor.
virtual const std::string getName() const
Gives back the name of this module.
std::shared_ptr< WModuleInputData< WDataSetSingle > > m_input
Input connector required by this module.
Definition: WMWriteNIfTI.h:124
void castData(void *&returnData)
Allows one to get a void* out of WValueSet.
virtual void moduleMain()
Entry point after loading the module.
WMWriteNIfTI()
Standard constructor.
WPropTrigger m_saveTriggerProp
This property triggers the actual writing,.
Definition: WMWriteNIfTI.h:122
WPropFilename m_filename
The filename property -> where to write the nifty file.
Definition: WMWriteNIfTI.h:121
virtual void properties()
Initialize the properties for this module.
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< WDataSetSingle > m_dataSet
Pointer providing access to the treated data set in the whole module.
Definition: WMWriteNIfTI.h:125
virtual const char ** getXPMIcon() const
Get the icon for this module in XPM format.
virtual const std::string getDescription() const
Gives back a description of this module.
virtual void connectors()
Initialize the connectors this module is using.
void writeToFile()
This performs all work necessary to actually write the data to the file.
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 ...
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
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 infoLog() const
Logger instance for comfortable info logging.
Definition: WModule.cpp:565
virtual void connectors()
Initialize connectors in this function.
Definition: WModule.cpp:208
static boost::filesystem::path getAppPath()
The path where the binary file resides in.
Definition: WPathHelper.cpp:93
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
@ PV_TRIGGER_TRIGGERED
Trigger property: got triggered.
@ PV_TRIGGER_READY
Trigger property: is ready to be triggered (again)