ITK/MetaIO/Documentation: Difference between revisions

From KitwarePublic
< ITK‎ | MetaIO
Jump to navigationJump to search
No edit summary
 
(16 intermediate revisions by 7 users not shown)
Line 8: Line 8:


== Obtaining MetaIO ==
== Obtaining MetaIO ==
The upstream MetaIO Git repository:
* https://github.com/Kitware/MetaIO


MetaIO is being distributed with the following packages:
MetaIO is being distributed with the following packages:
Line 60: Line 64:
* VTK/IO
* VTK/IO


=== ITK Stand Alone ===
=== Stand Alone MetaIO ===
MetaIO can also be compiled outside of these toolkits.  This is left as an exercise to the user (hint: requires the kwsys and zlib libraries).  Instead of a stand-alone installation, we highly recommend using the distribution in ITK - if you build ITK, you get MetaIO for free!
MetaIO can also be compiled outside of these toolkits.  This is left as an exercise to the user (hint: requires the kwsys and zlib libraries).  Instead of a stand-alone installation, we highly recommend using the distribution in ITK - if you build ITK, you get MetaIO for free!


Line 80: Line 84:


MetaImageImporter is part of the InsightApplications repository.  See http://www.itk.org for information on downloading and installing InsightApplications - the companion to the Insight repository.
MetaImageImporter is part of the InsightApplications repository.  See http://www.itk.org for information on downloading and installing InsightApplications - the companion to the Insight repository.
MetaImageImporter now has a QT graphical user interface. Please see the [[KWPublic/Applications/MetaImageImporter|documentation]].


Otherwise, the following two sub-sections will step you through the conversion process.  The first sub-section applies if all of your data is in one file, i.e., is a "brick-of-bytes".  The second sub-section applies if your data is spread across files, e.g., is dicom or a tiff sequence.
Otherwise, the following two sub-sections will step you through the conversion process.  The first sub-section applies if all of your data is in one file, i.e., is a "brick-of-bytes".  The second sub-section applies if your data is spread across files, e.g., is dicom or a tiff sequence.
Line 85: Line 91:
=== Reading a Brick-of-Bytes (an N-Dimensional volume in a single file) ===
=== Reading a Brick-of-Bytes (an N-Dimensional volume in a single file) ===


A “brick of bytes” is a volume of image data stored in a single file possibly with preceding and trailing non-image data.
A “brick of bytes” is a volume of image data stored in a single file possibly with preceding and trailing non-image data.  A volume can be of any dimension (1 dimensional to N dimensional).


To correctly load these images, the minimal information that you need to know is:
To correctly load these images, the minimal information that you need to know is:
Line 95: Line 101:
For example, let’s say the data was 3 dimensional, had 256 x 256 x 64 voxels, used an unsigned short to represent the value at each voxel, and was stored in the file “image.raw”. The resulting MetaHeader (our naming convention would call this file “image.mhd”) file would read
For example, let’s say the data was 3 dimensional, had 256 x 256 x 64 voxels, used an unsigned short to represent the value at each voxel, and was stored in the file “image.raw”. The resulting MetaHeader (our naming convention would call this file “image.mhd”) file would read


        ObjectType = Image
ObjectType = Image
NDims = 3
NDims = 3
DimSize = 256 256 64
DimSize = 256 256 64
ElementType = MET_USHORT
ElementType = MET_USHORT
ElementDataFile = image.raw (this tag must be last in a MetaImageHeader)
ElementDataFile = image.raw (this tag must be last in a MetaImageHeader)


That’s it, but this assumes quite a bit about the image data.  Specifically, it assumes
That’s it, but this assumes quite a bit about the image data.  Specifically, it assumes
Line 106: Line 112:
# The byte-order of the data in image.raw matches the byte ordering native to the machine the application is running on (e.g., PC’s use LSB ordering and Suns/Macs use MSB ordering).
# The byte-order of the data in image.raw matches the byte ordering native to the machine the application is running on (e.g., PC’s use LSB ordering and Suns/Macs use MSB ordering).


If these assumptions are false, the data will not be loaded correctly by the application.  To fix these problems….
If these assumptions are false, the data will not be loaded correctly by the application.  To fix these problems, MetaIO allows you to specify additional tag/value pairs in the header:
# To skip the header bytes in the image data file, use
# To skip the header bytes in the image data file, use
  HeaderSize = X
  HeaderSize = X
Line 133: Line 139:


Putting it all together, to “convert” a file containing the image data in a continuous block at the end of the file, specify the header
Putting it all together, to “convert” a file containing the image data in a continuous block at the end of the file, specify the header
        ObjectType = Image
ObjectType = Image
NDims = 3
NDims = 3
DimSize = 256 256 64
DimSize = 256 256 64
ElementType = MET_USHORT
ElementType = MET_USHORT
HeaderSize = -1
HeaderSize = -1
ElementSize = 1 1 3
ElementSize = 1 1 3
ElementSpacing = 1 1 1
ElementSpacing = 1 1 1
ElementByteOrderMSB = False
ElementByteOrderMSB = False
ElementDataFile = image.raw
ElementDataFile = image.raw
 
=== Reading DICOM and Other One-Slice-Per-File Data Formats ===
=== Reading DICOM and Other One-Slice-Per-File Data Formats ===


If the data is split to be one slice per file, as is done with DICOM data, only the ElementDataFile tag’s option needs to change.  
If the data is split into one slice per file, as is done with most DICOM object files, only the ElementDataFile tag’s option needs to change.  Note that 3D DICOM object files are becoming popular, and some such DICOM files can be read using the above, volume, technique.


Since the MetaLibrary cannot automatically parse DICOM headers, those headers must be skipped and the user must specify the image dimensions and other essential image information.  For DICOM files, the MetaLibrary must automatically calculate the header size of each file (luckily for almost every type of DICOM object in common use, the image data is stored at the end).  
Since the MetaLibrary cannot directly parse DICOM headers, those headers must be skipped and the user must specify the image dimensions and other essential image information.  For DICOM files, the MetaLibrary must automatically calculate the header size of each file (luckily for almost every DICOM object the image data is stored at the end of the file).  For this reason, this method only works for uncompressed files.


To specify which files comprise the volume, they can be specified as an ordered list in the MetaHeader using the ElementDataFile=LIST option. The filenames should be listed at the end of the MetaHeader, after the ElementDataFile option, and the filenames should be separated by whitespace:
To specify which files comprise the volume, they can be specified as an ordered list in the MetaHeader using the ElementDataFile=LIST option. The filenames should be listed at the end of the MetaHeader, after the ElementDataFile option, and the filenames should be separated by whitespace:
        ObjectType = Image
 
NDims = 3
ObjectType = Image
DimSize = 512 512 100
NDims = 3
ElementType = MET_USHORT
DimSize = 512 512 100
HeaderSize = -1
ElementType = MET_USHORT
ElementSize = 1 1 3
HeaderSize = -1
ElementSpacing = 1 1 1
ElementSize = 1 1 3
ElementByteOrderMSB = False
ElementSpacing = 1 1 1
ElementDataFile = LIST
ElementByteOrderMSB = False
filenameOfSlice1
ElementDataFile = LIST
filenameOfSlice2
filenameOfSlice1
filenameOfSlice3
filenameOfSlice2
filenameOfSlice4
filenameOfSlice3
.
filenameOfSlice4
. (one hundred filenames must be specified to specify the 100 slices in the volume)
.
.
. (one hundred filenames must be specified to specify the 100 slices in the volume)
The second way of specifying a series of files can be used if the filenames are numerically distinguished.  That is, the files names should be able to be specified using a numeric substitution into a c-style printf-string, for a range of values.  In pseudo-code:
.
for i=numBegin to numEnd step numStep
 
sprintf(sliceName, “baseName.%03d”, i);
This method works even if there are spaces in the file paths and file names.
end
 
Notice that this method can become tedious if a large number of files need to be read.  To alleviate this, a second way of specifying a series of files can be used if the filenames are numerically distinguished.  That is, the file names should be able to be specified using a numeric substitution into a c-style printf-string, for a range of values.  In pseudo-code:
 
for i=numBegin to numEnd step numStep
  sprintf(sliceName, “baseName.%03d”, i);
end
 
The parameters of this system are numBegin, numEnd, numStep, and the c-style printf string (e.g., “baseName.%03d”).  The begin, end, and step parameters appear in order after the c-style printf string:
The parameters of this system are numBegin, numEnd, numStep, and the c-style printf string (e.g., “baseName.%03d”).  The begin, end, and step parameters appear in order after the c-style printf string:
ObjectType = Image
NDims = 3
DimSize = 512 512 100
ElementType = MET_USHORT
HeaderSize = -1
ElementSize = 1 1 3
ElementSpacing = 1 1 1
ElementByteOrderMSB = False
ElementDataFile = baseName.%03d 1 100 1
This MetaImage will cause the files “baseName.001” to “baseName.100” to be read to create a 100-slice volume.


In this case, because of the overlap of the slices, it may be helpful to only consider every-other slice in the volume.  Changing the slice spacing and the ElementDataFileNumStep enacts this…
ObjectType = Image
ObjectType = Image
NDims = 3
NDims = 3
DimSize = 512 512 100
DimSize = 512 512 50
ElementType = MET_USHORT
ElementType = MET_USHORT
HeaderSize = -1
HeaderSize = -1
ElementSize = 1 1 3
ElementSize = 1 1 3
ElementSpacing = 1 1 1
ElementSpacing = 1 1 2
ElementByteOrderMSB = False
ElementByteOrderMSB = False
ElementDataFile = baseName.%03d 1 100 1
ElementDataFile = baseName.%03d 1 100 2
 
The above MetaImage header will cause the files “baseName.001” to “baseName.100” to be read to create a 100-slice volume.  This method works even if there are spaces in the file paths and file names.  However, when spaces are present in the file path and/or file name, all three parameters (begin, end, and step) need to be specified as the last parameters.  The remaining parameters (initially parsed based on spaces) are then joined back together (including spaces) to generate the file name.
 
In some cases, it may be helpful to skip slices in the volume.  Changing the slice spacing and the ElementDataFileNumStep enacts this…
 
ObjectType = Image
NDims = 3
DimSize = 512 512 50
ElementType = MET_USHORT
HeaderSize = -1
ElementSize = 1 1 3
ElementSpacing = 1 1 2
ElementByteOrderMSB = False
ElementDataFile = baseName.%03d 1 100 2


The complete set of MetaImage Tags are given in the Reference section of this document. The next section discusses how to use the MetaImage Library for image reading and writing in your own programs.
The complete set of MetaImage Tags are given in the Reference section of this document. The next section discusses how to use the MetaImage Library for image reading and writing in your own programs.


MetaIO Library
== MetaIO Library Architecture ==


The base class of the MetaIO library is the MetaObject class.  It defines a base set of tags that are common to all metaObjects such as MetaImages, MetaTubes, etc.
The base class of the MetaIO library is the MetaObject class.  It defines a base set of tags that are common to all metaObjects such as MetaImages, MetaTubes, etc.
Line 202: Line 217:


