diff --git a/Core/Code/IO/mitkImageWriter.cpp b/Core/Code/IO/mitkImageWriter.cpp index f413db3663..37083e8e45 100644 --- a/Core/Code/IO/mitkImageWriter.cpp +++ b/Core/Code/IO/mitkImageWriter.cpp @@ -1,348 +1,353 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkImageWriter.h" #include "mitkItkPictureWrite.h" #include "mitkImage.h" #include "mitkImageTimeSelector.h" #include "mitkImageAccessByItk.h" #include #include mitk::ImageWriter::ImageWriter() { this->SetNumberOfRequiredInputs( 1 ); m_MimeType = ""; SetDefaultExtension(); } mitk::ImageWriter::~ImageWriter() { } void mitk::ImageWriter::SetDefaultExtension() { m_Extension = ".mhd"; } #include #include #include static void writeVti(const char * filename, mitk::Image* image, int t=0) { vtkXMLImageDataWriter * vtkwriter = vtkXMLImageDataWriter::New(); vtkwriter->SetFileName( filename ); vtkwriter->SetInput(image->GetVtkImageData(t)); vtkwriter->Write(); vtkwriter->Delete(); } void mitk::ImageWriter::WriteByITK(mitk::Image* image, const std::string& fileName) { // Pictures and picture series like .png are written via a different mechanism then volume images. // So, they are still multiplexed and thus not support vector images. if (fileName.find(".png") != std::string::npos || fileName.find(".tif") != std::string::npos || fileName.find(".jpg") != std::string::npos) { AccessByItk_1( image, _mitkItkPictureWrite, fileName ); return; } // Implementation of writer using itkImageIO directly. This skips the use // of templated itkImageFileWriter, which saves the multiplexing on MITK side. unsigned int dimension = image->GetDimension(); unsigned int* dimensions = image->GetDimensions(); mitk::PixelType pixelType = image->GetPixelType(); mitk::Vector3D spacing = image->GetGeometry()->GetSpacing(); mitk::Point3D origin = image->GetGeometry()->GetOrigin(); itk::ImageIOBase::Pointer imageIO = itk::ImageIOFactory::CreateImageIO( fileName.c_str(), itk::ImageIOFactory::WriteMode ); if(imageIO.IsNull()) { itkExceptionMacro(<< "Error: Could not create itkImageIO via factory for file " << fileName); } // Set the necessary information for imageIO imageIO->SetNumberOfDimensions(dimension); imageIO->SetPixelTypeInfo( pixelType.GetTypeId() ); if(pixelType.GetNumberOfComponents() > 1) imageIO->SetNumberOfComponents(pixelType.GetNumberOfComponents()); itk::ImageIORegion ioRegion( dimension ); for(unsigned int i=0; iSetDimensions(i,dimensions[i]); imageIO->SetSpacing(i,spacing[i]); imageIO->SetOrigin(i,origin[i]); mitk::Vector3D direction; direction.Set_vnl_vector(image->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(i)); vnl_vector< double > axisDirection(dimension); for(unsigned int j=0; jSetDirection( i, axisDirection ); ioRegion.SetSize(i, image->GetLargestPossibleRegion().GetSize(i) ); ioRegion.SetIndex(i, image->GetLargestPossibleRegion().GetIndex(i) ); } //use compression if available imageIO->UseCompressionOn(); imageIO->SetIORegion(ioRegion); imageIO->SetFileName(fileName); const void * data = image->GetData(); imageIO->Write(data); } void mitk::ImageWriter::GenerateData() { 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(...) { MITK_INFO << "Could not set locale " << locale; } } if ( m_FileName == "" ) { itkWarningMacro( << "Sorry, filename has not been set!" ); return ; } FILE* tempFile = fopen(m_FileName.c_str(),"w"); if (tempFile==NULL) { itkExceptionMacro(<<"File location not writeable"); return; } fclose(tempFile); remove(m_FileName.c_str()); - mitk::Image::Pointer input = const_cast(this->GetInput()); + // Creating clone of input image, since i might change the geometry + mitk::Image::Pointer input = const_cast(this->GetInput())->Clone(); // Check if geometry information will be lost if (input->GetDimension() == 2) { if (!input->GetGeometry()->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 affTrans; + mitk::AffineTransform3D::Pointer affTrans = mitk::AffineTransform3D::New(); affTrans->SetIdentity(); - input->GetGeometry()->SetIndexToWorldTransform(affTrans); + mitk::Vector3D spacing = input->GetGeometry()->GetSpacing(); + mitk::Point3D origin = input->GetGeometry()->GetOrigin(); + input->GetGeometry()->SetIndexToWorldTransform(affTrans); + input->GetGeometry()->SetSpacing(spacing); + input->GetGeometry()->SetOrigin(origin); } } bool vti = (m_Extension.find(".vti") != std::string::npos); // If the extension is NOT .pic and NOT .nrrd and NOT .nii and NOT .nii.gz the following block is entered if ( m_Extension.find(".pic") == std::string::npos && m_Extension.find(".nrrd") == std::string::npos && m_Extension.find(".nii") == std::string::npos && m_Extension.find(".nii.gz") == std::string::npos ) { if(input->GetDimension() > 3) { int t, timesteps; timesteps = input->GetDimension(3); ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); timeSelector->SetInput(input); mitk::Image::Pointer image = timeSelector->GetOutput(); for(t = 0; t < timesteps; ++t) { ::itk::OStringStream filename; timeSelector->SetTimeNr(t); timeSelector->Update(); if(input->GetTimeSlicedGeometry()->IsValidTime(t)) { const mitk::TimeBounds& timebounds = input->GetTimeSlicedGeometry()->GetGeometry3D(t)->GetTimeBounds(); filename << m_FileName.c_str() << "_S" << std::setprecision(0) << timebounds[0] << "_E" << std::setprecision(0) << timebounds[1] << "_T" << t << m_Extension; } else { itkWarningMacro(<<"Error on write: TimeSlicedGeometry invalid of image " << filename << "."); filename << m_FileName.c_str() << "_T" << t << m_Extension; } if ( vti ) { writeVti(filename.str().c_str(), input, t); } else { WriteByITK(image, filename.str()); } } } else if ( vti ) { ::itk::OStringStream filename; filename << m_FileName.c_str() << m_Extension; writeVti(filename.str().c_str(), input); } else { ::itk::OStringStream filename; filename << m_FileName.c_str() << m_Extension; WriteByITK(input, filename.str()); } } else { // use the PicFileWriter for the .pic data type if( m_Extension.find(".pic") != std::string::npos ) { /* PicFileWriter::Pointer picWriter = PicFileWriter::New(); size_t found; found = m_FileName.find( m_Extension ); // !!! HAS to be at the very end of the filename (not somewhere in the middle) if( m_FileName.length() > 3 && found != m_FileName.length() - 4 ) { //if Extension not in Filename ::itk::OStringStream filename; filename << m_FileName.c_str() << m_Extension; picWriter->SetFileName( filename.str().c_str() ); } else { picWriter->SetFileName( m_FileName.c_str() ); } picWriter->SetInputImage( input ); picWriter->Write(); */ } // use the ITK .nrrd Image writer if( m_Extension.find(".nrrd") != std::string::npos || m_Extension.find(".nii") != std::string::npos || m_Extension.find(".nii.gz") != std::string::npos ) { ::itk::OStringStream filename; filename << this->m_FileName.c_str() << this->m_Extension; WriteByITK(input, filename.str()); } } m_MimeType = "application/MITK.Pic"; try { setlocale(LC_ALL, currLocale.c_str()); } catch(...) { MITK_INFO << "Could not reset locale " << currLocale; } } bool mitk::ImageWriter::CanWriteDataType( DataNode* input ) { if ( input ) { mitk::BaseData* data = input->GetData(); if ( data ) { mitk::Image::Pointer image = dynamic_cast( data ); if( image.IsNotNull() ) { //"SetDefaultExtension()" set m_Extension to ".mhd" ????? m_Extension = ".pic"; return true; } } } return false; } void mitk::ImageWriter::SetInput( DataNode* input ) { if( input && CanWriteDataType( input ) ) this->ProcessObject::SetNthInput( 0, dynamic_cast( input->GetData() ) ); } std::string mitk::ImageWriter::GetWritenMIMEType() { return m_MimeType; } std::vector mitk::ImageWriter::GetPossibleFileExtensions() { std::vector possibleFileExtensions; possibleFileExtensions.push_back(".pic"); possibleFileExtensions.push_back(".bmp"); possibleFileExtensions.push_back(".dcm"); possibleFileExtensions.push_back(".DCM"); possibleFileExtensions.push_back(".dicom"); possibleFileExtensions.push_back(".DICOM"); possibleFileExtensions.push_back(".gipl"); possibleFileExtensions.push_back(".gipl.gz"); possibleFileExtensions.push_back(".mha"); possibleFileExtensions.push_back(".nii"); possibleFileExtensions.push_back(".nrrd"); possibleFileExtensions.push_back(".nhdr"); possibleFileExtensions.push_back(".png"); possibleFileExtensions.push_back(".PNG"); possibleFileExtensions.push_back(".spr"); possibleFileExtensions.push_back(".mhd"); possibleFileExtensions.push_back(".vtk"); possibleFileExtensions.push_back(".vti"); possibleFileExtensions.push_back(".hdr"); possibleFileExtensions.push_back(".png"); possibleFileExtensions.push_back(".tif"); possibleFileExtensions.push_back(".jpg"); return possibleFileExtensions; } std::string mitk::ImageWriter::GetFileExtension() { return m_Extension; } void mitk::ImageWriter::SetInput( mitk::Image* image ) { this->ProcessObject::SetNthInput( 0, image ); } const mitk::Image* mitk::ImageWriter::GetInput() { if ( this->GetNumberOfInputs() < 1 ) { return NULL; } else { return static_cast< const mitk::Image * >( this->ProcessObject::GetInput( 0 ) ); } } diff --git a/Core/Code/Testing/mitkImageDimensionConverterTest.cpp b/Core/Code/Testing/mitkImageDimensionConverterTest.cpp index d29104de5c..7f53e30b6f 100644 --- a/Core/Code/Testing/mitkImageDimensionConverterTest.cpp +++ b/Core/Code/Testing/mitkImageDimensionConverterTest.cpp @@ -1,290 +1,292 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // mitk includes #include #include #include #include "mitkItkImageFileReader.h" #include #include #include #include #include #include #include #include "mitkTestingConfig.h" #include "mitkItkImageFileReader.h" // itk includes #include #include // stl includes #include // vtk includes #include int mitkImageDimensionConverterTest(int argc, char* argv[]) { MITK_TEST_BEGIN(mitkImageDimensionConverterTest); // Define an epsilon which is the allowed error float eps = 0.00001; // Define helper variables float error = 0; bool matrixIsEqual = true; - std::stringstream sstream = ""; + std::stringstream sstream; mitk::ImageWriter::Pointer imageWriter = mitk::ImageWriter::New(); mitk::ItkImageFileReader::Pointer imageReader = mitk::ItkImageFileReader::New(); mitk::Convert2Dto3DImageFilter::Pointer convertFilter = mitk::Convert2Dto3DImageFilter::New(); /////////////////////////////////////// // Create 2D Image with a 3D rotation from scratch. typedef itk::Image ImageType; ImageType::Pointer itkImage = ImageType::New(); ImageType::RegionType myRegion; ImageType::SizeType mySize; ImageType::IndexType myIndex; ImageType::SpacingType mySpacing; mySpacing[0] = 1; mySpacing[1] = 1; myIndex[0] = 0; myIndex[1] = 0; mySize[0] = 50; mySize[1] = 50; myRegion.SetSize( mySize); myRegion.SetIndex( myIndex ); itkImage->SetSpacing(mySpacing); itkImage->SetRegions( myRegion); itkImage->Allocate(); itkImage->FillBuffer(50); mitk::Image::Pointer mitkImage2D; mitk::CastToMitkImage(itkImage,mitkImage2D); // rotate mitk::Point3D p; p[0] = 1; p[1] = 3; p[2] = 5; mitk::Vector3D v; v[0] = 0.3; v[1] = 1; v[2] = 0.1; mitk::RotationOperation op(mitk::OpROTATE, p, v, 35); mitkImage2D->GetGeometry()->ExecuteOperation(&op); // Save original Geometry infos mitk::Vector3D Original_col0, Original_col1, Original_col2; Original_col0.Set_vnl_vector(mitkImage2D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(0)); Original_col1.Set_vnl_vector(mitkImage2D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(1)); Original_col2.Set_vnl_vector(mitkImage2D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)); MITK_INFO << "Rotated Matrix: " << Original_col0 << " " << Original_col1 << " " << Original_col2; mitk::Point3D Original_Origin = mitkImage2D->GetGeometry()->GetOrigin(); mitk::Vector3D Original_Spacing = mitkImage2D->GetGeometry()->GetSpacing(); MITK_TEST_CONDITION_REQUIRED( mitkImage2D->GetDimension() == 2 , "Created Image is Dimension 2"); /////////////////////////////////////// // mitkImage2D is now a 2D image with 3D Geometry information. // Save it without conversion and load it again. It should have an identitiy matrix - sstream = ""; + sstream.clear(); sstream << MITK_TEST_OUTPUT_DIR << "" << "/rotatedImage2D"; imageWriter->SetInput(mitkImage2D); imageWriter->SetFileName(sstream.str().c_str()); imageWriter->SetExtension(".nrrd"); imageWriter->Write(); sstream << ".nrrd"; + imageReader->SetFileName(sstream.str().c_str()); imageReader->Update(); mitk::Image::Pointer imageLoaded2D = imageReader->GetOutput(); // check if image can be loaded MITK_TEST_CONDITION_REQUIRED( imageLoaded2D.IsNotNull() , "Loading saved 2D Image"); MITK_TEST_CONDITION_REQUIRED( imageLoaded2D->GetDimension() == 2 , "Loaded Image is Dimension 2"); // check if spacing is ok mitk::Vector3D Loaded2D_Spacing = imageLoaded2D->GetGeometry()->GetSpacing(); error = abs(Loaded2D_Spacing[0] - Original_Spacing[0]) + abs(Loaded2D_Spacing[1] - Original_Spacing[1]) + abs(Loaded2D_Spacing[2] - 1) ; MITK_TEST_CONDITION_REQUIRED( error < eps , "Compare Geometry: Spacing"); // Check origin mitk::Point3D Loaded2D_Origin = imageLoaded2D->GetGeometry()->GetOrigin(); error = abs(Loaded2D_Origin[0] - Original_Origin[0]) + abs(Loaded2D_Origin[1] - Original_Origin[1]) + abs(Loaded2D_Origin[2] - 0) ; MITK_TEST_CONDITION_REQUIRED( error == error < eps, "Compare Geometry: Origin"); // Check matrix mitk::Vector3D Loaded2D_col0, Loaded2D_col1, Loaded2D_col2; - Loaded2D_col0.Set_vnl_vector(mitkImage3D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(0)); - Loaded2D_col1.Set_vnl_vector(mitkImage3D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(1)); - Loaded2D_col2.Set_vnl_vector(mitkImage3D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)); + Loaded2D_col0.Set_vnl_vector(imageLoaded2D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(0)); + Loaded2D_col1.Set_vnl_vector(imageLoaded2D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(1)); + Loaded2D_col2.Set_vnl_vector(imageLoaded2D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)); if ( (abs(1 - Loaded2D_col0[0]) > eps) || (abs(0 - Loaded2D_col0[1]) > eps) || (abs(0 - Loaded2D_col0[2]) > eps) || (abs(0 - Loaded2D_col1[0]) > eps) || (abs(1 - Loaded2D_col1[1]) > eps) || (abs(0 - Loaded2D_col1[2]) > eps) || (abs(0 - Loaded2D_col2[0]) > eps) || (abs(0 - Loaded2D_col2[1]) > eps) || (abs(1 - Loaded2D_col2[2]) > eps) ) { matrixIsEqual = false; } else matrixIsEqual = true; MITK_TEST_CONDITION_REQUIRED( matrixIsEqual , "Compare Geometry: Matrix"); /////////////////////////////////////// // mitkImage2D is a 2D image with 3D Geometry information. // Convert it with filter to a 3D image and check if everything went well convertFilter->SetInput(mitkImage2D); convertFilter->Update(); mitk::Image::Pointer mitkImage3D = convertFilter->GetOutput(); MITK_TEST_CONDITION_REQUIRED( mitkImage3D->GetDimension() == 3 , "Converted Image is Dimension 3"); // check if geometry is still same mitk::Vector3D Converted_Spacing = mitkImage3D->GetGeometry()->GetSpacing(); error = abs(Converted_Spacing[0] - Original_Spacing[0]) + abs(Converted_Spacing[1] - Original_Spacing[1]) + abs(Converted_Spacing[2] - Original_Spacing[2]) ; MITK_TEST_CONDITION_REQUIRED( error < eps , "Compare Geometry: Spacing"); mitk::Point3D Converted_Origin = mitkImage3D->GetGeometry()->GetOrigin(); error = abs(Converted_Origin[0] - Original_Origin[0]) + abs(Converted_Origin[1] - Original_Origin[1]) + abs(Converted_Origin[2] - Original_Origin[2]) ; + MITK_INFO << Converted_Origin << " and " << Original_Origin; MITK_TEST_CONDITION_REQUIRED( error < eps , "Compare Geometry: Origin"); mitk::Vector3D Converted_col0, Converted_col1, Converted_col2; Converted_col0.Set_vnl_vector(mitkImage3D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(0)); Converted_col1.Set_vnl_vector(mitkImage3D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(1)); Converted_col2.Set_vnl_vector(mitkImage3D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)); if ( (abs(Original_col0[0] - Converted_col0[0]) > eps) || (abs(Original_col0[1] - Converted_col0[1]) > eps) || (abs(Original_col0[2] - Converted_col0[2]) > eps) || (abs(Original_col1[0] - Converted_col1[0]) > eps) || (abs(Original_col1[1] - Converted_col1[1]) > eps) || (abs(Original_col1[2] - Converted_col1[2]) > eps) || (abs(Original_col2[0] - Converted_col2[0]) > eps) || (abs(Original_col2[1] - Converted_col2[1]) > eps) || (abs(Original_col2[2] - Converted_col2[2]) > eps) ) { MITK_INFO << "Oh No! Original Image Matrix and Converted Image Matrix are different!"; MITK_INFO << "original Image:" << Original_col0 << " " << Original_col1 << " " << Original_col2; MITK_INFO << "converted Image:" << Converted_col0 << " " << Converted_col1 << " " << Converted_col2; matrixIsEqual = false; } else matrixIsEqual = true; MITK_TEST_CONDITION_REQUIRED( matrixIsEqual , "Compare Geometry: Matrix"); /////////////////////////////////////// // So far it seems good! now try to save and load the file - sstream = ""; + sstream.clear(); sstream << MITK_TEST_OUTPUT_DIR << "" << "/rotatedImage"; imageWriter->SetInput(mitkImage3D); imageWriter->SetFileName(sstream.str().c_str()); imageWriter->SetExtension(".nrrd"); imageWriter->Write(); sstream << ".nrrd"; imageReader->SetFileName(sstream.str().c_str()); imageReader->Update(); mitk::Image::Pointer imageLoaded = imageReader->GetOutput(); // check if image can be loaded MITK_TEST_CONDITION_REQUIRED( imageLoaded.IsNotNull() , "Loading saved Image"); // check if loaded image is still what it should be: MITK_TEST_CONDITION_REQUIRED( imageLoaded->GetDimension() == 3 , "Loaded Image is Dimension 3"); // check if geometry is still same mitk::Vector3D Loaded_Spacing = imageLoaded->GetGeometry()->GetSpacing(); error = abs(Loaded_Spacing[0] - Original_Spacing[0]) + abs(Loaded_Spacing[1] - Original_Spacing[1]) + abs(Loaded_Spacing[2] - Original_Spacing[2]) ; MITK_TEST_CONDITION_REQUIRED( error < eps , "Compare Geometry: Spacing"); mitk::Point3D Loaded_Origin = imageLoaded->GetGeometry()->GetOrigin(); error = abs(Loaded_Origin[0] - Original_Origin[0]) + abs(Loaded_Origin[1] - Original_Origin[1]) + abs(Loaded_Origin[2] - Original_Origin[2]) ; MITK_TEST_CONDITION_REQUIRED( error < eps , "Compare Geometry: Origin"); mitk::Vector3D Loaded_col0, Loaded_col1, Loaded_col2; Loaded_col0.Set_vnl_vector(imageLoaded->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(0)); Loaded_col1.Set_vnl_vector(imageLoaded->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(1)); Loaded_col2.Set_vnl_vector(imageLoaded->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)); if ( (abs(Original_col0[0] - Loaded_col0[0]) > eps) || (abs(Original_col0[1] - Loaded_col0[1]) > eps) || (abs(Original_col0[2] - Loaded_col0[2]) > eps) || (abs(Original_col1[0] - Loaded_col1[0]) > eps) || (abs(Original_col1[1] - Loaded_col1[1]) > eps) || (abs(Original_col1[2] - Loaded_col1[2]) > eps) || (abs(Original_col2[0] - Loaded_col2[0]) > eps) || (abs(Original_col2[1] - Loaded_col2[1]) > eps) || (abs(Original_col2[2] - Loaded_col2[2]) > eps) ) { MITK_INFO << "Oh No! Original Image Matrix and Converted Image Matrix are different!"; MITK_INFO << "original Image:" << Original_col0 << " " << Original_col1 << " " << Original_col2; MITK_INFO << "converted Image:" << Loaded_col0 << " " << Loaded_col1 << " " << Loaded_col2; matrixIsEqual = false; } else matrixIsEqual = true; MITK_TEST_CONDITION_REQUIRED( matrixIsEqual , "Compare Geometry: Matrix"); MITK_TEST_END(); }