Commit 916d730d authored by Emmanuel Christophe's avatar Emmanuel Christophe

ENH: add streaming/multithreading capabilities to ImageToPointSetFilter....

ENH: add streaming/multithreading capabilities to ImageToPointSetFilter. Adaptation of ThresholdImageToPointSetFilter
parent b37754bb
......@@ -55,8 +55,8 @@ public:
/** Some PointSet related typedefs. */
typedef typename Superclass::OutputPointSetType OutputPointSetType;
typedef typename Superclass::OutputPointSetPointer OutputPointSetPointer;
typedef itk::ProcessObject ProcessObjectType;
typedef typename Superclass::PointsContainerType PointsContainerType;
typedef itk::ProcessObject ProcessObjectType;
/** Set the input image of this process object. */
void SetInput(unsigned int idx, const InputImageType *input);
......@@ -71,9 +71,38 @@ public:
protected:
ImageToPointSetFilter();
~ImageToPointSetFilter();
virtual ~ImageToPointSetFilter() {};
void PrintSelf(std::ostream& os, itk::Indent indent) const;
virtual void GenerateData(void);
/** Multi-threading implementation */
typedef std::vector<typename OutputPointSetType::PointsContainer::Pointer> OutputPointContainerForThreadType;
virtual void BeforeThreadedGenerateData();
virtual void AfterThreadedGenerateData();
virtual int SplitRequestedRegion(int i, int num, InputImageRegionType& splitRegion);
virtual void ThreadedGenerateData(const InputImageRegionType &inputRegionForThread, int threadId);
/** Static function used as a "callback" by the MultiThreader. The threading
* library will call this routine for each thread, which will delegate the
* control to ThreadedGenerateData(). */
static ITK_THREAD_RETURN_TYPE ThreaderCallback( void *arg );
/** Internal structure used for passing image data into the threading library */
struct ThreadStruct
{
Pointer Filter;
};
OutputPointContainerForThreadType m_PointContainerPerThread;
/** End Multi-threading implementation */
private:
ImageToPointSetFilter(const ImageToPointSetFilter&); //purposely not implemented
void operator=(const ImageToPointSetFilter&); //purposely not implemented
......
......@@ -41,15 +41,6 @@ ImageToPointSetFilter<TInputImage,TOutputPointSet>
}
/**
*
*/
template <class TInputImage, class TOutputPointSet>
ImageToPointSetFilter<TInputImage,TOutputPointSet>
::~ImageToPointSetFilter()
{
}
/**
*
*/
......@@ -63,6 +54,7 @@ ImageToPointSetFilter<TInputImage,TOutputPointSet>
this->ProcessObjectType::SetNthInput(idx,
const_cast< InputImageType * >(input) );
}
/**
*
*/
......@@ -77,8 +69,6 @@ ImageToPointSetFilter<TInputImage,TOutputPointSet>
const_cast< InputImageType * >(input) );
}
/**
*
*/
......@@ -118,8 +108,6 @@ ImageToPointSetFilter<TInputImage,TOutputPointSet>
Superclass::PrintSelf(os,indent);
}
/**
* copy information from first input to all outputs
* This is a void implementation to prevent the
......@@ -132,6 +120,182 @@ ImageToPointSetFilter<TInputImage,TOutputPointSet>
{
}
/**
* GenerateData
*/
template <class TInputImage, class TOutputPointSet>
void
ImageToPointSetFilter<TInputImage,TOutputPointSet>
::GenerateData(void)
{
// Call a method that can be overridden by a subclass to perform
// some calculations prior to splitting the main computations into
// separate threads
this->BeforeThreadedGenerateData();
// Set up the multithreaded processing
ThreadStruct str;
str.Filter = this;
// Initializing object per thread
typename PointsContainerType::Pointer defaultPointsContainer
= OutputPointSetType::PointsContainer::New();
this->m_PointContainerPerThread
= OutputPointContainerForThreadType(this->GetNumberOfThreads(),defaultPointsContainer);
// Setting up multithreader
this->GetMultiThreader()->SetNumberOfThreads(this->GetNumberOfThreads());
this->GetMultiThreader()->SetSingleMethod(this->ThreaderCallback, &str);
// multithread the execution
this->GetMultiThreader()->SingleMethodExecute();
// Call a method that can be overridden by a subclass to perform
// some calculations after all the threads have completed
this->AfterThreadedGenerateData();
}
template <class TInputImage, class TOutputPointSet>
void
ImageToPointSetFilter<TInputImage,TOutputPointSet>
::BeforeThreadedGenerateData(void)
{
// this->AllocateOutputs();
}
template <class TInputImage, class TOutputPointSet>
void
ImageToPointSetFilter<TInputImage,TOutputPointSet>
::AfterThreadedGenerateData(void)
{
// copy the lists to the output
//TODO rename PointContainer in PointsContainer
typename OutputPointSetType::PointsContainer * outputPointContainer = this->GetOutput()->GetPoints();
outputPointContainer->Initialize();
typedef typename OutputPointSetType::PointsContainer::ConstIterator OutputPointContainerIterator;
for (unsigned int i=0; i< this->m_PointContainerPerThread.size(); ++i)
{
if (this->m_PointContainerPerThread[i].IsNotNull())
{
for (OutputPointContainerIterator it = this->m_PointContainerPerThread[i]->Begin();
it != this->m_PointContainerPerThread[i]->End();
++it)
{
outputPointContainer->push_back(it.Value());
}
}
}
}
template <class TInputImage, class TOutputPointSet>
void
ImageToPointSetFilter<TInputImage,TOutputPointSet>
::ThreadedGenerateData(const InputImageRegionType&, int)
{
// The following code is equivalent to:
// itkExceptionMacro("subclass should override this method!!!");
// The ExceptionMacro is not used because gcc warns that a
// 'noreturn' function does return
itk::OStringStream message;
message << "itk::ERROR: " << this->GetNameOfClass()
<< "(" << this << "): " << "Subclass should override this method!!!";
itk::ExceptionObject e_(__FILE__, __LINE__, message.str().c_str(),ITK_LOCATION);
throw e_;
}
template <class TInputImage, class TOutputPointSet>
ITK_THREAD_RETURN_TYPE
ImageToPointSetFilter<TInputImage,TOutputPointSet>
::ThreaderCallback( void *arg )
{
ThreadStruct *str;
int total, threadId, threadCount;
threadId = ((itk::MultiThreader::ThreadInfoStruct *)(arg))->ThreadID;
threadCount = ((itk::MultiThreader::ThreadInfoStruct *)(arg))->NumberOfThreads;
str = (ThreadStruct *)(((itk::MultiThreader::ThreadInfoStruct *)(arg))->UserData);
// execute the actual method with appropriate output region
// first find out how many pieces extent can be split into.
typename TInputImage::RegionType splitRegion;
total = str->Filter->SplitRequestedRegion(threadId, threadCount,
splitRegion);
if (threadId < total)
{
str->Filter->ThreadedGenerateData(splitRegion, threadId);
}
// else
// {
// otherwise don't use this thread. Sometimes the threads dont
// break up very well and it is just as efficient to leave a
// few threads idle.
// }
return ITK_THREAD_RETURN_VALUE;
}
template <class TInputImage, class TOutputPointSet>
int
ImageToPointSetFilter<TInputImage,TOutputPointSet>
::SplitRequestedRegion(int i, int num, InputImageRegionType& splitRegion)
{
// Get the output pointer
typename InputImageType::ConstPointer inputPtr = this->GetInput();
const typename TInputImage::SizeType& requestedRegionSize
= inputPtr->GetLargestPossibleRegion().GetSize();
int splitAxis;
typename TInputImage::IndexType splitIndex;
typename TInputImage::SizeType splitSize;
// Initialize the splitRegion to the output requested region
splitRegion = inputPtr->GetLargestPossibleRegion();
splitIndex = splitRegion.GetIndex();
splitSize = splitRegion.GetSize();
// split on the outermost dimension available
splitAxis = inputPtr->GetImageDimension() - 1;
while (requestedRegionSize[splitAxis] == 1)
{
--splitAxis;
if (splitAxis < 0)
{ // cannot split
itkDebugMacro(" Cannot Split");
return 1;
}
}
// determine the actual number of pieces that will be generated
typename TInputImage::SizeType::SizeValueType range = requestedRegionSize[splitAxis];
int valuesPerThread = (int)::vcl_ceil(range/(double)num);
int maxThreadIdUsed = (int)::vcl_ceil(range/(double)valuesPerThread) - 1;
// Split the region
if (i < maxThreadIdUsed)
{
splitIndex[splitAxis] += i*valuesPerThread;
splitSize[splitAxis] = valuesPerThread;
}
if (i == maxThreadIdUsed)
{
splitIndex[splitAxis] += i*valuesPerThread;
// last thread needs to process the "rest" dimension being split
splitSize[splitAxis] = splitSize[splitAxis] - i*valuesPerThread;
}
// set the split region ivars
splitRegion.SetIndex( splitIndex );
splitRegion.SetSize( splitSize );
itkDebugMacro(" Split Piece: " << splitRegion );
return maxThreadIdUsed + 1;
}
} // end namespace otb
......
......@@ -38,10 +38,10 @@ class ITK_EXPORT UnaryFunctorObjectListFilter :
{
public:
/** Standard class typedefs. */
typedef UnaryFunctorObjectListFilter Self;
typedef UnaryFunctorObjectListFilter Self;
typedef otb::ObjectListToObjectListFilter<TInputList,TOutputList> Superclass;
typedef itk::SmartPointer<Self> Pointer;
typedef itk::SmartPointer<const Self> ConstPointer;
typedef itk::SmartPointer<Self> Pointer;
typedef itk::SmartPointer<const Self> ConstPointer;
/** Method for creation through the object factory. */
itkNewMacro(Self);
......@@ -50,12 +50,12 @@ public:
itkTypeMacro(UnaryFunctorObjectListFilter, ObjectListToObjectListFilter);
/** Some typedefs. */
typedef TFunction FunctorType;
typedef TInputList InputListType;
typedef TOutputList OutputListType;
typedef typename TInputList::ConstPointer InputListPointer;
typedef typename TOutputList::Pointer OutputListPointer;
typedef typename TInputList::ConstIterator InputListIterator;
typedef TFunction FunctorType;
typedef TInputList InputListType;
typedef TOutputList OutputListType;
typedef typename TInputList::ConstPointer InputListPointer;
typedef typename TOutputList::Pointer OutputListPointer;
typedef typename TInputList::ConstIterator InputListIterator;
typedef typename TOutputList::ConstIterator OutputListIterator;
......@@ -66,11 +66,12 @@ public:
FunctorType& GetFunctor()
{
return m_Functor;
};
}
const FunctorType& GetFunctor() const
{
return m_Functor;
};
}
/** Set the functor object. This replaces the current Functor with a
* copy of the specified Functor. This allows the user to specify a
......@@ -102,12 +103,6 @@ protected:
virtual void ThreadedGenerateData(unsigned int startIndex, unsigned int stopIndex, int threadId);
/** Internal structure used for passing image data into the threading library */
struct ThreadStruct
{
Pointer Filter;
};
/** End Multi-threading implementation */
private:
......
......@@ -103,9 +103,10 @@ protected:
Pointer Filter;
};
OutputListForThreadType m_ObjectListPerThread;
/** End Multi-threading implementation */
OutputListForThreadType m_ObjectListPerThread;
private:
ObjectListToObjectListFilter(const Self&); //purposely not implemented
......
......@@ -55,9 +55,10 @@ public:
itkTypeMacro(PointSetSource,itk::ProcessObject);
/** Some convenient typedefs. */
typedef itk::DataObject::Pointer DataObjectPointer;
typedef TOutputPointSet OutputPointSetType;
typedef typename OutputPointSetType::Pointer OutputPointSetPointer;
typedef itk::DataObject::Pointer DataObjectPointer;
typedef TOutputPointSet OutputPointSetType;
typedef typename OutputPointSetType::Pointer OutputPointSetPointer;
typedef typename OutputPointSetType::PointsContainer PointsContainerType;
/** Get the point set output of this process object. */
OutputPointSetType * GetOutput(void);
......
......@@ -25,11 +25,11 @@ namespace otb
{
/** \class ThresholdImageToPointSetFilter
* \brief Produce a PointSet according to filtering conditions
*
*/
template <class TInputImage,
// class TOutputPointSet>
class TOutputPointSet = itk::PointSet<ITK_TYPENAME TInputImage::PixelType,2> >
class ITK_EXPORT ThresholdImageToPointSetFilter :
public ImageToPointSetFilter< TInputImage,TOutputPointSet >
......@@ -43,8 +43,8 @@ public:
typedef TInputImage InputImageType;
typedef ThresholdImageToPointSetFilter Self;
typedef ImageToPointSetFilter< InputImageType, TOutputPointSet> Superclass;
typedef typename Superclass::OutputPointSetType OutputPointSetType;
typedef ImageToPointSetFilter< InputImageType, TOutputPointSet> Superclass;
typedef typename Superclass::OutputPointSetType OutputPointSetType;
typedef itk::SmartPointer<Self> Pointer;
typedef itk::SmartPointer<const Self> ConstPointer;
......@@ -54,13 +54,14 @@ public:
typedef typename Superclass::InputImagePixelType InputPixelType;
typedef typename Superclass::InputImagePointer InputImagePointer;
typedef typename Superclass::InputImageRegionType InputImageRegionType;
typedef typename Superclass::InputImageConstPointer InputImageConstPointer;
typedef typename Superclass::InputImageType::SizeType SizeType;
typedef typename Superclass::InputImageType::IndexType IndexType;
//typedef typename Superclass::OutputPointSetType OutputPointSetType;
typedef typename Superclass::OutputPointSetPointer OutputPointSetPointer;
typedef typename Superclass::OutputPointSetType::PixelType OutputPointSetPixelType;
typedef typename Superclass::OutputPointSetPointer OutputPointSetPointer;
typedef typename Superclass::OutputPointSetType::PixelType OutputPointSetPixelType;
typedef typename Superclass::PointsContainerType PointsContainerType;
itkSetMacro(LowerThreshold,InputPixelType);
itkGetConstReferenceMacro(LowerThreshold, InputPixelType);
......@@ -71,7 +72,8 @@ protected:
ThresholdImageToPointSetFilter();
virtual ~ThresholdImageToPointSetFilter() {};
virtual void GenerateData();
// virtual void GenerateData();
virtual void ThreadedGenerateData(const InputImageRegionType &inputRegionForThread, int threadId);
void PrintSelf(std::ostream& os, itk::Indent indent) const;
......
......@@ -21,6 +21,7 @@
#include "otbThresholdImageToPointSetFilter.h"
#include "itkImageRegionConstIterator.h"
#include "itkProgressReporter.h"
namespace otb
{
......@@ -34,40 +35,76 @@ ThresholdImageToPointSetFilter<TInputImage, TOutputPointSet>
}
//template <class TInputImage, class TOutputPointSet>
//void
//ThresholdImageToPointSetFilter<TInputImage, TOutputPointSet>
//::GenerateData()
//{
// InputImageConstPointer inputPtr = this->GetInput(0);
// OutputPointSetPointer outputPtr = this->GetOutput();
//
// unsigned int pointId = 0;
// typename OutputPointSetType::PointType position;
//
// outputPtr->Initialize();
//
// typedef itk::ImageRegionConstIterator<TInputImage> InputIterator;
// InputIterator inIt(inputPtr, inputPtr->GetRequestedRegion() );
//
// // walk the regions, threshold each pixel
// while ( !inIt.IsAtEnd() )
// {
//
// const InputPixelType value = inIt.Get();
// const IndexType index = inIt.GetIndex();
//
// if ((value >= m_LowerThreshold) && (value <= m_UpperThreshold))
// {
// position[0] = index[0];
// position[1] = index[1];
//
// outputPtr->SetPoint(pointId,position);
//
// pointId++;
//
// }
// ++inIt;
// }
//}
template <class TInputImage, class TOutputPointSet>
void
ThresholdImageToPointSetFilter<TInputImage, TOutputPointSet>
::GenerateData()
::ThreadedGenerateData(const InputImageRegionType &inputRegionForThread, int threadId)
{
InputImageConstPointer inputPtr = this->GetInput(0);
OutputPointSetPointer outputPtr = this->GetOutput();
otbMsgDevMacro(<< "Processing thread: " << threadId);
this->m_PointContainerPerThread[threadId] = PointsContainerType::New();
InputImageConstPointer inputPtr = this->GetInput();
unsigned int pointId = 0;
typename OutputPointSetType::PointType position;
// Define the iterators
itk::ImageRegionConstIterator<TInputImage> inputIt(inputPtr, inputRegionForThread);
outputPtr->Initialize();
itk::ProgressReporter progress(this, threadId, inputRegionForThread.GetNumberOfPixels());
typedef itk::ImageRegionConstIterator<TInputImage> InputIterator;
InputIterator inIt(inputPtr, inputPtr->GetRequestedRegion() );
// walk the regions, threshold each pixel
while ( !inIt.IsAtEnd() )
{
typename OutputPointSetType::PointType position;
const InputPixelType value = inIt.Get();
const IndexType index = inIt.GetIndex();
inputIt.GoToBegin();
while( !inputIt.IsAtEnd() )
{
const InputPixelType value = inputIt.Get();
if ((value >= m_LowerThreshold) && (value <= m_UpperThreshold))
{
//FIXME: non valid for image with dim > 2
const IndexType index = inputIt.GetIndex();
position[0] = index[0];
position[1] = index[1];
outputPtr->SetPoint(pointId,position);
pointId++;
this->m_PointContainerPerThread[threadId]->push_back(position);
}
++inIt;
++inputIt;
progress.CompletedPixel(); // potential exception thrown here
}
}
......
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