33 #include "WReaderNIfTI.h"
34 #include "core/common/WIOTools.h"
35 #include "core/common/WLogger.h"
36 #include "core/dataHandler/WDataHandlerEnums.h"
37 #include "core/dataHandler/WDataSet.h"
38 #include "core/dataHandler/WDataSetDTI.h"
39 #include "core/dataHandler/WDataSetRawHARDI.h"
40 #include "core/dataHandler/WDataSetScalar.h"
41 #include "core/dataHandler/WDataSetSegmentation.h"
42 #include "core/dataHandler/WDataSetSingle.h"
43 #include "core/dataHandler/WDataSetSphericalHarmonics.h"
44 #include "core/dataHandler/WDataSetTimeSeries.h"
45 #include "core/dataHandler/WDataSetVector.h"
46 #include "core/dataHandler/WGrid.h"
47 #include "core/dataHandler/WGridRegular3D.h"
48 #include "core/dataHandler/WSubject.h"
49 #include "core/dataHandler/WValueSet.h"
50 #include "core/dataHandler/WValueSetBase.h"
59 template<
typename T > std::shared_ptr< std::vector< T > >
WReaderNIfTI::copyArray(
const T* dataArray,
const size_t countVoxels,
62 std::shared_ptr< std::vector< T > > data(
new std::vector< T >( countVoxels * vDim ) );
63 for(
unsigned int i = 0; i < countVoxels; ++i )
65 for(
unsigned int j = 0; j < vDim; ++j )
67 (*data)[i * vDim + j] = dataArray[( j * countVoxels ) + i];
79 for(
size_t i = 0; i < 4; ++i )
81 for(
size_t j = 0; j < 4; ++j )
83 out( i, j ) = in.m[i][j];
84 isZero = isZero && out( i, j ) == 0.0;
97 std::string gradientFileName =
m_fname;
98 std::string suffix = getSuffix(
m_fname );
100 if( suffix ==
".gz" )
102 WAssert( gradientFileName.length() > 3,
"" );
103 gradientFileName.resize( gradientFileName.length() - 3 );
104 suffix = getSuffix( gradientFileName );
106 WAssert( suffix ==
".nii",
"Input file is not a nifti file." );
108 WAssert( gradientFileName.length() > 4,
"" );
109 gradientFileName.resize( gradientFileName.length() - 4 );
110 gradientFileName +=
".bvec";
115 std::ifstream i( gradientFileName.c_str() );
116 if( i.bad() || !i.is_open() )
122 wlog::debug(
"WReaderNIfTI" ) <<
"Could not find gradient file expected at: \"" << gradientFileName <<
"\", skipping this.";
126 wlog::debug(
"WReaderNIfTI" ) <<
"Found b-vectors file: " << gradientFileName <<
" will try reading...";
127 result =
GradVec(
new std::vector< WVector3d >( vDim ) );
131 for(
unsigned int j = 0; j < 3; ++j )
133 for(
unsigned int k = 0; k < vDim; ++k )
135 i >> result->operator[] ( k )[ j ];
138 bool success = !i.eof();
142 wlog::error(
"WReaderNIfTI" ) <<
"Error while reading gradient file: did not contain enough gradients: " << result->size();
147 wlog::debug(
"WReaderNIfTI" ) <<
"Successfully loaded " << result->size() <<
" gradients";
155 std::string bvaluesFileName =
m_fname;
156 std::string suffix = getSuffix(
m_fname );
158 if( suffix ==
".gz" )
160 WAssert( bvaluesFileName.length() > 3,
"" );
161 bvaluesFileName.resize( bvaluesFileName.length() - 3 );
162 suffix = getSuffix( bvaluesFileName );
164 WAssert( suffix ==
".nii",
"Input file is not a nifti file." );
166 WAssert( bvaluesFileName.length() > 4,
"" );
167 bvaluesFileName.resize( bvaluesFileName.length() - 4 );
168 bvaluesFileName +=
".bval";
173 std::ifstream i( bvaluesFileName.c_str() );
174 if( i.bad() || !i.is_open() )
180 wlog::debug(
"WReaderNIfTI" ) <<
"Could not find b-values file expected at: \"" << bvaluesFileName <<
"\", skipping this.";
187 result =
BValues(
new std::vector< float >( vDim * 3, 0 ) );
188 size_t numValues = 0;
189 while( i.good() && !i.eof() )
191 i.getline( value, 8 );
193 std::istringstream( value ) >> fVal;
194 ( *result )[ numValues ] = fVal;
195 if( numValues > vDim * 3 )
197 wlog::error(
"WReaderNIfTI" ) <<
"Too many b-Values: " << numValues <<
" but expected: " << vDim * 3;
205 wlog::debug(
"WReaderNIfTI" ) <<
"Found b-values file and loaded " << result->size() <<
" values.";
212 std::shared_ptr< nifti_image > filedata( nifti_image_read(
m_fname.c_str(), 1 ), &nifti_image_free );
214 WAssert( filedata,
"Error during file access to NIfTI file. This probably means that the file is corrupted." );
216 WAssert( filedata->ndim >= 3,
217 "The NIfTI file contains data that has less than the three spatial dimension. OpenWalnut is not able to handle this." );
219 int columns = filedata->dim[1];
220 int rows = filedata->dim[2];
221 int frames = filedata->dim[3];
223 std::shared_ptr< WValueSetBase > newValueSet;
224 std::shared_ptr< WGrid > newGrid;
227 if( filedata->ndim >= 4 )
229 vDim = filedata->dim[4];
236 unsigned int order = ( ( vDim == 1 ) ? 0 : 1 );
237 unsigned int countVoxels = columns * rows * frames;
240 if( filedata->dim[ 5 ] <= 1 )
242 switch( filedata->datatype )
246 std::shared_ptr< std::vector< uint8_t > > data =
copyArray(
reinterpret_cast< uint8_t*
>( filedata->data ), countVoxels, vDim );
247 newValueSet = std::shared_ptr< WValueSetBase >(
new WValueSet< uint8_t >( order, vDim, data, W_DT_UINT8 ) );
252 std::shared_ptr< std::vector< int8_t > > data =
copyArray(
reinterpret_cast< int8_t*
>( filedata->data ), countVoxels, vDim );
253 newValueSet = std::shared_ptr< WValueSetBase >(
new WValueSet< int8_t >( order, vDim, data, W_DT_INT8 ) );
258 std::shared_ptr< std::vector< int16_t > > data =
copyArray(
reinterpret_cast< int16_t*
>( filedata->data ), countVoxels, vDim );
259 newValueSet = std::shared_ptr< WValueSetBase >(
new WValueSet< int16_t >( order, vDim, data, W_DT_INT16 ) );
264 std::shared_ptr< std::vector< uint16_t > > data
265 =
copyArray(
reinterpret_cast< uint16_t*
>( filedata->data ), countVoxels, vDim );
266 newValueSet = std::shared_ptr< WValueSetBase >(
new WValueSet< uint16_t >( order, vDim, data, W_DT_UINT16 ) );
271 std::shared_ptr< std::vector< int32_t > > data =
copyArray(
reinterpret_cast< int32_t*
>( filedata->data ), countVoxels, vDim );
272 newValueSet = std::shared_ptr< WValueSetBase >(
new WValueSet< int32_t >( order, vDim, data, W_DT_SIGNED_INT ) );
277 std::shared_ptr< std::vector< uint32_t > > data
278 =
copyArray(
reinterpret_cast< uint32_t*
>( filedata->data ), countVoxels, vDim );
279 newValueSet = std::shared_ptr< WValueSetBase >(
new WValueSet< uint32_t >( order, vDim, data, W_DT_UINT32 ) );
284 std::shared_ptr< std::vector< int64_t > > data =
copyArray(
reinterpret_cast< int64_t*
>( filedata->data ), countVoxels, vDim );
285 newValueSet = std::shared_ptr< WValueSetBase >(
new WValueSet< int64_t >( order, vDim, data, W_DT_INT64 ) );
290 std::shared_ptr< std::vector< uint64_t > > data =
291 copyArray(
reinterpret_cast< uint64_t*
>( filedata->data ), countVoxels, vDim );
292 newValueSet = std::shared_ptr< WValueSetBase >(
new WValueSet< uint64_t >( order, vDim, data, W_DT_UINT64 ) );
297 std::shared_ptr< std::vector< float > > data =
copyArray(
reinterpret_cast< float*
>( filedata->data ), countVoxels, vDim );
298 newValueSet = std::shared_ptr< WValueSetBase >(
new WValueSet< float >( order, vDim, data, W_DT_FLOAT ) );
303 std::shared_ptr< std::vector< double > > data =
copyArray(
reinterpret_cast< double*
>( filedata->data ), countVoxels, vDim );
304 newValueSet = std::shared_ptr< WValueSetBase >(
new WValueSet< double >( order, vDim, data, W_DT_DOUBLE ) );
309 std::shared_ptr< std::vector< long double > > data =
310 copyArray(
reinterpret_cast< long double*
>( filedata->data ), countVoxels, vDim );
315 wlog::error(
"WReaderNIfTI" ) <<
"unknown data type " << filedata->datatype << std::endl;
316 newValueSet = std::shared_ptr< WValueSetBase >();
322 newGrid = std::shared_ptr< WGridRegular3D >(
325 std::shared_ptr< WDataSet > newDataSet;
327 std::string description( filedata->descrip );
328 if( !description.compare(
"WDataSetSegmentation" ) )
330 wlog::debug(
"WReaderNIfTI" ) <<
"Load as segmentation" << std::endl;
333 else if( description.compare(
"WDataSetSphericalHarmonics" ) == 0 || dataSetType == W_DATASET_SPHERICALHARMONICS )
335 wlog::debug(
"WReaderNIfTI" ) <<
"Load as spherical harmonics" << std::endl;
341 else if( filedata->dim[ 5 ] > 1 )
343 WAssert( filedata->dim[ 4 ] == 1,
"Only scalar datasets are supported for time series so far." );
344 wlog::debug(
"WReaderNIfTI" ) <<
"Load as WDataSetTimeSeries";
345 std::size_t numTimeSlices = filedata->dim[ 5 ];
346 float tw = filedata->pixdim[ 5 ];
347 WAssert( tw != 0.0f,
"" );
349 std::vector< std::shared_ptr< WDataSetScalar const > > ds;
350 std::vector< float > times;
352 for( std::size_t k = 0; k < numTimeSlices; ++k )
354 times.push_back( t );
356 std::shared_ptr< WValueSetBase > vs;
357 switch( filedata->datatype )
361 uint8_t* ptr =
reinterpret_cast< uint8_t*
>( filedata->data );
362 std::shared_ptr< std::vector< uint8_t > > values =
363 std::shared_ptr< std::vector< uint8_t > >(
364 new std::vector< uint8_t >( ptr + k * countVoxels, ptr + ( k + 1 ) * countVoxels ) );
370 int8_t* ptr =
reinterpret_cast< int8_t*
>( filedata->data );
371 std::shared_ptr< std::vector< int8_t > > values =
372 std::shared_ptr< std::vector< int8_t > >(
373 new std::vector< int8_t >( ptr + k * countVoxels, ptr + ( k + 1 ) * countVoxels ) );
374 vs = std::shared_ptr< WValueSetBase >(
new WValueSet< int8_t >( 0, 1, values, W_DT_INT8 ) );
379 uint16_t* ptr =
reinterpret_cast< uint16_t*
>( filedata->data );
380 std::shared_ptr< std::vector< uint16_t > >values =
381 std::shared_ptr< std::vector< uint16_t > >(
382 new std::vector< uint16_t >( ptr + k * countVoxels, ptr + ( k + 1 ) * countVoxels ) );
388 int16_t* ptr =
reinterpret_cast< int16_t*
>( filedata->data );
389 std::shared_ptr< std::vector< int16_t > > values =
390 std::shared_ptr< std::vector< int16_t > >(
391 new std::vector< int16_t >( ptr + k * countVoxels, ptr + ( k + 1 ) * countVoxels ) );
397 uint32_t* ptr =
reinterpret_cast< uint32_t*
>( filedata->data );
398 std::shared_ptr< std::vector< uint32_t > > values =
399 std::shared_ptr< std::vector< uint32_t > >(
400 new std::vector< uint32_t >( ptr + k * countVoxels, ptr + ( k + 1 ) * countVoxels ) );
406 int32_t* ptr =
reinterpret_cast< int32_t*
>( filedata->data );
407 std::shared_ptr< std::vector< int32_t > > values =
408 std::shared_ptr< std::vector< int32_t > >(
409 new std::vector< int32_t >( ptr + k * countVoxels, ptr + ( k + 1 ) * countVoxels ) );
410 vs = std::shared_ptr< WValueSetBase >(
new WValueSet< int32_t >( 0, 1, values, W_DT_SIGNED_INT ) );
415 uint64_t* ptr =
reinterpret_cast< uint64_t*
>( filedata->data );
416 std::shared_ptr< std::vector< uint64_t > > values =
417 std::shared_ptr< std::vector< uint64_t > >(
418 new std::vector< uint64_t >( ptr + k * countVoxels, ptr + ( k + 1 ) * countVoxels ) );
424 int64_t* ptr =
reinterpret_cast< int64_t*
>( filedata->data );
425 std::shared_ptr< std::vector< int64_t > > values =
426 std::shared_ptr< std::vector< int64_t > >(
427 new std::vector< int64_t >( ptr + k * countVoxels, ptr + ( k + 1 ) * countVoxels ) );
433 float* ptr =
reinterpret_cast< float*
>( filedata->data );
434 std::shared_ptr< std::vector< float > > values =
435 std::shared_ptr< std::vector< float > >(
436 new std::vector< float >( ptr + k * countVoxels, ptr + ( k + 1 ) * countVoxels ) );
437 vs = std::shared_ptr< WValueSetBase >(
new WValueSet< float >( 0, 1, values, W_DT_FLOAT ) );
442 double* ptr =
reinterpret_cast< double*
>( filedata->data );
443 std::shared_ptr< std::vector< double > > values =
444 std::shared_ptr< std::vector< double > >(
445 new std::vector< double >( ptr + k * countVoxels, ptr + ( k + 1 ) * countVoxels ) );
446 vs = std::shared_ptr< WValueSetBase >(
new WValueSet< double >( 0, 1, values, W_DT_DOUBLE ) );
450 throw WException( std::string(
"Unsupported datatype in WReaderNIfTI" ) );
453 ds.push_back( std::shared_ptr< WDataSetScalar >(
new WDataSetScalar( vs, newGrid ) ) );
462 wlog::debug(
"WReaderNIfTI" ) <<
"Load as WDataSetVector";
463 newDataSet = std::shared_ptr< WDataSet >(
new WDataSetVector( newValueSet, newGrid ) );
467 wlog::debug(
"WReaderNIfTI" ) <<
"Load as WDataSetScalar";
468 newDataSet = std::shared_ptr< WDataSet >(
new WDataSetScalar( newValueSet, newGrid ) );
470 else if( vDim > 20 && filedata->dim[ 5 ] <= 1 )
472 wlog::debug(
"WReaderNIfTI" ) <<
"Load as WDataSetRawHARDI";
480 newDataSet = std::shared_ptr< WDataSet >(
new WDataSetSingle( newValueSet, newGrid ) );
481 wlog::debug(
"WReaderNIfTI" ) <<
"No gradients given. See above for expected filename. Loading as WDataSetSingle instead.";
487 newDataSet = std::shared_ptr< WDataSet >(
new WDataSetRawHARDI( newValueSet, newGrid, newGradients ) );
491 newDataSet = std::shared_ptr< WDataSet >(
new WDataSetRawHARDI( newValueSet, newGrid, newGradients, newBValues ) );
495 if( newBValues && newGradients && ( newBValues->size() > 1 && newBValues->size() != newGradients->size() * 3 ) )
497 wlog::warn(
"WReaderNIfTI" ) <<
"Be careful: there are " << newBValues->size() / 3 <<
" b-values but only "
498 << newGradients->size() <<
" gradients.";
501 else if( filedata->intent_code == NIFTI_INTENT_SYMMATRIX )
503 wlog::debug(
"WReaderNIfTI" ) <<
"Load as WDataSetDTI";
504 newDataSet = std::shared_ptr< WDataSetDTI >(
new WDataSetDTI( newValueSet, newGrid ) );
508 wlog::debug(
"WReaderNIfTI" ) <<
"Load as WDataSetSingle";
509 newDataSet = std::shared_ptr< WDataSet >(
new WDataSetSingle( newValueSet, newGrid ) );
512 newDataSet->setFilename(
m_fname );
Represents a Diffusion-Tensor-Image dataset.
This data set type contains raw HARDI and its gradients.
This data set type contains scalars as values.
A dataset that stores the segmentation of the brain into CSF, white and gray matter.
A data set consisting of a set of values based on a grid.
This data set type contains spherical harmonic coefficients as values.
A dataset that stores a time series.
This data set type contains vectors as values.
A grid that has parallelepiped cells which all have the same proportion.
WMatrix & makeIdentity()
Makes the matrix contain the identity matrix, i.e.
WMatrix< double > getQFormTransform() const
Returns the QForm transformation stored in the nifti file's header.
WMatrix< double > convertMatrix(const mat44 &in)
This function converts a 4x4 matrix from the NIfTI libs into the format used by OpenWalnut.
WMatrix< double > m_sform
the sform transform stored in the file header
WReaderNIfTI(std::string fileName)
Constructs a loader to be executed in its own thread and ets the data needed for the loader when exec...
GradVec readGradientsIfAvailable(unsigned int vDim)
Reads the additional gradient file if available.
WMatrix< double > getSFormTransform() const
Returns the SForm transformation stored in the nifti file's header.
WMatrix< double > m_qform
the qform transform stored in the file header
std::shared_ptr< std::vector< T > > copyArray(const T *dataArray, const size_t countVoxels, const size_t vDim)
This function allows one to copy the data given as a T* by niftilibio into a std::vector< T >
std::shared_ptr< std::vector< WVector3d > > GradVec
Shorthand type for a vector of gradients.
std::shared_ptr< std::vector< float > > BValues
Shorthand type for a vector of bvalues.
WMatrix< double > getStandardTransform() const
Returns a standard transformation.
virtual std::shared_ptr< WDataSet > load(DataSetType dataSetType=W_DATASET_NONE)
Loads the dataset.
BValues readBValuesIfAvailable(unsigned int vDim)
Reads the additional bval file if available.
Read some data from a given file.
std::string m_fname
Absolute path of the file to read from.
Base Class for all value set types.
DataSetType
Data set types.
WStreamedLogger debug(const std::string &source)
Logging a debug message.
WStreamedLogger warn(const std::string &source)
Logging a warning message.
WStreamedLogger error(const std::string &source)
Logging an error message.