File: NeighborhoodIterators1.cxx

package info (click to toggle)
otb 8.1.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,030,436 kB
  • sloc: xml: 231,007; cpp: 224,490; ansic: 4,592; sh: 1,790; python: 1,131; perl: 92; makefile: 72
file content (195 lines) | stat: -rw-r--r-- 7,710 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/*
 * Copyright (C) 2005-2022 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * 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
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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.
 */


/* Example usage:
./NeighborhoodIterators1 Input/ROI_QB_PAN_1.tif Output/NeighborhoodIterators1a.png
*/


// This example uses the \doxygen{itk}{NeighborhoodIterator} to implement a simple
// Sobel edge detection algorithm \cite{Gonzalez1993}.  The algorithm uses the
// neighborhood iterator to iterate through an input image and calculate a
// series of finite difference derivatives.  Since the derivative results
// cannot be written back to the input image without affecting later
// calculations, they are written instead to a second, output image.  Most
// neighborhood processing algorithms follow this read-only model on their
// inputs.
//
// We begin by including the proper header files.  The
// \doxygen{itk}{ImageRegionIterator} will be used to write the results of
// computations to the output image.  A const version of the neighborhood
// iterator is used because the input image is read-only.

#include "otbImage.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"
#include "itkUnaryFunctorImageFilter.h"
#include "itkRescaleIntensityImageFilter.h"

#include "itkConstNeighborhoodIterator.h"
#include "itkImageRegionIterator.h"

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

  // The finite difference calculations
  // in this algorithm require floating point values.  Hence, we define the image
  // pixel type to be \code{float} and the file reader will
  // automatically cast fixed-point data to \code{float}.
  //
  // We declare the iterator types using the image type as
  // the template parameter. The second template parameter of the
  // neighborhood iterator, which specifies
  // the boundary condition, has been omitted because the default condition is
  // appropriate for this algorithm.

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

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

  // The following code creates and executes the OTB image reader.
  // The \code{Update}
  // call on the reader object is surrounded by the standard \code{try/catch}
  // blocks to handle any exceptions that may be thrown by the reader.

  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName(argv[1]);
  try
  {
    reader->Update();
  }
  catch (itk::ExceptionObject& err)
  {
    std::cout << "ExceptionObject caught !" << std::endl;
    std::cout << err << std::endl;
    return -1;
  }

  //  We can now create a neighborhood iterator to range over the output of the
  //  reader. For Sobel edge-detection in 2D, we need a square iterator that
  //  extends one pixel away from the neighborhood center in every dimension.

  NeighborhoodIteratorType::RadiusType radius;
  radius.Fill(1);
  NeighborhoodIteratorType it(radius, reader->GetOutput(), reader->GetOutput()->GetRequestedRegion());

  // The following code creates an output image and iterator.

  ImageType::Pointer output = ImageType::New();
  output->SetRegions(reader->GetOutput()->GetRequestedRegion());
  output->Allocate();

  IteratorType out(output, reader->GetOutput()->GetRequestedRegion());

  // Sobel edge detection uses weighted finite difference calculations to
  // construct an edge magnitude image.  Normally the edge magnitude is the
  // root sum of squares of partial derivatives in all directions, but for
  // simplicity this example only calculates the $x$ component. The result is a
  // derivative image biased toward maximally vertical edges.
  //
  // The finite differences are computed from pixels at six locations in the
  // neighborhood.  In this example, we use the iterator \code{GetPixel()}
  // method to query the values from their offsets in the neighborhood.
  // The example in Section~\ref{sec:NeighborhoodExample2} uses convolution
  // with a Sobel kernel instead.
  //
  // Six positions in the neighborhood are necessary for the finite difference
  // calculations. These positions are recorded in \code{offset1} through
  // \code{offset6}.

  NeighborhoodIteratorType::OffsetType offset1 = {{-1, -1}};
  NeighborhoodIteratorType::OffsetType offset2 = {{1, -1}};
  NeighborhoodIteratorType::OffsetType offset3 = {{-1, 0}};
  NeighborhoodIteratorType::OffsetType offset4 = {{1, 0}};
  NeighborhoodIteratorType::OffsetType offset5 = {{-1, 1}};
  NeighborhoodIteratorType::OffsetType offset6 = {{1, 1}};

  // It is equivalent to use the six corresponding integer array indices instead.
  // For example, the offsets \code{(-1, -1)} and \code{(1, -1)} are
  // equivalent to the integer indices \code{0} and \code{2}, respectively.
  //
  // The calculations are done in a \code{for} loop that moves the input and
  // output iterators synchronously across their respective images.  The
  // \code{sum} variable is used to sum the results of the finite differences.

  for (it.GoToBegin(), out.GoToBegin(); !it.IsAtEnd(); ++it, ++out)
  {
    float sum;
    sum = it.GetPixel(offset2) - it.GetPixel(offset1);
    sum += 2.0 * it.GetPixel(offset4) - 2.0 * it.GetPixel(offset3);
    sum += it.GetPixel(offset6) - it.GetPixel(offset5);
    out.Set(sum);
  }

  // The last step is to write the output buffer to an image file.  Writing is
  // done inside a \code{try/catch} block to handle any exceptions.  The output
  // is rescaled to intensity range $[0, 255]$ and cast to unsigned char so that
  // it can be saved and visualized as a PNG image.

  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[2]);
  writer->SetInput(rescaler->GetOutput());
  try
  {
    writer->Update();
  }
  catch (itk::ExceptionObject& err)
  {
    std::cout << "ExceptionObject caught !" << std::endl;
    std::cout << err << std::endl;
    return -1;
  }

  // The center image of Figure~\ref{fig:NeighborhoodExamples1} shows the
  // output of the Sobel algorithm applied to
  // \code{Examples/Data/ROI\_QB\_PAN\_1.tif}.
  //
  // \begin{figure} \centering
  // \includegraphics[width=0.45\textwidth]{ROI_QB_PAN_1.eps}
  // \includegraphics[width=0.45\textwidth]{NeighborhoodIterators1a.eps}
  // \itkcaption[Sobel edge detection results]{Applying the Sobel operator to an image (left) produces $x$ (right)  derivative image.}
  // \protect\label{fig:NeighborhoodExamples1}
  // \end{figure}

  return EXIT_SUCCESS;
}