The derived classes add tags to the list via their own SetupReadFields and SetupWriteFields member functions. The MetaImage subclass also re-implements the Read and Write methods since non tag data (i.e., the pixel values) must also be read.  Compare the derived classes for MetaCube and MetaImage.
The derived classes add tags to the list via their own SetupReadFields and SetupWriteFields member functions. The MetaImage subclass also re-implements the Read and Write methods since non tag data (i.e., the pixel values) must also be read.  Compare the derived classes for MetaCube and MetaImage.
MetaObjects
 
=== MetaObjects ===
   
   
In this section we describe the metaObjects which have been implemented already. If you want to implement other objects, you can easily derive these classes.  metaObject is the base class for metaIO. metaScene and metaGroup are also a useful objects that support multiple metaObjects.
In this section we describe the metaObjects which have been implemented already. If you want to implement other objects, you can easily derive these classes.  metaObject is the base class for metaIO. metaScene and metaGroup are also a useful objects that support multiple metaObjects.
All these objects are described in details next.
All these objects are described in details next.


MetaObject
==== Constructors ====
Constructors


Simple constructor
Simple constructor
Line 219: Line 234:
       MetaObject(unsigned int dim);
       MetaObject(unsigned int dim);


Member functions
==== Member functions ====


Specify the filename to read (Optional)
Specify the filename to read (Optional)
Line 238: Line 253:
       virtual void Clear(void);
       virtual void Clear(void);


Field descriptions
==== Field descriptions ====


Name:
Name:
Line 278: Line 293:
       void    ObjectSubTypeName(const char * _objectSubTypeName);
       void    ObjectSubTypeName(const char * _objectSubTypeName);


==== Associated transformations ====


Associated transformations:
Physical location (in millimeters and with respect to  machine coordinate system or the patient) of the first element in the image. Physical orientation of the object is defined as an NDims x NDims matrix that is serialized in a column-major format in MetaIO files.
Physical location (in millimeters and with respect to  machine coordinate system or the patient) of the first element in the image. Physical orientation of the object is defined as an NDims x NDims matrix.


Offset:
Offset: (equiv. to position and origin)
       const float * Offset(void) const;
       const float * Offset(void) const;
       float Offset(int _i) const;
       float Offset(int _i) const;
Line 288: Line 303:
       void  Offset(int _i, float _value);
       void  Offset(int _i, float _value);


Position:
Position: (equiv. to offset and origin)
       const float * Position(void) const;
       const float * Position(void) const;
       float Position(int _i) const;
       float Position(int _i) const;
Line 294: Line 309:
       void  Position(int _i, float _value);
       void  Position(int _i, float _value);


Origin:
Origin: (equiv. to offset and position)
       const float * Origin(void) const;
       const float * Origin(void) const;
       float Origin(int _i) const;
       float Origin(int _i) const;
Line 301: Line 316:




Rotation:
Rotation: (equiv. to orientation and transformMatrix)
       const float * Rotation(void) const;
       const float * Rotation(void) const;
       float Rotation(int _i, int _j) const;
       float Rotation(int _i, int _j) const;
Line 307: Line 322:
       void  Rotation(int _i, int _j, float _value);
       void  Rotation(int _i, int _j, float _value);


Orientation:
Orientation: (equiv. to rotation and transformMatrix)
       const float * Orientation(void) const;
       const float * Orientation(void) const;
       float Orientation(int _i, int _j) const;
       float Orientation(int _i, int _j) const;
       void  Orientation(const float * _orientation);
       void  Orientation(const float * _orientation);
       void  Orientation(int _i, int _j, float _value);
       void  Orientation(int _i, int _j, float _value);
TransformMatrix: (equiv. to rotation and orientation)
      const float * TransformMatrix(void) const;
      float TransformMatrix(int _i, int _j) const;
      void  TransformMatrix(const float * _transformMatrix);
      void  TransformMatrix(int _i, int _j, float _value);


Center of rotation of the object:
Center of rotation of the object:
Line 346: Line 367:
                         T *_v,bool _required=true,int _dependsOn=-1 )
                         T *_v,bool _required=true,int _dependsOn=-1 )
    
    
The user may also want to clear the fields created by using ClearUserFields().
The user may also want to clear the fields created by using  
 
ClearUserFields().
 
To determine the value of a field


       void* GetUserField(const char* _name);
       void* GetUserField(const char* _name);
Line 352: Line 377:
Note: When using GetUserField() function, the user is responsible for the deletion of the pointer created. See the following example for details.
Note: When using GetUserField() function, the user is responsible for the deletion of the pointer created. See the following example for details.


Example
==== Example ====


/** We create a simple 3D metaObject with some properties */
  /** We create a simple 3D metaObject with some properties */
   MetaObject tObj(3); // Create a 3D metaObject
   MetaObject tObj(3); // Create a 3D metaObject
   tObj.FileName("testObject.txt"); // Define the name of the file
   tObj.FileName("testObject.txt"); // Define the name of the file
Line 360: Line 385:
   tObj.ObjectTypeName("Object"); // Define the type of the object
   tObj.ObjectTypeName("Object"); // Define the type of the object
   tObj.ObjectSubTypeName("MinorObject"); // and the subtype as well
   tObj.ObjectSubTypeName("MinorObject"); // and the subtype as well
 
/** We now define the position and the orientation as well as the spacing of the created object */
  /** We now define the position and the orientation as well as the spacing of the created object */
// The position part
  // The position part
   tObj.Position(0, 1);
   tObj.Position(0, 1);
   tObj.Position(1, 2);
   tObj.Position(1, 2);
   tObj.Position(2, 3);
   tObj.Position(2, 3);
 
// The orientation part
  // The orientation part
   float orient[9];
   float orient[9];
   int i;
   int i;
Line 378: Line 403:
   orient[7] = 1;
   orient[7] = 1;
   tObj.Orientation(orient);
   tObj.Orientation(orient);
 
// The element spacing part
  // The element spacing part
   tObj.ElementSpacing(0, 1);
   tObj.ElementSpacing(0, 1);
   tObj.ElementSpacing(1, 2);
   tObj.ElementSpacing(1, 2);
   tObj.ElementSpacing(2, 1);
   tObj.ElementSpacing(2, 1);
 
 
   /** Add user's defined fields */
   /** Add user's defined fields */
   tObj.AddUserField("MyName", MET_STRING, strlen("JulienAndStephen"), "JulienAndStephen");
   tObj.AddUserField("MyName", MET_STRING, strlen("JulienAndStephen"), "JulienAndStephen");
 
/** Write the object */
  /** Write the object */
   tObj.Write();
   tObj.Write();
 
/** Clear completely the object */
  /** Clear completely the object */
   tObj.Clear();
   tObj.Clear();
   tObj.ClearUserFields();
   tObj.ClearUserFields();
    
    
/** Specify that we want to read the field  ‘MyName’ */
  /** Specify that we want to read the field  ‘MyName’ */
   tObj.AddUserField("MyName", MET_STRING);
   tObj.AddUserField("MyName", MET_STRING);
 
/** Read the object */
  /** Read the object */
   tObj.Read("testObject.txt");
   tObj.Read("testObject.txt");
 
/** Print the object */
  /** Print the object */
   tObj.PrintInfo();
   tObj.PrintInfo();


/** Get the name in the file */
  /** Get the name in the file */
   char* name = static_cast<char*>(tObj.GetUserField("MyName"));
   char* name = static_cast<char*>(tObj.GetUserField("MyName"));
   std::cout << name << std::endl;
   std::cout << name << std::endl;
  /** delete the allocated pointer */
  delete [] name;


/** delete the allocated pointer */
== Types of MetaObjects ==
  delete [] name;


All of the following objects derive from metaObject.
All of the following objects derive from metaObject.
MetaBlob
 
=== MetaBlob ===


A blob is defined by a list of points that describe the object. The points can be inside the object (if obtained by connected-component for instance) or only on the surface. Note that a color (RGBA) can be associated which each point.
A blob is defined by a list of points that describe the object. The points can be inside the object (if obtained by connected-component for instance) or only on the surface. Note that a color (RGBA) can be associated which each point.


The required fields are:
The required fields are:
 
* The number of points defining the object:
The number of points defining the object:
NPoints(int npnt);
NPoints(int npnt);
* How the position of the points is stored in the file. By default the configuration is x y z red green blue alpha
 
PointDim(const char* pointDim);
How the position of the points is stored in the file. By default the configuration is x y z red green blue alpha
PointDim(const char* pointDim);


To access the internal list of points user should use the GetPoints() function which returns the internal list by reference. Note that the list is a list of pointers to point and is deleted automatically by the object itself so the user does not need to free the allocated memory.
To access the internal list of points user should use the GetPoints() function which returns the internal list by reference. Note that the list is a list of pointers to point and is deleted automatically by the object itself so the user does not need to free the allocated memory.


Example
==== Example ====


/** Create a 3D blob */
  /** Create a 3D blob */
   MetaBlob blob(3);
   MetaBlob blob(3);
   blob.ID(0); // define the ID of the blob
   blob.ID(0); // define the ID of the blob
 
/** Add 10 points to the blob */
  /** Add 10 points to the blob */
   BlobPnt* pnt;
   BlobPnt* pnt;
 
   unsigned int i;
   unsigned int i;
   for(i=0;i<10;i++)
   for(i=0;i<10;i++)
  {
    {
     pnt = new BlobPnt(3);
     pnt = new BlobPnt(3);
     pnt->m_X[0]=(float)0.2;
     pnt->m_X[0]=(float)0.2;
Line 443: Line 469:
     pnt->m_X[2]=i;
     pnt->m_X[2]=i;
     blob.GetPoints().push_back(pnt); // push the created point into the list of points
     blob.GetPoints().push_back(pnt); // push the created point into the list of points
  }
    }
    
    
/** Write the blob in binary format */
  /** Write the blob in binary format */
   blob.BinaryData(true);
   blob.BinaryData(true);
   blob.ElementType(MET_FLOAT);
   blob.ElementType(MET_FLOAT);
   blob.Write("myBlob.meta");
   blob.Write("myBlob.meta");
 
/** Read the file */
  /** Read the file */
   blob.Read("myBlob.meta");  
   blob.Read("myBlob.meta");  
   blob.PrintInfo();
   blob.PrintInfo();


/** Access the list of points */
  /** Access the list of points */
   std::cout << "Accessing pointlist..." << std::endl;
   std::cout << "Accessing pointlist..." << std::endl;
 
   MetaBlob::PointListType plist =  blob.GetPoints();
   MetaBlob::PointListType plist =  blob.GetPoints();
   MetaBlob::PointListType::const_iterator it = plist.begin();
   MetaBlob::PointListType::const_iterator it = plist.begin();
    
    
   while(it != plist.end())
   while(it != plist.end())
  {
    {
     for(unsigned int d = 0; d < 3; d++)
     for(unsigned int d = 0; d < 3; d++)
    {
      {
       std::cout << (*it)->m_X[d] << " ";
       std::cout << (*it)->m_X[d] << " ";
      }
    std::cout << std::endl;
    it++;
     }
     }


    std::cout << std::endl;
=== MetaEllipse ===
    it++;
  }
