Commit 4c56f42d authored by Julien Malik's avatar Julien Malik

ENH: add a ImageRegionSquareTileSplitter

parent 87c262bd
/*=========================================================================
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 __otbImageRegionSquareTileSplitter_h
#define __otbImageRegionSquareTileSplitter_h
#include "itkObject.h"
#include "itkRegion.h"
#include "itkImageRegion.h"
#include "itkImageRegionSplitter.h"
#include "itkObjectFactory.h"
#include "itkIndex.h"
#include "itkSize.h"
namespace otb
{
/** \class ImageRegionSquareTileSplitter
* \brief Divide a region into several pieces.
*
* ImageRegionSquareTileSplitter divides an ImageRegion into smaller regions.
* ImageRegionSquareTileSplitter is used by the StreamingImageFilter to divide a
* requested output region into a series of smaller requests of the
* pipeline. This object has two basic methods: GetNumberOfSplits()
* and GetSplit().
*
* GetNumberOfSplits() is used to determine how may subregions a given
* region can be divided. You call GetNumberOfSplits with an argument
* that is the number of subregions you want. If the image region can
* support that number of subregions, that number is returned.
* Otherwise, the maximum number of splits a region can support will
* be returned. For example, if a region splitter class only divides
* a region into horizontal slabs, then the maximum number of splits
* will be the number of rows in the region.
*
* GetSplit() returns the ith of N subregions (as an ImageRegion object).
*
* This ImageRegionSquareTileSplitter class divides a region along the outermost
* dimension. If the outermost dimension has size 1 (i.e. a volume
* with a single slice), the ImageRegionSquareTileSplitter will divide the
* region along the next outermost dimension. If that dimension has size 1,
* the process continues with the next outermost dimension.
*
* Regions obtained by the ImageRegionSquareTileSplitter are aligned on a grid
* with width of 256. Divisions can occur only at line defined as k*256.
*
* Other ImageRegionSquareTileSplitter subclasses could divide an image into
* more uniform shaped regions instead of slabs.
*
* \sa ImageRegionMultidimensionalSplitter
*
* \ingroup ITKSystemObjects
* \ingroup DataProcessing
*/
template <unsigned int VImageDimension>
class ITK_EXPORT ImageRegionSquareTileSplitter : public itk::ImageRegionSplitter<VImageDimension>
{
public:
/** Standard class typedefs. */
typedef ImageRegionSquareTileSplitter Self;
typedef itk::ImageRegionSplitter<VImageDimension> Superclass;
typedef itk::SmartPointer<Self> Pointer;
typedef itk::SmartPointer<const Self> ConstPointer;
/** Method for creation through the object factory. */
itkNewMacro(Self);
/** Run-time type information (and related methods). */
itkTypeMacro(ImageRegionSquareTileSplitter, itk::Object);
/** Dimension of the image available at compile time. */
itkStaticConstMacro(ImageDimension, unsigned int, VImageDimension);
/** Dimension of the image available at run time. */
static unsigned int GetImageDimension()
{
return VImageDimension;
}
/** Index typedef support. An index is used to access pixel values. */
typedef itk::Index<VImageDimension> IndexType;
typedef typename IndexType::IndexValueType IndexValueType;
/** Size typedef support. A size is used to define region bounds. */
typedef itk::Size<VImageDimension> SizeType;
typedef typename SizeType::SizeValueType SizeValueType;
/** Region typedef support. */
typedef itk::ImageRegion<VImageDimension> RegionType;
itkSetMacro(PixelSizeInBytes, unsigned int);
itkGetMacro(PixelSizeInBytes, unsigned int);
itkSetMacro(TileSizeInBytes, unsigned int);
itkGetMacro(TileSizeInBytes, unsigned int);
/** How many pieces can the specifed region be split? A given region
* cannot always be divided into the requested number of pieces. For
* instance, if the numberOfPieces exceeds the number of pixels along
* a certain dimensions, then some splits will not be possible. This
* method returns a number less than or equal to the requested number
* of pieces. */
virtual unsigned int GetNumberOfSplits(const RegionType& region,
unsigned int requestedNumber);
/** Get a region definition that represents the ith piece a specified region.
* The "numberOfPieces" specified should be less than or equal to what
* GetNumberOfSplits() returns. */
virtual RegionType GetSplit(unsigned int i, unsigned int numberOfPieces,
const RegionType& region);
protected:
ImageRegionSquareTileSplitter() : m_AlignStep(0), m_PixelSizeInBytes(0), m_TileSizeInBytes(0){}
virtual ~ImageRegionSquareTileSplitter() {}
void PrintSelf(std::ostream& os, itk::Indent indent) const;
private:
ImageRegionSquareTileSplitter(const ImageRegionSquareTileSplitter &); //purposely not implemented
void operator =(const ImageRegionSquareTileSplitter&); //purposely not implemented
unsigned int m_SplitsPerDimension[VImageDimension];
unsigned int m_AlignStep;
unsigned int m_PixelSizeInBytes;
unsigned int m_TileSizeInBytes;
};
} // end namespace otb
#ifndef OTB_MANUAL_INSTANTIATION
# include "otbImageRegionSquareTileSplitter.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 __otbImageRegionSquareTileSplitter_txx
#define __otbImageRegionSquareTileSplitter_txx
#include "otbImageRegionSquareTileSplitter.h"
#include "otbMath.h"
#include "otbMacro.h"
namespace otb
{
/**
*
*/
template <unsigned int VImageDimension>
unsigned int
ImageRegionSquareTileSplitter<VImageDimension>
::GetNumberOfSplits(const RegionType& region, unsigned int requestedNumber)
{
if (m_TileSizeInBytes == 0)
{
itkExceptionMacro(<< "SetTileSizeInBytes has not been called");
}
if (m_PixelSizeInBytes == 0)
{
itkExceptionMacro(<< "SetPixelSizeInBytes has not been called");
}
// Compute the theorical square tile dimensions
const unsigned int nbPixelPerTile = m_TileSizeInBytes / m_PixelSizeInBytes;
unsigned int nbPixelPerDim = static_cast<unsigned int>( vcl_sqrt(nbPixelPerTile));
// Use a reference tile size corresponding to a 256 * 256 region of a 4 bands unsigned short image (=512 k)
const unsigned int ReferenceTileSizeInBytes = 256 * 256 * 4 * 2;
unsigned int nbPixelPerReferenceTile = ReferenceTileSizeInBytes / m_PixelSizeInBytes;
unsigned int referenceNbPixelPerDim = static_cast<unsigned int>( vcl_sqrt(static_cast<float>(nbPixelPerReferenceTile)) );
// Align the tile dimension to the next multiple of 16 using integer division (TIFF tiles are aligned with 16)
referenceNbPixelPerDim = ( referenceNbPixelPerDim + 15 ) / 16 * 16;
// Align nbPixelPerDim with the next multiple of referenceNbPixelPerDim using integer division
m_AlignStep = (nbPixelPerDim + referenceNbPixelPerDim) / referenceNbPixelPerDim * referenceNbPixelPerDim;
// Use at least 16*16 tiles
if (m_AlignStep < 16)
{
m_AlignStep = 16;
}
const SizeType& regionSize = region.GetSize();
const IndexType& regionIndex = region.GetIndex();
// requested number of splits per dimension
unsigned int numPieces = 1;
// determine the actual number of pieces that will be generated
for (unsigned int j = VImageDimension; j > 0; --j)
{
// otbMsgDevMacro(<< "*** Dimension: " << j-1);
unsigned long int remainingToDo =
static_cast<unsigned long int>(vcl_ceil(static_cast<double>(requestedNumber) / numPieces));
unsigned int maxPieces = (regionIndex[j - 1] + regionSize[j - 1] - 1) / m_AlignStep - regionIndex[j - 1]
/ m_AlignStep + 1;
unsigned int stepPerPiece = 1;
if (remainingToDo < maxPieces)
{
stepPerPiece = static_cast<unsigned int> (vcl_floor(static_cast<double> (maxPieces) / remainingToDo));
if ((remainingToDo - 1) * (stepPerPiece + 1) < maxPieces)
{
stepPerPiece += 1;
}
}
unsigned int maxPieceUsed = static_cast<unsigned int> (vcl_ceil(static_cast<double> (maxPieces) / stepPerPiece));
m_SplitsPerDimension[j - 1] = maxPieceUsed;
// otbMsgDevMacro("*** maxPieces stepPerPiece maxPieceUsed " << maxPieces
// << " " << stepPerPiece << " " << maxPieceUsed);
numPieces *= maxPieceUsed;
}
// otbMsgDevMacro("*** numPieces " << numPieces);
return numPieces;
}
/**
*
*/
template <unsigned int VImageDimension>
itk::ImageRegion<VImageDimension>
ImageRegionSquareTileSplitter<VImageDimension>
::GetSplit(unsigned int i, unsigned int numberOfPieces, const RegionType& region)
{
RegionType splitRegion;
IndexType splitIndex, regionIndex;
SizeType splitSize, regionSize;
// Initialize the splitRegion to the requested region
splitRegion = region;
splitIndex = splitRegion.GetIndex();
splitSize = splitRegion.GetSize();
regionSize = region.GetSize();
regionIndex = region.GetIndex();
unsigned int numPieces = GetNumberOfSplits(region, numberOfPieces);
if (i > numPieces)
{
itkDebugMacro(" Cannot Split");
return splitRegion;
}
unsigned int stackSize = 1;
for (unsigned int j = 0; j < VImageDimension; ++j)
{
unsigned int slicePos = (i % (stackSize * m_SplitsPerDimension[j])) / stackSize;
stackSize *= m_SplitsPerDimension[j];
unsigned int generalSplitSize =
static_cast<unsigned int> (vcl_ceil(static_cast<double> (regionSize[j]) / (m_SplitsPerDimension[j]
*
m_AlignStep))) * m_AlignStep;
if (slicePos == 0)
{
splitIndex[j] = regionIndex[j];
}
else
{
splitIndex[j] = (regionIndex[j] / generalSplitSize + slicePos) * generalSplitSize;
}
if (slicePos == 0)
{
splitSize[j] = generalSplitSize - (regionIndex[j] % generalSplitSize);
}
else if (slicePos == m_SplitsPerDimension[j] - 1)
{
splitSize[j] = regionSize[j] - (generalSplitSize - (regionIndex[j] % generalSplitSize))
- (m_SplitsPerDimension[j] - 2) * generalSplitSize;
}
else
{
splitSize[j] = generalSplitSize;
}
}
// set the split region ivars
splitRegion.SetIndex(splitIndex);
splitRegion.SetSize(splitSize);
return splitRegion;
}
/**
*
*/
template <unsigned int VImageDimension>
void
ImageRegionSquareTileSplitter<VImageDimension>
::PrintSelf(std::ostream& os, itk::Indent indent) const
{
Superclass::PrintSelf(os, indent);
os << indent << "AlignStep : " << m_AlignStep << std::endl;
os << indent << "PixelSizeInBytes : " << m_PixelSizeInBytes << std::endl;
os << indent << "TileSizeInBytes : " << m_TileSizeInBytes << std::endl;
}
} // end namespace itk
#endif
......@@ -28,6 +28,8 @@
#include "itkLinearInterpolateImageFunction.h"
#include "itkNearestNeighborInterpolateImageFunction.h"
#include "otbImageRegionSquareTileSplitter.h"
namespace otb
{
......@@ -53,32 +55,30 @@ unsigned long StreamingTraitsBase<TImage>
break;
case SET_BUFFER_MEMORY_SIZE:
{
const unsigned long bufferMemorySizeOctet = bufferMemorySize / 8;
unsigned long numberColumnsOfRegion = region.GetSize()[0]; // X dimension
const unsigned long sizeLine = numberColumnsOfRegion * \
const unsigned long sizeLineInBytes = numberColumnsOfRegion * \
image->GetNumberOfComponentsPerPixel() * \
sizeof(PixelType);
unsigned long regionSize = region.GetSize()[1] * sizeLine;
unsigned long regionSizeInBytes = region.GetSize()[1] * sizeLineInBytes;
otbMsgDevMacro(<< "image->GetNumberOfComponentsPerPixel() = " << image->GetNumberOfComponentsPerPixel());
otbMsgDevMacro(<< "sizeof(PixelType) = " << sizeof(PixelType));
otbMsgDevMacro(<< "numberColumnsOfRegion = " << numberColumnsOfRegion);
otbMsgDevMacro(<< "sizeLine = " << sizeLine);
otbMsgDevMacro(<< "regionSize = " << regionSize);
otbMsgDevMacro(<< "sizeLine = " << sizeLineInBytes);
otbMsgDevMacro(<< "regionSize = " << regionSizeInBytes);
otbMsgDevMacro(<< "BufferMemorySize = " << bufferMemorySize);
otbMsgDevMacro(<< "bufferMemorySizeOctet = " << bufferMemorySizeOctet);
//Active streaming
if (regionSize > bufferMemorySizeOctet)
if (regionSizeInBytes > bufferMemorySize)
{
//The regionSize must be at list equal to the sizeLine
if (regionSize < sizeLine)
if (regionSizeInBytes < sizeLineInBytes)
{
otbMsgDevMacro(<< "Force buffer size.");
regionSize = sizeLine;
regionSizeInBytes = sizeLineInBytes;
}
//Calculate NumberOfStreamDivisions
numDivisions = static_cast<unsigned long>(
vcl_ceil(static_cast<double>(regionSize) / static_cast<double>(bufferMemorySizeOctet))
vcl_ceil(static_cast<double>(regionSizeInBytes) / static_cast<double>(bufferMemorySize))
);
}
else
......@@ -161,6 +161,19 @@ unsigned long StreamingTraitsBase<TImage>
otbMsgDevMacro(<< "streamMaxSizeBufferForStreaming in Bytes = " << streamMaxSizeBufferForStreamingInBytes);
// Is the splitter a otb::ImageRegionSquareTileSplitter ?
otb::ImageRegionSquareTileSplitter<2>* squareTileSplitter = dynamic_cast<otb::ImageRegionSquareTileSplitter<2>*>(splitter);
if (squareTileSplitter)
{
// in that case, inform it about PixelSize so that the tiles
squareTileSplitter->SetPixelSizeInBytes(static_cast<std::streamoff>(image->GetNumberOfComponentsPerPixel()) *
static_cast<std::streamoff>(sizeof(PixelType)));
squareTileSplitter->SetTileSizeInBytes(streamMaxSizeBufferForStreamingInBytes);
}
//Calculate NumberOfStreamDivisions
numDivisions =
static_cast<unsigned long>(vcl_ceil(static_cast<double>(regionSizeInBytes) /
......
......@@ -736,6 +736,19 @@ ADD_TEST(coTvImageRegionTileMapSplitter ${COMMON_TESTS8}
${TEMP}/coImageRegionTileMapSplitter.txt
)
# ------------- otb::ImageRegionSquareTileSplitter ----------------------------
ADD_TEST(coTuImageRegionSquareTileSplitterNew ${COMMON_TESTS8}
otbImageRegionSquareTileSplitterNew
)
ADD_TEST(coTvImageRegionSquareTileSplitter ${COMMON_TESTS8}
--compare-ascii ${NOTOL}
${BASELINE_FILES}/coImageRegionTileMapSplitter.txt
${TEMP}/coImageRegionTileMapSplitter.txt
otbImageRegionSquareTileSplitter
${TEMP}/coImageRegionTileMapSplitter.txt
)
# ------------- otb::ImageOfVectorsToMonoChannelExtractROI ----------------------------
ADD_TEST(coTuImageOfVectorsToMonoChannelExtractROINew ${COMMON_TESTS8}
otbImageOfVectorsToMonoChannelExtractROINew
......@@ -1103,6 +1116,7 @@ otbQuickLookImageGeneratorNew.cxx
otbQuickLookImageGenerator.cxx
otbImageRegionTileMapSplitterNew.cxx
otbImageRegionTileMapSplitter.cxx
otbImageRegionSquareTileSplitter.cxx
otbImageOfVectorsToMonoChannelExtractROINew.cxx
otbImageOfVectorsToMonoChannelExtractROI.cxx
otbImageRegionNonUniformMultidimensionalSplitterNew.cxx
......
......@@ -30,6 +30,8 @@ void RegisterTests()
REGISTER_TEST(otbQuickLookImageGenerator);
REGISTER_TEST(otbImageRegionTileMapSplitterNew);
REGISTER_TEST(otbImageRegionTileMapSplitter);
REGISTER_TEST(otbImageRegionSquareTileSplitterNew);
REGISTER_TEST(otbImageRegionSquareTileSplitter);
REGISTER_TEST(otbImageOfVectorsToMonoChannelExtractROINew);
REGISTER_TEST(otbImageOfVectorsToMonoChannelExtractROI);
REGISTER_TEST(otbImageRegionNonUniformMultidimensionalSplitterNew);
......
/*=========================================================================
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 "otbImageRegionSquareTileSplitter.h"
#include <fstream>
const int Dimension = 2;
typedef otb::ImageRegionSquareTileSplitter<Dimension> SplitterType;
int otbImageRegionSquareTileSplitterNew(int argc, char * argv[])
{
SplitterType::Pointer splitter = SplitterType::New();
std::cout << splitter << std::endl;
return EXIT_SUCCESS;
}
int otbImageRegionSquareTileSplitter(int argc, char * argv[])
{
typedef SplitterType::IndexType IndexType;
typedef SplitterType::SizeType SizeType;
typedef SplitterType::RegionType RegionType;
typedef unsigned short PixelPrecisionType;
const unsigned int NbComponents = 8;
const unsigned int PixelSizeInBytes = NbComponents * sizeof(PixelPrecisionType);
std::ofstream outfile(argv[1]);
SplitterType::Pointer filter = FilterType::New();
RegionType region, region2;
unsigned int nb, nbSplitTheoric, nbAsked;
IndexType index;
SizeType size;
//Case 1
index[0] = 45;
index[1] = 45;
size[0] = 1000;
size[1] = 1500;
nbSplitTheoric = 10;
nbAsked = 2;
region.SetSize(size);
region.SetIndex(index);
nb = filter->GetNumberOfSplits(region, nbSplitTheoric);
region2 = filter->GetSplit(nbAsked, nb, region);
outfile << "\nCase 1 \n";
outfile << "Input region: " << region << std::endl;
outfile << "Input NumberOfSplits: " << nbSplitTheoric << std::endl;
outfile << "Output GetNumberOfSplits: " << nb << std::endl;
outfile << "Output GetSplit(" << nbAsked << "," << nb << ", input region): " << std::endl;
outfile << "Output region: " << region2 << std::endl;
//Case 2
index[0] = 45;
index[1] = 45;
size[0] = 1048576;
size[1] = 1048576;
nbSplitTheoric = 16777216;
nbAsked = 2;
region.SetSize(size);
region.SetIndex(index);
nb = filter->GetNumberOfSplits(region, nbSplitTheoric);
region2 = filter->GetSplit(nbAsked, nb, region);
outfile << "\nCase 2 \n";
outfile << "Input region: " << region << std::endl;
outfile << "Input NumberOfSplits: " << nbSplitTheoric << std::endl;
outfile << "Output GetNumberOfSplits: " << nb << std::endl;
outfile << "Output GetSplit(" << nbAsked << "," << nb << ", input region): " << std::endl;
outfile << "Output region: " << region2 << std::endl;
//Case 3
index[0] = 45;
index[1] = 45;
size[0] = 1048576;
size[1] = 1048576;
nbSplitTheoric = 23;
nbAsked = 4;
region.SetSize(size);
region.SetIndex(index);
nb = filter->GetNumberOfSplits(region, nbSplitTheoric);
region2 = filter->GetSplit(nbAsked, nb, region);
outfile << "\nCase 3 \n";
outfile << "Input region: " << region << std::endl;
outfile << "Input NumberOfSplits: " << nbSplitTheoric << std::endl;
outfile << "Output GetNumberOfSplits: " << nb << std::endl;
outfile << "Output GetSplit(" << nbAsked << "," << nb << ", input region): " << std::endl;
outfile << "Output region: " << region2 << std::endl;
//Case 4
index[0] = 45;
index[1] = 45;
size[0] = 1048576;
size[1] = 1024;
nbSplitTheoric = 16777216;
nbAsked = 16387;
region.SetSize(size);
region.SetIndex(index);
nb = filter->GetNumberOfSplits(region, nbSplitTheoric);
region2 = filter->GetSplit(nbAsked, nb, region);
outfile << "\nCase 4 \n";
outfile << "Input region: " << region << std::endl;
outfile << "Input NumberOfSplits: " << nbSplitTheoric << std::endl;
outfile << "Output GetNumberOfSplits: " << nb << std::endl;
outfile << "Output GetSplit(" << nbAsked << "," << nb << ", input region): " << std::endl;
outfile << "Output region: " << region2 << std::endl;
//Case 5
index[0] = 0;
index[1] = 0;
size[0] = 513;
size[1] = 5376;
nbSplitTheoric = 8;
nbAsked = 9;
region.SetSize(size);
region.SetIndex(index);
nb = filter->GetNumberOfSplits(region, nbSplitTheoric);
region2 = filter->GetSplit(nbAsked, nb, region);
outfile << "\nCase 5 \n";
outfile << "Input region: " << region << std::endl;
outfile << "Input NumberOfSplits: " << nbSplitTheoric << std::endl;
outfile << "Output GetNumberOfSplits: " << nb << std::endl;
outfile << "Output GetSplit(" << nbAsked << "," << nb << ", input region): " << std::endl;
outfile << "Output region: " << region2 << std::endl;
//Case 6
index[0] = 0;
index[1] = 0;
size[0] = 3;
size[1] = 2;
nbSplitTheoric = 5;
nbAsked = 0;
region.SetSize(size);
region.SetIndex(index);
nb = filter->GetNumberOfSplits(region, nbSplitTheoric);
region2 = filter->GetSplit(nbAsked, nb, region);
outfile << "\nCase 5 \n";
outfile << "Input region: " << region << std::endl;
outfile << "Input NumberOfSplits: " << nbSplitTheoric << std::endl;
outfile << "Output GetNumberOfSplits: " << nb << std::endl;
outfile << "Output GetSplit(" << nbAsked << "," << nb << ", input region): " << std::endl;
outfile << "Output region: " << region2 << std::endl;
outfile.close();
return EXIT_SUCCESS;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment