Commit 68c43d05 authored by Guillaume Pasero's avatar Guillaume Pasero

Merge branch 'masked_iterator_decorator' into develop

parents 16fc6cd6 8686293f
......@@ -316,7 +316,7 @@ SubsampledImageRegionConstIterator<TImage>
{
// Get the index of the first pixel on the span (row)
IndexType ind = this->m_Image->ComputeIndex(static_cast<IndexValueType>(this->m_Offset));
IndexType& startIndex = this->m_Region.GetIndex();
const IndexType& startIndex = this->m_Region.GetIndex();
// Deccrement along a row, then wrap at the beginning of the region row.
bool done;
......
/*=========================================================================
Program: ORFEO Toolbox
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
See OTBCopyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef otbMaskedIteratorDecorator_h
#define otbMaskedIteratorDecorator_h
#include "itkMacro.h"
namespace otb
{
/** \class MaskedIteratorDecorator
* \brief Decorate an iterator to ignore masked pixels
*
* An iterator that dispatches its operations on both an image and a mask using
* two iterators of the same type. It skips over pixels where the value of the
* mask is zero. There is a limitation that the image and the mask must both be
* of the same type.
*
* \ingroup ImageIterator
* \ingroup OTBCommon
*/
template <typename TIteratorType,typename TMaskIteratorType = TIteratorType>
class MaskedIteratorDecorator
{
public:
typedef MaskedIteratorDecorator
<TIteratorType,TMaskIteratorType> Self;
typedef typename TMaskIteratorType::ImageType MaskType;
typedef typename TIteratorType::ImageType ImageType;
typedef typename ImageType::IndexType IndexType;
typedef typename ImageType::RegionType RegionType;
typedef typename ImageType::PixelType PixelType;
typedef typename MaskType::PixelType MaskPixelType;
// Run-time type information
itkTypeMacroNoParent(MaskedIteratorDecorator);
/** Constructors forward arguments to both iterators
* Beware that the iterator is in a undefinite state after construction
* GoToBegin() or GoToEnd() should be called */
MaskedIteratorDecorator(MaskType* mask,
ImageType* image,
const RegionType& region);
/** Current iterator index. Wraps the underlying iterator GetIndex() */
IndexType GetIndex() const;
/** Move to the first valid iteration position. Note that this is different
* from the underlying iterators GoToBegin because their first pixels might be
* masked */
void GoToBegin();
/** Move one pixel past the last valid iteration index */
void GoToEnd();
/** True if the iterator is at the beginning */
bool IsAtBegin() const;
/** True if the iterator is at the end */
bool IsAtEnd() const;
/** Advance to the next valid iteration position. That is the next non masked
* position of the image iterator */
Self& operator++();
/** Move to the previous valid iteration position. That is the previous non
* masked position of the image iterator */
Self & operator--();
/** Set the image pixel value */
//void Set(const PixelType& value) const;
/** Get the image pixel value */
const PixelType& Value(void) const;
// Can't wrap all methods because iterator interface is open ended
// So provide access to inner iterators:
/** Underlying mask iterator accessor */
TMaskIteratorType& GetMaskIterator();
/** Underlying mask iterator const accessor */
const TMaskIteratorType& GetMaskIterator() const;
/** Underlying image iterator accessor */
TIteratorType& GetImageIterator();
/** Underlying image iterator const accessor */
const TIteratorType& GetImageIterator() const;
const bool& HasMask() const;
private:
/** Private method to compute the begin iterator position taking into account
the mask. Called by the constructor. */
void ComputeMaskedBegin();
private:
// Inner iterators on the image and mask
TMaskIteratorType m_ItMask;
TIteratorType m_ItImage;
// flag to check if mask is present
bool m_UseMask;
// Unmasked bounds
TMaskIteratorType m_StartMask;
TIteratorType m_StartImage;
};
}
#ifndef OTB_MANUAL_INSTANTIATION
#include "otbMaskedIteratorDecorator.txx"
#endif
#endif
/*=========================================================================
Program: ORFEO Toolbox
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
See OTBCopyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef otbMaskedIteratorDecorator_hxx
#define otbMaskedIteratorDecorator_hxx
#include "otbMaskedIteratorDecorator.h"
#include "itkMacro.h"
namespace otb
{
template <typename TIteratorType, typename TMaskIteratorType>
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>
::MaskedIteratorDecorator( MaskType* mask,
ImageType* image,
const RegionType& region)
{
m_ItImage = TIteratorType(image,region);
if (mask == NULL)
{
m_UseMask = false;
}
else
{
if (image->GetLargestPossibleRegion() != mask->GetLargestPossibleRegion())
{
itkGenericExceptionMacro("Input image and mask have different largest regions : mask is discarded!");
}
else
{
m_UseMask = true;
m_ItMask = TMaskIteratorType(mask,region);
m_StartMask = TMaskIteratorType(mask,region);
m_StartImage = TIteratorType(image,region);
}
}
}
template <typename TIteratorType, typename TMaskIteratorType>
typename MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>::IndexType
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>
::GetIndex() const
{
return m_ItImage.GetIndex();
}
template <typename TIteratorType, typename TMaskIteratorType>
void
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>
::GoToBegin()
{
if (m_UseMask)
{
this->ComputeMaskedBegin();
}
else
{
m_ItImage.GoToBegin();
}
}
template <typename TIteratorType, typename TMaskIteratorType>
void
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>
::GoToEnd()
{
if (m_UseMask)
{
// make sure masked begin is computed as next calls might be operator--()
// and IsAtBegin() (for a reverse iteration)
this->ComputeMaskedBegin();
m_ItMask.GoToEnd();
}
m_ItImage.GoToEnd();
}
template <typename TIteratorType, typename TMaskIteratorType>
bool
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>
::IsAtBegin() const
{
if (m_UseMask)
{
return m_ItMask == m_StartMask || m_ItImage == m_StartImage;
}
return m_ItImage.IsAtBegin();
}
template <typename TIteratorType, typename TMaskIteratorType>
bool
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>
::IsAtEnd() const
{
if (m_UseMask)
{
return m_ItMask.IsAtEnd() || m_ItImage.IsAtEnd();
}
return m_ItImage.IsAtEnd();
}
// Wrap the underlying iterators to skip masked pixels
template <typename TIteratorType, typename TMaskIteratorType>
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>&
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>
::operator++()
{
if (m_UseMask)
{
do
{
++m_ItMask;
++m_ItImage;
} while (m_ItMask.Value() == 0 && !this->IsAtEnd());
}
else
{
++m_ItImage;
}
return *this;
}
// Wrap the underlying iterators to skip masked pixels
template <typename TIteratorType, typename TMaskIteratorType>
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>&
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>
::operator--()
{
if (m_UseMask)
{
do
{
--m_ItMask;
--m_ItImage;
} while (m_ItMask.Value() == 0 && !this->IsAtBegin());
}
else
{
--m_ItImage;
}
return *this;
}
/*
template <typename TIteratorType, typename TMaskIteratorType>
void MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>::Set(const PixelType& value) const
{
m_ItImage.Set(value);
}
*/
template <typename TIteratorType, typename TMaskIteratorType>
const typename MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>::PixelType&
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>
::Value(void) const
{
return m_ItImage.Value();
}
template <typename TIteratorType, typename TMaskIteratorType>
TMaskIteratorType&
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>
::GetMaskIterator()
{
return m_ItMask;
}
template <typename TIteratorType, typename TMaskIteratorType>
const TMaskIteratorType&
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>
::GetMaskIterator() const
{
return m_ItMask;
}
template <typename TIteratorType, typename TMaskIteratorType>
TIteratorType&
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>
::GetImageIterator()
{
return m_ItImage;
}
template <typename TIteratorType, typename TMaskIteratorType>
const TIteratorType&
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>
::GetImageIterator() const
{
return m_ItImage;
}
template <typename TIteratorType, typename TMaskIteratorType>
const bool&
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>
::HasMask() const
{
return m_UseMask;
}
// Compute begin iterator position taking into account the mask
template <typename TIteratorType, typename TMaskIteratorType>
void
MaskedIteratorDecorator<TIteratorType,TMaskIteratorType>
::ComputeMaskedBegin()
{
// We must search for the first index where the image is not masked
// Start searching at the begining
m_ItMask.GoToBegin();
m_ItImage.GoToBegin();
// Advance to the first non-masked position, or the end
while (m_ItMask.Value() == 0 && !m_ItMask.IsAtEnd() && !m_ItImage.IsAtEnd())
{
++m_ItMask;
++m_ItImage;
}
m_StartMask.SetIndex(m_ItMask.GetIndex());
m_StartImage.SetIndex(m_ItImage.GetIndex());
}
} // namespace otb
#endif
......@@ -7,6 +7,7 @@ data.")
otb_module(OTBImageManipulation
DEPENDS
OTBBoostAdapters
OTBCommon
OTBITK
OTBImageBase
......
......@@ -76,6 +76,7 @@ otbTwoNRIBandsImageToNComplexBandsImage.cxx
otbChangeNoDataValueFilter.cxx
otbImageToNoDataMaskFilter.cxx
otbChangeInformationImageFilter.cxx
otbMaskedIteratorDecorator.cxx
)
add_executable(otbImageManipulationTestDriver ${OTBImageManipulationTests})
......@@ -716,3 +717,19 @@ otb_add_test(NAME bfTvChangeInformationImageFilter COMMAND otbImageManipulation
otbChangeInformationImageFilter
${INPUTDATA}/WV2_PAN_ROI_1000_100.tif
)
otb_add_test(NAME bfTuMaskedIteratorDecoratorNew COMMAND otbImageManipulationTestDriver
otbMaskedIteratorDecoratorNew
)
otb_add_test(NAME bfTvMaskedIteratorDecoratorNominal COMMAND otbImageManipulationTestDriver
otbMaskedIteratorDecoratorNominal
)
otb_add_test(NAME bfTvMaskedIteratorDecoratorDegenerate COMMAND otbImageManipulationTestDriver
otbMaskedIteratorDecoratorDegenerate
)
otb_add_test(NAME bfTvMaskedIteratorDecoratorExtended COMMAND otbImageManipulationTestDriver
otbMaskedIteratorDecoratorExtended
)
......@@ -82,4 +82,8 @@ void RegisterTests()
REGISTER_TEST(otbChangeNoDataValueFilter);
REGISTER_TEST(otbImageToNoDataMaskFilter);
REGISTER_TEST(otbChangeInformationImageFilter);
REGISTER_TEST(otbMaskedIteratorDecoratorNew);
REGISTER_TEST(otbMaskedIteratorDecoratorNominal);
REGISTER_TEST(otbMaskedIteratorDecoratorDegenerate);
REGISTER_TEST(otbMaskedIteratorDecoratorExtended);
}
/*=========================================================================
Program: ORFEO Toolbox
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
See OTBCopyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#include <set>
#include "otbImage.h"
#include "otbVectorImage.h"
#include "itkImageRegionIterator.h"
#include "itkImageRegionReverseIterator.h"
#include "itkImageRandomIteratorWithIndex.h"
#include "itkImageScanlineIterator.h"
#include "itkImageRandomNonRepeatingIteratorWithIndex.h"
#include "otbSubsampledImageRegionIterator.h"
#include "otbMaskedIteratorDecorator.h"
// Generate a test image of specified size and value
template <typename ImageType>
typename ImageType::Pointer GetTestImage(itk::SizeValueType fillSize, const typename ImageType::PixelType& value, unsigned int nbBand=1)
{
typename ImageType::Pointer image = ImageType::New();
typename ImageType::SizeType size;
size.Fill(fillSize);
typename ImageType::RegionType region;
region.SetSize(size);
image->SetNumberOfComponentsPerPixel(nbBand);
image->SetRegions(region);
image->Allocate();
image->FillBuffer(value);
return image;
}
// Fill half of the pixels with a value
// Used for generating a test mask
template <typename ImageType>
void FillHalf(typename ImageType::Pointer image, const typename ImageType::RegionType& region, const typename ImageType::PixelType& value)
{
itk::ImageRegionIterator<ImageType> it(image, region);
unsigned int count = 0;
for(it.GoToBegin(); !it.IsAtEnd(); ++it, ++count)
{
if (count % 2 == 0)
{
it.Set(value);
}
}
}
// Test template instanciation
int otbMaskedIteratorDecoratorNew(int itkNotUsed(argc), char * itkNotUsed(argv) [])
{
typedef otb::Image<double, 2> ImageType;
ImageType::Pointer image = GetTestImage<ImageType>(10, 10);
ImageType::Pointer mask = GetTestImage<ImageType>(10, 0);
ImageType::RegionType region(image->GetLargestPossibleRegion());
otb::MaskedIteratorDecorator<itk::ImageRegionIterator<ImageType> > it(mask, image, region);
return EXIT_SUCCESS;
}
// ---------------------- Initialization code ----------------------------------
template <typename IteratorType>
void
InitializeIterator(IteratorType&, typename IteratorType::RegionType)
{
// by default : nothing to do
}
// specialization for otb::SubsampledImageRegionIterator<otb::Image<double, 2> >
template <>
void
InitializeIterator< otb::SubsampledImageRegionIterator< otb::Image<double, 2> > >(
otb::SubsampledImageRegionIterator< otb::Image<double, 2> >& it,
typename otb::SubsampledImageRegionIterator<otb::Image<double, 2> >::RegionType)
{
it.SetSubsampleFactor(2);
}
// -------------------------- ForwardTest --------------------------------------
// Function to test the forward iteration interface
template <typename IteratorType, typename MaskIteratorType>
int ForwardTest(typename MaskIteratorType::ImageType::Pointer mask, typename IteratorType::ImageType::Pointer image, typename IteratorType::ImageType::RegionType region)
{
otb::MaskedIteratorDecorator<IteratorType,MaskIteratorType> it(mask, image, region);
// specific initialization code
InitializeIterator<IteratorType>(it.GetImageIterator(),region);
if (it.HasMask())
{
InitializeIterator<MaskIteratorType>(it.GetMaskIterator(),region);
}
it.GoToBegin();
if (!it.IsAtBegin()) {return 1;}
unsigned int loopCount = 0;
for(; !it.IsAtEnd(); ++it)
{
if (loopCount != 0 && it.IsAtBegin()) {return 2;}
if (it.IsAtEnd()) {return 3;}
//it.Set(it.Value() * 0.42);
loopCount += 1;
}
if(!it.IsAtEnd()) {return 4;}
return 0;
}
// -------------------------- ReverseTest --------------------------------------
// Test reverse iteration interface
template <typename IteratorType, typename MaskIteratorType>
int ReverseTest(typename MaskIteratorType::ImageType::Pointer mask, typename IteratorType::ImageType::Pointer image, typename IteratorType::ImageType::RegionType region)
{
otb::MaskedIteratorDecorator<IteratorType,MaskIteratorType> it(mask, image, region);
// specific initialization code
InitializeIterator<IteratorType>(it.GetImageIterator(),region);
if (it.HasMask())
{
InitializeIterator<MaskIteratorType>(it.GetMaskIterator(),region);
}
it.GoToEnd();
if (!it.IsAtEnd()) {return 1;}
bool beginReached = false;
while (!it.IsAtBegin())
{
--it;
if (it.IsAtEnd()) {return 2;}
if (beginReached)
{
return 3;
}
if (it.IsAtBegin())
{
beginReached = true;
}
}
if(!it.IsAtBegin()) {return 4;}
return 0;
}
// -------------------------- BijectiveTest --------------------------------------
// Check bijection between iterated and non masked
// i.e all locations where mask value != 0 are in the iteration (injection)
// and mask value != 0 at all iteration locations (surjection)
// Templated to test decoration of different iterator types
template <typename IteratorType, typename MaskIteratorType>
int BijectiveTest(typename MaskIteratorType::ImageType::Pointer mask, typename IteratorType::ImageType::Pointer image, typename IteratorType::ImageType::RegionType region)
{
otb::MaskedIteratorDecorator<IteratorType,MaskIteratorType> itDecorated(mask, image, region);
IteratorType it(image, region);