MetaEllipse


MetaEllipse is an N-Dimensional object to define ellipsoids like circles, spheres or even hyper-ellipsoids.
MetaEllipse is an N-Dimensional object to define ellipsoids like circles, spheres or even hyper-ellipsoids.
Line 476: Line 502:


There are several ways to input the radius:
There are several ways to input the radius:
# As an array of floats: void  Radius(const float* radius);
# As a single value which means that we are defining an hyper-sphere: void  Radius(float radius);
# A convenient way to define a 2D ellipse:  void  Radius(float r1,float r2);
# A convenient way to define a 3D ellipse: void  Radius(float r1,float r2, float r3);
   
==== Example ====


a) As an array of floats: void Radius(const float* radius);
  /** Create a sphere */
b) As a single value which means that we are defining an hyper-sphere: void  Radius(float radius);
  MetaEllipse myEllipse (3);
c) A convenient way to define a 2D ellipse:  void Radius(float r1,float r2);
  myEllipse ->Radius(3); // radius of 3
d) A convenient way to define a 3D ellipse: void Radius(float r1,float r2, float r3);
   
   
=== MetaGroup ===
Example


/** Create a sphere */
MetaGroup does not have added functionalities compared to metaObject. It allows to group object in a metafile.
MetaEllipse  myEllipse (3);
myEllipse ->Radius(3); // radius of  3


MetaGroup
=== MetaImage ===


MetaGroup does not have added functionalities compared to metaObject. It allows to group object in a metafile.
==== Constructors ====
MetaImage
Constructors


Simple constructor by specifying the filename
Simple constructor by specifying the filename
    MetaImage(const char *_headerName);   
MetaImage(const char *_headerName);   


Constructor by shared memory  
Constructor by shared memory  
    MetaImage(MetaImage *_im);   
MetaImage(MetaImage *_im);   


Other constructors
Other constructors
MetaImage(int _nDims,
          const int * _dimSize,
          const float *_elementSpacing,
          MET_ValueEnumType _elementType,
          int _elementNumberOfChannels=1,
          void *_elementData=NULL);


    MetaImage(int _nDims,  
MetaImage(int _x, int _y,  
              const int * _dimSize,
          float _elementSpacingX,  
              const float *_elementSpacing,
          float _elementSpacingY,
              MET_ValueEnumType _elementType,
          MET_ValueEnumType _elementType,  
              int _elementNumberOfChannels=1,
          int _elementNumberOfChannels=1,
              void *_elementData=NULL);
          void *_elementData=NULL);


    MetaImage(int _x, int _y,  
MetaImage(int _x, int _y, int _z,  
              float _elementSpacingX,  
          float _elementSpacingX,
              float _elementSpacingY,
          float _elementSpacingY,
              MET_ValueEnumType _elementType,  
          float _elementSpacingZ,
              int _elementNumberOfChannels=1,
          MET_ValueEnumType _elementType,
              void *_elementData=NULL);
          int _elementNumberOfChannels=1,
          void *_elementData=NULL);


    MetaImage(int _x, int _y, int _z,
==== Member functions ====
              float _elementSpacingX,
              float _elementSpacingY,
              float _elementSpacingZ,
              MET_ValueEnumType _elementType,
              int _elementNumberOfChannels=1,
              void *_elementData=NULL);
Member functions


HeaderSize:
HeaderSize: Return the size of the header.
Return the size of the header.
     int  HeaderSize(void) const;
     int  HeaderSize(void) const;


Quantity:
Quantity: Total number of elements in the image.
Total number of elements in the image.
     int  Quantity(void) const;
     int  Quantity(void) const;


SubQuantity:
SubQuantity: Number of elements in image spanning sub-dimensions. E.g., elements per line, 2D sub-image, 3D sub-volume.
    Number of elements in image spanning sub-dimensions. E.g., elements per line, 2D sub-image, 3D sub-volume.
     const int * SubQuantity(void) const;       
     const int * SubQuantity(void) const;       
     int  SubQuantity(int _i) const;   
     int  SubQuantity(int _i) const;   


ElementMin/Max:
ElementMin/Max: The default max returned is the largest allowed by ElemNBytes (12 bit uint16_t will give 4096 max). This may not represent the true max.  Use _reCalc=true to force a calcuation of the actual max element value.
    The default max returned is the largest allowed by ElemNBytes (12 bit uint16_t will give 4096 max). This may not represent the true max.  Use _reCalc=true to force a calcuation of the actual max element value.
     bool  ElementMinMaxValid(void) const;
     bool  ElementMinMaxValid(void) const;
     void  ElementMinMaxValid(bool _elementMinMaxValid);
     void  ElementMinMaxValid(bool _elementMinMaxValid);
Line 548: Line 571:
     void  ElementMax(double _elementMax);
     void  ElementMax(double _elementMax);


ElementByteOrderSwap:
ElementByteOrderSwap: These functions are available only after ReadImageData() or if _read_and_close=TRUE when read
    These functions are available only after ReadImageData() or if _read_and_close=TRUE when read
     void  ElementByteOrderSwap(void);
     void  ElementByteOrderSwap(void);
     bool  ElementByteOrderFix(void);
     bool  ElementByteOrderFix(void);




ConverTo:
ConverTo: Converts to a new data type. Rescales using Min and Max.
    Converts to a new data type. Rescales using Min and Max.
     bool  ConvertElementDataTo(MET_ValueEnumType _elementType=MET_UCHAR,
     bool  ConvertElementDataTo(MET_ValueEnumType _elementType=MET_UCHAR,
                       double _toMin=0, double _toMax=0);
                       double _toMin=0, double _toMax=0);
  Field descriptions


Modality:
==== Field descriptions ====
Specify the modality of the image
 
Modality: Specify the modality of the image
     MET_ImageModalityEnumType  Modality(void) const;
     MET_ImageModalityEnumType  Modality(void) const;
     void Modality(MET_ImageModalityEnumType _modality);
     void Modality(MET_ImageModalityEnumType _modality);


Dimension size:
Dimension size: Specify the size of the image in each dimension
Specify the size of the image in each dimension
     void  DimSize(const int * _dimSize);
     void  DimSize(const int * _dimSize);
     void  DimSize(int _i, int _value);
     void  DimSize(int _i, int _value);


SequenceID:
SequenceID: DICOM designation of this image relative to other images acquired at the same time
  DICOM designation of this image relative to other images acquired at the same time
     const float * SequenceID(void) const;
     const float * SequenceID(void) const;
     float SequenceID(int _i) const;
     float SequenceID(int _i) const;
Line 577: Line 596:
     void  SequenceID(int _i, float _value);
     void  SequenceID(int _i, float _value);


ElementSize:
ElementSize: Optional Field. Physical size (in MM) of each element in the image  (0 = xSize, 1 = ySize, 2 = zSize)
    Optional Field. Physical size (in MM) of each element in the image  (0 = xSize, 1 = ySize, 2 = zSize)
     const float * ElementSize(void) const;
     const float * ElementSize(void) const;
     float ElementSize(int i) const;
     float ElementSize(int i) const;
Line 584: Line 602:
     void  ElementSize(int _i, float _value);
     void  ElementSize(int _i, float _value);


ElementType:
ElementType: Pixel type
  Pixel type
     MET_ValueEnumType ElementType(void) const;
     MET_ValueEnumType ElementType(void) const;
     void  ElementType(MET_ValueEnumType _elementType);
     void  ElementType(MET_ValueEnumType _elementType);


ElementNumberOfChannels:
ElementNumberOfChannels: Number of channels
  Number of channels
     int  ElementNumberOfChannels(void) const;
     int  ElementNumberOfChannels(void) const;
     void  ElementNumberOfChannels(int _elementNumberOfChannels);
     void  ElementNumberOfChannels(int _elementNumberOfChannels);


 
ElementData: Returns a pointer to the data.  
ElementData:
Returns a pointer to the data.  
     void * ElementData(void);
     void * ElementData(void);
     double ElementData(int _i) const;
     double ElementData(int _i) const;
Line 602: Line 616:
     bool  ElementData(int _i, double _v);
     bool  ElementData(int _i, double _v);


ElementDataFileName:
ElementDataFileName: Set/Get the filename
Set/Get the filename
     const char * ElementDataFileName(void) const;
     const char * ElementDataFileName(void) const;
     void ElementDataFileName(const char * _dataFileName);
     void ElementDataFileName(const char * _dataFileName);


Example
==== Example ====


ObjectType = Image
ObjectType = Image
NDims = 2
NDims = 2
BinaryData = True
BinaryData = True
BinaryDataByteOrderMSB = False
BinaryDataByteOrderMSB = False
ElementSpacing = 1 2
ElementSpacing = 1 2
DimSize = 8 8
DimSize = 8 8
ElementType = MET_CHAR
ElementType = MET_CHAR
ElementDataFile = LOCAL
ElementDataFile = LOCAL
[Pixel Data]
[Pixel Data]


MetaLandmark
=== MetaLandmark ===


MetaLandmark is a simple list of landmarks.
MetaLandmark is a simple list of landmarks.


The number of landmarks defining the object is set using the function
The number of landmarks defining the object is set using the function
NPoints(int npnt);
NPoints(int npnt);


How the position of the points is stored in the file. By default the configuration is x y z red green blue alpha
How the position of the points is stored in the file: By default the configuration is x y z red green blue alpha
PointDim(const char* pointDim);
PointDim(const char* pointDim);


To access the internal list of points user should use the GetPoints() function which returns the internal list by reference. Note that the list is a list of pointers to point and is deleted automatically by the object itself so the user does not need to free the allocated memory.
To access the internal list of points user should use the GetPoints() function which returns the internal list by reference. Note that the list is a list of pointers to point and is deleted automatically by the object itself so the user does not need to free the allocated memory.


Example
==== Example ====


/** Create a 3D Landmark */
  /** Create a 3D Landmark */
   MetaLandmark Landmark(3);
   MetaLandmark Landmark(3);
   Landmark.ID(0);
   Landmark.ID(0);
   LandmarkPnt* pnt;
   LandmarkPnt* pnt;


/** Add some landmarks to the list of landmark points*/
  /** Add some landmarks to the list of landmark points*/
   for(unsigned int i=0;i<10;i++)
   for(unsigned int i=0;i<10;i++)
  {
    {
     pnt = new LandmarkPnt(3);
     pnt = new LandmarkPnt(3);
     pnt->m_X[0]=(float)0.2;
     pnt->m_X[0]=(float)0.2;
Line 646: Line 659:
     pnt->m_X[2]=i;
     pnt->m_X[2]=i;
     Landmark.GetPoints().push_back(pnt);
     Landmark.GetPoints().push_back(pnt);
  }
    }
    
    
