Iterate Over A Region With A Shaped Neighborhood Iterator Manually

Synopsis

Iterate over a region of an image with a shaped neighborhood manually.

Results

Output:

By default there are 0 active indices.
Now there are 2 active indices.
1 7
New position:
Centered at [0, 0]
Neighborhood index 1 is offset [0, -1] and has value 0 The real index is [0, -1]
Centered at [0, 0]
Neighborhood index 7 is offset [0, 1] and has value 0 The real index is [0, 1]
New position:
Centered at [1, 0]
Neighborhood index 1 is offset [0, -1] and has value 0 The real index is [1, -1]
Centered at [1, 0]
Neighborhood index 7 is offset [0, 1] and has value 0 The real index is [1, 1]
New position:
Centered at [2, 0]
Neighborhood index 1 is offset [0, -1] and has value 0 The real index is [2, -1]
Centered at [2, 0]
Neighborhood index 7 is offset [0, 1] and has value 0 The real index is [2, 1]

[...]

New position:
Centered at [7, 9]
Neighborhood index 1 is offset [0, -1] and has value 0 The real index is [7, 8]
Centered at [7, 9]
Neighborhood index 7 is offset [0, 1] and has value 0 The real index is [7, 10]
New position:
Centered at [8, 9]
Neighborhood index 1 is offset [0, -1] and has value 0 The real index is [8, 8]
Centered at [8, 9]
Neighborhood index 7 is offset [0, 1] and has value 0 The real index is [8, 10]
New position:
Centered at [9, 9]
Neighborhood index 1 is offset [0, -1] and has value 0 The real index is [9, 8]
Centered at [9, 9]
Neighborhood index 7 is offset [0, 1] and has value 0 The real index is [9, 10]

Code

C++

#include "itkImage.h"
#include "itkShapedNeighborhoodIterator.h"
#include "itkImageRegionIterator.h"
#include "itkNeighborhoodAlgorithm.h"

// Notice that char type pixel values will not appear
// properly on the command prompt therefore for the
// demonstration purposes it is best to use the int
// type, however in real applications iterators have
// no problems with char type images.
// using ImageType = itk::Image<unsigned char, 2>;
using ImageType = itk::Image<unsigned int, 2>;

void
CreateImage(ImageType::Pointer image);

int
main(int, char *[])
{
  ImageType::Pointer image = ImageType::New();
  CreateImage(image);

  using IteratorType = itk::ShapedNeighborhoodIterator<ImageType>;

  itk::Size<2> radius;
  radius.Fill(1);
  IteratorType iterator(radius, image, image->GetLargestPossibleRegion());
  std::cout << "By default there are " << iterator.GetActiveIndexListSize() << " active indices." << std::endl;

  IteratorType::OffsetType top = { { 0, -1 } };
  iterator.ActivateOffset(top);
  IteratorType::OffsetType bottom = { { 0, 1 } };
  iterator.ActivateOffset(bottom);

  std::cout << "Now there are " << iterator.GetActiveIndexListSize() << " active indices." << std::endl;

  IteratorType::IndexListType                 indexList = iterator.GetActiveIndexList();
  IteratorType::IndexListType::const_iterator listIterator = indexList.begin();
  while (listIterator != indexList.end())
  {
    std::cout << *listIterator << " ";
    ++listIterator;
  }
  std::cout << std::endl;

  // Note that ZeroFluxNeumannBoundaryCondition is used by default so even
  // pixels outside of the image will have valid values (equivalent to their neighbors just inside the image)
  for (iterator.GoToBegin(); !iterator.IsAtEnd(); ++iterator)
  {
    std::cout << "New position: " << std::endl;
    IteratorType::ConstIterator ci = iterator.Begin();

    while (!ci.IsAtEnd())
    {
      std::cout << "Centered at " << iterator.GetIndex() << std::endl;
      std::cout << "Neighborhood index " << ci.GetNeighborhoodIndex() << " is offset " << ci.GetNeighborhoodOffset()
                << " and has value " << ci.Get() << " The real index is "
                << iterator.GetIndex() + ci.GetNeighborhoodOffset() << std::endl;
      ci++;
    }
  }

  std::cout << std::endl;

  return EXIT_SUCCESS;
}

void
CreateImage(ImageType::Pointer image)
{
  ImageType::IndexType start;
  start.Fill(0);

  ImageType::SizeType size;
  size.Fill(10);

  ImageType::RegionType region(start, size);

  image->SetRegions(region);
  image->Allocate();
  image->FillBuffer(0);
}

Classes demonstrated

template<typename TImage, typename TBoundaryCondition = ZeroFluxNeumannBoundaryCondition<TImage>>
class ShapedNeighborhoodIterator : public itk::ConstShapedNeighborhoodIterator<TImage, TBoundaryCondition>

