Image4.cxxΒΆ
Example source code (Image4.cxx):
/*
* Copyright (C) 1999-2011 Insight Software Consortium
* Copyright (C) 2005-2024 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.
*/
// Even though OTB can be used to perform
// general image processing tasks, the primary purpose of the toolkit is the
// processing of remote sensing image data. In that respect, additional
// information about the images is considered mandatory. In particular the
// information associated with the physical spacing between pixels and the
// position of the image in space with respect to some world coordinate
// system are extremely important.
//
// Image origin and spacing are fundamental to many
// applications. Registration, for example, is performed in physical
// coordinates. Improperly defined spacing and origins will result in
// inconsistent results in such processes. Remote sensing images with no spatial
// information should not be used for image analysis,
// feature extraction, GIS input, etc. In
// other words, remote sensing images lacking spatial information are not only
// useless but also hazardous.
//
// \begin{figure} \center
// \includegraphics[width=\textwidth]{ImageOriginAndSpacing.eps}
// \itkcaption[OTB Image Geometrical Concepts]{Geometrical concepts associated
// with the OTB image.}
// \label{fig:ImageOriginAndSpacing}
// \end{figure}
//
// Figure \ref{fig:ImageOriginAndSpacing} illustrates the main geometrical
// concepts associated with the \doxygen{otb}{Image}. In this figure,
// circles are
// used to represent the center of pixels. The value of the pixel is assumed
// to exist as a Dirac Delta Function located at the pixel center. Pixel
// spacing is measured between the pixel centers and can be different along
// each dimension. The image origin is associated with the coordinates of the
// first pixel in the image. A \emph{pixel} is considered to be the
// rectangular region surrounding the pixel center holding the data
// value. This can be viewed as the Voronoi region of the image grid, as
// illustrated in the right side of the figure. Linear interpolation of
// image values is performed inside the Delaunay region whose corners
// are pixel centers.
#include "otbImage.h"
#include "itkPoint.h"
int main(int, char* [])
{
using ImageType = otb::Image<unsigned short, 2>;
ImageType::Pointer image = ImageType::New();
ImageType::IndexType start;
ImageType::SizeType size;
size[0] = 200; // size along X
size[1] = 200; // size along Y
start[0] = 0; // first index on X
start[1] = 0; // first index on Y
ImageType::RegionType region;
region.SetSize(size);
region.SetIndex(start);
image->SetRegions(region);
image->Allocate();
image->FillBuffer(0);
// Image spacing is represented in a \code{FixedArray}
// whose size matches the dimension of the image. In order to manually set
// the spacing of the image, an array of the corresponding type must be
// created. The elements of the array should then be initialized with the
// spacing between the centers of adjacent pixels. The following code
// illustrates the methods available in the Image class for dealing with
// spacing and origin.
//
// \index{otb::Image!Spacing}
ImageType::SpacingType spacing;
// Note: measurement units (e.g., meters, feet, etc.) are defined by the application.
spacing[0] = 0.70; // spacing along X
spacing[1] = 0.70; // spacing along Y
// The array can be assigned to the image using
// the \code{SetSignedSpacing()} method.
//
// \index{otb::Image!SetSignedSpacing()}
image->SetSignedSpacing(spacing);
// The spacing information can be retrieved from an image by using the
// \code{GetSignedSpacing()} method. This method returns a reference to a
// \code{FixedArray}. The returned object can then be used to read the
// contents of the array. Note the use of the \code{const} keyword to indicate
// that the array will not be modified.
const ImageType::SpacingType& sp = image->GetSignedSpacing();
std::cout << "Spacing = ";
std::cout << sp[0] << ", " << sp[1] << std::endl;
// The image origin is managed in a similar way to the spacing. A
// \code{Point} of the appropriate dimension must first be
// allocated. The coordinates of the origin can then be assigned to
// every component. These coordinates correspond to the position of
// the first pixel of the image with respect to an arbitrary
// reference system in physical space. It is the user's
// responsibility to make sure that multiple images used in the same
// application are using a consistent reference system. This is
// extremely important in image registration applications.
//
// The following code illustrates the creation and assignment of a variable
// suitable for initializing the image origin.
//
// \index{otb::Image!origin}
// \index{otb::Image!SetOrigin()}
ImageType::PointType origin;
origin[0] = 0.0; // coordinates of the
origin[1] = 0.0; // first pixel in 2-D
image->SetOrigin(origin);
// The origin can also be retrieved from an image by using the
// \code{GetOrigin()} method. This will return a reference to a
// \code{Point}. The reference can be used to read the contents of
// the array. Note again the use of the \code{const} keyword to indicate
// that the array contents will not be modified.
const ImageType::PointType& orgn = image->GetOrigin();
std::cout << "Origin = ";
std::cout << orgn[0] << ", " << orgn[1] << std::endl;
// Once the spacing and origin of the image have been initialized, the image
// will correctly map pixel indices to and from physical space
// coordinates. The following code illustrates how a point in physical
// space can be mapped into an image index for the purpose of reading the
// content of the closest pixel.
//
// First, a \doxygen{itk}{Point} type must be declared. The point type is
// templated over the type used to represent coordinates and over the
// dimension of the space. In this particular case, the dimension of the
// point must match the dimension of the image.
using PointType = itk::Point<double, ImageType::ImageDimension>;
// The Point class, like an \doxygen{itk}{Index}, is a relatively small and
// simple object. For this reason, it is not reference-counted like the
// large data objects in OTB. Consequently, it is also not manipulated
// with \doxygen{itk}{SmartPointer}s. Point objects are simply declared as
// instances of any other C++ class. Once the point is declared, its
// components can be accessed using traditional array notation. In
// particular, the \code{[]} operator is available. For efficiency reasons,
// no bounds checking is performed on the index used to access a particular
// point component. It is the user's responsibility to make sure that the
// index is in the range $\{0, Dimension-1\}$.
PointType point;
point[0] = 1.45; // x coordinate
point[1] = 7.21; // y coordinate
// The image will map the point to an index using the values of the
// current spacing and origin. An index object must be provided to
// receive the results of the mapping. The index object can be
// instantiated by using the \code{IndexType} defined in the Image
// type.
ImageType::IndexType pixelIndex;
// The \code{TransformPhysicalPointToIndex()} method of the image class
// will compute the pixel index closest to the point provided. The method
// checks for this index to be contained inside the current buffered pixel
// data. The method returns a boolean indicating whether the resulting
// index falls inside the buffered region or not. The output index should
// not be used when the returned value of the method is \code{false}.
//
// The following lines illustrate the point to index mapping and the
// subsequent use of the pixel index for accessing pixel data from the
// image.
//
// \index{otb::Image!TransformPhysicalPointToIndex()}
bool isInside = image->TransformPhysicalPointToIndex(point, pixelIndex);
if (isInside)
{
ImageType::PixelType pixelValue = image->GetPixel(pixelIndex);
pixelValue += 5;
image->SetPixel(pixelIndex, pixelValue);
}
// Remember that \code{GetPixel()} and \code{SetPixel()} are very
// inefficient methods for accessing pixel data. Image iterators should be
// used when massive access to pixel data is required.
return EXIT_SUCCESS;
}