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 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
|
/*
* 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:
./SIFTFastExample Input/ROISpot5.png Output/ROISpot5SIFTFast.png 3
*/
// This example illustrates the use of the \doxygen{otb}{SiftFastImageFilter}.
// The Scale-Invariant Feature Transform (or SIFT) is an algorithm in
// computer vision to detect and describe local features in
// images. The algorithm was published by David Lowe
// \cite{LoweSIFT}. The detection and description of local image
// features can help in object recognition and image registration. The
// SIFT features are local and based on the appearance of the object
// at particular interest points, and are invariant to image scale and
// rotation. They are also robust to changes in illumination, noise,
// occlusion and minor changes in viewpoint.
//
// The first step required to use this filter is to include its header file.
#include "otbSiftFastImageFilter.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"
#include "itkPointSet.h"
#include "itkVariableLengthVector.h"
#include "itkRGBPixel.h"
#include "itkImageRegionIterator.h"
#include <iostream>
#include <fstream>
int main(int argc, char* argv[])
{
if (argc != 4)
{
std::cerr << "Usage: " << argv[0];
std::cerr << " InputImage OutputImage scales" << std::endl;
return 1;
}
const char* infname = argv[1];
const char* outputImageFilename = argv[2];
const unsigned int scales = atoi(argv[3]);
const unsigned int Dimension = 2;
// We will start by defining the required types. We will work with a
// scalar image of float pixels. We also define the corresponding
// image reader.
using RealType = float;
using ImageType = otb::Image<RealType, Dimension>;
using ReaderType = otb::ImageFileReader<ImageType>;
// The SIFT descriptors will be stored in a point set containing the
// vector of features.
using RealVectorType = itk::VariableLengthVector<RealType>;
using PointSetType = itk::PointSet<RealVectorType, Dimension>;
// The SIFT filter itself is templated over the input image and the
// generated point set.
using ImageToFastSIFTKeyPointSetFilterType = otb::SiftFastImageFilter<ImageType, PointSetType>;
// We instantiate the reader.
ReaderType::Pointer reader = ReaderType::New();
reader->SetFileName(infname);
// We instantiate the filter.
ImageToFastSIFTKeyPointSetFilterType::Pointer filter = ImageToFastSIFTKeyPointSetFilterType::New();
// We plug the filter and set the number of scales for the SIFT
// computation. We can afterwards run the processing with the
// \code{Update()} method.
filter->SetInput(reader->GetOutput());
filter->SetScalesNumber(scales);
filter->Update();
// Once the SIFT are computed, we may want to draw them on top of the
// input image. In order to do this, we will create the following RGB
// image and the corresponding writer:
using PixelType = unsigned char;
using RGBPixelType = itk::RGBPixel<PixelType>;
using OutputImageType = otb::Image<RGBPixelType, 2>;
using WriterType = otb::ImageFileWriter<OutputImageType>;
OutputImageType::Pointer outputImage = OutputImageType::New();
// We set the regions of the image by copying the information from the
// input image and we allocate the memory for the output image.
outputImage->SetRegions(reader->GetOutput()->GetLargestPossibleRegion());
outputImage->Allocate();
// We can now proceed to copy the input image into the output one
// using region iterators. The input image is a grey level one. The
// output image will be made of color crosses for each SIFT on top of
// the grey level input image. So we start by copying the grey level
// values on each of the 3 channels of the color image.
itk::ImageRegionIterator<OutputImageType> iterOutput(outputImage, outputImage->GetLargestPossibleRegion());
itk::ImageRegionIterator<ImageType> iterInput(reader->GetOutput(), reader->GetOutput()->GetLargestPossibleRegion());
for (iterOutput.GoToBegin(), iterInput.GoToBegin(); !iterOutput.IsAtEnd(); ++iterOutput, ++iterInput)
{
OutputImageType::PixelType rgbPixel;
rgbPixel.SetRed(static_cast<PixelType>(iterInput.Get()));
rgbPixel.SetGreen(static_cast<PixelType>(iterInput.Get()));
rgbPixel.SetBlue(static_cast<PixelType>(iterInput.Get()));
iterOutput.Set(rgbPixel);
}
// We are now going to plot color crosses on the output image. We will
// need to define offsets (top, bottom, left and right) with respect
// to the SIFT position in order to draw the cross segments.
ImageType::OffsetType t = {{0, 1}};
ImageType::OffsetType b = {{0, -1}};
ImageType::OffsetType l = {{1, 0}};
ImageType::OffsetType r = {{-1, 0}};
// Now, we are going to access the point set generated by the SIFT
// filter. The points are stored into a points container that we are
// going to walk through using an iterator. These are the types needed
// for this task:
using PointsContainerType = PointSetType::PointsContainer;
using PointsIteratorType = PointsContainerType::Iterator;
// We set the iterator to the beginning of the point set.
PointsIteratorType pIt = filter->GetOutput()->GetPoints()->Begin();
// We get the information about image size and spacing before drawing
// the crosses.
ImageType::SpacingType spacing = reader->GetOutput()->GetSignedSpacing();
ImageType::PointType origin = reader->GetOutput()->GetOrigin();
// And we iterate through the SIFT set:
while (pIt != filter->GetOutput()->GetPoints()->End())
{
// We get the pixel coordinates for each SIFT by using the
// \code{Value()} method on the point set iterator. We use the
// information about size and spacing in order to convert the physical
// coordinates of the point into pixel coordinates.
ImageType::IndexType index;
index[0] = static_cast<unsigned int>(std::floor(static_cast<double>((pIt.Value()[0] - origin[0]) / spacing[0] + 0.5)));
index[1] = static_cast<unsigned int>(std::floor(static_cast<double>((pIt.Value()[1] - origin[1]) / spacing[1] + 0.5)));
// We create a green pixel.
OutputImageType::PixelType keyPixel;
keyPixel.SetRed(0);
keyPixel.SetGreen(255);
keyPixel.SetBlue(0);
// We draw the crosses using the offsets and checking that we are
// inside the image, since SIFTs on the image borders would cause an
// out of bounds pixel access.
if (outputImage->GetLargestPossibleRegion().IsInside(index))
{
outputImage->SetPixel(index, keyPixel);
if (outputImage->GetLargestPossibleRegion().IsInside(index + t))
outputImage->SetPixel(index + t, keyPixel);
if (outputImage->GetLargestPossibleRegion().IsInside(index + b))
outputImage->SetPixel(index + b, keyPixel);
if (outputImage->GetLargestPossibleRegion().IsInside(index + l))
outputImage->SetPixel(index + l, keyPixel);
if (outputImage->GetLargestPossibleRegion().IsInside(index + r))
outputImage->SetPixel(index + r, keyPixel);
}
++pIt;
}
// Finally, we write the image.
WriterType::Pointer writer = WriterType::New();
writer->SetFileName(outputImageFilename);
writer->SetInput(outputImage);
writer->Update();
// Figure~\ref{fig:SIFTFast} shows the result of applying the SIFT
// point detector to a small patch extracted from a Spot 5 image.
// \begin{figure}
// \center
// \includegraphics[width=0.40\textwidth]{ROISpot5.eps}
// \includegraphics[width=0.40\textwidth]{ROISpot5SIFTFast.eps}
// \itkcaption[SIFT Application]{Result of applying the
// \doxygen{otb}{SiftFastImageFilter} to a Spot 5
// image.}
// \label{fig:SIFTFast}
// \end{figure}
return EXIT_SUCCESS;
}
|