Iterate Over an Image Buffer and an Index Range#

Synopsis#

This example demonstrates how to iterate over all pixels of the buffered region of an image, using either an iterator-based algorithm from the C++ Standard Library, or a range-based for loop.

Results#

Output:

Region index: [100, 200]; Region size: [4, 5]

Pixel index: [100, 200]; Pixel value: 0
Pixel index: [101, 200]; Pixel value: 1
Pixel index: [102, 200]; Pixel value: 2
Pixel index: [103, 200]; Pixel value: 3
Pixel index: [100, 201]; Pixel value: 4
Pixel index: [101, 201]; Pixel value: 5
Pixel index: [102, 201]; Pixel value: 6
Pixel index: [103, 201]; Pixel value: 7
Pixel index: [100, 202]; Pixel value: 8
Pixel index: [101, 202]; Pixel value: 9
Pixel index: [102, 202]; Pixel value: 10
Pixel index: [103, 202]; Pixel value: 11
Pixel index: [100, 203]; Pixel value: 12
Pixel index: [101, 203]; Pixel value: 13
Pixel index: [102, 203]; Pixel value: 14
Pixel index: [103, 203]; Pixel value: 15
Pixel index: [100, 204]; Pixel value: 16
Pixel index: [101, 204]; Pixel value: 17
Pixel index: [102, 204]; Pixel value: 18
Pixel index: [103, 204]; Pixel value: 19

Code#

C++#

#include "itkImage.h"
#include "itkImageBufferRange.h"
#include "itkIndexRange.h"
#include "itkNumericTraits.h"

#include <cassert>
#include <numeric> // For iota

namespace
{
// Creates an image with sequentially increasing pixel values (0, 1, 2, ...).
template <typename TImage>
typename TImage::Pointer
CreateImageWithSequentiallyIncreasingPixelValues(const typename TImage::RegionType & region)
{
  using PixelType = typename TImage::PixelType;

  const auto image = TImage::New();
  image->SetRegions(region);
  image->Allocate();

  const itk::ImageBufferRange<TImage> imageBufferRange(*image);
  std::iota(imageBufferRange.begin(), imageBufferRange.end(), PixelType{ 0 });

  return image;
}


// Prints all pixel values with their N-dimensional indices.
template <typename TImage>
void
PrintPixelValues(const TImage & image)
{
  constexpr unsigned int                      Dimension{ TImage::ImageDimension };
  const itk::ImageRegion<Dimension>           region = image.GetBufferedRegion();
  const itk::ImageRegionIndexRange<Dimension> indexRange(region);
  const itk::ImageBufferRange<const TImage>   imageBufferRange(image);

  using PixelType = typename TImage::PixelType;
  using PrintType = typename itk::NumericTraits<PixelType>::PrintType;

  std::cout << "Region index: " << region.GetIndex() << "; Region size: " << region.GetSize() << "\n\n";

  auto indexIterator = indexRange.cbegin();

  for (const PixelType pixel : imageBufferRange)
  {
    const itk::Index<Dimension> index = *indexIterator;
    std::cout << "Pixel index: " << index << "; Pixel value: " << PrintType{ pixel } << '\n';
    ++indexIterator;
  }

  assert(indexIterator == indexRange.cend());
}

} // namespace


int
main()
{
  using PixelType = unsigned char;
  using ImageType = itk::Image<PixelType>;
  using RegionType = ImageType::RegionType;

  const RegionType              region(itk::MakeIndex(100, 200), itk::MakeSize(4, 5));
  const ImageType::ConstPointer image = CreateImageWithSequentiallyIncreasingPixelValues<ImageType>(region);
  PrintPixelValues(*image);
}

Classes demonstrated#

template<typename TImage>
class ImageBufferRange

Modern C++11 range to iterate over the pixels of an image. Designed to conform to Standard C++ Iterator requirements, so that it can be used in range-based for loop, and passed to Standard C++ algorithms.

The following example adds 42 to each pixel, using a range-based for loop:

ImageBufferRange<ImageType> range{ *image };

for (auto&& pixel : range)
{
  pixel = pixel + 42;
}

The following example prints the values of the pixels:

for (const auto pixel : range)
{
  std::cout << pixel << std::endl;
}

Author

Niels Dekker, LKEB, Leiden University Medical Center

See

ImageIterator

See

ImageConstIterator

See

IndexRange

See

ShapedImageNeighborhoodRange

See itk::ImageBufferRange for additional documentation.
template<unsigned VDimension, bool VBeginAtZero>
class IndexRange

Modern C++11 range, supporting efficient iteration over the indices of an image grid space.

The following example prints all indices of an 2-D grid space of size 2x3.

constexpr unsigned Dimension = 2;
const Size<Dimension> size = { {2, 3} };
const ZeroBasedIndexRange<Dimension> indexRange{ size };

for (const Index<Dimension> index : indexRange)
{
  std::cout << index;
}
// Output: "[0, 0][1, 0][0, 1][1, 1][0, 2][1, 2]"

The indices from IndexRange can also be used as consecutive locations of a ShapedImageNeighborhoodRange, for example:

for (const auto index : indexRange)
{
  shapedImageNeighborhoodRange.SetLocation(index);

  for (const PixelType neighborPixel : shapedImageNeighborhoodRange)
  {
    // Process neighbor pixel...
  }
}

IndexRange is designed to conform to Standard C++ Iterator requirements, so that it can be used in range-based for loop, and its iterators can be passed to Standard C++ algorithms.

Author

Niels Dekker, LKEB, Leiden University Medical Center

See

ShapedImageNeighborhoodRange

See itk::IndexRange for additional documentation.