MetaLine
=== MetaLine ===


A metaLine is actually a polyline defined by a list of connected points.
A metaLine is actually a polyline defined by a list of connected points.
Line 659: Line 672:
To access the internal list of points user should use the GetPoints() function which returns the internal list by reference. Note that the list is a list of pointers to point and is deleted automatically by the object itself so the user does not need to free the allocated memory.
To access the internal list of points user should use the GetPoints() function which returns the internal list by reference. Note that the list is a list of pointers to point and is deleted automatically by the object itself so the user does not need to free the allocated memory.


Example
==== Example ====
/** Create a 3D MetaLine */
  /** Create a 3D MetaLine */
   MetaLine Line(3);
   MetaLine Line(3);
   LinePnt* pnt;
   LinePnt* pnt;
 
   for(unsigned int i=0;i<10;i++)
   for(unsigned int i=0;i<10;i++)
  {
    {
     pnt = new LinePnt(3);
     pnt = new LinePnt(3);
 
/** Define the position */
    /** Define the position */
     pnt->m_X[0]=(float)0.2;
     pnt->m_X[0]=(float)0.2;
     pnt->m_X[1]=i;
     pnt->m_X[1]=i;
     pnt->m_X[2]=i;
     pnt->m_X[2]=i;


/** Define the normals */
    /** Define the normals */
     pnt->m_V[0][0]=(float)0.3;
     pnt->m_V[0][0]=(float)0.3;
     pnt->m_V[0][1]=i;
     pnt->m_V[0][1]=i;
Line 681: Line 694:
     pnt->m_V[1][2]=i+1;
     pnt->m_V[1][2]=i+1;
     Line->GetPoints().push_back(pnt);
     Line->GetPoints().push_back(pnt);
  }
    }
    
 
/** Write the result */
   /** Write the result */
   Line.BinaryData(true);
   Line.BinaryData(true);
   Line.Write("myLine.meta");
   Line.Write("myLine.meta");
MetaSurface
 
=== MetaSurface ===


The definition of a metaSurface is quite similar to the metaLine’s, except for the normal which is only a NDim vector (i.e. an array of floats) where NDim is the dimension of the metaObject.
The definition of a metaSurface is quite similar to the metaLine’s, except for the normal which is only a NDim vector (i.e. an array of floats) where NDim is the dimension of the metaObject.
Line 692: Line 706:
To access the internal list of points user should use the GetPoints() function which returns the internal list by reference. Note that the list is a list of pointers to point and is deleted automatically by the object itself so the user does not need to free the allocated memory.
To access the internal list of points user should use the GetPoints() function which returns the internal list by reference. Note that the list is a list of pointers to point and is deleted automatically by the object itself so the user does not need to free the allocated memory.


Example
==== Example ====
 
   MetaSurface surface(3);
   MetaSurface surface(3);
   SurfacePnt* pnt;
   SurfacePnt* pnt;
 
   for(unsigned int i=0;i<10;i++)
   for(unsigned int i=0;i<10;i++)
  {
    {
     pnt = new SurfacePnt(3);
     pnt = new SurfacePnt(3);
 
 
/** Position */
    /** Position */
     pnt->m_X[0]=(float)0.2;
     pnt->m_X[0]=(float)0.2;
     pnt->m_X[1]=i;
     pnt->m_X[1]=i;
     pnt->m_X[2]=i;
     pnt->m_X[2]=i;
 
/* Normal */
    /* Normal */
     pnt->m_V[0]=(float)0.8;
     pnt->m_V[0]=(float)0.8;
     pnt->m_V[1]=i;
     pnt->m_V[1]=i;
     pnt->m_V[2]=i;
     pnt->m_V[2]=i;
     surface->GetPoints().push_back(pnt);
     surface->GetPoints().push_back(pnt);
  }
    }
MetaTube
 
=== MetaTube ===


A metaTube is a tubular structure defined by a list of connected points (like a metaLine) but more fields have been added for a complete representation, especially the one of blood vessels.
A metaTube is a tubular structure defined by a list of connected points (like a metaLine) but more fields have been added for a complete representation, especially the one of blood vessels.
Line 722: Line 738:
To access the internal list of points user should use the GetPoints() function which returns the internal list by reference. Note that the list is a list of pointers to point and is deleted automatically by the object itself so the user does not need to free the allocated memory.
To access the internal list of points user should use the GetPoints() function which returns the internal list by reference. Note that the list is a list of pointers to point and is deleted automatically by the object itself so the user does not need to free the allocated memory.


Example
==== Example ====
    
 
/** Create a 3D tube*/
   /** Create a 3D tube*/
   MetaTube* tube1 = new MetaTube(3);
   MetaTube* tube1 = new MetaTube(3);
   tube1->ID(0);
   tube1->ID(0);
 
/** Add 10 points to the list of tubePoints */
  /** Add 10 points to the list of tubePoints */
   TubePnt* pnt;
   TubePnt* pnt;
   for(unsigned int i=0;i<10;i++)
   for(unsigned int i=0;i<10;i++)
  {
    {
     pnt = new TubePnt(3);
     pnt = new TubePnt(3);
 
     pnt->m_X[0]=i; // position
     pnt->m_X[0]=i; // position
     pnt->m_X[1]=i;
     pnt->m_X[1]=i;
Line 739: Line 755:
     pnt->m_R=i; // radius
     pnt->m_R=i; // radius
     tube1->GetPoints().push_back(pnt);
     tube1->GetPoints().push_back(pnt);
  }
    }
    
    
MetaScene
=== MetaScene ===


A metaScene is a metaObject that contains a flat list of metaObjects.
A metaScene is a metaObject that contains a flat list of metaObjects.
Member functions


Add an object to the scene:
==== Member functions ====
 
Add an object to the scene:
   void AddObject(MetaObject* object);
   void AddObject(MetaObject* object);


Return the number of objects in the scene:
Return the number of objects in the scene:
int  NObjects(void) const;
  int  NObjects(void) const;


Get a list of objects present in the scene:
Get a list of objects present in the scene:
ObjectListType * GetObjectList(void) {return & m_ObjectList;}
  ObjectListType * GetObjectList(void) {return & m_ObjectList;}
Example
 
/** Define a 3D Scene */
==== Example ====
  /** Define a 3D Scene */
   MetaScene scene(3);
   MetaScene scene(3);
 
   MetaEllipse * e1 = new MetaEllipse(3);
   MetaEllipse * e1 = new MetaEllipse(3);
   e1->ID(0);
   e1->ID(0);
   e1->Radius(3);
   e1->Radius(3);
 
   MetaGroup g0;
   MetaGroup g0;
   MetaGroup * g1 = new MetaGroup(3);
   MetaGroup * g1 = new MetaGroup(3);
   g1->ID(2);
   g1->ID(2);
 
   s->AddObject(g1);
   s->AddObject(g1);
   s->AddObject(e1);
   s->AddObject(e1);
 
   s->Write("scene.scn");
   s->Write("scene.scn");
   scene.Clear();
   scene.Clear();
 
   s->Read("scene.scn");
   s->Read("scene.scn");
==== Output File Example ====


Annex: Output File Example
Here is the example of a metafile with a scene that contains metaObjects
Here is the example of a metafile with a scene that contains metaObjects


ObjectType = Scene
ObjectType = Scene
NDims = 3
NDims = 3
NObjects = 3
NObjects = 3
ObjectType = Group
ObjectType = Group
NDims = 3
NDims = 3
ID = 2
ID = 2
EndGroup =  
EndGroup =  
ObjectType = Ellipse
ObjectType = Ellipse
NDims = 3
NDims = 3
ID = 0
ID = 0
ParentID = 2
ParentID = 2
Radius = 1 2 3
Radius = 1 2 3
ObjectType = Line
ObjectType = Line
NDims = 3
NDims = 3
ID = 0
ID = 0
BinaryData = False
BinaryData = False
BinaryDataByteOrderMSB = False
BinaryDataByteOrderMSB = False
ElementType = MET_FLOAT
ElementType = MET_FLOAT
PointDim = x y z v1x v1y v1z
PointDim = x y z v1x v1y v1z
NPoints = 3
NPoints = 3
Points =  
Points =  
1 2 3 0 0 0
1 2 3 0 0 0
1 2 3 0 0 0
1 2 3 0 0 0
1 2 3 0 0 0
1 2 3 0 0 0
ObjectType = Landmark
ObjectType = Landmark
NDims = 3
NDims = 3
ID = 0
ID = 0
BinaryData = True
BinaryData = True
BinaryDataByteOrderMSB = False
BinaryDataByteOrderMSB = False
ElementType = MET_FLOAT
ElementType = MET_FLOAT
PointDim = x y z red green blue alpha
PointDim = x y z red green blue alpha
NPoints = 2
NPoints = 2
Points =  
Points =  
1 2 3 1.0 0.0 0.0 1.0
1 2 3 1.0 0.0 0.0 1.0
1 2 3 1.0 0.0 0.0 1.0
1 2 3 1.0 0.0 0.0 1.0
1 2 3 1.0 0.0 0.0 1.0
1 2 3 1.0 0.0 0.0 1.0  
 


== Spatial Objects ==


Annex: Spatial Objects
MetaIO has also been chosen to support Spatial Objects IO.  To obtain a complete documentation of Spatial Objects and how to read/write them out please see the Insight user’s manual available at www.itk.org.


MetaIO has also been chosen to support Spatial Objects IO.  To obtain a complete documentation of Spatial Objects and how to read/write them out please see the Insight user’s manual available at www.itk.org,.
== Reference: Tags of MetaImage ==


Reference: Tags of MetaImage
=== MetaObject Tags ===
MetaObject Tags


The tags of MetaObject are:
The tags of MetaObject are:


