Commit 939f2d3f authored by remi cresson's avatar remi cresson
Browse files

ADD: CacheLessLabelImageFilter

No related merge requests found
Showing with 502 additions and 0 deletions
+502 -0
/*=========================================================================
Copyright (c) Remi Cresson (IRSTEA). All rights reserved.
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 MODULES_REMOTE_SIMPLEEXTRACTIONTOOLS_INCLUDE_OTBCACHELESSLABELIMAGETOVECTORDATA_H_
#define MODULES_REMOTE_SIMPLEEXTRACTIONTOOLS_INCLUDE_OTBCACHELESSLABELIMAGETOVECTORDATA_H_
#include "otbImage.h"
#include "itkImageRegionIterator.h"
#include "itkImageRegionConstIterator.h"
#include "itkProcessObject.h"
#include "otbStreamingManager.h"
#include "otbLabelImageToVectorDataFilter.h"
namespace otb
{
/** \class CacheLessLabelImageToVectorData
* \brief Produce a VectorData from an input pipeline. The pipeline is executed with
* explicit streaming and the resulting image is stored in the internal cache of the filter.
* This ensure that only the output image is cached, rather than all pipeline buffers.
*
* \ingroup SimpleExtractionTools
*/
template <class TInputImagePixel>
class ITK_EXPORT CacheLessLabelImageToVectorData :
public VectorDataSource< otb::VectorData<double> >
{
public:
/** Standard class typedefs. */
typedef CacheLessLabelImageToVectorData Self;
typedef VectorDataSource< VectorData<double> > 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(CacheLessLabelImageToVectorData, VectorDataSource);
/** Some typedefs for the input. */
typedef typename otb::Image<TInputImagePixel, 2> InputImageType;
typedef typename InputImageType::Pointer InputImagePointer;
typedef typename InputImageType::RegionType InputImageRegionType;
typedef typename InputImageType::PixelType InputImagePixelType;
typedef typename InputImageType::IndexType InputIndexType;
typedef itk::ImageRegionConstIterator<InputImageType> ConstIteratorType;
typedef itk::ImageRegionIterator<InputImageType> IteratorType;
/** Definition of the output vector data. */
typedef VectorData<double> VectorDataType;
typedef typename VectorDataType::Pointer VectorDataPointerType;
typedef LabelImageToVectorDataFilter<InputImageType, double> LabelImageToVectorDataFilterType;
/** Dimension of input image. */
itkStaticConstMacro(InputImageDimension, unsigned int,
InputImageType::ImageDimension);
/** Streaming manager base class pointer */
typedef StreamingManager<InputImageType> StreamingManagerType;
typedef typename StreamingManagerType::Pointer StreamingManagerPointerType;
/** Return the StreamingManager object responsible for dividing
* the region to write */
StreamingManagerType* GetStreamingManager(void)
{
return m_StreamingManager;
}
/** Set a user-specified implementation of StreamingManager
* used to divide the largest possible region in several divisions */
void SetStreamingManager(StreamingManagerType* streamingManager)
{
m_StreamingManager = streamingManager;
}
/** Set the streaming mode to 'stripped' and configure the number of strips
* which will be used to stream the image */
void SetNumberOfDivisionsStrippedStreaming(unsigned int nbDivisions);
/** Set the streaming mode to 'tiled' and configure the number of tiles
* which will be used to stream the image */
void SetNumberOfDivisionsTiledStreaming(unsigned int nbDivisions);
/** Set the streaming mode to 'stripped' and configure the number of strips
* which will be used to stream the image with respect to a number of line
* per strip */
void SetNumberOfLinesStrippedStreaming(unsigned int nbLinesPerStrip);
/** Set the streaming mode to 'stripped' and configure the number of MB
* available. The actual number of divisions is computed automatically
* by estimating the memory consumption of the pipeline.
* Setting the availableRAM parameter to 0 means that the available RAM
* is set from the CMake configuration option.
* The bias parameter is a multiplier applied on the estimated memory size
* of the pipeline and can be used to fine tune the potential gap between
* estimated memory and actual memory used, which can happen because of
* composite filters for example */
void SetAutomaticStrippedStreaming(unsigned int availableRAM = 0, double bias = 1.0);
/** Set the streaming mode to 'tiled' and configure the dimension of the tiles
* in pixels for each dimension (square tiles will be generated) */
void SetTileDimensionTiledStreaming(unsigned int tileDimension);
/** Set the streaming mode to 'tiled' and configure the number of MB
* available. The actual number of divisions is computed automatically
* by estimating the memory consumption of the pipeline.
* Tiles will be square.
* Setting the availableRAM parameter to 0 means that the available RAM
* is set from the CMake configuration option
* The bias parameter is a multiplier applied on the estimated memory size
* of the pipeline and can be used to fine tune the potential gap between
* estimated memory and actual memory used, which can happen because of
* composite filters for example */
void SetAutomaticTiledStreaming(unsigned int availableRAM = 0, double bias = 1.0);
/** Set the streaming mode to 'adaptative' and configure the number of MB
* available. The actual number of divisions is computed automatically
* by estimating the memory consumption of the pipeline.
* Tiles will try to match the input file tile scheme.
* Setting the availableRAM parameter to 0 means that the available RAM
* is set from the CMake configuration option */
void SetAutomaticAdaptativeStreaming(unsigned int availableRAM = 0, double bias = 1.0);
/** Set the only input of the writer */
using Superclass::SetInput;
virtual void SetInput(const InputImageType *input);
/** Get writer only input */
const InputImageType* GetInput();
/** Override Update() from ProcessObject because this filter
* has no output. */
void Update() ITK_OVERRIDE;
void GenerateInputRequestedRegion() {};
protected:
CacheLessLabelImageToVectorData();
~CacheLessLabelImageToVectorData() ITK_OVERRIDE;
private:
CacheLessLabelImageToVectorData(const CacheLessLabelImageToVectorData &); //purposely not implemented
void operator =(const CacheLessLabelImageToVectorData&); //purposely not implemented
void ObserveSourceFilterProgress(itk::Object* object, const itk::EventObject & event )
{
if (typeid(event) != typeid(itk::ProgressEvent))
{
return;
}
itk::ProcessObject* processObject = dynamic_cast<itk::ProcessObject*>(object);
if (processObject)
{
m_DivisionProgress = processObject->GetProgress();
}
this->UpdateFilterProgress();
}
void UpdateFilterProgress()
{
this->UpdateProgress( (m_DivisionProgress + m_CurrentDivision) / m_NumberOfDivisions );
}
unsigned int m_NumberOfDivisions;
unsigned int m_CurrentDivision;
float m_DivisionProgress;
StreamingManagerPointerType m_StreamingManager;
bool m_IsObserving;
unsigned long m_ObserverID;
typename InputImageType::Pointer bufferedInputImage;
typename LabelImageToVectorDataFilterType::Pointer vectorizeFilter;
};
} // end namespace otb
#ifndef OTB_MANUAL_INSTANTIATION
#include "otbCacheLessLabelImageToVectorData.txx"
#endif
#endif /* MODULES_REMOTE_SIMPLEEXTRACTIONTOOLS_INCLUDE_OTBCACHELESSLABELIMAGETOVECTORDATA_H_ */
/*=========================================================================
Copyright (c) Remi Cresson (IRSTEA). All rights reserved.
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 MODULES_REMOTE_SIMPLEEXTRACTIONTOOLS_INCLUDE_OTBCACHELESSLABELIMAGETOVECTORDATA_txx_
#define MODULES_REMOTE_SIMPLEEXTRACTIONTOOLS_INCLUDE_OTBCACHELESSLABELIMAGETOVECTORDATA_txx_
#include "otbCacheLessLabelImageToVectorData.h"
#include "itkObjectFactoryBase.h"
#include "itkImageRegionMultidimensionalSplitter.h"
#include "itkImageRegionIterator.h"
#include "otbNumberOfDivisionsStrippedStreamingManager.h"
#include "otbNumberOfDivisionsTiledStreamingManager.h"
#include "otbNumberOfLinesStrippedStreamingManager.h"
#include "otbRAMDrivenStrippedStreamingManager.h"
#include "otbTileDimensionTiledStreamingManager.h"
#include "otbRAMDrivenTiledStreamingManager.h"
#include "otbRAMDrivenAdaptativeStreamingManager.h"
namespace otb
{
/**
*
*/
template <class TInputImagePixel>
CacheLessLabelImageToVectorData<TInputImagePixel>
::CacheLessLabelImageToVectorData()
: m_NumberOfDivisions(0),
m_CurrentDivision(0),
m_DivisionProgress(0.0),
m_IsObserving(true),
m_ObserverID(0)
{
// By default, we use tiled streaming, with automatic tile size
// We don't set any parameter, so the memory size is retrieved from the OTB configuration options
this->SetAutomaticAdaptativeStreaming();
}
/**
*
*/
template <class TInputImagePixel>
CacheLessLabelImageToVectorData<TInputImagePixel>
::~CacheLessLabelImageToVectorData()
{
}
template <class TInputImagePixel>
void
CacheLessLabelImageToVectorData<TInputImagePixel>
::SetNumberOfDivisionsStrippedStreaming(unsigned int nbDivisions)
{
typedef NumberOfDivisionsStrippedStreamingManager<InputImageType> NumberOfDivisionsStrippedStreamingManagerType;
typename NumberOfDivisionsStrippedStreamingManagerType::Pointer streamingManager = NumberOfDivisionsStrippedStreamingManagerType::New();
streamingManager->SetNumberOfDivisions(nbDivisions);
m_StreamingManager = streamingManager;
}
template <class TInputImagePixel>
void
CacheLessLabelImageToVectorData<TInputImagePixel>
::SetNumberOfDivisionsTiledStreaming(unsigned int nbDivisions)
{
typedef NumberOfDivisionsTiledStreamingManager<InputImageType> NumberOfDivisionsTiledStreamingManagerType;
typename NumberOfDivisionsTiledStreamingManagerType::Pointer streamingManager = NumberOfDivisionsTiledStreamingManagerType::New();
streamingManager->SetNumberOfDivisions(nbDivisions);
m_StreamingManager = streamingManager;
}
template <class TInputImagePixel>
void
CacheLessLabelImageToVectorData<TInputImagePixel>
::SetNumberOfLinesStrippedStreaming(unsigned int nbLinesPerStrip)
{
typedef NumberOfLinesStrippedStreamingManager<InputImageType> NumberOfLinesStrippedStreamingManagerType;
typename NumberOfLinesStrippedStreamingManagerType::Pointer streamingManager = NumberOfLinesStrippedStreamingManagerType::New();
streamingManager->SetNumberOfLinesPerStrip(nbLinesPerStrip);
m_StreamingManager = streamingManager;
}
template <class TInputImagePixel>
void
CacheLessLabelImageToVectorData<TInputImagePixel>
::SetAutomaticStrippedStreaming(unsigned int availableRAM, double bias)
{
typedef RAMDrivenStrippedStreamingManager<InputImageType> RAMDrivenStrippedStreamingManagerType;
typename RAMDrivenStrippedStreamingManagerType::Pointer streamingManager = RAMDrivenStrippedStreamingManagerType::New();
streamingManager->SetAvailableRAMInMB(availableRAM);
streamingManager->SetBias(bias);
m_StreamingManager = streamingManager;
}
template <class TInputImagePixel>
void
CacheLessLabelImageToVectorData<TInputImagePixel>
::SetTileDimensionTiledStreaming(unsigned int tileDimension)
{
typedef TileDimensionTiledStreamingManager<InputImageType> TileDimensionTiledStreamingManagerType;
typename TileDimensionTiledStreamingManagerType::Pointer streamingManager = TileDimensionTiledStreamingManagerType::New();
streamingManager->SetTileDimension(tileDimension);
m_StreamingManager = streamingManager;
}
template <class TInputImagePixel>
void
CacheLessLabelImageToVectorData<TInputImagePixel>
::SetAutomaticTiledStreaming(unsigned int availableRAM, double bias)
{
typedef RAMDrivenTiledStreamingManager<InputImageType> RAMDrivenTiledStreamingManagerType;
typename RAMDrivenTiledStreamingManagerType::Pointer streamingManager = RAMDrivenTiledStreamingManagerType::New();
streamingManager->SetAvailableRAMInMB(availableRAM);
streamingManager->SetBias(bias);
m_StreamingManager = streamingManager;
}
template <class TInputImagePixel>
void
CacheLessLabelImageToVectorData<TInputImagePixel>
::SetAutomaticAdaptativeStreaming(unsigned int availableRAM, double bias)
{
typedef RAMDrivenAdaptativeStreamingManager<InputImageType> RAMDrivenAdaptativeStreamingManagerType;
typename RAMDrivenAdaptativeStreamingManagerType::Pointer streamingManager = RAMDrivenAdaptativeStreamingManagerType::New();
streamingManager->SetAvailableRAMInMB(availableRAM);
streamingManager->SetBias(bias);
m_StreamingManager = streamingManager;
}
template<class TInputImagePixel>
void
CacheLessLabelImageToVectorData<TInputImagePixel>
::SetInput(const InputImageType* input)
{
this->ProcessObject::SetNthInput(0,const_cast<InputImageType*>(input));
}
template<class TInputImagePixel>
const typename CacheLessLabelImageToVectorData<TInputImagePixel>::InputImageType*
CacheLessLabelImageToVectorData<TInputImagePixel>
::GetInput()
{
if (this->GetNumberOfInputs() < 1)
{
return ITK_NULLPTR;
}
return static_cast<const InputImageType*>(this->ProcessObject::GetInput(0));
}
/**
* Update method : update output information of input and write to file
*/
template<class TInputImagePixel>
void
CacheLessLabelImageToVectorData<TInputImagePixel>
::Update()
{
// Update output information on input image
InputImagePointer inputPtr =
const_cast<InputImageType *>(this->GetInput());
// Make sure input is available
if ( inputPtr.IsNull() )
{
itkExceptionMacro(<< "No input to writer");
}
this->SetAbortGenerateData(0);
this->SetProgress(0.0);
/**
* Tell all Observers that the filter is starting
*/
this->InvokeEvent(itk::StartEvent());
/**
* Grab the input
*/
inputPtr->UpdateOutputInformation();
InputImageRegionType inputRegion = inputPtr->GetLargestPossibleRegion();
// Allocate the buffer image
bufferedInputImage = InputImageType::New();
bufferedInputImage->SetRegions(inputRegion);
bufferedInputImage->Allocate();
bufferedInputImage->SetMetaDataDictionary(inputPtr->GetMetaDataDictionary());
bufferedInputImage->SetSpacing(inputPtr->GetSpacing());
bufferedInputImage->SetOrigin (inputPtr->GetOrigin() );
/** Compare the buffered region with the inputRegion which is the largest
* possible region or a user defined region through extended filename
* Not sure that if this modification is needed */
if (inputPtr->GetBufferedRegion() == inputRegion)
{
otbMsgDevMacro(<< "Buffered region is the largest possible region, there is no need for streaming.");
this->SetNumberOfDivisionsStrippedStreaming(1);
}
m_StreamingManager->PrepareStreaming(inputPtr, inputRegion);
m_NumberOfDivisions = m_StreamingManager->GetNumberOfSplits();
otbMsgDebugMacro(<< "Number Of Stream Divisions : " << m_NumberOfDivisions);
/**
* Loop over the number of pieces, execute the upstream pipeline on each
* piece, and copy the results into the output image.
*/
InputImageRegionType streamRegion;
this->UpdateProgress(0);
m_CurrentDivision = 0;
m_DivisionProgress = 0;
// Get the source process object
itk::ProcessObject* source = inputPtr->GetSource();
m_IsObserving = false;
m_ObserverID = 0;
// Check if source exists
if(source)
{
typedef itk::MemberCommand<Self> CommandType;
typedef typename CommandType::Pointer CommandPointerType;
CommandPointerType command = CommandType::New();
command->SetCallbackFunction(this, &Self::ObserveSourceFilterProgress);
m_ObserverID = source->AddObserver(itk::ProgressEvent(), command);
m_IsObserving = true;
}
else
{
itkWarningMacro(<< "Could not get the source process object. Progress report might be buggy");
}
for (m_CurrentDivision = 0;
m_CurrentDivision < m_NumberOfDivisions && !this->GetAbortGenerateData();
m_CurrentDivision++, m_DivisionProgress = 0, this->UpdateFilterProgress())
{
streamRegion = m_StreamingManager->GetSplit(m_CurrentDivision);
inputPtr->SetRequestedRegion(streamRegion);
inputPtr->PropagateRequestedRegion();
inputPtr->UpdateOutputData();
// Copy output in buffer
ConstIteratorType inIt(inputPtr, streamRegion);
IteratorType outIt(bufferedInputImage, streamRegion);
for (inIt.GoToBegin(), outIt.GoToBegin(); !inIt.IsAtEnd(); ++outIt, ++inIt)
{
outIt.Set(inIt.Get());
}
}
// Vectorize the buffered image
vectorizeFilter = LabelImageToVectorDataFilterType::New();
vectorizeFilter->SetInput(bufferedInputImage);
vectorizeFilter->SetInputMask(bufferedInputImage);
vectorizeFilter->Update();
this->GraftOutput( vectorizeFilter->GetOutput() );
/**
* If we ended due to aborting, push the progress up to 1.0 (since
* it probably didn't end there)
*/
if (!this->GetAbortGenerateData())
{
this->UpdateProgress(1.0);
}
// Notify end event observers
this->InvokeEvent(itk::EndEvent());
if (m_IsObserving)
{
m_IsObserving = false;
source->RemoveObserver(m_ObserverID);
}
/**
* Release any inputs if marked for release
*/
this->ReleaseInputs();
}
} // end namespace otb
#endif
Supports Markdown
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