Orfeo Toolbox  3.16
itkPhilipsRECImageIO.cxx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkPhilipsRECImageIO.cxx,v $
5  Language: C++
6  Date: $Date: 2009-11-29 02:06:56 $
7  Version: $Revision: 1.14 $
8 
9  Copyright (c) Insight Software Consortium. All rights reserved.
10  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
11 
12  This software is distributed WITHOUT ANY WARRANTY; without even
13  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  PURPOSE. See the above copyright notices for more information.
15 
16 =========================================================================*/
26 #include "itkPhilipsRECImageIO.h"
27 #include "itkPhilipsPAR.h"
28 #include "itkIOCommon.h"
29 #include "itkExceptionObject.h"
30 #include "itkByteSwapper.h"
31 #include "itkMetaDataObject.h"
33 #include <itksys/SystemTools.hxx>
34 #include "itk_zlib.h"
35 #include <fstream>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <vector>
39 
40 namespace itk
41 {
42 
43 const char *const PAR_Version = "PAR_Version";
44 const char *const PAR_SliceOrientation = "PAR_SliceOrientation";
45 const char *const PAR_ExaminationName = "PAR_ExaminationName";
46 const char *const PAR_ProtocolName = "PAR_ProtocolName";
47 const char *const PAR_SeriesType = "PAR_SeriesType";
48 const char *const PAR_AcquisitionNr = "PAR_AcquisitionNr";
49 const char *const PAR_ReconstructionNr = "PAR_ReconstructionNr";
50 const char *const PAR_ScanDuration = "PAR_ScanDuration";
51 const char *const PAR_MaxNumberOfCardiacPhases = "PAR_MaxNumberOfCardiacPhases";
52 const char *const PAR_TriggerTimes = "PAR_TriggerTimes";
53 const char *const PAR_MaxNumberOfEchoes = "PAR_MaxNumberOfEchoes";
54 const char *const PAR_EchoTimes = "PAR_EchoTimes";
55 const char *const PAR_MaxNumberOfDynamics = "PAR_MaxNumberOfDynamics";
56 const char *const PAR_MaxNumberOfMixes = "PAR_MaxNumberOfMixes";
57 const char *const PAR_PatientPosition = "PAR_PatientPosition";
58 const char *const PAR_PreparationDirection = "PAR_PreparationDirection";
59 const char *const PAR_Technique = "PAR_Technique";
60 const char *const PAR_ScanMode = "PAR_ScanMode";
61 const char *const PAR_NumberOfAverages = "PAR_NumberOfAverages";
62 const char *const PAR_ScanResolution = "PAR_ScanResolution";
63 const char *const PAR_RepetitionTimes = "PAR_RepetitionTimes";
64 const char *const PAR_ScanPercentage = "PAR_ScanPercentage";
65 const char *const PAR_FOV = "PAR_FOV";
66 const char *const PAR_WaterFatShiftPixels = "PAR_WaterFatShiftPixels";
67 const char *const PAR_AngulationMidSlice = "PAR_AngulationMidSlice";
68 const char *const PAR_OffCentreMidSlice = "PAR_OffCentreMidSlice";
69 const char *const PAR_FlowCompensation = "PAR_FlowCompensation";
70 const char *const PAR_Presaturation = "PAR_Presaturation";
71 const char *const PAR_CardiacFrequency = "PAR_CardiacFrequency";
72 const char *const PAR_MinRRInterval = "PAR_MinRRInterval";
73 const char *const PAR_MaxRRInterval = "PAR_MaxRRInterval";
74 const char *const PAR_PhaseEncodingVelocity = "PAR_PhaseEncodingVelocity";
75 const char *const PAR_MTC = "PAR_MTC";
76 const char *const PAR_SPIR = "PAR_SPIR";
77 const char *const PAR_EPIFactor = "PAR_EPIFactor";
78 const char *const PAR_TurboFactor = "PAR_TurboFactor";
79 const char *const PAR_DynamicScan = "PAR_DynamicScan";
80 const char *const PAR_Diffusion = "PAR_Diffusion";
81 const char *const PAR_DiffusionEchoTime = "PAR_DiffusionEchoTime";
82 const char *const PAR_MaxNumberOfDiffusionValues =
83  "PAR_MaxNumberOfDiffusionValues";
84 const char *const PAR_GradientBValues = "PAR_GradientBValues";
85 const char *const PAR_MaxNumberOfGradientOrients =
86  "PAR_MaxNumberOfGradientOrients";
87 const char *const PAR_GradientDirectionValues = "PAR_GradientDirectionValues";
88 const char *const PAR_InversionDelay = "PAR_InversionDelay";
89 const char *const PAR_NumberOfImageTypes = "PAR_NumberOfImageTypes";
90 const char *const PAR_ImageTypes = "PAR_ImageTypes";
91 const char *const PAR_NumberOfScanningSequences =
92  "PAR_NumberOfScanningSequences";
93 const char *const PAR_ScanningSequences = "PAR_ScanningSequences";
95  "PAR_ScanningSequenceImageTypeRescaleValues";
96 const char *const PAR_NumberOfASLLabelTypes = "PAR_NumberOfASLLabelTypes";
97 const char *const PAR_ASLLabelTypes = "PAR_ASLLabelTypes";
98 
99 static std::string
100 GetExtension( const std::string& filename )
101 {
102 
103  std::string fileExt(itksys::SystemTools::GetFilenameLastExtension(filename));
104  // If the last extension is .gz, then need to pull off 2 extensions.
105  //.gz is the only valid compression extension.
106  if(fileExt == std::string(".gz"))
107  {
108  fileExt = itksys::SystemTools::GetFilenameLastExtension(
109  itksys::SystemTools::GetFilenameWithoutLastExtension(filename));
110  fileExt += ".gz";
111  }
112  // Check that a valid extension was found
113  // Will check for either all caps or all lower-case.
114  // By default the Philips Pride Workstation outputs
115  // the filenames as all caps, but a user may change the
116  // filenames to lowercase. This will allow one or the
117  // other. Mixed caps/lower-case will always (with the
118  // exception of the lower-case gz on the end which is
119  // always assumed to be lower-case) fail on an OS with
120  // a case sensitive file system.
121  if(fileExt != ".REC.gz"
122  && fileExt != ".REC"
123  && fileExt != ".PAR"
124  && fileExt != ".rec.gz"
125  && fileExt != ".rec"
126  && fileExt != ".par")
127  {
128  return ( "" );
129  }
130 
131  return( fileExt );
132 }
133 
134 static std::string
135 GetRootName( const std::string& filename )
136 {
137  const std::string fileExt = GetExtension(filename);
138 
139  // Create a base filename
140  // i.e Image.PAR --> Image
141  if( fileExt.length() > 0
142  && filename.length() > fileExt.length() )
143  {
144  const std::string::size_type it = filename.find_last_of( fileExt );
145  std::string baseName( filename, 0, it-(fileExt.length()-1) );
146  return( baseName );
147  }
148  //Default to return same as input when the extension is nothing.
149  return( filename );
150 }
151 
152 
153 static std::string
154 GetHeaderFileName( const std::string & filename )
155 {
156  std::string ImageFileName(filename);
157  const std::string fileExt = GetExtension(filename);
158  // Accomodate either all caps or all lower-case filenames.
159  if( (fileExt == ".REC") || (fileExt == ".REC.gz") )
160  {
161  ImageFileName = GetRootName(filename);
162  ImageFileName += ".PAR";
163  }
164  else if( (fileExt == ".rec") || (fileExt == ".rec.gz") )
165  {
166  ImageFileName = GetRootName(filename);
167  ImageFileName += ".par";
168  }
169  return( ImageFileName );
170 }
171 
172 //Returns the base image filename.
173 static std::string GetImageFileName( const std::string& filename )
174 {
175  std::string ImageFileName(filename);
176  const std::string fileExt = GetExtension(filename);
177  // Default to uncompressed .REC if .PAR is given as file name.
178  if(fileExt == ".PAR")
179  {
180  ImageFileName = GetRootName(filename);
181  ImageFileName += ".REC";
182  }
183  else if(fileExt == ".par")
184  {
185  ImageFileName = GetRootName(filename);
186  ImageFileName += ".rec";
187  }
188  return( ImageFileName );
189 }
190 
191 //----------------------------------------------------------------------------
192 // This generates the correct offset to the desired image type and
193 // scanning sequence (randomly ordered in the REC).
194 int PhilipsRECImageIOGetImageTypeOffset(int imageType, int scanSequence,
195  int volumeIndex, int slice, int numSlices, struct par_parameter parParam,
196  PhilipsPAR::PARSliceIndexImageTypeVector sliceImageTypesIndex,
197  PhilipsPAR::PARSliceIndexScanSequenceVector sliceScanSequenceIndex)
198 {
199  int index = volumeIndex*parParam.num_slice_repetitions*numSlices +
200  slice*parParam.num_slice_repetitions;
201  int i;
202  for(i=0; i<parParam.num_slice_repetitions; i++)
203  {
204  if( (sliceImageTypesIndex[index+i].second == imageType) &&
205  (sliceScanSequenceIndex[index+i].second == scanSequence) )
206  {
207  break;
208  }
209  }
210  return i;
211 }
212 
213 //----------------------------------------------------------------------------
214 // This creates the desired slice order index (slice or image block).
216  PhilipsRECImageIO::SliceIndexType *indexMatrix, int sortBlock,
217  struct par_parameter parParam,
218  PhilipsPAR::PARImageTypeScanSequenceVector imageTypesScanSequenceIndex,
219  PhilipsPAR::PARSliceIndexImageTypeVector sliceImageTypesIndex,
220  PhilipsPAR::PARSliceIndexScanSequenceVector sliceScanSequenceIndex)
221 {
222  int index = 0;
223  int actualSlices = parParam.slice;
224  int remainingVolumes = parParam.image_blocks/parParam.num_slice_repetitions;
225 
226  if(indexMatrix->size() !=
227  (PhilipsRECImageIO::SliceIndexType::size_type)parParam.dim[2])
228  {
229  OStringStream message;
230  message << "indexMatrix->size(): "
231  << indexMatrix->size()
232  << " != parParam.dim[2]: "
233  << parParam.dim[2];
234  ExceptionObject exception(__FILE__, __LINE__,
235  message.str(),
236  ITK_LOCATION);
237  throw exception;
238  }
239  if(parParam.dim[2] != (parParam.slice*parParam.image_blocks))
240  {
241  OStringStream message;
242  message << "parParam.dim[2]: "
243  << parParam.dim[2]
244  << " != (parParam.slice*parParam.image_blocks): "
245  << parParam.slice * parParam.image_blocks;
246  ExceptionObject exception(__FILE__, __LINE__,
247  message.str(),
248  ITK_LOCATION);
249  throw exception;
250  }
251  if(imageTypesScanSequenceIndex.size() !=
252  (PhilipsRECImageIO::SliceIndexType::size_type)parParam.num_slice_repetitions)
253  {
254  OStringStream message;
255  message << "imageTypesScanSequenceIndex.size(): "
256  << imageTypesScanSequenceIndex.size()
257  << " != parParam.num_slice_repetitions "
258  << parParam.num_slice_repetitions;
259  ExceptionObject exception(__FILE__, __LINE__,
260  message.str(),
261  ITK_LOCATION);
262  throw exception;
263  }
264 
265  // Different index depending on the desired slice sort and the REC
266  // slice order.
267  if( (sortBlock && parParam.slicessorted) ||
268  (!sortBlock && !parParam.slicessorted) )
269  {
270  // No sorting nessecary for these cases.
271  for(int i=0; i<parParam.dim[2]; i++)
272  {
273  (*indexMatrix)[i] = i;
274  }
275  }
276  // This case is the real problematic one.
277  else if( sortBlock && !parParam.slicessorted &&
278  (parParam.num_slice_repetitions > 1) )
279  {
280  // Ok, need to figure out where all of the images are located
281  // using sliceImageTypesIndex and sliceScanSequenceIndex.
282  for(int i=0; i<parParam.num_slice_repetitions; i++)
283  {
284  for(int j=0; j<remainingVolumes; j++)
285  {
286  for(int k=0; k<actualSlices; k++)
287  {
288  (*indexMatrix)[index] = j*parParam.num_slice_repetitions*actualSlices
289  + k*parParam.num_slice_repetitions
291  imageTypesScanSequenceIndex[i].first,
292  imageTypesScanSequenceIndex[i].second,j,k,actualSlices,parParam,
293  sliceImageTypesIndex,sliceScanSequenceIndex);
294  index++;
295  }
296  }
297  }
298  }
299  else
300  {
301  // Unsort image block or sort by image block.
302  for(int i=0; i<parParam.image_blocks; i++)
303  {
304  for(int j=0; j<actualSlices; j++)
305  {
306  (*indexMatrix)[index] = j*parParam.image_blocks+i;
307  index++;
308  }
309  }
310  }
311 }
312 
313 void
315  unsigned long numberOfPixels )
316 {
317  if ( m_ByteOrder == LittleEndian )
318  {
319  switch(this->m_ComponentType)
320  {
321  case CHAR:
323  ((char*)buffer, numberOfPixels );
324  break;
325  case UCHAR:
327  ((unsigned char*)buffer, numberOfPixels );
328  break;
329  case SHORT:
331  ((short*)buffer, numberOfPixels );
332  break;
333  case USHORT:
335  ((unsigned short*)buffer, numberOfPixels );
336  break;
337  case INT:
339  ((int*)buffer, numberOfPixels );
340  break;
341  case UINT:
343  ((unsigned int*)buffer, numberOfPixels );
344  break;
345  case LONG:
347  ((long*)buffer, numberOfPixels );
348  break;
349  case ULONG:
351  ((unsigned long*)buffer, numberOfPixels );
352  break;
353  case FLOAT:
355  ((float*)buffer, numberOfPixels );
356  break;
357  case DOUBLE:
359  ((double*)buffer, numberOfPixels );
360  break;
361  default:
362  ExceptionObject exception(__FILE__, __LINE__,
363  "Component Type Unknown",
364  ITK_LOCATION);
365  throw exception;
366  }
367  }
368  else
369  {
370  switch(this->m_ComponentType)
371  {
372  case CHAR:
374  ((char *)buffer, numberOfPixels );
375  break;
376  case UCHAR:
378  ((unsigned char *)buffer, numberOfPixels );
379  break;
380  case SHORT:
382  ((short *)buffer, numberOfPixels );
383  break;
384  case USHORT:
386  ((unsigned short *)buffer, numberOfPixels );
387  break;
388  case INT:
390  ((int *)buffer, numberOfPixels );
391  break;
392  case UINT:
394  ((unsigned int *)buffer, numberOfPixels );
395  break;
396  case LONG:
398  ((long *)buffer, numberOfPixels );
399  break;
400  case ULONG:
402  ((unsigned long *)buffer, numberOfPixels );
403  break;
404  case FLOAT:
406  ((float *)buffer, numberOfPixels );
407  break;
408  case DOUBLE:
410  ((double *)buffer, numberOfPixels );
411  break;
412  default:
413  ExceptionObject exception(__FILE__, __LINE__,
414  "Component Type Unknown",
415  ITK_LOCATION);
416  throw exception;
417  }
418  }
419 }
420 
422 {
423  //by default, have 4 dimensions
424  this->SetNumberOfDimensions(4);
425  this->m_PixelType = SCALAR;
426  this->m_ComponentType = CHAR;
427 
428  // Set m_MachineByteOrder to the ByteOrder of the machine
429  // Start out with file byte order == system byte order
430  // this will be changed if we're reading a file to whatever
431  // the file actually contains.
433  {
434  this->m_MachineByteOrder = this->m_ByteOrder = BigEndian;
435  }
436  else
437  {
439  }
440  this->m_SliceIndex = new SliceIndexType();
441 }
442 
444 {
445  delete this->m_SliceIndex;
446 }
447 
448 void PhilipsRECImageIO::PrintSelf(std::ostream& os, Indent indent) const
449 {
450  Superclass::PrintSelf(os, indent);
451 }
452 
455 {
456  IndexValueType maximumSliceNumber =
457  Math::CastWithRangeCheck< IndexValueType, size_t >( this->m_SliceIndex->size() ) - 1;
458 
459  if( (index < 0) || (index > maximumSliceNumber ) )
460  {
461  return -1;
462  }
463  return (*this->m_SliceIndex)[index];
464 }
465 
466 void PhilipsRECImageIO::Read(void* buffer)
467 {
468  unsigned int dim;
469  const unsigned int dimensions = this->GetNumberOfDimensions();
470  unsigned int numberOfPixels = 1;
471  for(dim=0; dim< dimensions; dim++ )
472  {
473  numberOfPixels *= this->m_Dimensions[ dim ];
474  }
475 
476  char * const p = static_cast<char *>(buffer);
477  //6 cases to handle
478  //1: given .PAR and image is .REC
479  //2: given .REC
480  //3: given .REC.gz
481  //4: given .par and image is .rec
482  //5: given .rec
483  //6: given .rec.gz
484 
485  /* Returns proper name for cases 1,2,3,4,5,6 */
486  std::string ImageFileName = GetImageFileName( this->m_FileName );
487  //NOTE: gzFile operations act just like FILE * operations when the files
488  // are not in gzip fromat.
489  // This greatly simplifies the following code, and gzFile types are used
490  // everywhere.
491  // In addition, it has the added benifit of reading gzip compressed image
492  // files that do not have a .gz ending.
493  gzFile file_p = ::gzopen( ImageFileName.c_str(), "rb" );
494  if( file_p == NULL )
495  {
496  OStringStream message;
497  message << "Philips REC Data File can not be opened. "
498  << "The following files were attempted:" << std::endl
499  << GetImageFileName( this->m_FileName ) << std::endl
500  << ImageFileName;
501  ExceptionObject exception(__FILE__, __LINE__,
502  message.str(),
503  ITK_LOCATION);
504  throw exception;
505  }
506 
507  // read image a slice at a time (sorted).
508  const SizeType numberOfPixelsInOneSlice = this->m_Dimensions[2]*this->m_Dimensions[3]; // BUG ?
509 
510  SizeType imageSliceSizeInBytes = this->GetImageSizeInBytes() / numberOfPixelsInOneSlice;
511 
512  for( IndexValueType slice=0; slice < numberOfPixelsInOneSlice; slice++)
513  {
514  IndexValueType realIndex = this->GetSliceIndex((int)slice);
515  if( realIndex < 0 )
516  {
517  OStringStream message;
518  message << "Philips REC Data File can not be read. "
519  << "The following files were attempted:" << std::endl
520  << GetImageFileName( this->m_FileName ) << std::endl
521  << ImageFileName;
522  ExceptionObject exception(__FILE__, __LINE__,
523  message.str(),
524  ITK_LOCATION);
525  throw exception;
526  }
527  const z_off_t offset = Math::CastWithRangeCheck< z_off_t, SizeType >( realIndex * imageSliceSizeInBytes );
528  ::gzseek( file_p, offset, SEEK_SET );
529  ::gzread( file_p, p+(slice*imageSliceSizeInBytes),
530  Math::CastWithRangeCheck< unsigned int, SizeType >( imageSliceSizeInBytes) );
531  }
532  gzclose( file_p );
533  SwapBytesIfNecessary( buffer, numberOfPixels );
534 }
535 
536 bool PhilipsRECImageIO::CanReadFile( const char* FileNameToRead )
537 {
538  std::string filename(FileNameToRead);
539 
540  // we check that the correct extension is given by the user
541  std::string filenameext = GetExtension(filename);
542  if( filenameext != std::string(".PAR")
543  && filenameext != std::string(".REC")
544  && filenameext != std::string(".REC.gz")
545  && filenameext != std::string(".par")
546  && filenameext != std::string(".rec")
547  && filenameext != std::string(".rec.gz"))
548  {
549  return false;
550  }
551 
552  const std::string HeaderFileName = GetHeaderFileName(filename);
553 
554  // Try to read the par file.
555  struct par_parameter par;
556  // Zero out par_parameter.
557  memset(&par,0, sizeof(struct par_parameter));
558 
559  PhilipsPAR::Pointer philipsPAR = PhilipsPAR::New();
560  try
561  {
562  philipsPAR->ReadPAR(HeaderFileName, &par);
563  // Check to see if there were any problems reading
564  // the par file.
565  if( par.problemreading )
566  {
567  return false;
568  }
569  }
570  catch(ExceptionObject &)
571  {
572  return false;
573  }
574 
575  return true;
576 }
577 
579 {
580  const std::string HeaderFileName = GetHeaderFileName( this->m_FileName );
581  struct par_parameter par;
582 
583  // Zero out par_parameter.
584  memset(&par,0, sizeof(struct par_parameter));
585 
586  // Read PAR file.
587  PhilipsPAR::Pointer philipsPAR = PhilipsPAR::New();
588  try
589  {
590  philipsPAR->ReadPAR( HeaderFileName, &par);
591  }
592  catch(itk::ExceptionObject &err)
593  {
594  throw err;
595  }
596  if( par.problemreading )
597  {
598  ExceptionObject exception(__FILE__, __LINE__,
599  "Problem reading PAR file",
600  ITK_LOCATION);
601  throw exception;
602  }
603 
604  // Get all the diffusion info, rescale, etc.
605  GradientBvalueContainerType::Pointer diffusionBvalueVector
607  GradientDirectionContainerType::Pointer diffusionGradientOrientationVector
609  if( !philipsPAR->GetDiffusionGradientOrientationAndBValues(HeaderFileName,
610  diffusionGradientOrientationVector, diffusionBvalueVector) )
611  {
612  ExceptionObject exception(__FILE__, __LINE__,
613  "Problem reading diffusion gradients and b values from PAR file",
614  ITK_LOCATION);
615  throw exception;
616  }
617 
618  // Get ASL label types.
619  LabelTypesASLContainerType::Pointer labelTypesASLVector =
621  if( !philipsPAR->GetLabelTypesASL(HeaderFileName, labelTypesASLVector) )
622  {
623  ExceptionObject exception(__FILE__, __LINE__,
624  "Problem reading ASL label types from PAR file",
625  ITK_LOCATION);
626  throw exception;
627  }
628 
629  // Get rescale values associated with each scanning sequence.
631  scanningSequenceImageTypeRescaleVector =
633  scanningSequenceImageTypeRescaleVector->clear();
634  // Must match number of scanning sequences.
635  scanningSequenceImageTypeRescaleVector->resize(par.num_scanning_sequences);
636  for(int scanIndex=0; scanIndex<par.num_scanning_sequences; scanIndex++)
637  {
638  ImageTypeRescaleValuesContainerType::Pointer imageTypeRescaleValuesVector =
640  if( !philipsPAR->GetRECRescaleValues(HeaderFileName,imageTypeRescaleValuesVector,
641  par.scanning_sequences[scanIndex]) )
642  {
643  ExceptionObject exception(__FILE__, __LINE__,
644  "Problem reading recale values for each scanning sequence from PAR file",
645  ITK_LOCATION);
646  throw exception;
647  }
648  (*scanningSequenceImageTypeRescaleVector)[scanIndex] =
649  imageTypeRescaleValuesVector;
650  }
651 
652  // Setup the slice index matrix.
653  this->m_SliceIndex->clear();
654  this->m_SliceIndex->resize(par.dim[2]);
655  PhilipsPAR::PARSliceIndexImageTypeVector sliceImageTypesIndexes =
656  philipsPAR->GetRECSliceIndexImageTypes(HeaderFileName);
657  PhilipsPAR::PARSliceIndexScanSequenceVector sliceScanSequencesIndexes =
658  philipsPAR->GetRECSliceIndexScanningSequence(HeaderFileName);
659  PhilipsPAR::PARImageTypeScanSequenceVector imageTypesScanSequencesIndexes =
660  philipsPAR->GetImageTypesScanningSequence(HeaderFileName);
662  imageTypesScanSequencesIndexes,sliceImageTypesIndexes,
663  sliceScanSequencesIndexes);
664 
665  // As far as I know all Philips REC files are littleEndian.
667 
668  // Set dimensions.
669  unsigned int numberOfDimensions = 4;
670  // In reality PAR/REC files can have more dimensions
671  // but it is very difficult to sort out all of the
672  // possibilities. The reader will sort the images
673  // by block and the different types of images
674  // stored in the blocks may be determined using the
675  // MetaDataDictionary.
676  this->SetNumberOfDimensions(numberOfDimensions);
677 
678  // As far as I know, Philips REC files are only
679  // 8-bit or 16-bit signed integers.
680  switch( par.bit )
681  {
682  case 8:
685  break;
686  case 16:
689  break;
690  default:
691  OStringStream message;
692  message << "Unknown data type. par.bit must be 8 or 16. "
693  << "par.bit is "
694  << par.bit;
695  ExceptionObject exception(__FILE__, __LINE__,
696  message.str(),
697  ITK_LOCATION);
698  throw exception;
699  }
700  //
701  // set up the dimension stuff
702  this->SetDimensions(0,par.dim[0]);
703  this->SetDimensions(1,par.dim[1]);
704  this->SetDimensions(2,par.slice);
705  this->SetDimensions(3,par.image_blocks);
706  this->SetSpacing(0,par.vox[0]);
707  this->SetSpacing(1,par.vox[1]);
708  this->SetSpacing(2,par.vox[2]);
709  // Just 1 for the fourth dimension.
710  this->SetSpacing(3,1.0f);
711 
712  //
713  // figure out re-orientation required if not in Coronal
714  this->ComputeStrides();
715 
716 
717  //Get Dictionary Information
718  //Important hk fields.
719  MetaDataDictionary &thisDic=this->GetMetaDataDictionary();
720  std::string classname(this->GetNameOfClass());
721  EncapsulateMetaData<std::string>(thisDic,ITK_InputFilterName, classname);
722 
723  EncapsulateMetaData<std::string>(thisDic,ITK_ImageFileBaseName,
724  GetRootName( this->m_FileName ));
725 
726  //Important dime fields
727  EncapsulateMetaData<std::string>(thisDic,ITK_VoxelUnits,std::string("mm",4));
728  EncapsulateMetaData<short int>(thisDic,ITK_OnDiskBitPerPixel,par.bit);
729  EncapsulateMetaData<int>(thisDic,ITK_NumberOfDimensions,numberOfDimensions);
730 
731  switch( par.bit )
732  {
733  case 8:
734  EncapsulateMetaData<std::string>(thisDic,ITK_OnDiskStorageTypeName,
735  std::string(typeid(char).name()));
736  break;
737  case 16:
738  EncapsulateMetaData<std::string>(thisDic,ITK_OnDiskStorageTypeName,
739  std::string(typeid(short).name()));
740  break;
741  default:
742  break;
743  }
744 
745  //Important hist fields
746  EncapsulateMetaData<std::string>(thisDic,ITK_FileNotes,
747  std::string(par.series_type,32));
748 
750 
751  switch (par.sliceorient)
752  {
754  // Transverse - the REC data appears to be stored as right-left,
755  // anterior-posterior, and inferior-superior.
756  // Verified using a marker on right side of brain.
758  break;
760  // Sagittal - the REC data appears to be stored as anterior-posterior,
761  // superior-inferior, and right-left.
762  // Verified using marker on right side of brain.
764  break;
766  // Coronal - the REC data appears to be stored as right-left,
767  // superior-inferior, and anterior-posterior.
768  // Verified using marker on right side of brain.
769  // fall thru
770  default:
772  }
773 
774  typedef SpatialOrientationAdapter OrientAdapterType;
776  OrientAdapterType().ToDirectionCosines(coord_orient);
777 
778  std::vector<double> dirx(numberOfDimensions,0),
779  diry(numberOfDimensions,0),dirz(numberOfDimensions,0),
780  dirBlock(numberOfDimensions,0);
781  dirBlock[numberOfDimensions-1] = 1;
782  dirx[0] = dir[0][0];
783  dirx[1] = dir[1][0];
784  dirx[2] = dir[2][0];
785  diry[0] = dir[0][1];
786  diry[1] = dir[1][1];
787  diry[2] = dir[2][1];
788  dirz[0] = dir[0][2];
789  dirz[1] = dir[1][2];
790  dirz[2] = dir[2][2];
791 
792  this->SetDirection(0,dirx);
793  this->SetDirection(1,diry);
794  this->SetDirection(2,dirz);
795  this->SetDirection(3,dirBlock);
796 
797 #if defined(ITKIO_DEPRECATED_METADATA_ORIENTATION)
798  EncapsulateMetaData<SpatialOrientation::ValidCoordinateOrientationFlags>(
799  thisDic,ITK_CoordinateOrientation, coord_orient);
800 #endif
801 
802  EncapsulateMetaData<std::string>(thisDic,ITK_PatientID,
803  std::string(par.patient_name,32));
804  EncapsulateMetaData<std::string>(thisDic,ITK_ExperimentDate,
805  std::string(par.exam_date,32));
806  EncapsulateMetaData<std::string>(thisDic,ITK_ExperimentTime,
807  std::string(par.exam_time,32));
808 
809  // Encapsulate remaining PAR parameters
810  EncapsulateMetaData<int>(thisDic,PAR_SliceOrientation,par.sliceorient);
811  switch(par.ResToolsVersion)
812  {
814  EncapsulateMetaData<std::string>(thisDic,PAR_Version,std::string("V3",4));
815  break;
817  EncapsulateMetaData<std::string>(thisDic,PAR_Version,std::string("V4",4));
818  break;
820  EncapsulateMetaData<std::string>(thisDic,PAR_Version,
821  std::string("V4.1",6));
822  break;
824  EncapsulateMetaData<std::string>(thisDic,PAR_Version,
825  std::string("V4.2",6));
826  break;
827  }
828 
829  EncapsulateMetaData<std::string>(thisDic,PAR_ExaminationName,
830  std::string(par.exam_name,32));
831  EncapsulateMetaData<std::string>(thisDic,PAR_ProtocolName,
832  std::string(par.protocol_name,32));
833  EncapsulateMetaData<std::string>(thisDic,PAR_SeriesType,
834  std::string(par.series_type,32));
835  EncapsulateMetaData<int>(thisDic,PAR_AcquisitionNr,par.scno);
836  EncapsulateMetaData<int>(thisDic,PAR_ReconstructionNr,par.recno);
837  EncapsulateMetaData<int>(thisDic,PAR_ScanDuration,par.scan_duration);
838  EncapsulateMetaData<int>(thisDic,PAR_MaxNumberOfCardiacPhases,
839  par.cardiac_phases);
840  TriggerTimesContainerType::Pointer triggerTimes =
842  triggerTimes->resize(par.cardiac_phases);
843 
844  for(unsigned int ttime_index=0; ttime_index<(unsigned int)par.cardiac_phases;
845  ttime_index++)
846  {
847  triggerTimes->SetElement(ttime_index,(double)par.trigger_times[ttime_index]);
848  }
849 
850  EncapsulateMetaData<TriggerTimesContainerType::Pointer>(thisDic,
851  PAR_TriggerTimes,triggerTimes);
852  EncapsulateMetaData<int>(thisDic,PAR_MaxNumberOfEchoes,par.echoes);
854  echoTimes->resize(par.echoes);
855 
856  for(unsigned int echo_index=0; echo_index<(unsigned int)par.echoes;
857  echo_index++)
858  {
859  echoTimes->SetElement(echo_index,(double)par.echo_times[echo_index]);
860  }
861 
862  EncapsulateMetaData<EchoTimesContainerType::Pointer>(thisDic,PAR_EchoTimes,
863  echoTimes);
864  EncapsulateMetaData<int>(thisDic,PAR_MaxNumberOfDynamics,par.dyn);
865  EncapsulateMetaData<int>(thisDic,PAR_MaxNumberOfMixes,par.mixes);
866  EncapsulateMetaData<std::string>(thisDic,PAR_PatientPosition,
867  std::string(par.patient_position,32));
868  EncapsulateMetaData<std::string>(thisDic,PAR_PreparationDirection,
869  std::string(par.prep_direction,32));
870  EncapsulateMetaData<std::string>(thisDic,PAR_Technique,
871  std::string(par.technique,32));
872  EncapsulateMetaData<std::string>(thisDic,PAR_ScanMode,
873  std::string(par.scan_mode,32));
874  EncapsulateMetaData<int>(thisDic,PAR_NumberOfAverages,par.num_averages);
875  EncapsulateMetaData<ScanResolutionType>(thisDic,PAR_ScanResolution,
879  repTimes->resize(par.mixes); // This has only been verified using a
880  // Look-Locker sequence and may not be valid.
881 
882  for(unsigned int rep_index=0; rep_index<(unsigned int)par.mixes; rep_index++)
883  {
884  repTimes->SetElement(rep_index,(double)par.repetition_time[rep_index]);
885  }
886 
887  EncapsulateMetaData<RepetitionTimesContainerType::Pointer>(thisDic,
888  PAR_RepetitionTimes,repTimes);
889  EncapsulateMetaData<int>(thisDic,PAR_ScanPercentage,par.scan_percent);
890  EncapsulateMetaData<FOVType>(thisDic,PAR_FOV,FOVType(par.fov));
891  EncapsulateMetaData<float>(thisDic,PAR_WaterFatShiftPixels,
892  par.water_fat_shift);
893  AngulationMidSliceType tempAngulation;
894  tempAngulation[0] = (double)par.angAP;
895  tempAngulation[1] = (double)par.angFH;
896  tempAngulation[2] = (double)par.angRL;
897  EncapsulateMetaData<AngulationMidSliceType>(thisDic,PAR_AngulationMidSlice,
898  tempAngulation);
899  OffCentreMidSliceType tempOffcentre;
900  tempOffcentre[0] = (double)par.offAP;
901  tempOffcentre[1] = (double)par.offFH;
902  tempOffcentre[2] = (double)par.offRL;
903  EncapsulateMetaData<OffCentreMidSliceType>(thisDic,PAR_OffCentreMidSlice,
904  tempOffcentre);
905  EncapsulateMetaData<int>(thisDic,PAR_FlowCompensation,par.flow_comp);
906  EncapsulateMetaData<int>(thisDic,PAR_Presaturation,par.presaturation);
907  EncapsulateMetaData<int>(thisDic,PAR_CardiacFrequency,par.cardiac_freq);
908  EncapsulateMetaData<int>(thisDic,PAR_MinRRInterval,par.min_rr_int);
909  EncapsulateMetaData<int>(thisDic,PAR_MaxRRInterval,par.max_rr_int);
910  EncapsulateMetaData<PhaseEncodingVelocityType>(thisDic,
912  EncapsulateMetaData<int>(thisDic,PAR_MTC,par.mtc);
913  EncapsulateMetaData<int>(thisDic,PAR_SPIR,par.spir);
914  EncapsulateMetaData<int>(thisDic,PAR_EPIFactor,par.epi);
915  EncapsulateMetaData<int>(thisDic,PAR_TurboFactor,par.turbo);
916  EncapsulateMetaData<int>(thisDic,PAR_DynamicScan,par.dynamic_scan);
917  EncapsulateMetaData<int>(thisDic,PAR_Diffusion,par.diffusion);
918  EncapsulateMetaData<float>(thisDic,PAR_DiffusionEchoTime,par.diff_echo);
919  EncapsulateMetaData<int>(thisDic,PAR_MaxNumberOfDiffusionValues,
920  par.max_num_diff_vals);
921  EncapsulateMetaData<GradientBvalueContainerType::Pointer>(thisDic,
922  PAR_GradientBValues, diffusionBvalueVector);
923  EncapsulateMetaData<int>(thisDic,PAR_MaxNumberOfGradientOrients,
924  par.max_num_grad_orient);
925  EncapsulateMetaData<GradientDirectionContainerType::Pointer>(thisDic,
926  PAR_GradientDirectionValues, diffusionGradientOrientationVector);
927  EncapsulateMetaData<float>(thisDic,PAR_InversionDelay,par.inversion_delay);
928  EncapsulateMetaData<int>(thisDic,PAR_NumberOfImageTypes,par.num_image_types);
929  EncapsulateMetaData<ImageTypesType>(thisDic,PAR_ImageTypes,
931  EncapsulateMetaData<int>(thisDic,PAR_NumberOfScanningSequences,
933  EncapsulateMetaData<ScanningSequencesType>(thisDic,PAR_ScanningSequences,
936  ScanningSequenceImageTypeRescaleValuesContainerTypePtr;
937  EncapsulateMetaData<ScanningSequenceImageTypeRescaleValuesContainerTypePtr>(
939  scanningSequenceImageTypeRescaleVector);
940  EncapsulateMetaData<int>(thisDic,PAR_NumberOfASLLabelTypes,
941  par.num_label_types);
942  EncapsulateMetaData<LabelTypesASLContainerType::Pointer>(thisDic,
943  PAR_ASLLabelTypes, labelTypesASLVector);
944 
945  return;
946 }
947 
948 } // end namespace itk

Generated at Sat Feb 2 2013 23:59:38 for Orfeo Toolbox with doxygen 1.8.1.1