Comment – MET_STRING – User defined - arbitrary
* Comment
** MET_STRING
** User defined - arbitrary
* ObjectType
** MET_STRING
** Defined by derived objects – e.g., Tube, Image
* ObjectSubType
** MET_STRING
** Defined by derived objects currently not used
* TransformType
** MET_STRING
** Defined by derived objects e.g., Rigid
* NDims
** MET_INT
** Defined at object instantiation
* Name
** MET_STRING
** User defined
* ID
** MET_INT
** User defined else -1
* ParentID
** MET_INT
** User defined else -1
* BinaryData
** MET_STRING
** Are the data associated with this object stored at Binary or ASCII
** Defined by derived objects
* ElementByteOrderMSB
** MET_STRING
* BinaryDataByteOrderMSB
** MET_STRING
* Color
** MET_FLOAT_ARRAY[4]
** R, G, B, alpha (opacity)
* Position
** MET_FLOAT_ARRAY[NDims]
** X, Y, Z,… of real-world coordinate of 0,0,0 index of image)
* Orientation
** MET_FLOAT_MATRIX[NDims][NDims]
** [0][0],[0][1],[0][2] specify X, Y, Z… direction in real-world of X-axis of image
** [1][0],[1][1],[1][2] specify X, Y, Z… direction in real-world of Y-axis of image, etc.
* AnatomicalOrientation
** MET_STRING
** This is a convenience tag, to be used and maintained by applications.  Changing this tag in a MetaIO file or via the MetaIO API will not cause the MetaIO library to resample or change the direction matrix of an image.  It is up to an application to correctly read, write, and maintain this tag.
** The history of the interpretation of this tag is as follows:
*** Labels: The labels used to define a space can be "from" labels or "to" labels, where "from" labels define the relative physical location of the origin of a space and "to" labels define the physical direction of movement of a space - thereby RAI "from" space is the same as LPS "to" space.  DICOM, ITK, and nearly every application consider label space to be "to" labels.
*** In an LPS "to" space ("to" space will be assumed in the remainder of this discussion), when moving in the x,y,z-directions of space, then you are physically moving to the left. 
*** The direction matrix specifies how "index" i,j,k-directions (sometimes referred to as the in-memory directions of an image) map into x,y,z-directions. Changing the direction matrix will never change the fact that you're in an LPS space, but changing a direction matrix will change how moving along the i-index direction maps to a movement in the LPS space.
*** Originally, AnatomicalOrientation was intended to define the space (LPS, RAS, etc) of an image; however, in early 2000s, its implementation was changed (and its documentation became unclear) to define how a patient was oriented in index space (it assumed an LPS space, and thus it became redundant with the direction matrix).  These changes seem to have coincided with ITK's introduction of a direction matrix (thanks goes to Alexis Girault for hunting down this history!). For the past fifteen years++, ITK writes AnatomicOrientation based on the direction matrix and assumes an LPS space.  See the code in itkSpatialOrientation.h that specifies a 3-letter code derived from an image's direction matrix and that 3-letter code is then used to specify the AnatomicalOrientation tag in MetaIO.
*** Moving forward, when implementing new applications, it is recommended that developers use the definition currently implemented by ITK.  It represents the most common use of MetaIO.
* ElementSpacing
** MET_FLOAT_ARRAY[NDims]
** The distance between voxel centers


ObjectType – MET_STRING – Defined by derived objects – e.g., Tube, Image
=== Tags Added by MetaImage ===
 
ObjectSubType – MET_STRING – Defined by derived objects – currently not used
 
TransformType – MET_STRING – Defined by derived objects – e.g., Rigid
 
NDims – MET_INT – Defined at object instantiation
 
Name – MET_STRING – User defined
 
ID – MET_INT – User defined else -1
 
ParentID – MET_INT – User defined else -1
 
BinaryData – MET_STRING – Are the data associated with this object stored at Binary or ASCII
– Defined by derived objects
 
ElementByteOrderMSB – MET_STRING
 
BinaryDataByteOrderMSB – MET_STRING
 
Color – MET_FLOAT_ARRAY[4] – R, G, B, alpha (opacity)
 
Position – MET_FLOAT_ARRAY[NDims] – X, Y, Z,… of real-world coordinate of 0,0,0 index of image)
 
Orientation – MET_FLOAT_MATRIX[NDims][NDims] – [0][0],[0][1],[0][2] specify X, Y, Z… direction in real-world of X-axis of image
– [1][0],[1][1],[1][2] specify X, Y, Z… direction in real-world of Y-axis of image, etc.
 
AnatomicalOrientation – MET_STRING – Specify anatomic ordering of the axis.  Use only [R|L] | [A|P] | [S|I] per axis.  For example, if the three letter code for (column index, row index, slice index is) ILP, then the origin is at the superior, right, anterior corner of the volume, and therefore the axes run from superior to inferior, from right to left, from anterior to posterior.
 
ElementSpacing – MET_FLOAT_ARRAY[NDims] – The distance between voxel centers
 
 
Tags Added by MetaImage


In addition to the above tags, MetaImage provides the following tags:
In addition to the above tags, MetaImage provides the following tags:


DimSize MET_INT_ARRAY[NDims] Number of elements per axis in data
* DimSize  
 
** MET_INT_ARRAY[NDims]
HeaderSize – MET_INT Number of Bytes to skip at the head of each data file.
** Number of elements per axis in data
Specify –1 to have MetaImage calculate the header size based on the assumption that the data occurs at the end of the file.
* HeaderSize
 
** MET_INT
Modality MET_STRING One of enum type: MET_MOD_CT, MET_MOD_MR, MET_MOD_US…  See MetaImageTypes.h
** Number of Bytes to skip at the head of each data file.
 
** Specify –1 to have MetaImage calculate the header size based on the assumption that the data occurs at the end of the file.
SequenceID – MET_INT_ARRAY[4] Four values comprising a DICOM sequence: Study, Series, Image numbers
** Specify 0 if the data occurs at the begining of the file.
 
* Modality
ElementMin – MET_FLOAT Minimum value in the data
** MET_STRING
 