A neighborhood iterator which can take on an arbitrary shape.

using ImageType = Image<float, 3>;
ShapedNeighborhoodIterator<ImageType> it(radius, image, region);
ShapedNeighborhoodIterator<ImageType>::OffsetType offset = {{0,0,0}};
it.ActivateOffset(offset);
General Information

The ShapedNeighborhoodIterator is a refinement of NeighborhoodIterator which allows the user to specify which of the neighborhood elements are active and which will be ignored. This is useful for applications which only need to work with a subset of the neighborhood around a pixel such as morphological operations or cellular automata. This iterator can also be used, for example, to specify “cross-shaped” neighborhood where only elements along a spatial axes are significant.

Constructing a shaped neighborhood iterator

A shaped neighborhood iterator is constructed by constructing a list of active neighbor locations. The list is called the ActiveIndexList. The methods ActivateOffset, DeactivateOffset, and ClearActiveList are used to construct the ActiveIndexList. The argument to Activate/DeactivateOffset is an itk::Offset which represents the ND spatial offset from the center of the neighborhood. For example, to activate the center pixel in the neighborhood, you would do the following:

where radius, image, and region are as described in NeighborhoodIterator.

Once a neighborhood location has been activated, iteration (operator++, operator–, operator+=, operator-=) will update the value at the active location. Note that values at inactive locations will NOT be valid if queried.

A second way to access active shaped neighborhood values is through a

ShapedNeighborhoodIterator::Iterator or ConstShapedNeighborhoodIterator::ConstIterator. The following example demonstrates the use of these iterators.
Accessing elements in a shaped neighborhood.

To access the value at an active neighborhood location, you can use the standard GetPixel, SetPixel methods. SetPixel is not defined for ConstShapedNeighborhoodIterator. The class will not complain if you attempt to access a value at a non-active location, but be aware that the result will be undefined. Error checking is not done in this case for the sake of efficiency.

using ImageType = Image<float, 3>;
ShapedNeighborhoodIterator<ImageType> it(radius, image, region);
.
.
.
it.ActivateOffset(offset1);
it.ActivateOffset(offset2);
it.ActivateOffset(offset3);
etc..
.
.
.
ShapedNeighborhoodIterator<ImageType>::Iterator i;
for (i = it.Begin(); ! i.IsAtEnd(); i++)
{ i.Set(i.Get() + 1.0); }
\\ you may also use i != i.End(), but IsAtEnd() may be slightly faster.

You can also iterate backward through the neighborhood active list.

i = it.End();
i--;
while (i != it.Begin())
{
  i.Set(i.Get() + 1.0);
  i--;
}
 i.Set(i.Get() + 1.0);

The Get() Set() syntax was chosen versus defining operator* for these iterators because lvalue vs. rvalue context information is needed to determine whether bounds checking must take place.

See

Neighborhood

MORE INFORMATION

For a complete description of the ITK Image Iterators and their API, please see the Iterators chapter in the ITK Software Guide. The ITK Software Guide is available in print and as a free .pdf download from https://www.itk.org.

See

ImageConstIterator

See

ConditionalConstIterator

See

ConstNeighborhoodIterator

See

ConstShapedNeighborhoodIterator

See

ConstSliceIterator

See

CorrespondenceDataStructureIterator

See

FloodFilledFunctionConditionalConstIterator

See

FloodFilledImageFunctionConditionalConstIterator

See

FloodFilledImageFunctionConditionalIterator

See

FloodFilledSpatialFunctionConditionalConstIterator

See

FloodFilledSpatialFunctionConditionalIterator

See

ImageConstIterator

See

ImageConstIteratorWithIndex

See

ImageIterator

See

ImageIteratorWithIndex

See

ImageLinearConstIteratorWithIndex

See

ImageLinearIteratorWithIndex

See

ImageRandomConstIteratorWithIndex

See

ImageRandomIteratorWithIndex

See

ImageRegionConstIterator

See

ImageRegionConstIteratorWithIndex

See

ImageRegionExclusionConstIteratorWithIndex

See

ImageRegionExclusionIteratorWithIndex

See

ImageRegionIterator

See

ImageRegionIteratorWithIndex

See

ImageRegionReverseConstIterator

See

ImageRegionReverseIterator

See

ImageReverseConstIterator

See

ImageReverseIterator

See

ImageSliceConstIteratorWithIndex

See

ImageSliceIteratorWithIndex

See

NeighborhoodIterator

See

PathConstIterator

See

PathIterator

See

ShapedNeighborhoodIterator

See

SliceIterator

See

ImageConstIteratorWithIndex

See

ShapedImageNeighborhoodRange

ITK Sphinx Examples:

See itk::ShapedNeighborhoodIterator for additional documentation.