# NeighborhoodIterators5.cxx¶

Example source code (NeighborhoodIterators5.cxx):

#include "otbImage.h"
#include "otbImageFileWriter.h"
#include "itkUnaryFunctorImageFilter.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkConstNeighborhoodIterator.h"
#include "itkImageRegionIterator.h"
#include "itkNeighborhoodAlgorithm.h"
#include "itkGaussianOperator.h"
#include "itkNeighborhoodInnerProduct.h"

// This example introduces slice-based neighborhood processing.  A slice, in
// this context, is a 1D path through an ND neighborhood. Slices are defined
// for generic arrays by the \code{std::slice} class as a start index, a step
// size, and an end index.  Slices simplify the implementation of certain
// neighborhood calculations.  They also provide a mechanism for taking inner
// products with subregions of neighborhoods.
//
// Suppose, for example, that we want to take partial derivatives in the $y$
// direction of a neighborhood, but offset those derivatives by one pixel
// position along the positive $x$ direction.  For a $3\times3$, 2D
// neighborhood iterator, we can construct an \code{std::slice}, \code{(start =
// 2, stride = 3, end = 8)}, that represents the neighborhood offsets $(1, // -1)$, $(1, 0)$, $(1, 1)$ (see Figure~\ref{fig:NeighborhoodIteratorFig2}). If we
// pass this slice as an extra argument to the
// \doxygen{itk}{NeighborhoodInnerProduct} function, then the inner product is taken
// only along that slice.  This sliced'' inner product with a 1D
// \doxygen{itk}{DerivativeOperator} gives the desired derivative.
//
// The previous separable Gaussian filtering example can be rewritten using
// slices and slice-based inner products.  In general, slice-based processing
// is most useful when doing many different calculations on the same
// neighborhood, where defining multiple iterators as in
// Section~\ref{sec:NeighborhoodExample4} becomes impractical or inefficient.
// Good examples of slice-based neighborhood processing can be found in any of
// the ND anisotropic diffusion function objects, such as
// \doxygen{itk}{CurvatureNDAnisotropicDiffusionFunction}.

int main(int argc, char* argv[])
{
if (argc < 4)
{
std::cerr << "Missing parameters. " << std::endl;
std::cerr << "Usage: " << std::endl;
std::cerr << argv << " inputImageFile outputImageFile sigma" << std::endl;
return -1;
}

using PixelType  = float;
using ImageType  = otb::Image<PixelType, 2>;

using NeighborhoodIteratorType = itk::ConstNeighborhoodIterator<ImageType>;
using IteratorType             = itk::ImageRegionIterator<ImageType>;

try
{
}
catch (itk::ExceptionObject& err)
{
std::cout << "ExceptionObject caught !" << std::endl;
std::cout << err << std::endl;
return -1;
}

ImageType::Pointer output = ImageType::New();
output->Allocate();

itk::NeighborhoodInnerProduct<ImageType> innerProduct;

using FaceCalculatorType = itk::NeighborhoodAlgorithm::ImageBoundaryFacesCalculator<ImageType>;

FaceCalculatorType                         faceCalculator;
FaceCalculatorType::FaceListType           faceList;
FaceCalculatorType::FaceListType::iterator fit;

IteratorType             out;
NeighborhoodIteratorType it;

// The first difference between this example and the previous example is that
// the Gaussian operator is only initialized once.  Its direction is not
// important because it is only a 1D array of coefficients.

itk::GaussianOperator<PixelType, 2> gaussianOperator;
gaussianOperator.SetDirection(0);
gaussianOperator.SetVariance(::atof(argv) * ::atof(argv));
gaussianOperator.CreateDirectional();

// Next we need to define a radius for the iterator.  The radius in all
// directions matches that of the single extent of the Gaussian operator,
// defining a square neighborhood.

// The inner product and face calculator are defined for the main processing
// loop as before, but now the iterator is reinitialized each iteration with
// inner product is taken using a slice along the axial direction corresponding
// to the current iteration.  Note the use of \code{GetSlice()} to return the
// proper slice from the iterator itself.  \code{GetSlice()} can only be used
// to return the slice along the complete extent of the axial direction of a
// neighborhood.

for (unsigned int i = 0; i < ImageType::ImageDimension; ++i)
{
for (fit = faceList.begin(); fit != faceList.end(); ++fit)
{
out = IteratorType(output, *fit);
for (it.GoToBegin(), out.GoToBegin(); !it.IsAtEnd(); ++it, ++out)
{
out.Set(innerProduct(it.GetSlice(i), it, gaussianOperator));
}
}

// Swap the input and output buffers
if (i != ImageType::ImageDimension - 1)
{
ImageType::Pointer tmp = input;
input                  = output;
output                 = tmp;
}
}

// This technique produces exactly the same results as the previous example.  A
// little experimentation, however, will reveal that it is less efficient since
// the neighborhood iterator is keeping track of extra, unused pixel locations
// for each iteration, while the previous example only references those pixels
// that it needs.  In cases, however, where an algorithm takes multiple
// derivatives or convolution products over the same neighborhood, slice-based
// processing can increase efficiency and simplify the implementation.

using WritePixelType = unsigned char;
using WriteImageType = otb::Image<WritePixelType, 2>;
using WriterType     = otb::ImageFileWriter<WriteImageType>;

using RescaleFilterType = itk::RescaleIntensityImageFilter<ImageType, WriteImageType>;

RescaleFilterType::Pointer rescaler = RescaleFilterType::New();

rescaler->SetOutputMinimum(0);
rescaler->SetOutputMaximum(255);
rescaler->SetInput(output);

WriterType::Pointer writer = WriterType::New();
writer->SetFileName(argv);
writer->SetInput(rescaler->GetOutput());
try
{
writer->Update();
}
catch (itk::ExceptionObject& err)
{
std::cout << "ExceptionObject caught !" << std::endl;
std::cout << err << std::endl;
return -1;
}

return EXIT_SUCCESS;
}