diff --git a/Code/BasicFilters/otbUnaryFunctorObjectListFilter.h b/Code/BasicFilters/otbUnaryFunctorObjectListFilter.h index 50c23fcc49dc749b88e735a783d4c4bdaf41d70e..caff14bd21e60f4b3a6325c24854e00ac06accb1 100644 --- a/Code/BasicFilters/otbUnaryFunctorObjectListFilter.h +++ b/Code/BasicFilters/otbUnaryFunctorObjectListFilter.h @@ -55,6 +55,9 @@ public: typedef typename TInputList::ConstPointer InputListPointer; typedef typename TOutputList::Pointer OutputListPointer; typedef typename TInputList::ConstIterator InputListIterator; + typedef typename TOutputList::ConstIterator OutputListIterator; + + typedef std::vector<OutputListPointer> OutputListForThreadType; // typedef itk::DataObject::Pointer DataObjectPointer; @@ -85,24 +88,37 @@ protected: UnaryFunctorObjectListFilter(); virtual ~UnaryFunctorObjectListFilter() {}; - - /** UnaryFunctorObjectListFilter can be implemented as a multithreaded filter. - * Therefore, this implementation provides a ThreadedGenerateData() routine - * which is called for each processing thread. The output image data is - * allocated automatically by the superclass prior to calling - * ThreadedGenerateData(). ThreadedGenerateData can only write to the - * portion of the output image specified by the parameter - * "outputRegionForThread" - * - * \sa ImageToImageFilter::ThreadedGenerateData(), - * ImageToImageFilter::GenerateData() */ void GenerateData(void); + /** Multi-threading implementation */ + + virtual void BeforeThreadedGenerateData(); + + virtual void AfterThreadedGenerateData(); + + /** startIndex and stopIndex represent the indices of the Objects to + examine in thread threadId */ + virtual void ThreadedGenerateData(unsigned int startIndex, unsigned int stopIndex,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; + }; + + /** End Multi-threading implementation */ + private: UnaryFunctorObjectListFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented FunctorType m_Functor; + OutputListForThreadType m_ObjectListPerThread; }; } // end namespace otb diff --git a/Code/BasicFilters/otbUnaryFunctorObjectListFilter.txx b/Code/BasicFilters/otbUnaryFunctorObjectListFilter.txx index ea0f362586e69597cf1270198ec8a31a8e5de8f8..7ff0c8d92fb2ed557480acb3086df5c682ae20b6 100644 --- a/Code/BasicFilters/otbUnaryFunctorObjectListFilter.txx +++ b/Code/BasicFilters/otbUnaryFunctorObjectListFilter.txx @@ -20,6 +20,7 @@ #include "otbUnaryFunctorObjectListFilter.h" #include "itkProgressReporter.h" +#include "otbMath.h" namespace otb { @@ -43,24 +44,145 @@ void UnaryFunctorObjectListFilter<TInputList,TOutputList,TFunction> ::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 + OutputListPointer defaultList; + m_ObjectListPerThread = OutputListForThreadType(this->GetNumberOfThreads(),defaultList); + + + // 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 TInputList, class TOutputList, class TFunction > + void + UnaryFunctorObjectListFilter<TInputList,TOutputList,TFunction> + ::BeforeThreadedGenerateData() +{ + this->AllocateOutputs(); +} + +template <class TInputList, class TOutputList, class TFunction > +void +UnaryFunctorObjectListFilter<TInputList,TOutputList,TFunction> +::ThreadedGenerateData(unsigned int startIndex, unsigned int stopIndex,int threadId) +{ + InputListPointer inputPtr = this->GetInput(); - OutputListPointer outputPtr = this->GetOutput(); + m_ObjectListPerThread[threadId] = OutputListType::New(); - itk::ProgressReporter progress(this, 0, inputPtr->Size()); + itk::ProgressReporter progress(this, threadId, stopIndex-startIndex); // Define the iterators - for(InputListIterator it = inputPtr->Begin(); it != inputPtr->End(); ++it) + InputListIterator it = inputPtr->Begin(); + unsigned int count = 0; + while ((count < startIndex) && (it != inputPtr->End())) { - outputPtr->PushBack(m_Functor(it.Get())); + ++it; + ++count; + } + + while((count < stopIndex) && (it != inputPtr->End())) + { + m_ObjectListPerThread[threadId]->PushBack(m_Functor(it.Get())); progress.CompletedPixel(); + ++it; + ++count; + } + +} + +template <class TInputList, class TOutputList, class TFunction > + void + UnaryFunctorObjectListFilter<TInputList,TOutputList,TFunction> + ::AfterThreadedGenerateData() +{ + // copy the lists to the output + OutputListPointer outputPtr = this->GetOutput(); + for (int i=0; i< m_ObjectListPerThread.size(); ++i) + { + for(OutputListIterator it = m_ObjectListPerThread[i]->Begin(); + it != m_ObjectListPerThread[i]->End(); + ++it) + { + outputPtr->PushBack(it.Get()); + } } } + + +template <class TInputList, class TOutputList, class TFunction > + ITK_THREAD_RETURN_TYPE + UnaryFunctorObjectListFilter<TInputList,TOutputList,TFunction> + ::ThreaderCallback( void *arg ) +{ + ThreadStruct *str; + int threadId, threadCount; + unsigned int total,start, stop; + + threadId = ((itk::MultiThreader::ThreadInfoStruct *)(arg))->ThreadID; + threadCount = ((itk::MultiThreader::ThreadInfoStruct *)(arg))->NumberOfThreads; + str = (ThreadStruct *)(((itk::MultiThreader::ThreadInfoStruct *)(arg))->UserData); + + total = str->Filter->GetInput()->Size(); + + if (threadId < static_cast<int>(total)) + { + + // Split the adjacency matrix in strip of equal dimension + start = static_cast<unsigned int>( vcl_floor( + total*static_cast<double>(threadId)/static_cast<double>(threadCount)+0.5 + )); + stop = static_cast<unsigned int>(vcl_floor( + total*static_cast<double>(threadId+1)/static_cast<double>(threadCount)+0.5 + )); + if (stop > total) + stop = total; + + // For very small list it might occur that start = stop. In this + // case the vertex at that index will be processed in the next strip. + if(start!=stop) + { + str->Filter->ThreadedGenerateData(start, stop, 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; +} + + + } // end namespace otb #endif