From b400cd2454bd06e0b99ef0c35237c505c363d661 Mon Sep 17 00:00:00 2001 From: Julien Malik <julien.malik@c-s.fr> Date: Wed, 11 May 2011 15:19:45 +0200 Subject: [PATCH] ENH: refactor StreamingLineSegmentDetector to use the PersistentImageToVectorDataFilter and ensure streaming during test --- .../otbStreamingLineSegmentDetector.h | 200 +++------------ .../otbStreamingLineSegmentDetector.txx | 228 ++---------------- Testing/Code/FeatureExtraction/CMakeLists.txt | 19 +- .../otbStreamingLineSegmentDetector.cxx | 22 +- 4 files changed, 84 insertions(+), 385 deletions(-) diff --git a/Code/FeatureExtraction/otbStreamingLineSegmentDetector.h b/Code/FeatureExtraction/otbStreamingLineSegmentDetector.h index 34c2a9aa04..7b623efbee 100644 --- a/Code/FeatureExtraction/otbStreamingLineSegmentDetector.h +++ b/Code/FeatureExtraction/otbStreamingLineSegmentDetector.h @@ -36,199 +36,71 @@ #include "otbPersistentImageFilter.h" #include "otbPersistentFilterStreamingDecorator.h" +#include "otbPersistentImageToVectorDataFilter.h" namespace otb { - -/** \class PersistentLineSegmentDetector - * \brief [internal] Helper class for the implementation of LineSegmentDetector - * with streaming capabilities. - * - * This class inherits PersistentImageFilter and provides the Reset/Synthesize functions, - * plus the ThreadedGenerateData function implementing the image function evaluation - * - * \sa LineSegmentDetector - * - * \ingroup Streamed - * \ingroup FeatureExtraction - */ -template<class TInputImage, class TPrecision = double> -class ITK_EXPORT PersistentLineSegmentDetector : - public PersistentImageFilter<TInputImage, TInputImage> +template <class TImageType> +class PersistentStreamingLineSegmentDetector + : public otb::PersistentImageToVectorDataFilter<TImageType, + typename otb::LineSegmentDetector<TImageType, double>::VectorDataType > { public: /** Standard Self typedef */ - typedef PersistentLineSegmentDetector Self; - typedef PersistentImageFilter<TInputImage, TInputImage> Superclass; - typedef itk::SmartPointer<Self> Pointer; - typedef itk::SmartPointer<const Self> ConstPointer; + typedef PersistentStreamingLineSegmentDetector Self; + typedef PersistentImageToVectorDataFilter<TImageType, + typename otb::LineSegmentDetector<TImageType, double>::VectorDataType > Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + typedef otb::LineSegmentDetector<TImageType, double> LSDType; + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::InputImagePointer InputImagePointerType; + + typedef typename Superclass::OutputVectorDataType OutputVectorDataType; + typedef typename Superclass::OutputVectorDataPointerType OutputVectorDataPointerType; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Runtime information support. */ - itkTypeMacro(PersistentLineSegmentDetector, PersistentImageFilter); - - /** Image related typedefs. */ - // First Input - typedef TInputImage ImageType; - typedef typename TInputImage::Pointer ImagePointerType; - typedef typename TInputImage::RegionType RegionType; - typedef typename TInputImage::SizeType SizeType; - typedef typename TInputImage::IndexType IndexType; - typedef typename TInputImage::PixelType PixelType; - - // Smart Pointer type to a DataObject - typedef typename itk::DataObject::Pointer DataObjectPointer; - - // Container types - typedef LineSegmentDetector<ImageType, TPrecision> LineDetectorType; - typedef typename LineDetectorType::Pointer LineDetectorPointerType; - - typedef typename LineDetectorType::VectorDataType VectorDataType; - typedef typename VectorDataType::DataNodeType DataNodeType; - typedef typename DataNodeType::Pointer DataNodePointerType; - typedef typename DataNodeType::LineType LineType; - typedef itk::PreOrderTreeIterator<typename VectorDataType::DataTreeType> TreeIteratorType; - - typedef itk::ExtractImageFilter<ImageType, ImageType> ExtractorType; - typedef typename ExtractorType::Pointer ExtractorPointerType; - - typedef std::vector<typename ExtractorType::Pointer> ExtractorListType; - typedef std::vector<RegionType> RegionListType; - typedef std::vector<typename LineDetectorType::Pointer> LineDetectorListType; - typedef std::vector<typename VectorDataType::Pointer> VectorDataListType; - - /** Set/Get methods */ - itkSetMacro(ThreadDistanceThreshold, double); - itkGetMacro(ThreadDistanceThreshold, double); - - VectorDataType* GetOutputVectorData(void); - - /** Make a DataObject of the correct type to be used as the specified - * output. */ - itk::DataObject::Pointer MakeOutput(unsigned int idx); - - void AllocateOutputs(); - - void GenerateOutputInformation(); - - void Reset(void); - - void Synthetize(void); + itkTypeMacro(PersistentStreamingLineSegmentDetector, PersistentImageToVectorDataFilter); protected: - PersistentLineSegmentDetector(); - virtual ~PersistentLineSegmentDetector(); - void PrintSelf(std::ostream& os, itk::Indent indent) const; - - void GenerateInputRequestedRegion(); - - void BeforeThreadedGenerateData(); + PersistentStreamingLineSegmentDetector(); - /** Multi-thread version GenerateData. */ - void ThreadedGenerateData(const RegionType& outputRegionForThread, - int threadId); + virtual ~PersistentStreamingLineSegmentDetector(); - void AfterThreadedGenerateData(); + void GenerateInputRequestedRegion(); private: - PersistentLineSegmentDetector(const Self &); //purposely not implemented + PersistentStreamingLineSegmentDetector(const Self &); //purposely not implemented void operator =(const Self&); //purposely not implemented - /** the "Folder" node of the output vector data */ - DataNodePointerType m_Folder; - /** store each thread output */ - VectorDataListType m_VectorDataList; - /** tolerance to fuse 2 lines in 2 threads. */ - double m_ThreadDistanceThreshold; - + virtual OutputVectorDataPointerType ProcessTile(const InputImageType* inputImage); }; - -/** \class StreamingLineSegmentDetector - * \brief This class streams the whole input image through the PersistentLineSegmentDetector. - * - * This way, it allows to compute the inner product of this image. It calls the - * Reset() method of the PersistentLineSegmentDetector before streaming the image and the - * Synthetize() method of the PersistentLineSegmentDetector after having streamed the image - * to compute the statistics. The accessor on the results are wrapping the accessors of the - * internal PersistentLineSegmentDetector. - * Its output is a vector data file. - * - * \sa PersistentLineSegmentDetector - * \sa PersistentImageFilter - * \sa PersistentFilterStreamingDecorator - * \sa StreamingImageVirtualWriter - * \ingroup Streamed - * \ingroup Multithreaded - * \ingroup MathematicalStatisticsImageFilters - */ - -template<class TInputImage, class TPrecision = double> -class ITK_EXPORT StreamingLineSegmentDetector : - public PersistentFilterStreamingDecorator<PersistentLineSegmentDetector<TInputImage, TPrecision> > +template <class TImageType> +class StreamingLineSegmentDetector { public: - /** Standard Self typedef */ - typedef StreamingLineSegmentDetector Self; - typedef PersistentFilterStreamingDecorator - <PersistentLineSegmentDetector<TInputImage, TPrecision> > Superclass; - typedef itk::SmartPointer<Self> Pointer; - typedef itk::SmartPointer<const Self> ConstPointer; - /** Type macro */ - itkNewMacro(Self); + // define the PersistentStreamingLineSegmentDetector template + typedef PersistentStreamingLineSegmentDetector<TImageType> + PersistentStreamingLineSegmentDetectorType; - /** Creation through object factory macro */ - itkTypeMacro(StreamingLineSegmentDetector, PersistentFilterStreamingDecorator); - - typedef TInputImage InputImageType; - typedef typename TInputImage::Pointer InputImagePointerType; - typedef typename TInputImage::RegionType RegionType; - typedef typename TInputImage::SizeType SizeType; - typedef typename TInputImage::IndexType IndexType; - typedef typename TInputImage::PixelType PixelType; - - /** Smart Pointer type to a DataObject. */ - typedef typename itk::DataObject::Pointer DataObjectPointer; - - /** Output Types */ - typedef typename Superclass::FilterType PersistentLSDFilterType; - typedef typename PersistentLSDFilterType::VectorDataType VectorDataType; - typedef typename VectorDataType::Pointer VectorDataPointerType; - typedef typename VectorDataType::DataNodeType DataNodeType; - typedef typename DataNodeType::Pointer DataNodePointerType; - typedef typename DataNodeType::LineType LineType; - typedef typename LineType::VertexType VertexType; - - /** Input image to extract feature */ - void SetInput(TInputImage * input) - { - this->GetFilter()->SetInput(input); - } - - /** Detected lines as a VectorData of lines */ - VectorDataType* GetOutputVectorData() - { - return this->GetFilter()->GetOutputVectorData(); - } - - otbSetObjectMemberMacro(Filter, ThreadDistanceThreshold, double); - otbGetObjectMemberMacro(Filter, ThreadDistanceThreshold, double); + typedef typename PersistentStreamingLineSegmentDetectorType::InputImageType + InputImageType; + typedef typename PersistentStreamingLineSegmentDetectorType::OutputVectorDataType + OutputVectorDataType; -protected: - /** Constructor */ - StreamingLineSegmentDetector(); - /** Destructor */ - virtual ~StreamingLineSegmentDetector(); + // typedef for streaming capable filter + typedef PersistentFilterStreamingDecorator<PersistentStreamingLineSegmentDetectorType> + FilterType; -private: - StreamingLineSegmentDetector(const Self &); //purposely not implemented - void operator =(const Self&); //purposely not implemented }; -} // end namespace otb +} #ifndef OTB_MANUAL_INSTANTIATION #include "otbStreamingLineSegmentDetector.txx" diff --git a/Code/FeatureExtraction/otbStreamingLineSegmentDetector.txx b/Code/FeatureExtraction/otbStreamingLineSegmentDetector.txx index 96e73883c9..6516a825e9 100644 --- a/Code/FeatureExtraction/otbStreamingLineSegmentDetector.txx +++ b/Code/FeatureExtraction/otbStreamingLineSegmentDetector.txx @@ -22,240 +22,54 @@ #define __otbStreamingLineSegmentDetector_txx #include "otbStreamingLineSegmentDetector.h" -#include "itkImageRegionConstIterator.h" -#include "itkImageRegionIterator.h" -#include "itkProgressReporter.h" namespace otb { -template<class TInputImage, class TPrecision> -PersistentLineSegmentDetector<TInputImage, TPrecision> -::PersistentLineSegmentDetector() - : m_ThreadDistanceThreshold(10.) +template<class TInputImage> +PersistentStreamingLineSegmentDetector<TInputImage> +::PersistentStreamingLineSegmentDetector() { - this->SetNumberOfRequiredInputs(1); - - // Have 2 outputs : the image created by Superclass, a vector data with lines - this->SetNumberOfRequiredOutputs(3); - this->itk::ProcessObject::SetNthOutput(1, this->MakeOutput(1).GetPointer()); - this->itk::ProcessObject::SetNthOutput(2, this->MakeOutput(2).GetPointer()); - - // Set the number of threads to 1 by default to avoid oversegmentation - // There also seem to be a bug in the underlying LineSegmentDetector - // for small regions (probably when a stream does not contain segment) - this->SetNumberOfThreads(1); -} - -template<class TInputImage, class TPrecision> -PersistentLineSegmentDetector<TInputImage, TPrecision> -::~PersistentLineSegmentDetector() -{ -} - -template<class TInputImage, class TPrecision> -void -PersistentLineSegmentDetector<TInputImage, TPrecision> -::AllocateOutputs() -{ - // This is commented to prevent the streaming of the whole image for the first stream strip - // It shall not cause any problem because the output image of this filter is not intended to be used. - //ImagePointerType image = const_cast< TInputImage * >( this->GetInput() ); - //this->GraftOutput( image ); - // Nothing that needs to be allocated for the remaining outputs -} - -template<class TInputImage, class TPrecision> -void -PersistentLineSegmentDetector<TInputImage, TPrecision> -::GenerateOutputInformation() -{ - Superclass::GenerateOutputInformation(); - if (this->GetInput()) - { - this->GetOutput()->CopyInformation(this->GetInput()); - this->GetOutput()->SetLargestPossibleRegion(this->GetInput()->GetLargestPossibleRegion()); - } - - if (this->GetOutput()->GetRequestedRegion().GetNumberOfPixels() == 0) - { - this->GetOutput()->SetRequestedRegion(this->GetOutput()->GetLargestPossibleRegion()); - } } -template<class TInputImage, class TPrecision> -typename PersistentLineSegmentDetector<TInputImage, TPrecision>::VectorDataType* -PersistentLineSegmentDetector<TInputImage, TPrecision> -::GetOutputVectorData() +template<class TInputImage> +PersistentStreamingLineSegmentDetector<TInputImage> +::~PersistentStreamingLineSegmentDetector() { - return static_cast<VectorDataType*>(this->itk::ProcessObject::GetOutput(1)); } -template<class TInputImage, class TPrecision> -itk::DataObject::Pointer -PersistentLineSegmentDetector<TInputImage, TPrecision> -::MakeOutput(unsigned int idx) -{ - itk::DataObject::Pointer output; - switch (idx) - { - case 0: - output = static_cast<itk::DataObject*>(ImageType::New().GetPointer()); - break; - case 1: - { - output = static_cast<itk::DataObject*>(VectorDataType::New().GetPointer()); - break; - } - default: - output = static_cast<itk::DataObject*>(ImageType::New().GetPointer()); - break; - } - return output; -} - -template<class TInputImage, class TPrecision> +template<class TInputImage> void -PersistentLineSegmentDetector<TInputImage, TPrecision> -::Reset() -{ - int nbThread = this->GetNumberOfThreads(); - - m_VectorDataList.clear(); - m_VectorDataList.resize(nbThread); - - // merge all lines in a single vector data - VectorDataType* outputVData = this->GetOutputVectorData(); - - // Retrieving root node - DataNodePointerType root = outputVData->GetDataTree()->GetRoot()->Get(); - // Create the document node - DataNodePointerType document = DataNodeType::New(); - document->SetNodeType(otb::DOCUMENT); - DataNodePointerType folder = DataNodeType::New(); - folder->SetNodeType(otb::FOLDER); - m_Folder = folder; - // Adding the layer to the data tree - outputVData->GetDataTree()->Add(document, root); - outputVData->GetDataTree()->Add(folder, document); - - -} - -template<class TInputImage, class TPrecision> -void -PersistentLineSegmentDetector<TInputImage, TPrecision> -::Synthetize() -{ -} - -template<class TInputImage, class TPrecision> -void -PersistentLineSegmentDetector<TInputImage, TPrecision> -::PrintSelf(std::ostream& os, itk::Indent indent) const -{ - Superclass::PrintSelf(os, indent); -} - -template<class TInputImage, class TPrecision> -void -PersistentLineSegmentDetector<TInputImage, TPrecision> +PersistentStreamingLineSegmentDetector<TInputImage> ::GenerateInputRequestedRegion() { Superclass::GenerateInputRequestedRegion(); if (this->GetInput()) { - ImagePointerType input = const_cast<ImageType *>(this->GetInput()); + InputImagePointerType input = const_cast<InputImageType *> (this->GetInput()); + + typename InputImageType::RegionType region = this->GetOutput()->GetRequestedRegion(); - RegionType region = this->GetOutput()->GetRequestedRegion(); region.PadByRadius(1); region.Crop(input->GetLargestPossibleRegion()); - input->SetRequestedRegion(region); - } -} - -template<class TInputImage, class TPrecision> -void -PersistentLineSegmentDetector<TInputImage, TPrecision> -::BeforeThreadedGenerateData() -{ -} -template<class TInputImage, class TPrecision> -void -PersistentLineSegmentDetector<TInputImage, TPrecision> -::ThreadedGenerateData(const RegionType& outputRegionForThread, int threadId) -{ - try - { - ImagePointerType inputPtr = const_cast<TInputImage *>(this->GetInput()); - - RegionType region = outputRegionForThread; - region.PadByRadius((unsigned int)(1)); - region.Crop(inputPtr->GetLargestPossibleRegion()); - - inputPtr->SetRequestedRegion(region); - inputPtr->PropagateRequestedRegion(); - inputPtr->UpdateOutputData(); - - typename ExtractorType::Pointer extractFilter = ExtractorType::New(); - extractFilter->SetInput(this->GetInput()); - extractFilter->SetExtractionRegion(region); - extractFilter->Update(); - - typename LineDetectorType::Pointer lineDetector = LineDetectorType::New(); - lineDetector->SetInput(extractFilter->GetOutput()); - lineDetector->Update(); - - m_VectorDataList[threadId] = lineDetector->GetOutput(); - } - catch (itk::ExceptionObject& e) - { - std::cout << "Exception : " << e; - throw; - } -} - -template<class TInputImage, class TPrecision> -void -PersistentLineSegmentDetector<TInputImage, TPrecision> -::AfterThreadedGenerateData() -{ - // merge all lines in a single vector data - VectorDataType* outputVData = this->GetOutputVectorData(); - outputVData->GetDataTree(); - - for (unsigned int threadId = 0; threadId < m_VectorDataList.size(); ++threadId) - { - TreeIteratorType itCurrentVData(m_VectorDataList[threadId]->GetDataTree()); - itCurrentVData.GoToBegin(); - while (!itCurrentVData.IsAtEnd()) - { - if (itCurrentVData.Get()->IsLineFeature()) - { - outputVData->GetDataTree()->Add(itCurrentVData.Get(), m_Folder); - } - itCurrentVData ++; - } + input->SetRequestedRegion(region); } - - this->GetOutputVectorData()->SetMetaDataDictionary(m_VectorDataList[0]->GetMetaDataDictionary()); } -// end of class PersistentLineSegmentDetector - -template<class TInputImage, class TPrecision> -StreamingLineSegmentDetector<TInputImage, TPrecision> -::StreamingLineSegmentDetector() +template<class TInputImage> +typename PersistentStreamingLineSegmentDetector<TInputImage>::OutputVectorDataPointerType +PersistentStreamingLineSegmentDetector<TInputImage> +::ProcessTile(const InputImageType* inputImage) { + typename LSDType::Pointer lsd = LSDType::New(); + lsd->SetInput(inputImage); + lsd->UpdateOutputInformation(); + lsd->Update(); + return lsd->GetOutput(); } -template<class TInputImage, class TPrecision> -StreamingLineSegmentDetector<TInputImage, TPrecision> -::~StreamingLineSegmentDetector() -{ -} } // end namespace otb #endif diff --git a/Testing/Code/FeatureExtraction/CMakeLists.txt b/Testing/Code/FeatureExtraction/CMakeLists.txt index d6ecafcc89..2a621b277a 100644 --- a/Testing/Code/FeatureExtraction/CMakeLists.txt +++ b/Testing/Code/FeatureExtraction/CMakeLists.txt @@ -1315,13 +1315,24 @@ ADD_TEST(feTvRegionImageToRectangularPathListFilter ${FEATUREEXTRACTION_TESTS14} ADD_TEST(feTuStreamingLineSegmentDetectorNew ${FEATUREEXTRACTION_TESTS15} otbStreamingLineSegmentDetectorNew) -ADD_TEST(feTvStreamingLineSegmentDetector ${FEATUREEXTRACTION_TESTS15} +ADD_TEST(feTvStreamingLineSegmentDetector10 ${FEATUREEXTRACTION_TESTS15} --compare-ogr ${EPSILON_8} - ${BASELINE_FILES}/feTvStreamingLineSegmentDetectorOutput.shp - ${TEMP}/feTvStreamingLineSegmentDetectorOutput.shp + ${BASELINE_FILES}/feTvStreamingLineSegmentDetectorOutput10.shp + ${TEMP}/feTvStreamingLineSegmentDetectorOutput10.shp otbStreamingLineSegmentDetector ${INPUTDATA}/scene.png - ${TEMP}/feTvStreamingLineSegmentDetectorOutput.shp + ${TEMP}/feTvStreamingLineSegmentDetectorOutput10.shp + 10 +) + +ADD_TEST(feTvStreamingLineSegmentDetector1000 ${FEATUREEXTRACTION_TESTS15} +--compare-ogr ${EPSILON_8} + ${BASELINE_FILES}/feTvStreamingLineSegmentDetectorOutput1000.shp + ${TEMP}/feTvStreamingLineSegmentDetectorOutput1000.shp + otbStreamingLineSegmentDetector + ${INPUTDATA}/scene.png + ${TEMP}/feTvStreamingLineSegmentDetectorOutput1000.shp + 1000 ) # ------- otb::SqrtSpectralAngleImageFilter (Ossman)------------------------------ diff --git a/Testing/Code/FeatureExtraction/otbStreamingLineSegmentDetector.cxx b/Testing/Code/FeatureExtraction/otbStreamingLineSegmentDetector.cxx index e125545253..53e8479066 100644 --- a/Testing/Code/FeatureExtraction/otbStreamingLineSegmentDetector.cxx +++ b/Testing/Code/FeatureExtraction/otbStreamingLineSegmentDetector.cxx @@ -21,15 +21,18 @@ #include "otbImageFileReader.h" #include "otbVectorDataFileWriter.h" +#include "otbVectorDataSourceImageToImageFilterAdapter.h" +#include "otbPersistentImageToVectorDataFilter.h" +#include "otbPersistentFilterStreamingDecorator.h" + int otbStreamingLineSegmentDetectorNew(int argc, char * argv[]) { - typedef float InputPixelType; const unsigned int Dimension = 2; /** Typedefs */ typedef otb::Image<InputPixelType, Dimension> ImageType; - typedef otb::StreamingLineSegmentDetector<ImageType> StreamingLSDFilterType; + typedef otb::StreamingLineSegmentDetector<ImageType>::FilterType StreamingLSDFilterType; StreamingLSDFilterType::Pointer lsdFilter = StreamingLSDFilterType::New(); @@ -48,24 +51,23 @@ int otbStreamingLineSegmentDetector(int argc, char * argv[]) typedef otb::Image<InputPixelType, Dimension> ImageType; typedef otb::ImageFileReader<ImageType> ReaderType; - typedef otb::StreamingLineSegmentDetector<ImageType> StreamingLSDFilterType; - typedef StreamingLSDFilterType::VectorDataType VectorDataType; - typedef otb::VectorDataFileWriter<VectorDataType> WriterType; + typedef otb::StreamingLineSegmentDetector<ImageType>::FilterType StreamingLineSegmentDetectorType; + typedef StreamingLineSegmentDetectorType::FilterType::OutputVectorDataType OutputVectorDataType; + typedef otb::VectorDataFileWriter<OutputVectorDataType> WriterType; - StreamingLSDFilterType::Pointer lsdFilter = StreamingLSDFilterType::New(); ReaderType::Pointer reader = ReaderType::New(); + StreamingLineSegmentDetectorType::Pointer lsdFilter = StreamingLineSegmentDetectorType::New(); WriterType::Pointer writer = WriterType::New(); reader->SetFileName(argv[1]); reader->GenerateOutputInformation(); - lsdFilter->SetInput(reader->GetOutput()); - //lsdFilter->SetThreadDistanceThreshold(10.); + lsdFilter->GetFilter()->SetInput(reader->GetOutput()); + lsdFilter->GetStreamer()->SetNumberOfLinesStrippedStreaming(atoi(argv[3])); lsdFilter->Update(); writer->SetFileName(argv[2]); - writer->SetInput(lsdFilter->GetOutputVectorData()); + writer->SetInput(lsdFilter->GetFilter()->GetOutputVectorData()); writer->Update(); return EXIT_SUCCESS; } - -- GitLab