** One of enum type: MET_MOD_CT, MET_MOD_MR, MET_MOD_US…  See [https://github.com/Kitware/MetaIO/blob/ffe3ce141c5a2394e40a0ecbe2a667cc0566baf5/src/metaImageTypes.h#L21 metaImageTypes.h]
ElementMax – MET_FLOAT Maximum value in the data
* SequenceID
 
** MET_INT_ARRAY[4]
ElementNumberOfChannels – MET_INT Number of values (of type ElementType) per voxel
** Four values comprising a DICOM sequence: Study, Series, Image numbers
 
* ElementMin
ElementSize – MET_FLOAT_ARRAY[NDims] Physical size of each voxel
** MET_FLOAT
 
** Minimum value in the data
ElementType – MET_STRING One of enum type: MET_UCHAR, MET_CHAR… See MetaImageTypes.h
* ElementMax
 
** MET_FLOAT
ElementDataFile – MET_STRING One of the following:
** Maximum value in the data
- Name of the file to be loaded
* ElementNumberOfChannels
- A printf-style string followed by the min, max, and step values to be used to pass an argument to the string to create list of file names to be loaded (must be (N-1)D blocks of data per file).
** MET_INT
- LIST [X] – This specifies that starting on the next line is a list of files (one filename per line) in which the data is stored.  Each file (by default) contains an (N-1)D block of data. If a second argument is given, its first character must be a number that specifies the dimension of the data in each file. For example ElementDataFile = LIST 2D means that there will be a 2D block of data per file.
** Number of values (of type ElementType) per voxel
- LOCAL – Indicates that the data begins at the beginning of the next line.
* ElementSize
** MET_FLOAT_ARRAY[NDims]
** Physical size of each voxel
* ElementType
** MET_STRING
** One of enum type: MET_UCHAR, MET_CHAR… See [https://github.com/Kitware/MetaIO/blob/ffe3ce141c5a2394e40a0ecbe2a667cc0566baf5/src/metaTypes.h#L63-94 metaTypes.h]
* ElementDataFile
** MET_STRING
** One of the following:
*** Name of the file to be loaded
*** A printf-style string followed by the min, max, and step values to be used to pass an argument to the string to create list of file names to be loaded (must be (N-1)D blocks of data per file).
*** LIST [X] – This specifies that starting on the next line is a list of files (one filename per line) in which the data is stored.  Each file (by default) contains an (N-1)D block of data. If a second argument is given, its first character must be a number that specifies the dimension of the data in each file. For example ElementDataFile = LIST 2D means that there will be a 2D block of data per file.
*** LOCAL – Indicates that the data begins at the beginning of the next line.

Latest revision as of 20:38, 26 October 2021

Abstract

MetaImage is the text-based tagged file format for medical images that resulted. We have now extended that file format to support a variety of objects that occur in medicine such a tubes (for vessels, needles, etc.), blobs (for arbitrary shaped objects), cubes, spheres, etc. The complete library is known at MetaIO.

The central code of MetaImage/MetaIO is quite stable. MetaImage has been in use for several years by a wide range of research at UNC, Chapel Hill. New features are occasionally added, but backward compatibility will always be maintained.

Introduction and Installation

Obtaining MetaIO

The upstream MetaIO Git repository:

MetaIO is being distributed with the following packages:

Installing The MetaIO Package

MetaIO is a hierarchy of C++ classes and functions. We have yet to find a modern C++ compiler that does not compile MetaIO. Know compatible compilers include G++ v2.95 and beyond (and probably previous), Microsoft Visual C++ 6.0, Sun’s CC on Solaris 2.6 and beyond, Intel compiler and compilers on other workstations including HPs, SGIs, and Alpha systems. Please contact us (Stephen R. Aylward, stephen.aylward@kitware.com or Julien Jomier, julien.jomier@kitware.com) if you encounter any incompatibilities between our code and your compiler.

MetaIO should be built as part of the standard ITK and VTK installations. It is also quite easy to use MetaIO from within these toolkits without using the rest of the toolkit.

ITK MetaIO

The hierarchy of the software in the stand-alone MetaIO package is as follows:

  • MetaIO/
    • doc/
    • tests/

The top level contains the source files, the header files, and the CMakeLists.txt file that is used by the CMake program to compile MetaIO. This document and the MetaObjects www pages are in the doc directory. A sequence of simple tests is available in the tests directory.

The hierarchy of the software in the Insight and InsightApplications distributions is as follows:

  • Insight
    • Code/Utilities/MetaIO/
      • doc/
      • tests/
  • InsightApplications
    • MetaImageImporter
    • ImageViewer (formerly MetaImageViewer)
    • ColorImageViewer (formerly MetaColorImageViewer)
    • MetaImageReadWrite

Routines that wrap MetaIO for ITK's image IO object factory are in

  • Insight/Code/IO/
    • itkMetaImageReader, itkMetaImageWriter

Routines that wrap MetaIO for reading and writing ITKS's Spatial Objects (tubes, blobs, ellipses, meshes, etc.) are in

  • Insight/Code/SpatialObject

Certain examples, such as the MetaImageViewer, also require FLTK (a cross-platform user interface library available from http://fltk.org). Install FLTK and then ITK and then InsightApplications to have every MetaIO example built. Numerous other examples and applications in InsightApplications also rely on FLTK.

See the file /Insight/Examples/MetaImageReadWrite for a working example on how to develop a program using MetaImage for IO.

VTK MetaIO

The hierarchy of the software in the Visualization toolkit is as follows:

  • VTK/Utilitites
    • vtkmetaio
  • VTK/IO

Stand Alone MetaIO

MetaIO can also be compiled outside of these toolkits. This is left as an exercise to the user (hint: requires the kwsys and zlib libraries). Instead of a stand-alone installation, we highly recommend using the distribution in ITK - if you build ITK, you get MetaIO for free!

Quick Start

Data conversion via MetaHeaders

This section assumes that you have data that you wish to process using an application that reads MetaImages. This section gives examples on how “convert” your data to the MetaImage format.

For uncompressed data, “conversion” to MetaImage is actually just a matter of specifying a MetaImage Headerfile (a “MetaHeader”) that describes and points to the file(s) containing your data.

  • Uncompressed data is data stored in a raw format, possibly with a header, as is often the case for DICOM, BMP, and PNG formatted images.

For compressed data, you must first convert your data to a non-compressed format. One of the most robust image conversion software packages is ImageMagick (http://www.imagemagick.org/; Unix and PC versions available). It has an application called “convert” that handles most of the popular 2D image formats.

  • Compressed data is includes JPEG or GIF formats as well as select PNG and TIFF images.

Using MetaImageImporter

MetaImageImporter asks a series of questions about your data and then produces a MetaImage header file that points to your data and allows the MetaIO library to read your data.

MetaImageImporter is part of the InsightApplications repository. See http://www.itk.org for information on downloading and installing InsightApplications - the companion to the Insight repository.

MetaImageImporter now has a QT graphical user interface. Please see the documentation.

Otherwise, the following two sub-sections will step you through the conversion process. The first sub-section applies if all of your data is in one file, i.e., is a "brick-of-bytes". The second sub-section applies if your data is spread across files, e.g., is dicom or a tiff sequence.

Reading a Brick-of-Bytes (an N-Dimensional volume in a single file)

A “brick of bytes” is a volume of image data stored in a single file possibly with preceding and trailing non-image data. A volume can be of any dimension (1 dimensional to N dimensional).

To correctly load these images, the minimal information that you need to know is:

  1. Number of dimensions
  2. Size of each dimension
  3. Data type
  4. Name of the data file

For example, let’s say the data was 3 dimensional, had 256 x 256 x 64 voxels, used an unsigned short to represent the value at each voxel, and was stored in the file “image.raw”. The resulting MetaHeader (our naming convention would call this file “image.mhd”) file would read

ObjectType = Image
NDims = 3
DimSize = 256 256 64
ElementType = MET_USHORT
ElementDataFile = image.raw	(this tag must be last in a MetaImageHeader)

That’s it, but this assumes quite a bit about the image data. Specifically, it assumes

  1. There are not any non-image data bytes (header data) at the beginning of the image data file “image.raw”.
  2. The voxels are cubes – the distance spanned by and between a voxel in each coordinate direction is 1 “unit”, e.g., 1x1x1mm voxel size and voxel spacing
  3. The byte-order of the data in image.raw matches the byte ordering native to the machine the application is running on (e.g., PC’s use LSB ordering and Suns/Macs use MSB ordering).

If these assumptions are false, the data will not be loaded correctly by the application. To fix these problems, MetaIO allows you to specify additional tag/value pairs in the header:

  1. To skip the header bytes in the image data file, use
HeaderSize = X

where X is the number of bytes to skip at the beginning of the file before reading image data. If you know there are no trailing bytes (extra bytes at the end of the file) you can specify

HeaderSize = -1

and MetaImage will automatically calculate the number of extract bytes in the data file, assume they those bytes are at the head of the data file, and automatically skip them before beginning to read the image data.

  1. To specify the spacing of the voxels, use
ElementSpacing = X Y Z

where X is the distance between of the centers of the voxels along the x-dimension, Y is the spacing in the y-dimension, and Z is the spacing in the z-dimension. Therefore, to specify a 1x1x3mm voxel spacing, use

ElementSpacing = 1 1 3

NOTE: If ElementSpacing is not specified, it is assumed to be equal to ElementSize. If neither is specified, both are assumed to be 1.

  1. To specify a voxel size, use
ElementSize = X Y Z

where X Y Z represent the size in the x, y, and z-dimensions respectively.

NOTE: If ElementSize is not specified, it is assumed to be equal to ElementSpacing. If neither is specified, both are assumed to be 1.

  1. To specify a particular byte ordering, use
ElementByteOrderMSB = True

or

ElementByteOrderMSB = False

MSB (aka big-endian) ordering is common to SPARC and Motorola processors (e.g., Macintoshes). LSB (aka little-endian) ordering is common to Intel processors (e.g., PC compatibles).

Putting it all together, to “convert” a file containing the image data in a continuous block at the end of the file, specify the header

ObjectType = Image
NDims = 3
DimSize = 256 256 64
ElementType = MET_USHORT
HeaderSize = -1
ElementSize = 1 1 3
ElementSpacing = 1 1 1
ElementByteOrderMSB = False
ElementDataFile = image.raw

Reading DICOM and Other One-Slice-Per-File Data Formats

If the data is split into one slice per file, as is done with most DICOM object files, only the ElementDataFile tag’s option needs to change. Note that 3D DICOM object files are becoming popular, and some such DICOM files can be read using the above, volume, technique.

Since the MetaLibrary cannot directly parse DICOM headers, those headers must be skipped and the user must specify the image dimensions and other essential image information. For DICOM files, the MetaLibrary must automatically calculate the header size of each file (luckily for almost every DICOM object the image data is stored at the end of the file). For this reason, this method only works for uncompressed files.

To specify which files comprise the volume, they can be specified as an ordered list in the MetaHeader using the ElementDataFile=LIST option. The filenames should be listed at the end of the MetaHeader, after the ElementDataFile option, and the filenames should be separated by whitespace:

ObjectType = Image
NDims = 3
DimSize = 512 512 100
ElementType = MET_USHORT
HeaderSize = -1
ElementSize = 1 1 3
ElementSpacing = 1 1 1
ElementByteOrderMSB = False
ElementDataFile = LIST
filenameOfSlice1
filenameOfSlice2
filenameOfSlice3
filenameOfSlice4
.
. (one hundred filenames must be specified to specify the 100 slices in the volume)
.

This method works even if there are spaces in the file paths and file names.

Notice that this method can become tedious if a large number of files need to be read. To alleviate this, a second way of specifying a series of files can be used if the filenames are numerically distinguished. That is, the file names should be able to be specified using a numeric substitution into a c-style printf-string, for a range of values. In pseudo-code:

for i=numBegin to numEnd step numStep
 sprintf(sliceName, “baseName.%03d”, i);
end

The parameters of this system are numBegin, numEnd, numStep, and the c-style printf string (e.g., “baseName.%03d”). The begin, end, and step parameters appear in order after the c-style printf string:

ObjectType = Image
NDims = 3
DimSize = 512 512 100
ElementType = MET_USHORT
HeaderSize = -1
ElementSize = 1 1 3
ElementSpacing = 1 1 1
ElementByteOrderMSB = False
ElementDataFile = baseName.%03d 1 100 1

The above MetaImage header will cause the files “baseName.001” to “baseName.100” to be read to create a 100-slice volume. This method works even if there are spaces in the file paths and file names. However, when spaces are present in the file path and/or file name, all three parameters (begin, end, and step) need to be specified as the last parameters. The remaining parameters (initially parsed based on spaces) are then joined back together (including spaces) to generate the file name.

In some cases, it may be helpful to skip slices in the volume. Changing the slice spacing and the ElementDataFileNumStep enacts this…

ObjectType = Image
NDims = 3
DimSize = 512 512 50
ElementType = MET_USHORT
HeaderSize = -1
ElementSize = 1 1 3
ElementSpacing = 1 1 2
ElementByteOrderMSB = False
ElementDataFile = baseName.%03d 1 100 2

The complete set of MetaImage Tags are given in the Reference section of this document. The next section discusses how to use the MetaImage Library for image reading and writing in your own programs.

MetaIO Library Architecture

The base class of the MetaIO library is the MetaObject class. It defines a base set of tags that are common to all metaObjects such as MetaImages, MetaTubes, etc.

The tags are defined using the protected member functions SetupReadFields and SetupWriteFields. These functions create a list of MetaFieldRecords to define the name, type, interdependence, and necessity of each tag. Helper functions for defining the fields are in MetaUtils.cxx. The types are defined via enums in MetaTypes.h

The derived classes add tags to the list via their own SetupReadFields and SetupWriteFields member functions. The MetaImage subclass also re-implements the Read and Write methods since non tag data (i.e., the pixel values) must also be read. Compare the derived classes for MetaCube and MetaImage.

MetaObjects

In this section we describe the metaObjects which have been implemented already. If you want to implement other objects, you can easily derive these classes. metaObject is the base class for metaIO. metaScene and metaGroup are also a useful objects that support multiple metaObjects. All these objects are described in details next.

Constructors

Simple constructor

     MetaObject(void);

Read a metafile and store the result in the current object

     MetaObject(const char * _fileName);

Define the dimension of the object at construction time.

     MetaObject(unsigned int dim);

Member functions

Specify the filename to read (Optional)

     void  FileName(const char *_fileName);
     const char  * FileName(void) const;

Read a MetaFile

     bool  Read(const char * _fileName=NULL);
    

Write a MetaFile

    bool  Write(const char * _fileName=NULL);
     virtual bool Append(const char *_headName=NULL);

Print the info about the metaObject

     virtual void  PrintInfo(void) const;

Clear the information as well as the data of the metObject

     virtual void Clear(void);

Field descriptions

Name:

     void  Name(const char *_Name);
     const char  * Name(void) const;

Color:

     const float * Color(void) const;
     void  Color(float _r, float _g, float _b, float _a);
     void  Color(const float * _color);

ID: ID number of the current metaObject

     void ID(int _id);
     int  ID(void) const;

Parent ID: ID number of the parent metaObject

     void  ParentID(int _parentId);
     int   ParentID(void) const;

Binary Data: Specify if the data is binary or not

     void  BinaryData(bool _binaryData);
     bool  BinaryData(void) const;

Binary Data Byte Order:

     void  BinaryDataByteOrderMSB(bool _binaryDataByteOrderMSB);
     bool  BinaryDataByteOrderMSB(void) const;

Comments:

     const char  * Comment(void) const;
     void    Comment(const char * _comment);

Object Typename and optional subtype (i.e. the type of the object)

     const char  * ObjectTypeName(void) const;
     void    ObjectTypeName(const char * _objectTypeName);
     const char  * ObjectSubTypeName(void) const;
     void    ObjectSubTypeName(const char * _objectSubTypeName);

Associated transformations

Physical location (in millimeters and with respect to machine coordinate system or the patient) of the first element in the image. Physical orientation of the object is defined as an NDims x NDims matrix that is serialized in a column-major format in MetaIO files.

Offset: (equiv. to position and origin)

     const float * Offset(void) const;
     float Offset(int _i) const;
     void  Offset(const float * _position);
     void  Offset(int _i, float _value);

Position: (equiv. to offset and origin)

     const float * Position(void) const;
     float Position(int _i) const;
     void  Position(const float * _position);
     void  Position(int _i, float _value);

Origin: (equiv. to offset and position)

     const float * Origin(void) const;
     float Origin(int _i) const;
     void  Origin(const float * _position);
     void  Origin(int _i, float _value);


Rotation: (equiv. to orientation and transformMatrix)

     const float * Rotation(void) const;
     float Rotation(int _i, int _j) const;
     void  Rotation(const float * _orientation);
     void  Rotation(int _i, int _j, float _value);

Orientation: (equiv. to rotation and transformMatrix)

     const float * Orientation(void) const;
     float Orientation(int _i, int _j) const;
     void  Orientation(const float * _orientation);
     void  Orientation(int _i, int _j, float _value);

TransformMatrix: (equiv. to rotation and orientation)

     const float * TransformMatrix(void) const;
     float TransformMatrix(int _i, int _j) const;
     void  TransformMatrix(const float * _transformMatrix);
     void  TransformMatrix(int _i, int _j, float _value);

Center of rotation of the object:

     const float * CenterOfRotation(void) const;
     float CenterOfRotation(int _i) const;
     void  CenterOfRotation(const float * _position);
     void  CenterOfRotation(int _i, float _value);

Anatomical Orientation:

     const char * AnatomicalOrientationAcronym(void) const;
     const MET_OrientationEnumType * AnatomicalOrientation(void) const;
     MET_OrientationEnumType AnatomicalOrientation(int _dim) const;
     void AnatomicalOrientation(const char *_ao);
     void AnatomicalOrientation(const MET_OrientationEnumType *_ao);
     void AnatomicalOrientation(int _dim, MET_OrientationEnumType _ao);
     void AnatomicalOrientation(int _dim, char ao);


Element Spacing: Physical Spacing (in same units as position)

     const float * ElementSpacing(void) const;
     float ElementSpacing(int _i) const;
     void  ElementSpacing(const float * _elementSpacing);
     void  ElementSpacing(int _i, float _value);


For simplicity, some dynamic functions have been recently added. They allow the user to add fields dynamically.

The function AddUserField is defined by:

     template <class T>
     bool AddUserField(const char* _fieldName,MET_ValueEnumType _type, int _length,
                       T *_v,bool _required=true,int _dependsOn=-1 )
 

The user may also want to clear the fields created by using

ClearUserFields().

To determine the value of a field

     void* GetUserField(const char* _name);

Note: When using GetUserField() function, the user is responsible for the deletion of the pointer created. See the following example for details.

Example

 /** We create a simple 3D metaObject with some properties */
 MetaObject tObj(3); // Create a 3D metaObject
 tObj.FileName("testObject.txt"); // Define the name of the file
 tObj.Comment("TestObject"); // Add some comments
 tObj.ObjectTypeName("Object"); // Define the type of the object
 tObj.ObjectSubTypeName("MinorObject"); // and the subtype as well

 /** We now define the position and the orientation as well as the spacing of the created object */
 // The position part
 tObj.Position(0, 1);
 tObj.Position(1, 2);
 tObj.Position(2, 3);

 // The orientation part
 float orient[9];
 int i;
 for(i=0; i<9; i++)
   {
   orient[i] = 0;
   }
 orient[0] = 1;
 orient[5] = 1;
 orient[7] = 1;
 tObj.Orientation(orient);

 // The element spacing part
 tObj.ElementSpacing(0, 1);
 tObj.ElementSpacing(1, 2);
 tObj.ElementSpacing(2, 1);


 /** Add user's defined fields */
 tObj.AddUserField("MyName", MET_STRING, strlen("JulienAndStephen"), "JulienAndStephen");

 /** Write the object */
 tObj.Write();

 /** Clear completely the object */
 tObj.Clear();
 tObj.ClearUserFields();
 
 /** Specify that we want to read the field  ‘MyName’ */
 tObj.AddUserField("MyName", MET_STRING);

 /** Read the object */
 tObj.Read("testObject.txt");

 /** Print the object */
 tObj.PrintInfo();
 /** Get the name in the file */
 char* name = static_cast<char*>(tObj.GetUserField("MyName"));
 std::cout << name << std::endl;

 /** delete the allocated pointer */
 delete [] name;

Types of MetaObjects

All of the following objects derive from metaObject.

MetaBlob

A blob is defined by a list of points that describe the object. The points can be inside the object (if obtained by connected-component for instance) or only on the surface. Note that a color (RGBA) can be associated which each point.

The required fields are:

  • The number of points defining the object:
NPoints(int npnt);
  • How the position of the points is stored in the file. By default the configuration is x y z red green blue alpha
PointDim(const char* pointDim);

To access the internal list of points user should use the GetPoints() function which returns the internal list by reference. Note that the list is a list of pointers to point and is deleted automatically by the object itself so the user does not need to free the allocated memory.

Example

 /** Create a 3D blob */
 MetaBlob blob(3);
 blob.ID(0); // define the ID of the blob

 /** Add 10 points to the blob */
 BlobPnt* pnt;

 unsigned int i;
 for(i=0;i<10;i++)
   {
   pnt = new BlobPnt(3);
   pnt->m_X[0]=(float)0.2;
   pnt->m_X[1]=i;
   pnt->m_X[2]=i;
   blob.GetPoints().push_back(pnt); // push the created point into the list of points
   }
  
 /** Write the blob in binary format */
 blob.BinaryData(true);
 blob.ElementType(MET_FLOAT);
 blob.Write("myBlob.meta");

 /** Read the file */
 blob.Read("myBlob.meta"); 
 blob.PrintInfo();
 /** Access the list of points */
 std::cout << "Accessing pointlist..." << std::endl;

 MetaBlob::PointListType plist =  blob.GetPoints();
 MetaBlob::PointListType::const_iterator it = plist.begin();
 
 while(it != plist.end())
   {
   for(unsigned int d = 0; d < 3; d++)
     {
     std::cout << (*it)->m_X[d] << " ";
     }
   std::cout << std::endl;
   it++;
   }

MetaEllipse

MetaEllipse is an N-Dimensional object to define ellipsoids like circles, spheres or even hyper-ellipsoids.

The only field you need to provide is the Radius.

There are several ways to input the radius:

  1. As an array of floats: void Radius(const float* radius);
  2. As a single value which means that we are defining an hyper-sphere: void Radius(float radius);
  3. A convenient way to define a 2D ellipse: void Radius(float r1,float r2);
  4. A convenient way to define a 3D ellipse: void Radius(float r1,float r2, float r3);

Example

 /** Create a sphere */
 MetaEllipse  myEllipse (3);
 myEllipse ->Radius(3); // radius of  3

MetaGroup

MetaGroup does not have added functionalities compared to metaObject. It allows to group object in a metafile.

MetaImage

Constructors

Simple constructor by specifying the filename

MetaImage(const char *_headerName);   

Constructor by shared memory

MetaImage(MetaImage *_im);  

Other constructors

MetaImage(int _nDims, 
          const int * _dimSize,
          const float *_elementSpacing,
          MET_ValueEnumType _elementType,
          int _elementNumberOfChannels=1,
          void *_elementData=NULL);
MetaImage(int _x, int _y, 
          float _elementSpacingX, 
          float _elementSpacingY,
          MET_ValueEnumType _elementType, 
          int _elementNumberOfChannels=1,
          void *_elementData=NULL);
MetaImage(int _x, int _y, int _z, 
          float _elementSpacingX,
          float _elementSpacingY,
          float _elementSpacingZ, 
          MET_ValueEnumType _elementType,
          int _elementNumberOfChannels=1,
          void *_elementData=NULL);

Member functions

HeaderSize: Return the size of the header.

   int  HeaderSize(void) const;

Quantity: Total number of elements in the image.

   int   Quantity(void) const;

SubQuantity: Number of elements in image spanning sub-dimensions. E.g., elements per line, 2D sub-image, 3D sub-volume.

   const int * SubQuantity(void) const;      
   int   SubQuantity(int _i) const;  

ElementMin/Max: The default max returned is the largest allowed by ElemNBytes (12 bit uint16_t will give 4096 max). This may not represent the true max. Use _reCalc=true to force a calcuation of the actual max element value.

   bool  ElementMinMaxValid(void) const;
   void  ElementMinMaxValid(bool _elementMinMaxValid);
   void  ElementMinMaxRecalc(void);
   double ElementMin(void) const;    
   void  ElementMin(double _elementMin);
   double ElementMax(void) const;
   void  ElementMax(double _elementMax);

ElementByteOrderSwap: These functions are available only after ReadImageData() or if _read_and_close=TRUE when read

   void  ElementByteOrderSwap(void);
   bool  ElementByteOrderFix(void);


ConverTo: Converts to a new data type. Rescales using Min and Max.

   bool  ConvertElementDataTo(MET_ValueEnumType _elementType=MET_UCHAR,
                      double _toMin=0, double _toMax=0);

Field descriptions

Modality: Specify the modality of the image

   MET_ImageModalityEnumType  Modality(void) const;
   void Modality(MET_ImageModalityEnumType _modality);

Dimension size: Specify the size of the image in each dimension

   void  DimSize(const int * _dimSize);
   void  DimSize(int _i, int _value);

SequenceID: DICOM designation of this image relative to other images acquired at the same time

   const float * SequenceID(void) const;
   float SequenceID(int _i) const;
   void  SequenceID(const float * _sequenceID);
   void  SequenceID(int _i, float _value);

ElementSize: Optional Field. Physical size (in MM) of each element in the image (0 = xSize, 1 = ySize, 2 = zSize)

   const float * ElementSize(void) const;
   float ElementSize(int i) const;
   void  ElementSize(const float * _pointSize);
   void  ElementSize(int _i, float _value);

ElementType: Pixel type

   MET_ValueEnumType ElementType(void) const;
   void  ElementType(MET_ValueEnumType _elementType);

ElementNumberOfChannels: Number of channels

   int   ElementNumberOfChannels(void) const;
   void  ElementNumberOfChannels(int _elementNumberOfChannels);

ElementData: Returns a pointer to the data.

   void * ElementData(void);
   double ElementData(int _i) const;
   void  ElementData(void * _data);
   bool  ElementData(int _i, double _v);

ElementDataFileName: Set/Get the filename

   const char * ElementDataFileName(void) const;
   void ElementDataFileName(const char * _dataFileName);

Example

ObjectType = Image
NDims = 2
BinaryData = True
BinaryDataByteOrderMSB = False
ElementSpacing = 1 2
DimSize = 8 8
ElementType = MET_CHAR
ElementDataFile = LOCAL
[Pixel Data]

MetaLandmark

MetaLandmark is a simple list of landmarks.

The number of landmarks defining the object is set using the function

NPoints(int npnt);

How the position of the points is stored in the file: By default the configuration is x y z red green blue alpha

PointDim(const char* pointDim);

To access the internal list of points user should use the GetPoints() function which returns the internal list by reference. Note that the list is a list of pointers to point and is deleted automatically by the object itself so the user does not need to free the allocated memory.

Example

 /** Create a 3D Landmark */
 MetaLandmark Landmark(3);
 Landmark.ID(0);
 LandmarkPnt* pnt;
 /** Add some landmarks to the list of landmark points*/
 for(unsigned int i=0;i<10;i++)
   {
   pnt = new LandmarkPnt(3);
   pnt->m_X[0]=(float)0.2;
   pnt->m_X[1]=i;
   pnt->m_X[2]=i;
   Landmark.GetPoints().push_back(pnt);
   }
 

MetaLine

A metaLine is actually a polyline defined by a list of connected points. A point on the line has a given position, a normal and a color.

To set the position the local variable m_X should be filled in the point structure. The variable m_V which is a double pointer to a float is used to assess the normal. The normal has the dimension of the object minus one since a metaLine in a 3D space will have two normals (a plane).

Note that the user does not need to allocate the memory for those variables, this is done automatically in the constructor of the point.

To access the internal list of points user should use the GetPoints() function which returns the internal list by reference. Note that the list is a list of pointers to point and is deleted automatically by the object itself so the user does not need to free the allocated memory.

Example

 /** Create a 3D MetaLine */
 MetaLine Line(3);
 LinePnt* pnt;

 for(unsigned int i=0;i<10;i++)
   {
   pnt = new LinePnt(3);

   /** Define the position */
   pnt->m_X[0]=(float)0.2;
   pnt->m_X[1]=i;
   pnt->m_X[2]=i;
   /** Define the normals */
   pnt->m_V[0][0]=(float)0.3;
   pnt->m_V[0][1]=i;
   pnt->m_V[0][2]=i;
   pnt->m_V[1][0]=(float)0.4;
   pnt->m_V[1][1]=i+1;
   pnt->m_V[1][2]=i+1;
   Line->GetPoints().push_back(pnt);
   }
  
 /** Write the result */
 Line.BinaryData(true);
 Line.Write("myLine.meta");

MetaSurface

The definition of a metaSurface is quite similar to the metaLine’s, except for the normal which is only a NDim vector (i.e. an array of floats) where NDim is the dimension of the metaObject.

To access the internal list of points user should use the GetPoints() function which returns the internal list by reference. Note that the list is a list of pointers to point and is deleted automatically by the object itself so the user does not need to free the allocated memory.

Example

 MetaSurface surface(3);
 SurfacePnt* pnt;

 for(unsigned int i=0;i<10;i++)
   {
   pnt = new SurfacePnt(3);
 
   /** Position */
   pnt->m_X[0]=(float)0.2;
   pnt->m_X[1]=i;
   pnt->m_X[2]=i;

   /* Normal */
   pnt->m_V[0]=(float)0.8;
   pnt->m_V[1]=i;
   pnt->m_V[2]=i;
   surface->GetPoints().push_back(pnt);
   }

MetaTube

A metaTube is a tubular structure defined by a list of connected points (like a metaLine) but more fields have been added for a complete representation, especially the one of blood vessels. To specify a point that belongs to the tube, the user can define: the position, the radius at that point, the normal(s), the tangent, the color, the Identification number, the medialness, the branchness, the ridgeness, and three alpha values that represents the ratio of the eigen values at that points.

Note that metaTube supports only 2D and 3D tubes.

Also for a metaTube, the ID of the root can be specified by the command Root(int rootID) and the ID of the parent point can also be assessed using ParentPoint(int parentpoint).

To access the internal list of points user should use the GetPoints() function which returns the internal list by reference. Note that the list is a list of pointers to point and is deleted automatically by the object itself so the user does not need to free the allocated memory.

Example

 /** Create a 3D tube*/
 MetaTube* tube1 = new MetaTube(3);
 tube1->ID(0);

 /** Add 10 points to the list of tubePoints */
 TubePnt* pnt;
 for(unsigned int i=0;i<10;i++)
   {
   pnt = new TubePnt(3);

   pnt->m_X[0]=i; // position
   pnt->m_X[1]=i;
   pnt->m_X[2]=i;
   pnt->m_R=i; // radius
   tube1->GetPoints().push_back(pnt);
   }
 

MetaScene

A metaScene is a metaObject that contains a flat list of metaObjects.

Member functions

Add an object to the scene:

  void AddObject(MetaObject* object);

Return the number of objects in the scene:

  int   NObjects(void) const;

Get a list of objects present in the scene:

  ObjectListType * GetObjectList(void) {return & m_ObjectList;}

Example

 /** Define a 3D Scene */
 MetaScene scene(3);

 MetaEllipse * e1 = new MetaEllipse(3);
 e1->ID(0);
 e1->Radius(3);

 MetaGroup g0;
 MetaGroup * g1 = new MetaGroup(3);
 g1->ID(2);

 s->AddObject(g1);
 s->AddObject(e1);

 s->Write("scene.scn");
 scene.Clear();

 s->Read("scene.scn");

Output File Example

Here is the example of a metafile with a scene that contains metaObjects

ObjectType = Scene
NDims = 3
NObjects = 3
ObjectType = Group
NDims = 3
ID = 2
EndGroup = 
ObjectType = Ellipse
NDims = 3
ID = 0
ParentID = 2
Radius = 1 2 3
ObjectType = Line
NDims = 3
ID = 0
BinaryData = False
BinaryDataByteOrderMSB = False
ElementType = MET_FLOAT
PointDim = x y z v1x v1y v1z
NPoints = 3
Points = 
1 2 3 0 0 0
1 2 3 0 0 0
1 2 3 0 0 0
ObjectType = Landmark
NDims = 3
ID = 0
BinaryData = True
BinaryDataByteOrderMSB = False
ElementType = MET_FLOAT
PointDim = x y z red green blue alpha
NPoints = 2
Points = 
1 2 3 1.0 0.0 0.0 1.0
1 2 3 1.0 0.0 0.0 1.0
1 2 3 1.0 0.0 0.0 1.0 

Spatial Objects

MetaIO has also been chosen to support Spatial Objects IO. To obtain a complete documentation of Spatial Objects and how to read/write them out please see the Insight user’s manual available at www.itk.org.

Reference: Tags of MetaImage

MetaObject Tags

The tags of MetaObject are:

  • Comment
    • MET_STRING
    • User defined - arbitrary
  • ObjectType
    • MET_STRING
    • Defined by derived objects – e.g., Tube, Image
  • ObjectSubType
    • MET_STRING
    • Defined by derived objects – currently not used
  • TransformType
    • MET_STRING
    • Defined by derived objects – e.g., Rigid
  • NDims
    • MET_INT
    • Defined at object instantiation
  • Name
    • MET_STRING
    • User defined
  • ID
    • MET_INT
    • User defined else -1
  • ParentID
    • MET_INT
    • User defined else -1
  • BinaryData
    • MET_STRING
    • Are the data associated with this object stored at Binary or ASCII
    • Defined by derived objects
  • ElementByteOrderMSB
    • MET_STRING
  • BinaryDataByteOrderMSB
    • MET_STRING
  • Color
    • MET_FLOAT_ARRAY[4]
    • R, G, B, alpha (opacity)
  • Position
    • MET_FLOAT_ARRAY[NDims]
    • X, Y, Z,… of real-world coordinate of 0,0,0 index of image)
  • Orientation
    • MET_FLOAT_MATRIX[NDims][NDims]
    • [0][0],[0][1],[0][2] specify X, Y, Z… direction in real-world of X-axis of image
    • [1][0],[1][1],[1][2] specify X, Y, Z… direction in real-world of Y-axis of image, etc.
  • AnatomicalOrientation
    • MET_STRING
    • This is a convenience tag, to be used and maintained by applications. Changing this tag in a MetaIO file or via the MetaIO API will not cause the MetaIO library to resample or change the direction matrix of an image. It is up to an application to correctly read, write, and maintain this tag.
    • The history of the interpretation of this tag is as follows:
      • Labels: The labels used to define a space can be "from" labels or "to" labels, where "from" labels define the relative physical location of the origin of a space and "to" labels define the physical direction of movement of a space - thereby RAI "from" space is the same as LPS "to" space. DICOM, ITK, and nearly every application consider label space to be "to" labels.
      • In an LPS "to" space ("to" space will be assumed in the remainder of this discussion), when moving in the x,y,z-directions of space, then you are physically moving to the left.
      • The direction matrix specifies how "index" i,j,k-directions (sometimes referred to as the in-memory directions of an image) map into x,y,z-directions. Changing the direction matrix will never change the fact that you're in an LPS space, but changing a direction matrix will change how moving along the i-index direction maps to a movement in the LPS space.
      • Originally, AnatomicalOrientation was intended to define the space (LPS, RAS, etc) of an image; however, in early 2000s, its implementation was changed (and its documentation became unclear) to define how a patient was oriented in index space (it assumed an LPS space, and thus it became redundant with the direction matrix). These changes seem to have coincided with ITK's introduction of a direction matrix (thanks goes to Alexis Girault for hunting down this history!). For the past fifteen years++, ITK writes AnatomicOrientation based on the direction matrix and assumes an LPS space. See the code in itkSpatialOrientation.h that specifies a 3-letter code derived from an image's direction matrix and that 3-letter code is then used to specify the AnatomicalOrientation tag in MetaIO.
      • Moving forward, when implementing new applications, it is recommended that developers use the definition currently implemented by ITK. It represents the most common use of MetaIO.
  • ElementSpacing
    • MET_FLOAT_ARRAY[NDims]
    • The distance between voxel centers

Tags Added by MetaImage

In addition to the above tags, MetaImage provides the following tags:

  • DimSize
    • MET_INT_ARRAY[NDims]
    • Number of elements per axis in data
  • HeaderSize
    • MET_INT
    • Number of Bytes to skip at the head of each data file.
    • Specify –1 to have MetaImage calculate the header size based on the assumption that the data occurs at the end of the file.
    • Specify 0 if the data occurs at the begining of the file.
  • Modality
    • MET_STRING
    • One of enum type: MET_MOD_CT, MET_MOD_MR, MET_MOD_US… See metaImageTypes.h
  • SequenceID
    • MET_INT_ARRAY[4]
    • Four values comprising a DICOM sequence: Study, Series, Image numbers
  • ElementMin
    • MET_FLOAT
    • Minimum value in the data
  • ElementMax
    • MET_FLOAT
    • Maximum value in the data
  • ElementNumberOfChannels
    • MET_INT
    • Number of values (of type ElementType) per voxel
  • ElementSize
    • MET_FLOAT_ARRAY[NDims]
    • Physical size of each voxel
  • ElementType
    • MET_STRING
    • One of enum type: MET_UCHAR, MET_CHAR… See metaTypes.h
  • ElementDataFile
    • MET_STRING
    • One of the following:
      • Name of the file to be loaded
      • A printf-style string followed by the min, max, and step values to be used to pass an argument to the string to create list of file names to be loaded (must be (N-1)D blocks of data per file).
      • LIST [X] – This specifies that starting on the next line is a list of files (one filename per line) in which the data is stored. Each file (by default) contains an (N-1)D block of data. If a second argument is given, its first character must be a number that specifies the dimension of the data in each file. For example ElementDataFile = LIST 2D means that there will be a 2D block of data per file.
      • LOCAL – Indicates that the data begins at the beginning of the next line.