/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #include "itkImageFileWriter.h" #include "itkImageFileReader.h" #include "itkMRCImageIO.h" #include "itkTestingMacros.h" #include "itkMath.h" static unsigned int m_CallNumber = 0; template class MRCImageIOTester { public: virtual int Test(int argc, char * argv[]); virtual ~MRCImageIOTester() = default; static bool Write(const std::string & filePrefix, std::string & outputPath); static bool Read(const std::string & filePrefix, std::string & outputPath, unsigned int index); }; template bool MRCImageIOTester::Write(const std::string & filePrefix, std::string & outputPath) { try { ++m_CallNumber; using ImageType = TImageType; using PixelType = typename ImageType::PixelType; // allocate an 10x10x10 image auto image = ImageType::New(); typename ImageType::SizeType m_ImageSize; m_ImageSize.Fill(10); image->SetRegions(m_ImageSize); image->Allocate(); unsigned int cnt = 0; itk::ImageRegionIterator i(image, image->GetLargestPossibleRegion()); i.GoToBegin(); while (!i.IsAtEnd()) { // fill the image switching between these pixels switch (cnt % 4) { case 0: i.Set(PixelType{}); break; case 1: i.Set(itk::NumericTraits::OneValue()); break; case 2: i.Set(itk::NumericTraits::min(PixelType())); break; case 3: i.Set(itk::NumericTraits::max(PixelType())); } ++cnt; ++i; } using ImageFileWriterType = itk::ImageFileWriter; auto writer = ImageFileWriterType::New(); writer->SetInput(image); // force use of MRCImageIO using IOType = itk::MRCImageIO; auto mrcIO = IOType::New(); writer->SetImageIO(mrcIO); std::ostringstream m_NameWithIndex; m_NameWithIndex << filePrefix << '_' << m_CallNumber << ".mrc"; std::ostringstream m_OutputFileName; #if defined(WIN32) // windows // if it ends in \\ just append the name if (outputPath.back() == '\\') { m_OutputFileName << outputPath << m_NameWithIndex.str(); } else { m_OutputFileName << outputPath << '\\' << m_NameWithIndex.str(); } #else /// POSIX UNIX // if it ends in / just append the name if (outputPath.back() == '/') { m_OutputFileName << outputPath << m_NameWithIndex.str(); } // otherwise, add / and the name else { m_OutputFileName << outputPath << '/' << m_NameWithIndex.str(); } #endif writer->SetFileName(m_OutputFileName.str()); writer->Update(); // test the CanWriteFile function after the fact (should always be true at // this point) if (!mrcIO->CanWriteFile(m_OutputFileName.str().c_str())) { return false; } return true; } catch (const itk::ExceptionObject & e) { std::cout << e.GetDescription() << std::endl; return false; } } template bool MRCImageIOTester::Read(const std::string & filePrefix, std::string & outputPath, unsigned int index) { try { using ImageType = TImageType; using PixelType = typename ImageType::PixelType; using ImageFileReaderType = itk::ImageFileReader; auto reader = ImageFileReaderType::New(); // force use of MRCImageIO using IOType = itk::MRCImageIO; auto mrcIO = IOType::New(); reader->SetImageIO(mrcIO); // construct the image filename std::ostringstream m_NameWithIndex; m_NameWithIndex << filePrefix << '_' << index << ".mrc"; std::ostringstream m_OutputFileName; #if defined(WIN32) // windows // if it ends in \\ just append the name if (outputPath.back() == '\\') { m_OutputFileName << outputPath << m_NameWithIndex.str(); } else { m_OutputFileName << outputPath << '\\' << m_NameWithIndex.str(); } #else /// POSIX UNIX // if it ends in / just append the name if (outputPath.back() == '/') { m_OutputFileName << outputPath << m_NameWithIndex.str(); } // otherwise, add / and the name else { m_OutputFileName << outputPath << '/' << m_NameWithIndex.str(); } #endif reader->SetFileName(m_OutputFileName.str()); // read the image typename ImageType::Pointer image = reader->GetOutput(); reader->Update(); // test the CanReadFile function after the fact (should always be true at // this point) if (!mrcIO->CanReadFile(m_OutputFileName.str().c_str())) { return false; } // check the size typename ImageType::RegionType region = image->GetLargestPossibleRegion(); typename ImageType::SizeType size = region.GetSize(); bool sizeGood = true; for (unsigned int i = 0; i < ImageType::GetImageDimension(); ++i) { if (size[i] != 10) { sizeGood = false; break; } } if (!sizeGood) { std::cout << "Error: Size didn't read properly" << std::endl; return false; } // check each pixel bool pixelsGood = true; unsigned int cnt = 0; itk::ImageRegionIterator iter(image, region); iter.GoToBegin(); while (!iter.IsAtEnd() && pixelsGood) { // check image switching between these pixels switch (cnt % 4) { case 0: if (itk::Math::NotExactlyEquals(iter.Get(), PixelType{})) { pixelsGood = false; } break; case 1: if (itk::Math::NotExactlyEquals(iter.Get(), itk::NumericTraits::OneValue())) { pixelsGood = false; } break; case 2: if (itk::Math::NotExactlyEquals(iter.Get(), itk::NumericTraits::min(PixelType()))) { pixelsGood = false; } break; case 3: if (itk::Math::NotExactlyEquals(iter.Get(), itk::NumericTraits::max(PixelType()))) { pixelsGood = false; } } ++cnt; ++iter; } if (!pixelsGood) { std::cout << "Error: Pixels didn't read properly" << std::endl; return false; } // reading successful, so return true return true; } catch (const itk::ExceptionObject & e) { std::cout << e.GetDescription() << std::endl; return false; } } // int MRCImageIOTester::Test(int argc, char* argv[] ) int itkMRCImageIOTest(int argc, char * argv[]) { if (argc < 2) { std::cerr << "Missing Parameters." << std::endl; std::cerr << "Usage: " << itkNameOfTestExecutableMacro(argv) << " outputPath" << std::endl; return EXIT_FAILURE; } std::string outputPath = argv[1]; std::string filePrefix = argv[0]; // // test all usable pixeltypes // // unsigned char using ImageTypeUnsignedChar3 = itk::Image; if (!(MRCImageIOTester::Write(filePrefix, outputPath))) { std::cout << "[FAILED] writing (unsighed char)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] writing (unsighed char)" << std::endl; if (!(MRCImageIOTester::Read(filePrefix, outputPath, m_CallNumber))) { std::cout << "[FAILED] reading (unsighed char)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] reading (unsighed char)" << std::endl; // short using ImageTypeShort3 = itk::Image; if (!(MRCImageIOTester::Write(filePrefix, outputPath))) { std::cout << "[FAILED] writing (short)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] writing (short)" << std::endl; if (!(MRCImageIOTester::Read(filePrefix, outputPath, m_CallNumber))) { std::cout << "[FAILED] reading (short)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] reading (short)" << std::endl; // float using ImageTypeFloat3 = itk::Image; if (!(MRCImageIOTester::Write(filePrefix, outputPath))) { std::cout << "[FAILED] writing (float)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] writing (float)" << std::endl; if (!(MRCImageIOTester::Read(filePrefix, outputPath, m_CallNumber))) { std::cout << "[FAILED] reading (float)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] reading (float)" << std::endl; // unsigned short using ImageTypeUnsignedShort3 = itk::Image; if (!(MRCImageIOTester::Write(filePrefix, outputPath))) { std::cout << "[FAILED] writing (unsighed short)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] writing (unsighed short)" << std::endl; if (!(MRCImageIOTester::Read(filePrefix, outputPath, m_CallNumber))) { std::cout << "[FAILED] reading (unsighed short)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] reading (unsighed short)" << std::endl; // RGBPixel using PixelTypeRGB = itk::RGBPixel; using ImageTypeRGB3 = itk::Image; if (!(MRCImageIOTester::Write(filePrefix, outputPath))) { std::cout << "[FAILED] writing (RGBPixel)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] writing (RGBPixel)" << std::endl; if (!(MRCImageIOTester::Read(filePrefix, outputPath, m_CallNumber))) { std::cout << "[FAILED] reading (RGBPixel)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] reading (RGBPixel)" << std::endl; // complex using PixelTypeComplexFloat = std::complex; using ImageTypeComplexFloat3 = itk::Image; if (!(MRCImageIOTester::Write(filePrefix, outputPath))) { std::cout << "[FAILED] writing (complex)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] writing (complex)" << std::endl; if (!(MRCImageIOTester::Read(filePrefix, outputPath, m_CallNumber))) { std::cout << "[FAILED] reading (complex)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] reading (complex)" << std::endl; // // test additional usable dimensions // // 1D using ImageTypeUnsignedChar1 = itk::Image; if (!(MRCImageIOTester::Write(filePrefix, outputPath))) { std::cout << "[FAILED] writing (1D)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] writing (1D)" << std::endl; if (!(MRCImageIOTester::Read(filePrefix, outputPath, m_CallNumber))) { std::cout << "[FAILED] reading (1D)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] reading (1D)" << std::endl; // 2D using ImageTypeUnsignedChar2 = itk::Image; if (!(MRCImageIOTester::Write(filePrefix, outputPath))) { std::cout << "[FAILED] writing (2D)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] writing (2D)" << std::endl; if (!(MRCImageIOTester::Read(filePrefix, outputPath, m_CallNumber))) { std::cout << "[FAILED] reading (2D)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] reading (2D)" << std::endl; // // expect exceptions with the following // using ImageTypeDouble = itk::Image; if (MRCImageIOTester::Write(filePrefix, outputPath)) { std::cout << "[FAILED] didn't throw exception (Image)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] threw exception (Image)" << std::endl; using ImageTypeInt = itk::Image; if (MRCImageIOTester::Write(filePrefix, outputPath)) { std::cout << "[FAILED] didn't throw exception (Image)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] threw exception (Image)" << std::endl; using ImageTypeUnsignedLong = itk::Image; if (MRCImageIOTester::Write(filePrefix, outputPath)) { std::cout << "[FAILED] didn't throw exception (Image)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] threw exception (Image)" << std::endl; // // test unusable dimensions // using ImageTypeUnsignedChar4 = itk::Image; if (MRCImageIOTester::Write(filePrefix, outputPath)) { std::cout << "[FAILED] incorrectly returned true (4D)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] threw exception (4D)" << std::endl; using ImageTypeUnsignedChar5 = itk::Image; if (MRCImageIOTester::Write(filePrefix, outputPath)) { std::cout << "[FAILED] incorrectly returned true (5D)" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED] threw exception (5D)" << std::endl; // Exercise other methods to improve coverage using IOType = itk::MRCImageIO; auto mrcIO = IOType::New(); ITK_EXERCISE_BASIC_OBJECT_METHODS(mrcIO, MRCImageIO, StreamingImageIOBase); // Not used; empty method body; called for coverage purposes mrcIO->WriteImageInformation(); std::cout << "Test finished." << std::endl; return EXIT_SUCCESS; }