Skip to content

Commit

Permalink
ENH: Add convenience function ReadImage
Browse files Browse the repository at this point in the history
Added `itk::ReadImage<TOutputImage>(const std::string & filename)`, to
allows simplifying the C++ code for reading an image.

Suggested by Dženan Zukić at
#2102 (comment)

Follow-up to:
"ENH: add a convenience function WriteImage"
Pull request: #2160
Commit: 60b0984

Replaced manual creation of `ImageFileReader` objects in Common tests by
calls to the new `itk::ReadImage` function. Also removed related
redundant try-catch blocks from SymmetricSecondRankTensorImage tests.
  • Loading branch information
N-Dekker authored and hjmjohnson committed Dec 22, 2020
1 parent c5aa259 commit aeea88b
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 108 deletions.
7 changes: 1 addition & 6 deletions Modules/Core/Common/test/itkImageDuplicatorTest2.cxx
Expand Up @@ -35,19 +35,14 @@ itkImageDuplicatorTest2(int argc, char * argv[])
constexpr unsigned int Dimension = 3;
using ImageType = itk::Image<PixelType, Dimension>;

using ReaderType = itk::ImageFileReader<ImageType>;
ReaderType::Pointer reader = ReaderType::New();
using DuplicatorType = itk::ImageDuplicator<ImageType>;
DuplicatorType::Pointer dup = DuplicatorType::New();
using AbsType = itk::AbsImageFilter<ImageType, ImageType>;
AbsType::Pointer absF = AbsType::New();

reader->SetFileName(argv[1]);

try
{
reader->Update();
ImageType::Pointer inImage = reader->GetOutput();
const auto inImage = itk::ReadImage<ImageType>(argv[1]);

ImageType::RegionType lpr = inImage->GetLargestPossibleRegion();
ImageType::RegionType region = lpr;
Expand Down
9 changes: 1 addition & 8 deletions Modules/Core/Common/test/itkImageRandomIteratorTest2.cxx
Expand Up @@ -86,13 +86,6 @@ itkImageRandomIteratorTest2(int argc, char * argv[])

if (argc > 4)
{

using ReaderType = itk::ImageFileReader<ImageType>;

ReaderType::Pointer reader = ReaderType::New();

reader->SetFileName(argv[2]);

using DifferencePixelType = signed long;
using DifferenceImageType = itk::Image<DifferencePixelType, ImageDimension>;

Expand All @@ -101,7 +94,7 @@ itkImageRandomIteratorTest2(int argc, char * argv[])
DifferenceFilterType::Pointer difference = DifferenceFilterType::New();

difference->SetValidInput(image);
difference->SetTestInput(reader->GetOutput());
difference->SetTestInput(itk::ReadImage<ImageType>(argv[2]));
difference->SetToleranceRadius(0);
difference->SetDifferenceThreshold(0);

Expand Down
Expand Up @@ -85,64 +85,46 @@ itkSymmetricSecondRankTensorImageReadTest(int ac, char * av[])
try
{
itk::WriteImage(matrixImage, av[1]);
}
catch (const itk::ExceptionObject & excp)
{
std::cerr << excp << std::endl;
return EXIT_FAILURE;
}


using TensorReaderType = itk::ImageFileReader<TensorImageType>;

TensorReaderType::Pointer tensorReader = TensorReaderType::New();

tensorReader->SetFileName(av[1]);

try
{
tensorReader->Update();
}
catch (const itk::ExceptionObject & excp)
{
std::cerr << excp << std::endl;
return EXIT_FAILURE;
}

TensorImageType::ConstPointer tensorImage = tensorReader->GetOutput();
const TensorImageType::ConstPointer tensorImage = itk::ReadImage<TensorImageType>(av[1]);

// Compare the read values to the original values
const float tolerance = 1e-5;
// Compare the read values to the original values
const float tolerance = 1e-5;

itk::ImageRegionConstIterator<TensorImageType> tItr(tensorImage, region);
itk::ImageRegionConstIterator<MatrixImageType> mItr(matrixImage, region);
itk::ImageRegionConstIterator<TensorImageType> tItr(tensorImage, region);
itk::ImageRegionConstIterator<MatrixImageType> mItr(matrixImage, region);

tItr.GoToBegin();
mItr.GoToBegin();
tItr.GoToBegin();
mItr.GoToBegin();

while (!mItr.IsAtEnd())
{
matrixPixel = mItr.Get();
const TensorPixelType tensorPixel = tItr.Get();

for (unsigned int i = 0; i < 3; i++)
while (!mItr.IsAtEnd())
{
for (unsigned int j = 0; j < 3; j++)
matrixPixel = mItr.Get();
const TensorPixelType tensorPixel = tItr.Get();

for (unsigned int i = 0; i < 3; i++)
{
if (std::abs(matrixPixel[i][j] - tensorPixel(i, j)) > tolerance)
for (unsigned int j = 0; j < 3; j++)
{
std::cerr << "Tensor read does not match expected values " << std::endl;
std::cerr << "Index " << tItr.GetIndex() << std::endl;
std::cerr << "Tensor value " << std::endl << tensorPixel << std::endl;
std::cerr << "Matrix value " << std::endl << matrixPixel << std::endl;
return EXIT_FAILURE;
if (std::abs(matrixPixel[i][j] - tensorPixel(i, j)) > tolerance)
{
std::cerr << "Tensor read does not match expected values " << std::endl;
std::cerr << "Index " << tItr.GetIndex() << std::endl;
std::cerr << "Tensor value " << std::endl << tensorPixel << std::endl;
std::cerr << "Matrix value " << std::endl << matrixPixel << std::endl;
return EXIT_FAILURE;
}
}
}
++mItr;
++tItr;
}
++mItr;
++tItr;
}


return EXIT_SUCCESS;
return EXIT_SUCCESS;
}
catch (const itk::ExceptionObject & excp)
{
std::cerr << excp << std::endl;
return EXIT_FAILURE;
}
}
Expand Up @@ -70,59 +70,41 @@ itkSymmetricSecondRankTensorImageWriteReadTest(int ac, char * av[])
try
{
itk::WriteImage(tensorImageInput, av[1]);
}
catch (const itk::ExceptionObject & excp)
{
std::cerr << excp << std::endl;
return EXIT_FAILURE;
}
const TensorImageType::ConstPointer tensorImageOutput = itk::ReadImage<TensorImageType>(av[1]);

