diff --git a/Code/BasicFilters/otbStreamingShrinkImageFilter.cxx b/Code/BasicFilters/otbStreamingShrinkImageFilter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3d4bd8d9e92b175790fb5236b101caa10bd7bf1e --- /dev/null +++ b/Code/BasicFilters/otbStreamingShrinkImageFilter.cxx @@ -0,0 +1,103 @@ +/*========================================================================= + + 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 "otbStreamingShrinkImageFilter.h" + +namespace otb +{ + +unsigned int +StreamingShrinkImageRegionSplitter +::GetNumberOfSplits(const RegionType& region, unsigned int requestedNumber) +{ + unsigned int theoricalNbPixelPerTile = region.GetNumberOfPixels() / requestedNumber; + unsigned int theoricalTileDimension = static_cast<unsigned int> (vcl_sqrt(static_cast<double>(theoricalNbPixelPerTile)) ); + + // Take the previous multiple of m_TileSizeAlignment (eventually generate more splits than requested) + m_TileDimension = theoricalTileDimension / m_TileSizeAlignment * m_TileSizeAlignment; + + // Minimal tile size is m_TileSizeAlignment * m_TileSizeAlignment + if (m_TileDimension < m_TileSizeAlignment) + { + otbMsgDevMacro(<< "Using the minimal tile size : " << m_TileSizeAlignment << " * " << m_TileSizeAlignment); + m_TileDimension = m_TileSizeAlignment; + } + + // Use the computed tile size, and generate (m_TileDimension * 1) tiles + const SizeType& regionSize = region.GetSize(); + m_SplitsPerDimension[0] = (regionSize[0] + m_TileDimension - 1) / m_TileDimension; + m_SplitsPerDimension[1] = regionSize[1] / m_TileSizeAlignment; + + unsigned int numPieces = 1; + for (unsigned int j = 0; j < ImageDimension; ++j) + { + numPieces *= m_SplitsPerDimension[j]; + } + + otbMsgDevMacro(<< "Tile dimension : " << m_TileDimension) + otbMsgDevMacro(<< "Number of splits per dimension : " << m_SplitsPerDimension[0] << " " << m_SplitsPerDimension[1]) + + return numPieces; +} + +StreamingShrinkImageRegionSplitter::RegionType +StreamingShrinkImageRegionSplitter +::GetSplit(unsigned int i, unsigned int numberOfPieces, const RegionType& region) +{ + RegionType splitRegion; + IndexType splitIndex; + + // Compute the actual number of splits + unsigned int numPieces = 1; + for (unsigned int j = 0; j < ImageDimension; ++j) + { + numPieces *= m_SplitsPerDimension[j]; + } + + if (i >= numPieces) + { + itkExceptionMacro("Requested split number " << i << " but region contains only " << numPieces << " splits"); + } + + // Compute the split index in the streaming grid + splitIndex[1] = i / m_SplitsPerDimension[0]; + splitIndex[0] = i % m_SplitsPerDimension[0]; + + // Transform the split index to the actual coordinates + splitRegion.SetIndex(0, region.GetIndex(0) + m_TileDimension * splitIndex[0]); + splitRegion.SetIndex(1, region.GetIndex(1) + m_TileSizeAlignment * splitIndex[1]); + + splitRegion.SetSize(0, m_TileDimension); + splitRegion.SetSize(1, 1); + + // Handle the borders + splitRegion.Crop(region); + + return splitRegion; +} + +void +StreamingShrinkImageRegionSplitter +::PrintSelf(std::ostream& os, itk::Indent indent) const +{ + Superclass::PrintSelf(os, indent); + os << indent << "SplitsPerDimension : " << m_SplitsPerDimension << std::endl; + os << indent << "TileDimension : " << m_TileDimension << std::endl; + os << indent << "TileSizeAlignment : " << m_TileSizeAlignment << std::endl; +} + +} // End namespace otb diff --git a/Code/BasicFilters/otbStreamingShrinkImageFilter.h b/Code/BasicFilters/otbStreamingShrinkImageFilter.h index c077557e021e7e242895479b509ad395c5efa305..b6b3e9eabc91da4b5c32fc56b3e5d7b8f29e407b 100644 --- a/Code/BasicFilters/otbStreamingShrinkImageFilter.h +++ b/Code/BasicFilters/otbStreamingShrinkImageFilter.h @@ -25,11 +25,134 @@ #include "otbPersistentImageFilter.h" #include "otbPersistentFilterStreamingDecorator.h" -#include "itkTimeProbe.h" +#include "otbStreamingManager.h" namespace otb { +class ITK_EXPORT StreamingShrinkImageRegionSplitter : public itk::ImageRegionSplitter<2> +{ +public: + /** Standard class typedefs. */ + typedef StreamingShrinkImageRegionSplitter Self; + typedef itk::ImageRegionSplitter<2> 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(StreamingShrinkImageRegionSplitter, itk::Object); + + /** Dimension of the image available at compile time. */ + itkStaticConstMacro(ImageDimension, unsigned int, 2); + + /** Dimension of the image available at run time. */ + static unsigned int GetImageDimension() + { + return ImageDimension; + } + + /** Index typedef support. An index is used to access pixel values. */ + typedef itk::Index<ImageDimension> IndexType; + typedef IndexType::IndexValueType IndexValueType; + + /** Size typedef support. A size is used to define region bounds. */ + typedef itk::Size<ImageDimension> SizeType; + typedef SizeType::SizeValueType SizeValueType; + + /** Region typedef support. */ + typedef itk::ImageRegion<ImageDimension> RegionType; + + /** How many pieces can the specified 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. + */ + 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); + + itkGetMacro(TileSizeAlignment, unsigned int); + itkSetMacro(TileSizeAlignment, unsigned int); + + itkGetMacro(TileDimension, unsigned int); + + itkSetMacro(ShrinkFactor, unsigned int); + itkGetMacro(ShrinkFactor, unsigned int); + +protected: + StreamingShrinkImageRegionSplitter() : m_SplitsPerDimension(0U), m_ShrinkFactor(10) {} + virtual ~StreamingShrinkImageRegionSplitter() {} + void PrintSelf(std::ostream& os, itk::Indent indent) const; + +private: + StreamingShrinkImageRegionSplitter(const StreamingShrinkImageRegionSplitter &); //purposely not implemented + void operator =(const StreamingShrinkImageRegionSplitter&); //purposely not implemented + + itk::FixedArray<unsigned int, ImageDimension> m_SplitsPerDimension; + unsigned int m_TileDimension; + unsigned int m_TileSizeAlignment; + unsigned int m_ShrinkFactor; +}; + + +template <class TInputImage> +class ITK_EXPORT StreamingShrinkStreamingManager : public StreamingManager<TInputImage> +{ +public: + /** Standard class typedefs. */ + typedef StreamingShrinkStreamingManager Self; + typedef StreamingManager<TInputImage> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Runtime information support. */ + itkTypeMacro(StreamingShrinkStreamingManager, StreamingManager); + + typedef TInputImage ImageType; + typedef typename ImageType::Pointer ImagePointerType; + typedef typename ImageType::RegionType RegionType; + typedef typename RegionType::IndexType IndexType; + typedef typename RegionType::SizeType SizeType; + typedef typename ImageType::InternalPixelType PixelType; + + itkStaticConstMacro(InputImageDimension, unsigned int, TInputImage::ImageDimension); + + /** Actually computes the stream divisions, according to the specified streaming mode, + * eventually using the input parameter to estimate memory consumption */ + virtual void PrepareStreaming(itk::DataObject * input, const RegionType ®ion); + + void SetShrinkFactor(unsigned int val) + { + m_ShrinkFactor = val; + } + + unsigned int GetShrinkFactor() const + { + return m_ShrinkFactor; + } + +protected: + StreamingShrinkStreamingManager(); + virtual ~StreamingShrinkStreamingManager(); + +private: + StreamingShrinkStreamingManager(const StreamingShrinkStreamingManager &); //purposely not implemented + void operator =(const StreamingShrinkStreamingManager&); //purposely not implemented + + unsigned int m_ShrinkFactor; +}; + /** \class PersistentShrinkImageFilter * \brief @@ -116,9 +239,6 @@ private: /** The shrink factor */ unsigned int m_ShrinkFactor; - - itk::TimeProbe m_Chrono; - }; // end of class PersistentStatisticsVectorImageFilter @@ -156,10 +276,14 @@ public: typedef TOutputImage OutputImageType; typedef typename Superclass::FilterType PersistentFilterType; + typedef StreamingShrinkStreamingManager<InputImageType> StreamingShrinkStreamingManagerType; + typedef typename StreamingShrinkStreamingManagerType::Pointer StreamingShrinkStreamingManagerPointerType; + void SetInput(InputImageType * input) { this->GetFilter()->SetInput(input); } + const InputImageType * GetInput() { return this->GetFilter()->GetInput(); @@ -173,15 +297,29 @@ public: otbSetObjectMemberMacro(Filter, ShrinkFactor, unsigned int); otbGetObjectMemberMacro(Filter, ShrinkFactor, unsigned int); + virtual void Update(void) + { + m_StreamingManager->SetShrinkFactor( this->GetFilter()->GetShrinkFactor() ); + Superclass::Update(); + } + protected: /** Constructor */ - StreamingShrinkImageFilter() {} + StreamingShrinkImageFilter() + { + // Use a specific StreamingManager implementation + m_StreamingManager = StreamingShrinkStreamingManagerType::New(); + this->GetStreamer()->SetStreamingManager( m_StreamingManager ); + } + /** Destructor */ virtual ~StreamingShrinkImageFilter() {} private: StreamingShrinkImageFilter(const Self &); //purposely not implemented void operator =(const Self&); //purposely not implemented + + StreamingShrinkStreamingManagerPointerType m_StreamingManager; }; } // End namespace otb diff --git a/Code/BasicFilters/otbStreamingShrinkImageFilter.txx b/Code/BasicFilters/otbStreamingShrinkImageFilter.txx index 4c7a810c1bf1d2ea5026ed9822ccd697cae73ca0..cd045e31f27cf8c625ed7bb97dda07de7a163956 100644 --- a/Code/BasicFilters/otbStreamingShrinkImageFilter.txx +++ b/Code/BasicFilters/otbStreamingShrinkImageFilter.txx @@ -26,6 +26,34 @@ namespace otb { +template <class TImage> +StreamingShrinkStreamingManager<TImage>::StreamingShrinkStreamingManager() +{ +} + +template <class TImage> +StreamingShrinkStreamingManager<TImage>::~StreamingShrinkStreamingManager() +{ +} + +template <class TImage> +void +StreamingShrinkStreamingManager<TImage>::PrepareStreaming( itk::DataObject * input, const RegionType ®ion ) +{ + typedef otb::StreamingShrinkImageRegionSplitter TileSplitterType; + TileSplitterType::Pointer splitter = TileSplitterType::New(); + splitter->SetTileSizeAlignment(m_ShrinkFactor); + this->m_Splitter = splitter; + + unsigned long nbDivisions = EstimateOptimalNumberOfDivisions(input, region); + this->m_ComputedNumberOfSplits = this->m_Splitter->GetNumberOfSplits(region, nbDivisions); + otbMsgDevMacro(<< "Number of split : " << this->m_ComputedNumberOfSplits) + + // Save the region to generate the splits later + this->m_Region = region; +} + + /** Constructor */ template <class TInputImage, class TOutputImage> PersistentShrinkImageFilter<TInputImage, TOutputImage> @@ -79,31 +107,22 @@ PersistentShrinkImageFilter<TInputImage, TOutputImage> // Nothing that needs to be allocated for the remaining outputs } + template<class TInputImage, class TOutputImage> void PersistentShrinkImageFilter<TInputImage, TOutputImage> ::Reset() { - // Reinit the chrono - m_Chrono = itk::TimeProbe(); - - // get pointers to the input and output + // Get pointers to the input and output InputImageType* inputPtr = const_cast<InputImageType*>(this->GetInput()); inputPtr->UpdateOutputInformation(); m_ShrinkedOutput = OutputImageType::New(); - // we need to compute the output spacing, the output image size, and the - // output image start index const typename InputImageType::SpacingType& inputSpacing = inputPtr->GetSpacing(); const typename InputImageType::SizeType& inputSize = inputPtr->GetLargestPossibleRegion().GetSize(); - const typename InputImageType::IndexType& inputStartIndex - = inputPtr->GetLargestPossibleRegion().GetIndex(); - - otbMsgDebugMacro(<< "Input index " << inputStartIndex); - otbMsgDebugMacro(<< "Input size: " << inputSize); typename OutputImageType::SpacingType shrinkedOutputSpacing; typename OutputImageType::RegionType shrinkedOutputLargestPossibleRegion; @@ -113,9 +132,7 @@ PersistentShrinkImageFilter<TInputImage, TOutputImage> for (unsigned int i = 0; i < OutputImageType::ImageDimension; ++i) { shrinkedOutputSpacing[i] = inputSpacing[i] * static_cast<double>(m_ShrinkFactor); - //shrinkedOutputSize[i] = static_cast<int>(static_cast<double>(inputSize[i]) / static_cast<double>(m_ShrinkFactor)); shrinkedOutputSize[i] = inputSize[i] / m_ShrinkFactor; - //outputStartIndex[i] = inputStartIndex[i]; shrinkedOutputStartIndex[i] = 0; } @@ -134,7 +151,6 @@ void PersistentShrinkImageFilter<TInputImage, TOutputImage> ::Synthetize() { - otbMsgDevMacro( "Shrink time : " << m_Chrono.GetTotal() ) } template<class TInputImage, class TOutputImage> @@ -142,7 +158,6 @@ void PersistentShrinkImageFilter<TInputImage, TOutputImage> ::BeforeThreadedGenerateData() { - m_Chrono.Start(); } template<class TInputImage, class TOutputImage> @@ -175,7 +190,6 @@ void PersistentShrinkImageFilter<TInputImage, TOutputImage> ::AfterThreadedGenerateData() { - m_Chrono.Stop(); } template <class TImage, class TOutputImage>