void mitk::ImageStatisticsHolder::ComputeImageStatistics(int t, unsigned int component)
{
  // timestep valid?
  if (!m_Image->IsValidTimeStep(t)) return;

  // image modified?
  if (this->m_Image->GetMTime() > m_LastRecomputeTimeStamp.GetMTime())
    this->ResetImageStatistics();

  Expand(t+1);

  // do we have valid information already?
  if( m_ScalarMin[t] != itk::NumericTraits<ScalarType>::max() ||
      m_Scalar2ndMin[t] != itk::NumericTraits<ScalarType>::max() ) return; // Values already calculated before...

  // used to avoid statistics calculation on qball images. property will be replaced as soons as bug 17928 is merged and the diffusion image refactoring is complete.
  mitk::BoolProperty* isqball = dynamic_cast< mitk::BoolProperty* >( m_Image->GetProperty( "IsQballImage" ).GetPointer() );
  const mitk::PixelType pType = m_Image->GetPixelType(0);
  if(pType.GetNumberOfComponents() == 1 && (pType.GetPixelType() != itk::ImageIOBase::UNKNOWNPIXELTYPE) && (pType.GetPixelType() != itk::ImageIOBase::VECTOR) )
  {
    // recompute
    mitk::ImageTimeSelector::Pointer timeSelector = this->GetTimeSelector();
    if(timeSelector.IsNotNull())
    {
      timeSelector->SetTimeNr(t);
      timeSelector->UpdateLargestPossibleRegion();
      const mitk::Image* image = timeSelector->GetOutput();
      AccessByItk_2( image, _ComputeExtremaInItkImage, this, t );
    }
  }
  else if (pType.GetPixelType() == itk::ImageIOBase::VECTOR && (!isqball || !isqball->GetValue()))  // we have a vector image
  {
      // recompute
      mitk::ImageTimeSelector::Pointer timeSelector = this->GetTimeSelector();
      if(timeSelector.IsNotNull())
      {
        timeSelector->SetTimeNr(t);
        timeSelector->UpdateLargestPossibleRegion();
        const mitk::Image* image = timeSelector->GetOutput();
        AccessVectorPixelTypeByItk_n( image, _ComputeExtremaInItkVectorImage, (this, t, component) );
      }
  }
  else
  {
    m_ScalarMin[t] = 0;
    m_ScalarMax[t] = 255;
    m_Scalar2ndMin[t] = 0;
    m_Scalar2ndMax[t] = 255;
  }
}
Example #2
0
double mitk::Image::GetPixelValueByIndex(const itk::Index<3> &position, unsigned int timestep, unsigned int component)
{
  double value = 0;
  if (this->GetTimeSteps() < timestep)
  {
    timestep = this->GetTimeSteps();
  }

  value = 0.0;

  const unsigned int* imageDims = this->m_ImageDescriptor->GetDimensions();
  const mitk::PixelType ptype = this->m_ImageDescriptor->GetChannelTypeById(0);

  // Comparison ?>=0 not needed since all position[i] and timestep are unsigned int
  // (position[0]>=0 && position[1] >=0 && position[2]>=0 && timestep>=0)
  // bug-11978 : we still need to catch index with negative values
  if ( position[0] < 0 ||
       position[1] < 0 ||
       position[2] < 0 )
  {
    MITK_WARN << "Given position ("<< position << ") is out of image range, returning 0." ;
  }
  // check if the given position is inside the index range of the image, the 3rd dimension needs to be compared only if the dimension is not 0
  else if ( (unsigned int)position[0] >= imageDims[0] ||
            (unsigned int)position[1] >= imageDims[1] ||
            ( imageDims[2] && (unsigned int)position[2] >= imageDims[2] ))
  {
    MITK_WARN << "Given position ("<< position << ") is out of image range, returning 0." ;
  }
  else
  {
    const unsigned int offset = component + ptype.GetNumberOfComponents()*(position[0] + position[1]*imageDims[0] + position[2]*imageDims[0]*imageDims[1] + timestep*imageDims[0]*imageDims[1]*imageDims[2]);

    mitkPixelTypeMultiplex3( AccessPixel, ptype, this->GetData(), offset, value );
  }

  return value;
}
void mitk::ImageStatisticsHolder::ComputeImageStatistics(int t)
{
  // timestep valid?
  if (!m_Image->IsValidTimeStep(t)) return;

  // image modified?
  if (this->m_Image->GetMTime() > m_LastRecomputeTimeStamp.GetMTime())
    this->ResetImageStatistics();

  Expand(t+1);

  // do we have valid information already?
  if( m_ScalarMin[t] != itk::NumericTraits<ScalarType>::max() ||
      m_Scalar2ndMin[t] != itk::NumericTraits<ScalarType>::max() ) return; // Values already calculated before...

  const mitk::PixelType pType = m_Image->GetPixelType(0);
  if(pType.GetNumberOfComponents() == 1 && (pType.GetPixelType() != itk::ImageIOBase::UNKNOWNPIXELTYPE) && (pType.GetPixelType() != itk::ImageIOBase::VECTOR) )
  {
    // recompute
    mitk::ImageTimeSelector::Pointer timeSelector = this->GetTimeSelector();
    if(timeSelector.IsNotNull())
    {
      timeSelector->SetTimeNr(t);
      timeSelector->UpdateLargestPossibleRegion();
      const mitk::Image* image = timeSelector->GetOutput();
      AccessByItk_2( image, _ComputeExtremaInItkImage, this, t );
    }
  }
  else
  {
    m_ScalarMin[t] = 0;
    m_ScalarMax[t] = 255;
    m_Scalar2ndMin[t] = 0;
    m_Scalar2ndMax[t] = 255;
  }
}
Example #4
0
void AccessPixel( const mitk::PixelType ptype, void* data, const unsigned int offset, double& value )
{
  value = 0.0;
  if( data == NULL ) return;

  if(ptype.GetBpe() != 24)
  {
    value = (double) (((T*) data)[ offset ]);
  }
  else
  {
    const unsigned int rgboffset = 3 * offset;

    double returnvalue = (((T*) data)[rgboffset ]);
    returnvalue += (((T*) data)[rgboffset + 1]);
    returnvalue += (((T*) data)[rgboffset + 2]);
    value = returnvalue;
  }
}
Example #5
0
  void ItkImageIO::Write()
  {
    const mitk::Image *image = dynamic_cast<const mitk::Image *>(this->GetInput());

    if (image == NULL)
    {
      mitkThrow() << "Cannot write non-image data";
    }

    // Switch the current locale to "C"
    LocaleSwitch localeSwitch("C");

    // Clone the image geometry, because we might have to change it
    // for writing purposes
    BaseGeometry::Pointer geometry = image->GetGeometry()->Clone();

    // Check if geometry information will be lost
    if (image->GetDimension() == 2 && !geometry->Is2DConvertable())
    {
      MITK_WARN << "Saving a 2D image with 3D geometry information. Geometry information will be lost! You might "
                   "consider using Convert2Dto3DImageFilter before saving.";

      // set matrix to identity
      mitk::AffineTransform3D::Pointer affTrans = mitk::AffineTransform3D::New();
      affTrans->SetIdentity();
      mitk::Vector3D spacing = geometry->GetSpacing();
      mitk::Point3D origin = geometry->GetOrigin();
      geometry->SetIndexToWorldTransform(affTrans);
      geometry->SetSpacing(spacing);
      geometry->SetOrigin(origin);
    }

    LocalFile localFile(this);
    const std::string path = localFile.GetFileName();

    MITK_INFO << "Writing image: " << path << std::endl;

    try
    {
      // Implementation of writer using itkImageIO directly. This skips the use
      // of templated itkImageFileWriter, which saves the multiplexing on MITK side.

      const unsigned int dimension = image->GetDimension();
      const unsigned int *const dimensions = image->GetDimensions();
      const mitk::PixelType pixelType = image->GetPixelType();
      const mitk::Vector3D mitkSpacing = geometry->GetSpacing();
      const mitk::Point3D mitkOrigin = geometry->GetOrigin();

      // Due to templating in itk, we are forced to save a 4D spacing and 4D Origin,
      // though they are not supported in MITK
      itk::Vector<double, 4u> spacing4D;
      spacing4D[0] = mitkSpacing[0];
      spacing4D[1] = mitkSpacing[1];
      spacing4D[2] = mitkSpacing[2];
      spacing4D[3] = 1; // There is no support for a 4D spacing. However, we should have a valid value here

      itk::Vector<double, 4u> origin4D;
      origin4D[0] = mitkOrigin[0];
      origin4D[1] = mitkOrigin[1];
      origin4D[2] = mitkOrigin[2];
      origin4D[3] = 0; // There is no support for a 4D origin. However, we should have a valid value here

      // Set the necessary information for imageIO
      m_ImageIO->SetNumberOfDimensions(dimension);
      m_ImageIO->SetPixelType(pixelType.GetPixelType());
      m_ImageIO->SetComponentType(pixelType.GetComponentType() < PixelComponentUserType ?
                                    static_cast<itk::ImageIOBase::IOComponentType>(pixelType.GetComponentType()) :
                                    itk::ImageIOBase::UNKNOWNCOMPONENTTYPE);
      m_ImageIO->SetNumberOfComponents(pixelType.GetNumberOfComponents());

      itk::ImageIORegion ioRegion(dimension);

      for (unsigned int i = 0; i < dimension; i++)
      {
        m_ImageIO->SetDimensions(i, dimensions[i]);
        m_ImageIO->SetSpacing(i, spacing4D[i]);
        m_ImageIO->SetOrigin(i, origin4D[i]);

        mitk::Vector3D mitkDirection;
        mitkDirection.SetVnlVector(geometry->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(i));
        itk::Vector<double, 4u> direction4D;
        direction4D[0] = mitkDirection[0];
        direction4D[1] = mitkDirection[1];
        direction4D[2] = mitkDirection[2];

        // MITK only supports a 3x3 direction matrix. Due to templating in itk, however, we must
        // save a 4x4 matrix for 4D images. in this case, add an homogneous component to the matrix.
        if (i == 3)
        {
          direction4D[3] = 1; // homogenous component
        }
        else
        {
          direction4D[3] = 0;
        }
        vnl_vector<double> axisDirection(dimension);
        for (unsigned int j = 0; j < dimension; j++)
        {
          axisDirection[j] = direction4D[j] / spacing4D[i];
        }
        m_ImageIO->SetDirection(i, axisDirection);

        ioRegion.SetSize(i, image->GetLargestPossibleRegion().GetSize(i));
        ioRegion.SetIndex(i, image->GetLargestPossibleRegion().GetIndex(i));
      }

      // use compression if available
      m_ImageIO->UseCompressionOn();

      m_ImageIO->SetIORegion(ioRegion);
      m_ImageIO->SetFileName(path);

      // Handle time geometry
      const ArbitraryTimeGeometry *arbitraryTG = dynamic_cast<const ArbitraryTimeGeometry *>(image->GetTimeGeometry());
      if (arbitraryTG)
      {
        itk::EncapsulateMetaData<std::string>(m_ImageIO->GetMetaDataDictionary(),
                                              PROPERTY_KEY_TIMEGEOMETRY_TYPE,
                                              ArbitraryTimeGeometry::GetStaticNameOfClass());

        std::stringstream stream;
        stream << arbitraryTG->GetTimeBounds(0)[0];
        for (TimeStepType pos = 0; pos < arbitraryTG->CountTimeSteps(); ++pos)
        {
          stream << " " << arbitraryTG->GetTimeBounds(pos)[1];
        }
        std::string data = stream.str();

        itk::EncapsulateMetaData<std::string>(
          m_ImageIO->GetMetaDataDictionary(), PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS, data);
      }

      // Handle properties
      mitk::PropertyList::Pointer imagePropertyList = image->GetPropertyList();

      for (const auto &property : *imagePropertyList->GetMap())
      {
        IPropertyPersistence::InfoResultType infoList =
          mitk::CoreServices::GetPropertyPersistence()->GetInfo(property.first, GetMimeType()->GetName(), true);

        if (infoList.empty())
        {
          continue;
        }

        std::string value = infoList.front()->GetSerializationFunction()(property.second);

        if (value == mitk::BaseProperty::VALUE_CANNOT_BE_CONVERTED_TO_STRING)
        {
          continue;
        }

        std::string key = infoList.front()->GetKey();

        itk::EncapsulateMetaData<std::string>(m_ImageIO->GetMetaDataDictionary(), key, value);
      }

      ImageReadAccessor imageAccess(image);
      m_ImageIO->Write(imageAccess.GetData());
    }
    catch (const std::exception &e)
    {
      mitkThrow() << e.what();
    }
  }
Example #6
0
void LabelSetImageIO::Write()
{
  ValidateOutputLocation();

  const LabelSetImage* input = static_cast<const LabelSetImage*>(this->GetInput());

  const std::string& locale = "C";
  const std::string& currLocale = setlocale( LC_ALL, NULL );

  if ( locale.compare(currLocale)!=0 )
  {
    try
    {
      setlocale(LC_ALL, locale.c_str());
    }
    catch(...)
    {
      mitkThrow() << "Could not set locale " << currLocale;
    }
  }

  mitk::Image::Pointer inputVector = mitk::LabelSetImageConverter::ConvertLabelSetImageToImage(input);

  // image write
  if ( inputVector.IsNull() )
  {
    mitkThrow() << "Cannot write non-image data";
  }

  itk::NrrdImageIO::Pointer nrrdImageIo = itk::NrrdImageIO::New();

  // Clone the image geometry, because we might have to change it
  // for writing purposes
  BaseGeometry::Pointer geometry = inputVector->GetGeometry()->Clone();

  // Check if geometry information will be lost
  if (inputVector->GetDimension() == 2 &&
    !geometry->Is2DConvertable())
  {
    MITK_WARN << "Saving a 2D image with 3D geometry information. Geometry information will be lost! You might consider using Convert2Dto3DImageFilter before saving.";

    // set matrix to identity
    mitk::AffineTransform3D::Pointer affTrans = mitk::AffineTransform3D::New();
    affTrans->SetIdentity();
    mitk::Vector3D spacing = geometry->GetSpacing();
    mitk::Point3D origin = geometry->GetOrigin();
    geometry->SetIndexToWorldTransform(affTrans);
    geometry->SetSpacing(spacing);
    geometry->SetOrigin(origin);
  }

  LocalFile localFile(this);
  const std::string path = localFile.GetFileName();

  MITK_INFO << "Writing image: " << path << std::endl;

  try
  {
    // Implementation of writer using itkImageIO directly. This skips the use
    // of templated itkImageFileWriter, which saves the multiplexing on MITK side.

    const unsigned int dimension = inputVector->GetDimension();
    const unsigned int* const dimensions = inputVector->GetDimensions();
    const mitk::PixelType pixelType = inputVector->GetPixelType();
    const mitk::Vector3D mitkSpacing = geometry->GetSpacing();
    const mitk::Point3D mitkOrigin = geometry->GetOrigin();

    // Due to templating in itk, we are forced to save a 4D spacing and 4D Origin,
    // though they are not supported in MITK
    itk::Vector<double, 4u> spacing4D;
    spacing4D[0] = mitkSpacing[0];
    spacing4D[1] = mitkSpacing[1];
    spacing4D[2] = mitkSpacing[2];
    spacing4D[3] = 1; // There is no support for a 4D spacing. However, we should have a valid value here

    itk::Vector<double, 4u> origin4D;
    origin4D[0] = mitkOrigin[0];
    origin4D[1] = mitkOrigin[1];
    origin4D[2] = mitkOrigin[2];
    origin4D[3] = 0; // There is no support for a 4D origin. However, we should have a valid value here

    // Set the necessary information for imageIO
    nrrdImageIo->SetNumberOfDimensions(dimension);
    nrrdImageIo->SetPixelType(pixelType.GetPixelType());
    nrrdImageIo->SetComponentType(pixelType.GetComponentType() < PixelComponentUserType ?
      static_cast<itk::ImageIOBase::IOComponentType>(pixelType.GetComponentType()) :
      itk::ImageIOBase::UNKNOWNCOMPONENTTYPE);
    nrrdImageIo->SetNumberOfComponents(pixelType.GetNumberOfComponents());

    itk::ImageIORegion ioRegion(dimension);

    for (unsigned int i = 0; i < dimension; i++)
    {
      nrrdImageIo->SetDimensions(i, dimensions[i]);
      nrrdImageIo->SetSpacing(i, spacing4D[i]);
      nrrdImageIo->SetOrigin(i, origin4D[i]);

      mitk::Vector3D mitkDirection;
      mitkDirection.SetVnlVector(geometry->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(i));
      itk::Vector<double, 4u> direction4D;
      direction4D[0] = mitkDirection[0];
      direction4D[1] = mitkDirection[1];
      direction4D[2] = mitkDirection[2];

      // MITK only supports a 3x3 direction matrix. Due to templating in itk, however, we must
      // save a 4x4 matrix for 4D images. in this case, add an homogneous component to the matrix.
      if (i == 3)
      {
        direction4D[3] = 1; // homogenous component
      }
      else
      {
        direction4D[3] = 0;
      }
      vnl_vector<double> axisDirection(dimension);
      for (unsigned int j = 0; j < dimension; j++)
      {
        axisDirection[j] = direction4D[j] / spacing4D[i];
      }
      nrrdImageIo->SetDirection(i, axisDirection);

      ioRegion.SetSize(i, inputVector->GetLargestPossibleRegion().GetSize(i));
      ioRegion.SetIndex(i, inputVector->GetLargestPossibleRegion().GetIndex(i));
    }

    //use compression if available
    nrrdImageIo->UseCompressionOn();

    nrrdImageIo->SetIORegion(ioRegion);
    nrrdImageIo->SetFileName(path);

    // label set specific meta data
    char keybuffer[512];
    char valbuffer[512];

    sprintf(keybuffer, "modality");
    sprintf(valbuffer, "org.mitk.image.multilabel");
    itk::EncapsulateMetaData<std::string>(nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), std::string(valbuffer));

    sprintf(keybuffer, "layers");
    sprintf(valbuffer, "%1d", input->GetNumberOfLayers());
    itk::EncapsulateMetaData<std::string>(nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), std::string(valbuffer));

    for (unsigned int layerIdx = 0; layerIdx<input->GetNumberOfLayers(); layerIdx++)
    {
      sprintf(keybuffer, "layer_%03d", layerIdx); // layer idx
      sprintf(valbuffer, "%1d", input->GetNumberOfLabels(layerIdx)); // number of labels for the layer
      itk::EncapsulateMetaData<std::string>(nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), std::string(valbuffer));

      mitk::LabelSet::LabelContainerConstIteratorType iter = input->GetLabelSet(layerIdx)->IteratorConstBegin();
      unsigned int count(0);
      while (iter != input->GetLabelSet(layerIdx)->IteratorConstEnd())
      {
        std::auto_ptr<TiXmlDocument> document;
        document.reset(new TiXmlDocument());

        TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "", ""); // TODO what to write here? encoding? etc....
        document->LinkEndChild(decl);
        TiXmlElement * labelElem = GetLabelAsTiXmlElement(iter->second);
        document->LinkEndChild(labelElem);
        TiXmlPrinter printer;
        printer.SetIndent("");
        printer.SetLineBreak("");

        document->Accept(&printer);

        sprintf(keybuffer, "org.mitk.label_%03u_%05u", layerIdx, count);
        itk::EncapsulateMetaData<std::string>(nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), printer.Str());
        ++iter;
        ++count;
      }
    }
    // end label set specific meta data

    ImageReadAccessor imageAccess(inputVector);
    nrrdImageIo->Write(imageAccess.GetData());
  }
  catch (const std::exception& e)
  {
    mitkThrow() << e.what();
  }
  // end image write

  try
  {
    setlocale(LC_ALL, currLocale.c_str());
  }
  catch(...)
  {
    mitkThrow() << "Could not reset locale " << currLocale;
  }
}
Example #7
0
void ItkImageIO::Write()
{
  const mitk::Image* image = dynamic_cast<const mitk::Image*>(this->GetInput());

  if (image == NULL)
  {
    mitkThrow() << "Cannot write non-image data";
  }

  struct LocaleSwitch
  {
    LocaleSwitch(const std::string& newLocale)
      : m_OldLocale(std::setlocale(LC_ALL, NULL))
      , m_NewLocale(newLocale)
    {
      if (m_OldLocale == NULL)
      {
        m_OldLocale = "";
      }
      else if (m_NewLocale != m_OldLocale)
      {
        // set the locale
        if (std::setlocale(LC_ALL, m_NewLocale.c_str()) == NULL)
        {
          MITK_INFO << "Could not set locale " << m_NewLocale;
          m_OldLocale = NULL;
        }
      }
    }

    ~LocaleSwitch()
    {
      if (m_OldLocale != NULL && std::setlocale(LC_ALL, m_OldLocale) == NULL)
      {
        MITK_INFO << "Could not reset locale " << m_OldLocale;
      }
    }

  private:
    const char* m_OldLocale;
    const std::string m_NewLocale;
  };

  // Switch the current locale to "C"
  LocaleSwitch localeSwitch("C");

  // Clone the image geometry, because we might have to change it
  // for writing purposes
  BaseGeometry::Pointer geometry = image->GetGeometry()->Clone();

  // Check if geometry information will be lost
  if (image->GetDimension() == 2 &&
      !geometry->Is2DConvertable())
  {
    MITK_WARN << "Saving a 2D image with 3D geometry information. Geometry information will be lost! You might consider using Convert2Dto3DImageFilter before saving.";

    // set matrix to identity
    mitk::AffineTransform3D::Pointer affTrans = mitk::AffineTransform3D::New();
    affTrans->SetIdentity();
    mitk::Vector3D spacing = geometry->GetSpacing();
    mitk::Point3D origin = geometry->GetOrigin();
    geometry->SetIndexToWorldTransform(affTrans);
    geometry->SetSpacing(spacing);
    geometry->SetOrigin(origin);
  }

  LocalFile localFile(this);
  const std::string path = localFile.GetFileName();

  MITK_INFO << "Writing image: " << path << std::endl;

  try
  {
    // Implementation of writer using itkImageIO directly. This skips the use
    // of templated itkImageFileWriter, which saves the multiplexing on MITK side.

    const unsigned int dimension = image->GetDimension();
    const unsigned int* const dimensions = image->GetDimensions();
    const mitk::PixelType pixelType = image->GetPixelType();
    const mitk::Vector3D mitkSpacing = geometry->GetSpacing();
    const mitk::Point3D mitkOrigin = geometry->GetOrigin();

    // Due to templating in itk, we are forced to save a 4D spacing and 4D Origin,
    // though they are not supported in MITK
    itk::Vector<double, 4u> spacing4D;
    spacing4D[0] = mitkSpacing[0];
    spacing4D[1] = mitkSpacing[1];
    spacing4D[2] = mitkSpacing[2];
    spacing4D[3] = 1; // There is no support for a 4D spacing. However, we should have a valid value here

    itk::Vector<double, 4u> origin4D;
    origin4D[0] = mitkOrigin[0];
    origin4D[1] = mitkOrigin[1];
    origin4D[2] = mitkOrigin[2];
    origin4D[3] = 0; // There is no support for a 4D origin. However, we should have a valid value here

    // Set the necessary information for imageIO
    m_ImageIO->SetNumberOfDimensions(dimension);
    m_ImageIO->SetPixelType(pixelType.GetPixelType());
    m_ImageIO->SetComponentType(pixelType.GetComponentType() < PixelComponentUserType ?
                                  static_cast<itk::ImageIOBase::IOComponentType>(pixelType.GetComponentType()) :
                                  itk::ImageIOBase::UNKNOWNCOMPONENTTYPE);
    m_ImageIO->SetNumberOfComponents( pixelType.GetNumberOfComponents() );

    itk::ImageIORegion ioRegion( dimension );

    for(unsigned int i = 0; i < dimension; i++)
    {
      m_ImageIO->SetDimensions(i, dimensions[i]);
      m_ImageIO->SetSpacing(i, spacing4D[i]);
      m_ImageIO->SetOrigin(i, origin4D[i]);

      mitk::Vector3D mitkDirection;
      mitkDirection.SetVnlVector(geometry->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(i));
      itk::Vector<double, 4u> direction4D;
      direction4D[0] = mitkDirection[0];
      direction4D[1] = mitkDirection[1];
      direction4D[2] = mitkDirection[2];

      // MITK only supports a 3x3 direction matrix. Due to templating in itk, however, we must
      // save a 4x4 matrix for 4D images. in this case, add an homogneous component to the matrix.
      if (i == 3)
      {
        direction4D[3] = 1; // homogenous component
      }
      else
      {
        direction4D[3] = 0;
      }
      vnl_vector<double> axisDirection(dimension);
      for(unsigned int j = 0; j < dimension; j++)
      {
        axisDirection[j] = direction4D[j] / spacing4D[i];
      }
      m_ImageIO->SetDirection(i, axisDirection);

      ioRegion.SetSize(i, image->GetLargestPossibleRegion().GetSize(i));
      ioRegion.SetIndex(i, image->GetLargestPossibleRegion().GetIndex(i));
    }

    //use compression if available
    m_ImageIO->UseCompressionOn();

    m_ImageIO->SetIORegion(ioRegion);
    m_ImageIO->SetFileName(path);

    // ***** Remove const_cast after bug 17952 is fixed ****
    ImageReadAccessor imageAccess(const_cast<mitk::Image*>(image));
    m_ImageIO->Write(imageAccess.GetData());
  }
  catch (const std::exception& e)
  {
    mitkThrow() << e.what();
  }
}