using TensorReaderType = itk::ImageFileReader<TensorImageType>;
// Compare the read values to the original values
const float tolerance = 1e-5;

TensorReaderType::Pointer tensorReader = TensorReaderType::New();
itk::ImageRegionConstIterator<TensorImageType> inIt(tensorImageInput, region);
itk::ImageRegionConstIterator<TensorImageType> outIt(tensorImageOutput, region);

tensorReader->SetFileName(av[1]);
inIt.GoToBegin();
outIt.GoToBegin();

try
{
tensorReader->Update();
while (!outIt.IsAtEnd())
{
tensorPixelInput = inIt.Get();
const TensorPixelType tensorPixelOutput = outIt.Get();

for (unsigned int i = 0; i < 3; i++)
{
if (std::abs(tensorPixelInput[i] - tensorPixelOutput[i]) > tolerance)
{
std::cerr << "Tensor read does not match expected values " << std::endl;
std::cerr << "Index " << inIt.GetIndex() << std::endl;
std::cerr << "Tensor input value " << std::endl << tensorPixelInput << std::endl;
std::cerr << "Tensor output value " << std::endl << tensorPixelOutput << std::endl;
return EXIT_FAILURE;
}
}
++inIt;
++outIt;
}
return EXIT_SUCCESS;
}
catch (const itk::ExceptionObject & excp)
{
std::cerr << excp << std::endl;
return EXIT_FAILURE;
}

TensorImageType::ConstPointer tensorImageOutput = tensorReader->GetOutput();

// Compare the read values to the original values
const float tolerance = 1e-5;

itk::ImageRegionConstIterator<TensorImageType> inIt(tensorImageInput, region);
itk::ImageRegionConstIterator<TensorImageType> outIt(tensorImageOutput, region);

inIt.GoToBegin();
outIt.GoToBegin();

while (!outIt.IsAtEnd())
{
tensorPixelInput = inIt.Get();
const TensorPixelType tensorPixelOutput = outIt.Get();

for (unsigned int i = 0; i < 3; i++)
{
if (std::abs(tensorPixelInput[i] - tensorPixelOutput[i]) > tolerance)
{
std::cerr << "Tensor read does not match expected values " << std::endl;
std::cerr << "Index " << inIt.GetIndex() << std::endl;
std::cerr << "Tensor input value " << std::endl << tensorPixelInput << std::endl;
std::cerr << "Tensor output value " << std::endl << tensorPixelOutput << std::endl;
return EXIT_FAILURE;
}
}
++inIt;
++outIt;
}

return EXIT_SUCCESS;
}
25 changes: 24 additions & 1 deletion Modules/IO/ImageBase/include/itkImageFileReader.h
Expand Up @@ -45,7 +45,7 @@ namespace itk
* filter. If data stored in the file is stored in a different format
* then specified by TOutputImage, than this filter converts data
* between the file type and the external expected type. The
* ConvertTraits template argument is used to do the conversion.
* `ConvertPixelTraits` template parameter is used to do the conversion.
*
* A Pluggable factory pattern is used this allows different kinds of readers
* to be registered (even at run time) without having to modify the
Expand Down Expand Up @@ -167,6 +167,29 @@ class ITK_TEMPLATE_EXPORT ImageFileReader : public ImageSource<TOutputImage>
// produce the requested region.
ImageIORegion m_ActualIORegion;
};


/** Convenience function for reading an image.
*
* `TOutputImage` is the expected output image type, and the optional
* `ConvertPixelTraits` template parameter is used to do the conversion,
* as specified by ImageFileReader.
*
* The function reads the image from the specified file, and returns the
* image that it has read.
* */
template <typename TOutputImage,
typename ConvertPixelTraits = DefaultConvertPixelTraits<typename TOutputImage::IOPixelType>>
typename TOutputImage::Pointer
ReadImage(const std::string & filename)
{
const auto reader = ImageFileReader<TOutputImage, ConvertPixelTraits>::New();
reader->SetFileName(filename);
reader->Update();
return reader->GetOutput();
}


} // namespace itk

#ifndef ITK_MANUAL_INSTANTIATION
Expand Down

0 comments on commit aeea88b

Please sign in to comment.