ITK  5.4.0 Insight Toolkit
Examples/Filtering/ResampleImageFilter2.cxx
/*=========================================================================
*
*
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
*
*=========================================================================*/
// Software Guide : BeginLatex
//
// During the computation of the resampled image all the pixels in the
// output region are visited. This visit is performed using
// \code{ImageIterators} which walk in the integer grid-space of the
// image. For each pixel, we need to convert grid position to space
// coordinates using the image spacing and origin.
//
// For example, the pixel of index $I=(20,50)$ in an image of origin
// $O=(19.0, 29.0)$ and pixel spacing $S=(1.3,1.5)$ corresponds to the
// spatial position
//
//
// P[i] = I[i] \times S[i] + O[i]
//
//
// which in this case leads to $P=( 20 \times 1.3 + 19.0, 50 \times 1.5 + // 29.0 )$ and finally $P=(45.0, 104.0)$
//
// The space coordinates of $P$ are mapped using the transform $T$ supplied
// to the \doxygen{ResampleImageFilter} in order to map the point $P$ to the
// input image space point $Q = T(P)$.
//
// The whole process is illustrated in Figure
// \ref{fig:ResampleImageFilterTransformComposition1}. In order to correctly
// interpret the process of the ResampleImageFilter you should be aware of
// the origin and spacing settings of both the input and output images.
//
// \index{itk::ResampleImageFilter!Image internal transform}
//
// Software Guide : EndLatex
#include "itkImage.h"
int
main(int argc, char * argv[])
{
if (argc < 4)
{
std::cerr << "Usage: " << std::endl;
std::cerr << argv[0] << " inputImageFile outputImageFile";
std::cerr << " [exampleAction={0,1,2,3,4}]" << std::endl;
return EXIT_FAILURE;
}
int exampleAction = 0;
if (argc >= 4)
{
exampleAction = std::stoi(argv[3]);
}
constexpr unsigned int Dimension = 2;
using InputPixelType = unsigned char;
using OutputPixelType = unsigned char;
using InputImageType = itk::Image<InputPixelType, Dimension>;
using OutputImageType = itk::Image<OutputPixelType, Dimension>;
auto writer = WriterType::New();
writer->SetFileName(argv[2]);
using FilterType =
auto filter = FilterType::New();
auto transform = TransformType::New();
using InterpolatorType =
auto interpolator = InterpolatorType::New();
filter->SetInterpolator(interpolator);
// Software Guide : BeginLatex
//
// In order to facilitate the interpretation of the transform we set the
// default pixel value to a value distinct from the image background.
//
// \index{itk::ResampleImageFilter!SetDefaultPixelValue()}
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
filter->SetDefaultPixelValue(50);
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// Let's set up a uniform spacing for the output image.
//
// \index{itk::ResampleImageFilter!SetOutputSpacing()}
//
// Software Guide : EndLatex
{
// Software Guide : BeginCodeSnippet
// pixel spacing in millimeters along X & Y
const double spacing[Dimension] = { 1.0, 1.0 };
filter->SetOutputSpacing(spacing);
// Software Guide : EndCodeSnippet
}
// Software Guide : BeginLatex
//
// We will preserve the orientation of the input image by using the
// following call.
//
// \index{itk::ResampleImageFilter!SetOutputOrigin()}
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// Additionally, we will specify a non-zero origin. Note that the values
// provided here will be those of the space coordinates for the pixel of
// index $(0,0)$.
//
// \index{itk::ResampleImageFilter!SetOutputOrigin()}
//
// Software Guide : EndLatex
{
// Software Guide : BeginCodeSnippet
// space coordinate of origin
const double origin[Dimension] = { 30.0, 40.0 };
filter->SetOutputOrigin(origin);
// Software Guide : EndCodeSnippet
}
size[0] = 300; // number of pixels along X
size[1] = 300; // number of pixels along Y
filter->SetSize(size);
writer->SetInput(filter->GetOutput());
// Software Guide : BeginLatex
//
// We set the transform to identity in order to better appreciate the
// effect of the origin selection.
//
// \index{itk::AffineTransform!SetIdentity()}
// \index{itk::ResampleImageFilter!SetTransform()}
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
transform->SetIdentity();
filter->SetTransform(transform);
// Software Guide : EndCodeSnippet
if (exampleAction == 0)
{
writer->Update();
}
// Software Guide : BeginLatex
//
// The output resulting from these filter settings is analyzed in Figure
// \ref{fig:ResampleImageFilterTransformComposition1}.
//
// \begin{figure}
// \center
// \includegraphics[width=\textwidth]{ResampleImageFilterTransformComposition1}
// \itkcaption[ResampleImageFilter selecting the origin of the output
// image]{ResampleImageFilter selecting the origin of the output image.}
// \label{fig:ResampleImageFilterTransformComposition1}
// \end{figure}
//
// In the figure, the output image point with index $I=(0,0)$ has space
// coordinates $P=(30,40)$. The identity transform maps this point to
// $Q=(30,40)$ in the input image space. Because the input image in this
// case happens to have spacing $(1.0,1.0)$ and origin $(0.0,0.0)$, the
// physical point $Q=(30,40)$ maps to the pixel with index $I=(30,40)$.
//
// Software Guide : EndLatex
// Software Guide : BeginLatex
//
// The code for a different selection of origin and image size is
// illustrated below. The resulting output is presented in Figure
// \ref{fig:ResampleImageFilterTransformComposition2}.
//
// \index{itk::ResampleImageFilter!SetSize()}
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
size[0] = 150; // number of pixels along X
size[1] = 200; // number of pixels along Y
filter->SetSize(size);
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// \index{itk::ResampleImageFilter!SetOutputOrigin()}
//
// Software Guide : EndLatex
{
// Software Guide : BeginCodeSnippet
// space coordinate of origin
const double origin[Dimension] = { 60.0, 30.0 };
filter->SetOutputOrigin(origin);
// Software Guide : EndCodeSnippet
}
if (exampleAction == 1)
{
writer->Update();
}
// Software Guide : BeginLatex
//
//
// \begin{figure}
// \center
// \includegraphics[width=\textwidth]{ResampleImageFilterTransformComposition2}
// \itkcaption[ResampleImageFilter origin in the output
// image]{ResampleImageFilter origin in the output image.}
// \label{fig:ResampleImageFilterTransformComposition2}
// \end{figure}
//
// The output image point with index $I=(0,0)$ now has space coordinates
// $P=(60,30)$. The identity transform maps this point to $Q=(60,30)$ in
// the input image space. Because the input image in this case happens to
// have spacing $(1.0,1.0)$ and origin $(0.0,0.0)$, the physical point
// $Q=(60,30)$ maps to the pixel with index $I=(60,30)$.
//
// Software Guide : EndLatex
// Software Guide : BeginLatex
//
// Let's now analyze the effect of a non-zero origin in the input image.
// Keeping the output image settings of the previous example, we modify
// only the origin values on the file header of the input image. The new
// origin assigned to the input image is $O=(50,70)$. An identity
// transform is still used as input for the ResampleImageFilter. The
// result of executing the filter with these parameters is presented in
// Figure \ref{fig:ResampleImageFilterTransformComposition3}.
//
// \begin{figure}
// \center
// \includegraphics[width=\textwidth]{ResampleImageFilterTransformComposition3}
// \itkcaption[ResampleImageFilter selecting the origin of the input
// image]{Effect of selecting the origin of the input
// image with ResampleImageFilter.}
// \label{fig:ResampleImageFilterTransformComposition3} \end{figure}
//
// The pixel with index $I=(56,120)$ on the output image has coordinates
// $P=(116,150)$ in physical space. The identity transform maps $P$ to the
// point $Q=(116,150)$ on the input image space. The coordinates of $Q$ are
// associated with the pixel of index $I=(66,80)$ on the input image.
//
// Software Guide : EndLatex
if (exampleAction == 2)
{
writer->Update();
}
// Software Guide : BeginLatex
//
// Now consider the effect of the output spacing on the process of image
// resampling. In order to simplify the analysis, let's set the origin
// back to zero in both the input and output images.
//
// \index{itk::ResampleImageFilter!SetOutputOrigin()}
//
// Software Guide : EndLatex
{
// Software Guide : BeginCodeSnippet
// space coordinate of origin
const double origin[Dimension] = { 0.0, 0.0 };
filter->SetOutputOrigin(origin);
// Software Guide : EndCodeSnippet
}
// Software Guide : BeginLatex
//
// We then specify a non-unit spacing for the output image.
//
// \index{itk::ResampleImageFilter!SetOutputSpacing()}
//
// Software Guide : EndLatex
{
// Software Guide : BeginCodeSnippet
// pixel spacing in millimeters
const double spacing[Dimension] = { 2.0, 3.0 };
filter->SetOutputSpacing(spacing);
// Software Guide : EndCodeSnippet
}
// Software Guide : BeginLatex
//
// Additionally, we reduce the output image extent, since the new pixels
// are now covering a larger area of $2.0\mbox{mm} \times 3.0\mbox{mm}$.
//
// \index{itk::ResampleImageFilter!SetSize()}
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
size[0] = 80; // number of pixels along X
size[1] = 50; // number of pixels along Y
filter->SetSize(size);
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// With these new parameters the physical extent of the output image is
// $160$ millimeters by $150$ millimeters.
//
// Software Guide : EndLatex
// Software Guide : BeginLatex
//
// Before attempting to analyze the effect of the resampling image filter
// it is important to make sure that the image viewer used to display the
// input and output images takes the spacing into account and
// appropriately scales the images on the screen. Please note that images
// in formats like PNG are not capable of representing origin and
// spacing. The toolkit assumes trivial default values for them. Figure
// \ref{fig:ResampleImageFilterOutput7} (center) illustrates the effect of
// using a naive viewer that does not take pixel spacing into account. A
// correct display is presented at the right in the same figure\footnote{A
// viewer is provided with ITK under the name of MetaImageViewer. This
// viewer takes into account pixel spacing.}.
//
// \begin{figure}
// \center
// \includegraphics[width=0.32\textwidth]{BrainProtonDensitySlice}
// \includegraphics[width=0.32\textwidth]{ResampleImageFilterOutput7}
// \includegraphics[width=0.32\textwidth]{ResampleImageFilterOutput7b}
// \itkcaption[ResampleImageFilter use of naive viewers]{Resampling with
// different spacing seen by a naive viewer (center) and a correct viewer
// (right), input image (left).}
// \label{fig:ResampleImageFilterOutput7}
// \end{figure}
//
//
// \begin{figure}
// \center
// \includegraphics[width=\textwidth]{ResampleImageFilterTransformComposition4}
// \itkcaption[ResampleImageFilter and output image spacing]{Effect of
// selecting the spacing on the output image.}
// \label{fig:ResampleImageFilterTransformComposition4}
// \end{figure}
//
// The filter output is analyzed in a common coordinate system with the
// input from Figure \ref{fig:ResampleImageFilterTransformComposition4}. In
// this figure, pixel $I=(33,27)$ of the output image is located at
// coordinates $P=(66.0,81.0)$ of the physical space. The identity
// transform maps this point to $Q=(66.0,81.0)$ in the input image physical
// space. The point $Q$ is then associated to the pixel of index
// $I=(66,81)$ on the input image, because this image has zero origin and
// unit spacing.
//
// Software Guide : EndLatex
if (exampleAction == 3)
{
writer->Update();
}
// Software Guide : BeginLatex
//
// \begin{figure}
// \center
// \includegraphics[width=0.42\textwidth]{BrainProtonDensitySlice2x3}
// \includegraphics[width=0.42\textwidth]{BrainProtonDensitySlice2x3b}
// \itkcaption[ResampleImageFilter naive viewers]{Input image with $2 \times // 3 \mbox{mm}$ spacing as seen with a naive viewer (left) and a correct
// viewer (right).\label{fig:ResampleImageFilterInput2}}
// \end{figure}
//
// The input image spacing is also an important factor in the process of
// resampling an image. The following example illustrates the effect of
// non-unit pixel spacing on the input image. An input image similar to
// the those used in Figures
// \ref{fig:ResampleImageFilterTransformComposition1} to
// \ref{fig:ResampleImageFilterTransformComposition4} has been
// resampled to have pixel spacing of $2\mbox{mm} \times 3\mbox{mm}$. The
// input image is presented in Figure \ref{fig:ResampleImageFilterInput2}
// as viewed with a naive image viewer (left) and with a correct image
// viewer (right).
//
// The following code is used to transform this non-unit spacing input
// image into another non-unit spacing image located at a non-zero origin.
// The comparison between input and output in a common reference system is
// presented in figure \ref{fig:ResampleImageFilterTransformComposition5}.
//
// Software Guide : EndLatex
// Software Guide : BeginLatex
//
// Here we start by selecting the origin of the output image.
//
// \index{itk::ResampleImageFilter!SetOutputOrigin()}
//
// Software Guide : EndLatex
{
// Software Guide : BeginCodeSnippet
// space coordinate of origin
const double origin[Dimension] = { 25.0, 35.0 };
filter->SetOutputOrigin(origin);
// Software Guide : EndCodeSnippet
}
// Software Guide : BeginLatex
//
// We then select the number of pixels along each dimension.
//
// \index{itk::ResampleImageFilter!SetSize()}
//
// Software Guide : EndLatex
// Software Guide : BeginCodeSnippet
size[0] = 40; // number of pixels along X
size[1] = 45; // number of pixels along Y
filter->SetSize(size);
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// Finally, we set the output pixel spacing.
//
// \index{itk::ResampleImageFilter!SetOutputSpacing()}
//
// Software Guide : EndLatex
{
// Software Guide : BeginCodeSnippet
const double spacing[Dimension] = { 4.0, 4.5 };
filter->SetOutputSpacing(spacing);
// Software Guide : EndCodeSnippet
}
if (exampleAction == 4)
{
writer->Update();
}
// Software Guide : BeginLatex
//
// Figure \ref{fig:ResampleImageFilterTransformComposition5} shows the
// analysis of the filter output under these conditions. First, notice that
// the origin of the output image corresponds to the settings
// $O=(25.0,35.0)$ millimeters, spacing $(4.0,4.5)$ millimeters and size
// $(40,45)$ pixels. With these parameters the pixel of index $I=(10,10)$
// in the output image is associated with the spatial point of coordinates
// $P=(10 \times 4.0 + 25.0, 10 \times 4.5 + 35.0)) =(65.0,80.0)$. This
// point is mapped by the transform---identity in this particular case---to
// the point $Q=(65.0,80.0)$ in the input image space. The point $Q$ is
// then associated with the pixel of index $I=( ( 65.0 - 0.0 )/2.0 - (80.0 // - 0.0)/3.0) =(32.5,26.6)$. Note that the index does not fall on a grid
// position. For this reason the value to be assigned to the output pixel
// is computed by interpolating values on the input image around the
// non-integer index $I=(32.5,26.6)$.
//
// \begin{figure}
// \center
// \includegraphics[width=\textwidth]{ResampleImageFilterTransformComposition5}
// \itkcaption[ResampleImageFilter with non-unit spacing]{Effect of non-unit
// spacing on the input and output images.}
// \label{fig:ResampleImageFilterTransformComposition5}
// \end{figure}
//
// Note also that the discretization of the image is more visible on the
// output presented on the right side of Figure
// \ref{fig:ResampleImageFilterTransformComposition5} due to the choice of
// a low resolution---just $40 \times 45$ pixels.
//
// Software Guide : EndLatex
return EXIT_SUCCESS;
}
itk::GTest::TypedefsAndConstructors::Dimension2::SizeType
ImageBaseType::SizeType SizeType
Definition: itkGTestTypedefsAndConstructors.h:49
itkImage.h
itkAffineTransform.h
itk::AffineTransform
Definition: itkAffineTransform.h:101
Data source that reads image data from a single file.
itk::ImageFileWriter
Writes image data to a single file.
Definition: itkImageFileWriter.h:88
itkNearestNeighborInterpolateImageFunction.h
itkImageFileWriter.h
itk::Size::SetSize
void SetSize(const SizeValueType val[VDimension])
Definition: itkSize.h:181
itk::ResampleImageFilter
Resample an image via a coordinate transform.
Definition: itkResampleImageFilter.h:90
itk::Image
Templated n-dimensional image class.
Definition: itkImage.h:88
New
static Pointer New()
itk::NearestNeighborInterpolateImageFunction
Nearest neighbor interpolation of a scalar image.
itkResampleImageFilter.h
itk::GTest::TypedefsAndConstructors::Dimension2::Dimension
constexpr unsigned int Dimension
Definition: itkGTestTypedefsAndConstructors.h:44