diff --git a/Code/FeatureExtraction/otbMaskedScalarImageToGreyLevelCoocurenceMatrixGenerator.h b/Code/FeatureExtraction/otbMaskedScalarImageToGreyLevelCoocurenceMatrixGenerator.h new file mode 100644 index 0000000000000000000000000000000000000000..4c787065f2bcf6d99247d1b4bee0bf17049b2325 --- /dev/null +++ b/Code/FeatureExtraction/otbMaskedScalarImageToGreyLevelCoocurenceMatrixGenerator.h @@ -0,0 +1,91 @@ +/*========================================================================= + + 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. + +=========================================================================*/ +#ifndef __otbMaskedScalarImageToGreyLevelCoocurrenceMatrixGenerator_h +#define __otbMaskedScalarImageToGreyLevelCoocurrenceMatrixGenerator_h + +#include "itkMaskedScalarImageToGreyLevelCooccurrenceMatrixGenerator.h" +#include "otbMacro.h" + +namespace otb +{ + /** \class MaskedScalarImageToGreyLevelCooccurrenceMatrixGenerator + * \brief This class extends the ITK version by providing matrix estimation on a sub-region. + * + * This class compute the co-occurence matrix over a given region of the image. The region can be set + * using the SetRegion()/GetRegion() methods. + * + * \sa itk::MaskedScalarImageToGreyLevelCooccurrenceMatrixGenerator + */ +template <class TImage, class THistogramFrequencyContainer = itk::Statistics::DenseFrequencyContainer > +class MaskedScalarImageToGreyLevelCooccurrenceMatrixGenerator + : public itk::Statistics::MaskedScalarImageToGreyLevelCooccurrenceMatrixGenerator<TImage,THistogramFrequencyContainer> +{ +public: + /** Standard class typedef */ + typedef MaskedScalarImageToGreyLevelCooccurrenceMatrixGenerator Self; + typedef itk::Statistics::MaskedScalarImageToGreyLevelCooccurrenceMatrixGenerator + <TImage,THistogramFrequencyContainer> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Creation through object factory */ + itkNewMacro(Self); + + /** RTTI */ + itkTypeMacro(MaskedScalarImageToGreyLevelCooccurrenceMatrixGenerator, + itk::MaskedScalarImageToGreyLevelCooccurrenceMatrixGenerator); + + /** Superclass typedefs */ + typedef TImage ImageType; + typedef typename ImageType::RegionType RegionType; + typedef typename Superclass::RadiusType RadiusType; + + /** Set/Get the region on which the co-occurence matrix is computed */ + itkSetMacro(Region,RegionType); + itkGetMacro(Region,RegionType); + +protected: + /** Constructor */ + MaskedScalarImageToGreyLevelCooccurrenceMatrixGenerator() : m_Region() {} + /** Destructor */ + ~MaskedScalarImageToGreyLevelCooccurrenceMatrixGenerator(){} + + /** Overload this method to restrict co-occurence to the given region */ + virtual void FillHistogram(RadiusType radius, RegionType region) + { + // Check that region is inside the requested region + RegionType subregion = m_Region; + + if(subregion.Crop(region)) + { + // If so, call superclass FillHistogram implementation + this->Superclass::FillHistogram(radius,subregion); + } + } + +private: + MaskedScalarImageToGreyLevelCooccurrenceMatrixGenerator(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + /** Region on which to compute co-occurence */ + RegionType m_Region; + + +}; +} // End namespace otb + #endif diff --git a/Code/FeatureExtraction/otbScalarImageToTexturesFilter.h b/Code/FeatureExtraction/otbScalarImageToTexturesFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..0dd152967c2390d2f6909e90ff170af5fd12ed56 --- /dev/null +++ b/Code/FeatureExtraction/otbScalarImageToTexturesFilter.h @@ -0,0 +1,207 @@ +/*========================================================================= + + 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. + + =========================================================================*/ +#ifndef __otbScalarImageToTexturesFilter_h +#define __otbScalarImageToTexturesFilter_h + +#include "itkImageToImageFilter.h" + +#include "otbMaskedScalarImageToGreyLevelCoocurenceMatrixGenerator.h" +#include "itkGreyLevelCooccurrenceMatrixTextureCoefficientsCalculator.h" + +namespace otb +{ +/** \class ScalarImageToTexturesFilter + * \brief This class computes the standard texture indices based on GLCM. + * + * This class computes the classical texture features based on the grey-level co-occurrence matrix. + * The co-occurence matrix is estimated over a neighborhood given by the user-defined radius, and the features + * are then derived from this matrix. + * + * This filter takes advantages of the GreyLevelCooccurrenceMatrixTextureCoefficientsCalculator filter from ITK, + * as well as the otb::MaskedScalarImageToGreyLevelCooccurrenceMatrixGenerator. + * + * The features calculated are as follows (where \f$ g(i, j) \f$ is the element in + * cell i, j of a a normalized GLCM): + * + * "Energy" \f$ = f_1 = \sum_{i,j}g(i, j)^2 \f$ + * + * "Entropy" \f$ = f_2 = -\sum_{i,j}g(i, j) \log_2 g(i, j)\f$, or 0 if \f$g(i, j) = 0\f$ + * + * "Correlation" \f$ = f_3 = \sum_{i,j}\frac{(i - \mu)(j - \mu)g(i, j)}{\sigma^2} \f$ + * + * "Difference Moment" \f$= f_4 = \sum_{i,j}\frac{1}{1 + (i - j)^2}g(i, j) \f$ + * + * "Inertia" \f$ = f_5 = \sum_{i,j}(i - j)^2g(i, j) \f$ (sometimes called "contrast.") + * + * "Cluster Shade" \f$ = f_6 = \sum_{i,j}((i - \mu) + (j - \mu))^3 g(i, j) \f$ + * + * "Cluster Prominence" \f$ = f_7 = \sum_{i,j}((i - \mu) + (j - \mu))^4 g(i, j) \f$ + * + * "Haralick's Correlation" \f$ = f_8 = \frac{\sum_{i,j}(i, j) g(i, j) -\mu_t^2}{\sigma_t^2} \f$ + * where \f$\mu_t\f$ and \f$\sigma_t\f$ are the mean and standard deviation of the row + * (or column, due to symmetry) sums. + * + * Above, \f$ \mu = \f$ (weighted pixel average) \f$ = \sum_{i,j}i \cdot g(i, j) = + * \sum_{i,j}j \cdot g(i, j) \f$ (due to matrix summetry), and + * + * \f$ \sigma = \f$ (weighted pixel variance) \f$ = \sum_{i,j}(i - \mu)^2 \cdot g(i, j) = + * \sum_{i,j}(j - \mu)^2 \cdot g(i, j) \f$ (due to matrix summetry) + * + * The Radius parameter is the radius of the window over which the co-occurence matrix is estimated at + * each pixel location. The Offset parameter is the offset used in the matrix estimation, defining orientation + * and frequency of the texture to denote. The NumberOfBinsPerAxis allows to tune the resolution of the bins in + * the co-occurence matrix, and the InputPixelMinimum and InputPixelMaximum parameters is used in bin width computation + * along with the NumberOfBinPerAxis. + * + * For more information, please refer to the documentation of the following class : + * \sa MaskedScalarImageToGreyLevelCooccurrenceMatrixGenerator + * \sa GreyLevelCooccurrenceMatrixTextureCoefficientsCalculator + * + * \ingroup Streamed + * \ingroup Threaded + */ + +template<class TInpuImage, class TOutputImage> +class ScalarImageToTexturesFilter : public itk::ImageToImageFilter + <TInpuImage, TOutputImage> +{ +public: + /** Standard class typedefs */ + typedef ScalarImageToTexturesFilter Self; + typedef itk::ImageToImageFilter<TInpuImage, TOutputImage> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Creation through the object factory */ + itkNewMacro(Self); + + /** RTTI */ + itkTypeMacro(ScalarImageToTexturesFilter,ImageToImageFilter); + + /** Template class typedefs */ + typedef TInpuImage InputImageType; + typedef typename InputImageType::Pointer InputImagePointerType; + typedef typename InputImageType::PixelType InputPixelType; + typedef typename InputImageType::RegionType InputRegionType; + typedef typename InputRegionType::SizeType SizeType; + typedef TOutputImage OutputImageType; + typedef typename OutputImageType::Pointer OutputImagePointerType; + typedef typename OutputImageType::RegionType OutputRegionType; + + /** Co-occurence matrix and textures calculator */ + typedef otb::MaskedScalarImageToGreyLevelCooccurrenceMatrixGenerator + <InputImageType> CoocurrenceMatrixGeneratorType; + typedef typename CoocurrenceMatrixGeneratorType::Pointer CoocurrenceMatrixGeneratorPointerType; + typedef typename CoocurrenceMatrixGeneratorType::OffsetType OffsetType; + typedef typename CoocurrenceMatrixGeneratorType::HistogramType HistogramType; + typedef itk::Statistics::GreyLevelCooccurrenceMatrixTextureCoefficientsCalculator + <HistogramType> TextureCoefficientsCalculatorType; + typedef typename TextureCoefficientsCalculatorType::Pointer TextureCoefficientsCalculatorPointerType; + + /** Set the radius of the window on which textures will be computed */ + itkSetMacro(Radius,SizeType); + /** Get the radius of the window on which textures will be computed */ + itkGetMacro(Radius,SizeType); + + /** Set the offset for co-occurence computation */ + itkSetMacro(Offset,OffsetType); + + /** Get the offset for co-occurence computation */ + itkGetMacro(Offset,OffsetType); + + /** Set the number of bin per axis for histogram generation */ + itkSetMacro(NumberOfBinsPerAxis,unsigned int); + + /** Get the number of bin per axis for histogram generation */ + itkGetMacro(NumberOfBinsPerAxis,unsigned int); + + /** Set the input image minimum */ + itkSetMacro(InputImageMinimum,InputPixelType); + + /** Get the input image minimum */ + itkGetMacro(InputImageMinimum,InputPixelType); + + /** Set the input image maximum */ + itkSetMacro(InputImageMaximum,InputPixelType); + + /** Get the input image maximum */ + itkGetMacro(InputImageMaximum,InputPixelType); + + /** Get the energy output image */ + OutputImageType * GetEnergyOutput(); + + /** Get the entropy output image */ + OutputImageType * GetEntropyOutput(); + + /** Get the correlation output image */ + OutputImageType * GetCorrelationOutput(); + + /** Get the inverse difference moment output image */ + OutputImageType * GetInverseDifferenceMomentOutput(); + + /** Get the inertia output image */ + OutputImageType * GetInertiaOutput(); + + /** Get the cluster shade output image */ + OutputImageType * GetClusterShadeOutput(); + + /** Get the cluster prominence image */ + OutputImageType * GetClusterProminenceOutput(); + + /** Get the Haralick correlation output image */ + OutputImageType * GetHaralickCorrelationOutput(); + +protected: + /** Constructor */ + ScalarImageToTexturesFilter(); + /** Destructor */ + ~ScalarImageToTexturesFilter(); + /** Generate the input requested region */ + virtual void GenerateInputRequestedRegion(); + /** Parallel textures extraction */ + virtual void ThreadedGenerateData(const OutputRegionType & outputRegion, int threadId); + +private: + ScalarImageToTexturesFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + /** Convenient method to compute union of 2 regions */ + static OutputRegionType RegionUnion(const OutputRegionType & region1, const OutputRegionType & region2); + + /** Radius of the window on which to compute textures */ + SizeType m_Radius; + + /** Offset for co-occurence */ + OffsetType m_Offset; + + /** Number of bins per axis for histogram generation */ + unsigned int m_NumberOfBinsPerAxis; + + /** Input image minimum */ + InputPixelType m_InputImageMinimum; + + /** Input image maximum */ + InputPixelType m_InputImageMaximum; +}; +} // End namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbScalarImageToTexturesFilter.txx" +#endif + +#endif diff --git a/Code/FeatureExtraction/otbScalarImageToTexturesFilter.txx b/Code/FeatureExtraction/otbScalarImageToTexturesFilter.txx new file mode 100644 index 0000000000000000000000000000000000000000..63ce37d029179d10d7bc01afc50b3718aa9da644 --- /dev/null +++ b/Code/FeatureExtraction/otbScalarImageToTexturesFilter.txx @@ -0,0 +1,331 @@ +/*========================================================================= + + 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. + +=========================================================================*/ +#ifndef __otbScalarImageToTexturesFilter_txx +#define __otbScalarImageToTexturesFilter_txx + +#include "otbScalarImageToTexturesFilter.h" +#include "itkImageRegionIteratorWithIndex.h" +#include "itkImageRegionIterator.h" +#include "itkProgressReporter.h" + +namespace otb +{ +template <class TInputImage,class TOutputImage> +ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::ScalarImageToTexturesFilter() : m_Radius(), + m_Offset(), + m_NumberOfBinsPerAxis(), + m_InputImageMinimum(0), + m_InputImageMaximum(256) +{ + // There are 8 outputs corresponding to the 8 textures indices + this->SetNumberOfOutputs(8); + + // Create the 8 outputs + this->SetNthOutput(0,OutputImageType::New()); + this->SetNthOutput(1,OutputImageType::New()); + this->SetNthOutput(2,OutputImageType::New()); + this->SetNthOutput(3,OutputImageType::New()); + this->SetNthOutput(4,OutputImageType::New()); + this->SetNthOutput(5,OutputImageType::New()); + this->SetNthOutput(6,OutputImageType::New()); + this->SetNthOutput(7,OutputImageType::New()); +} + +template <class TInputImage,class TOutputImage> +ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::~ScalarImageToTexturesFilter() +{} + +template <class TInputImage,class TOutputImage> +typename ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::OutputImageType * +ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::GetEnergyOutput() +{ + if(this->GetNumberOfOutputs()<1) + { + return 0; + } + return static_cast<OutputImageType *>(this->GetOutput(0)); +} + +template <class TInputImage,class TOutputImage> +typename ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::OutputImageType * +ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::GetEntropyOutput() +{ + if(this->GetNumberOfOutputs()<2) + { + return 0; + } + return static_cast<OutputImageType *>(this->GetOutput(1)); +} + +template <class TInputImage,class TOutputImage> +typename ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::OutputImageType * +ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::GetCorrelationOutput() +{ + if(this->GetNumberOfOutputs()<3) + { + return 0; + } + return static_cast<OutputImageType *>(this->GetOutput(2)); +} + +template <class TInputImage,class TOutputImage> +typename ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::OutputImageType * +ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::GetInverseDifferenceMomentOutput() +{ + if(this->GetNumberOfOutputs()<4) + { + return 0; + } + return static_cast<OutputImageType *>(this->GetOutput(3)); +} + +template <class TInputImage,class TOutputImage> +typename ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::OutputImageType * +ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::GetInertiaOutput() +{ + if(this->GetNumberOfOutputs()<5) + { + return 0; + } + return static_cast<OutputImageType *>(this->GetOutput(4)); +} + +template <class TInputImage,class TOutputImage> +typename ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::OutputImageType * +ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::GetClusterShadeOutput() +{ + if(this->GetNumberOfOutputs()<6) + { + return 0; + } + return static_cast<OutputImageType *>(this->GetOutput(5)); +} + +template <class TInputImage,class TOutputImage> +typename ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::OutputImageType * +ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::GetClusterProminenceOutput() +{ + if(this->GetNumberOfOutputs()<7) + { + return 0; + } + return static_cast<OutputImageType *>(this->GetOutput(6)); +} + +template <class TInputImage,class TOutputImage> +typename ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::OutputImageType * +ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::GetHaralickCorrelationOutput() +{ + if(this->GetNumberOfOutputs()<8) + { + return 0; + } + return static_cast<OutputImageType *>(this->GetOutput(7)); +} + +template <class TInputImage,class TOutputImage> +void +ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::GenerateInputRequestedRegion() +{ + // First, call superclass implementation + Superclass::GenerateInputRequestedRegion(); + + // Retrieve the input and output pointers + InputImagePointerType inputPtr = const_cast<InputImageType *>(this->GetInput()); + OutputImagePointerType outputPtr = this->GetOutput(); + + if(!inputPtr || !outputPtr) + { + return; + } + + // Retrieve the output requested region + // We use only the first output since requested regions for all outputs are enforced to be equal + // by the default GenerateOutputRequestedRegiont() implementation + OutputRegionType outputRequestedRegion = outputPtr->GetRequestedRegion(); + + typename OutputRegionType::IndexType outputIndex = outputRequestedRegion.GetIndex(); + typename OutputRegionType::SizeType outputSize = outputRequestedRegion.GetSize(); + typename InputRegionType::IndexType inputIndex; + typename InputRegionType::SizeType inputSize; + + // First, apply offset + for(unsigned int dim = 0; dim<InputImageType::ImageDimension;++dim) + { + inputIndex[dim]=std::min(outputIndex[dim],outputIndex[dim]+m_Offset[dim]); + inputSize[dim] =std::max(outputIndex[dim]+outputSize[dim],outputIndex[dim]+outputSize[dim]+m_Offset[dim])-inputIndex[dim]; + } + + // Build the input requested region + InputRegionType inputRequestedRegion; + inputRequestedRegion.SetIndex(inputIndex); + inputRequestedRegion.SetSize(inputSize); + + // Apply the radius + inputRequestedRegion.PadByRadius(m_Radius); + + // Try to apply the requested region to the input image + if(inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion())) + { + inputPtr->SetRequestedRegion(inputRequestedRegion); + } + else + { + // Build an exception + itk::InvalidRequestedRegionError e(__FILE__,__LINE__); + e.SetLocation(ITK_LOCATION); + e.SetDescription("Requested region is (at least partially) outside the largest possible region."); + e.SetDataObject(inputPtr); + throw e; + } +} + +template <class TInputImage,class TOutputImage> +void +ScalarImageToTexturesFilter<TInputImage,TOutputImage> +::ThreadedGenerateData(const OutputRegionType & outputRegionForThread, int threadId) +{ + // Retrieve the input and output pointers + InputImagePointerType inputPtr = const_cast<InputImageType *>(this->GetInput()); + OutputImagePointerType energyPtr = this->GetEnergyOutput(); + OutputImagePointerType entropyPtr = this->GetEntropyOutput(); + OutputImagePointerType correlationPtr = this->GetCorrelationOutput(); + OutputImagePointerType invDiffMomentPtr = this->GetInverseDifferenceMomentOutput(); + OutputImagePointerType inertiaPtr = this->GetInertiaOutput(); + OutputImagePointerType clusterShadePtr = this->GetClusterShadeOutput(); + OutputImagePointerType clusterProminencePtr = this->GetClusterProminenceOutput(); + OutputImagePointerType haralickCorPtr = this->GetHaralickCorrelationOutput(); + + // Build output iterators + itk::ImageRegionIteratorWithIndex<OutputImageType> energyIt(energyPtr,outputRegionForThread); + itk::ImageRegionIterator<OutputImageType> entropyIt(entropyPtr,outputRegionForThread); + itk::ImageRegionIterator<OutputImageType> correlationIt(correlationPtr,outputRegionForThread); + itk::ImageRegionIterator<OutputImageType> invDiffMomentIt(invDiffMomentPtr,outputRegionForThread); + itk::ImageRegionIterator<OutputImageType> inertiaIt(inertiaPtr,outputRegionForThread); + itk::ImageRegionIterator<OutputImageType> clusterShadeIt(clusterShadePtr,outputRegionForThread); + itk::ImageRegionIterator<OutputImageType> clusterProminenceIt(clusterProminencePtr,outputRegionForThread); + itk::ImageRegionIterator<OutputImageType> haralickCorIt(haralickCorPtr,outputRegionForThread); + + // Go to begin + energyIt.GoToBegin(); + entropyIt.GoToBegin(); + correlationIt.GoToBegin(); + invDiffMomentIt.GoToBegin(); + inertiaIt.GoToBegin(); + clusterShadeIt.GoToBegin(); + clusterProminenceIt.GoToBegin(); + haralickCorIt.GoToBegin(); + + // Build the co-occurence matrix generator + CoocurrenceMatrixGeneratorPointerType coOccurenceMatrixGenerator = CoocurrenceMatrixGeneratorType::New(); + coOccurenceMatrixGenerator->SetInput(inputPtr); + coOccurenceMatrixGenerator->SetOffset(m_Offset); + coOccurenceMatrixGenerator->SetNumberOfBinsPerAxis(m_NumberOfBinsPerAxis); + coOccurenceMatrixGenerator->SetPixelValueMinMax(m_InputImageMinimum,m_InputImageMaximum); + + // Build the texture calculator + TextureCoefficientsCalculatorPointerType texturesCalculator = TextureCoefficientsCalculatorType::New(); + + // Set-up progress reporting + itk::ProgressReporter progress(this,threadId,outputRegionForThread.GetNumberOfPixels()); + + // Iterate on outputs to compute textures + while(!energyIt.IsAtEnd() + &&!entropyIt.IsAtEnd() + &&!correlationIt.IsAtEnd() + &&!invDiffMomentIt.IsAtEnd() + &&!inertiaIt.IsAtEnd() + &&!clusterShadeIt.IsAtEnd() + &&!clusterProminenceIt.IsAtEnd() + &&!haralickCorIt.IsAtEnd()) + { + // Find the input region on which texture will be computed + InputRegionType currentRegion; + typename InputRegionType::IndexType currentIndex = energyIt.GetIndex()-m_Radius; + typename InputRegionType::SizeType currentSize; + + for(unsigned int dim = 0; dim<InputImageType::ImageDimension;++dim) + { + // Compute current size before applying offset + currentSize[dim] = 2*m_Radius[dim]+1; + + // Apply offset + currentIndex[dim] = std::min(currentIndex[dim],currentIndex[dim]+m_Offset[dim]); + currentSize[dim] = std::max(currentIndex[dim]+currentSize[dim],currentIndex[dim]+currentSize[dim]+m_Offset[dim])-currentIndex[dim]; + } + + // Fill current region + currentRegion.SetIndex(currentIndex); + currentRegion.SetSize(currentSize); + + // Compute the co-occurence matrix + coOccurenceMatrixGenerator->SetRegion(currentRegion); + coOccurenceMatrixGenerator->Compute(); + + // Compute textures indices + texturesCalculator->SetHistogram(coOccurenceMatrixGenerator->GetOutput()); + texturesCalculator->Compute(); + + // Fill outputs + energyIt.Set(texturesCalculator->GetEnergy()); + entropyIt.Set(texturesCalculator->GetEntropy()); + correlationIt.Set(texturesCalculator->GetCorrelation()); + invDiffMomentIt.Set(texturesCalculator->GetInverseDifferenceMoment()); + inertiaIt.Set(texturesCalculator->GetInertia()); + clusterShadeIt.Set(texturesCalculator->GetClusterShade()); + clusterProminenceIt.Set(texturesCalculator->GetClusterProminence()); + haralickCorIt.Set(texturesCalculator->GetHaralickCorrelation()); + + // Update progress + progress.CompletedPixel(); + + // Increment iterators + ++energyIt; + ++entropyIt; + ++correlationIt; + ++invDiffMomentIt; + ++inertiaIt; + ++clusterShadeIt; + ++clusterProminenceIt; + ++haralickCorIt; + } + +} + +} // End namespace otb + +#endif diff --git a/Code/IO/otbCurlHelper.cxx b/Code/IO/otbCurlHelper.cxx old mode 100644 new mode 100755 index 10b11490d4cc49c1c0a279fc8042c7d397625bb4..7ee36bb306b2dc28fdd309c7f2416184ced311a5 --- a/Code/IO/otbCurlHelper.cxx +++ b/Code/IO/otbCurlHelper.cxx @@ -35,13 +35,9 @@ int CurlHelper::TestUrlAvailability(const std::string& url) const CURLcode res = CURL_LAST; curl = curl_easy_init(); - // Set up the browser - std::string browser = - "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11"; - if (curl) { - curl_easy_setopt(curl, CURLOPT_USERAGENT, browser.data()); + curl_easy_setopt(curl, CURLOPT_USERAGENT, m_Browser.data()); curl_easy_setopt(curl, CURLOPT_URL, url.data()); // Set the dummy write function curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &Self::curlDummyWriteFunction); @@ -69,26 +65,32 @@ int CurlHelper::RetrieveFile(const std::string& urlString, std::string filename) CURLcode res = CURL_LAST; FILE* output_file = fopen(filename.c_str(), "w"); + curl = curl_easy_init(); - + char url[256]; - strcpy(url, urlString.data()); + strcpy(url, urlString.c_str()); -// std::cout << url << std::endl; if (curl) { - std::vector<char> chunk; curl_easy_setopt(curl, CURLOPT_URL, url); // Set 5s timeout curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5); - - curl_easy_setopt(curl, CURLOPT_WRITEDATA, output_file); + + // Use our writing static function to avoid file descriptor + // pointer crash on windows + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &Self::write_data); + + // Say the file where to write the received data + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)output_file); + res = curl_easy_perform(curl); - fclose(output_file); /* always cleanup */ curl_easy_cleanup(curl); + + fclose(output_file); } return res; #else @@ -105,7 +107,7 @@ int CurlHelper::RetrieveFileMulti(const std::vector<std::string>& listURLs, #ifdef OTB_USE_CURL #ifdef OTB_CURL_MULTI_AVAILABLE otbMsgDevMacro(<< "Using curl multi"); - std::string m_Browser = "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11"; + //std::string m_Browser = "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11"; CURLM * multiHandle; std::vector<CURL *> listCurlHandles; @@ -155,7 +157,8 @@ int CurlHelper::RetrieveFileMulti(const std::vector<std::string>& listURLs, // Param easy handle curl_easy_setopt(lEasyHandle, CURLOPT_USERAGENT, m_Browser.data()); curl_easy_setopt(lEasyHandle, CURLOPT_URL, (*url).data()); - curl_easy_setopt(lEasyHandle, CURLOPT_WRITEDATA, *file); + curl_easy_setopt(lEasyHandle, CURLOPT_WRITEFUNCTION, &Self::write_data); + curl_easy_setopt(lEasyHandle, CURLOPT_WRITEDATA, (void*)(*file)); // Add easy handle to multi handle curl_multi_add_handle(multiHandle, lEasyHandle); @@ -166,7 +169,7 @@ int CurlHelper::RetrieveFileMulti(const std::vector<std::string>& listURLs, ++file; } -//fetch tiles + //fetch tiles // Configure multi handle - set the maximum connections curl_multi_setopt(multiHandle, CURLMOPT_MAXCONNECTS, maxConnect); curl_multi_setopt(multiHandle, CURLMOPT_PIPELINING, 0); diff --git a/Code/IO/otbCurlHelper.h b/Code/IO/otbCurlHelper.h index e0ffa8d10ef7b5b2cdd8d53e349c08bec220e1df..1918566b982db897a8c72a0b632ca2656a09c4af 100644 --- a/Code/IO/otbCurlHelper.h +++ b/Code/IO/otbCurlHelper.h @@ -49,7 +49,10 @@ public: const std::vector<std::string>& listFiles, int maxConnect) const; protected: - CurlHelper() {} + CurlHelper() + { + m_Browser = "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11"; + } ~CurlHelper() {} @@ -61,7 +64,23 @@ private: { return nmemb; } + + // Need to use our writing function to handle windows segfaults + // Need to be static cause the CURL_OPT is excpecting a pure C + // function or a static c++ method. + static size_t write_data(void* ptr, size_t size, size_t nmemb, void* data) + { + size_t written; + + FILE * fDescriptor = (FILE *)(data); + + written = fwrite(ptr,size,nmemb,fDescriptor); + + return written; + } + // Browser Agent used + std::string m_Browser; }; } #endif diff --git a/Testing/Code/FeatureExtraction/CMakeLists.txt b/Testing/Code/FeatureExtraction/CMakeLists.txt index a60d28cf4b0c178918c8110c8213cb351dd200f6..f63642788d7263c0cd731ad4cf3319c0a5a2331b 100644 --- a/Testing/Code/FeatureExtraction/CMakeLists.txt +++ b/Testing/Code/FeatureExtraction/CMakeLists.txt @@ -1776,6 +1776,21 @@ ADD_TEST(feTvSqrtSpectralAngleImageFilter ${FEATUREEXTRACTION_TESTS15} 185 270 150 619 #reference pixel ) +# ------- otb::ScalarImageToTexturesFilter (Ossman)------------------------------ +ADD_TEST(feTuScalarImageToTexturesFilterNew ${FEATUREEXTRACTION_TESTS15} + otbScalarImageToTexturesfilterNew +) + +ADD_TEST(feTvScalarImageToTexturesFilter ${FEATUREEXTRACTION_TESTS15} + otbScalarImageToTexturesFilter + ${INPUTDATA}/Mire_Cosinus_500_500.png + ${TEMP}/feTvScalarImageToTexturesFilterOutput + 256 + 5 + 1 + 1 +) + # A enrichir SET(BasicFeatureExtraction_SRCS1 @@ -1955,6 +1970,8 @@ otbFeatureExtractionTests15.cxx otbImageToLineSegmentVectorDataNew.cxx otbImageToLineSegmentVectorData.cxx otbSqrtSpectralAngleImageFilter.cxx +otbScalarImageToTexturesFilterNew.cxx +otbScalarImageToTexturesFilter.cxx ) OTB_ADD_EXECUTABLE(otbFeatureExtractionTests1 "${BasicFeatureExtraction_SRCS1}" "OTBFeatureExtraction;OTBIO;OTBTesting") diff --git a/Testing/Code/FeatureExtraction/otbFeatureExtractionTests15.cxx b/Testing/Code/FeatureExtraction/otbFeatureExtractionTests15.cxx index adee6ddccb6b2e42b6e06b3dc21df6bb6ac5800d..0176e2601552b8b272de0b5abc1be23106099afe 100644 --- a/Testing/Code/FeatureExtraction/otbFeatureExtractionTests15.cxx +++ b/Testing/Code/FeatureExtraction/otbFeatureExtractionTests15.cxx @@ -29,4 +29,6 @@ void RegisterTests() REGISTER_TEST(otbImageToLineSegmentVectorDataNew); REGISTER_TEST(otbImageToLineSegmentVectorData); REGISTER_TEST(otbSqrtSpectralAngleImageFilter); + REGISTER_TEST(otbScalarImageToTexturesFilterNew); + REGISTER_TEST(otbScalarImageToTexturesFilter); } diff --git a/Testing/Code/FeatureExtraction/otbScalarImageToTexturesFilter.cxx b/Testing/Code/FeatureExtraction/otbScalarImageToTexturesFilter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..dadae54aef03e8216fb7cbf06d97dc1a92ae930a --- /dev/null +++ b/Testing/Code/FeatureExtraction/otbScalarImageToTexturesFilter.cxx @@ -0,0 +1,135 @@ +/*========================================================================= + + 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 "itkExceptionObject.h" + +#include "otbScalarImageToTexturesFilter.h" +#include "itkMinimumMaximumImageCalculator.h" +#include "otbImage.h" +#include "otbImageFileReader.h" +#include "otbImageFileWriter.h" +#include "otbStandardFilterWatcher.h" + +int otbScalarImageToTexturesFilter(int argc, char * argv[]) +{ + if(argc != 7) + { + std::cerr<<"Usage: "<<argv[0]<<" infname outprefix nbBins radius offsetx offsety"<<std::endl; + return EXIT_FAILURE; + } + const char * infname = argv[1]; + const char * outprefix = argv[2]; + const unsigned int nbBins = atoi(argv[3]); + const unsigned int radius = atoi(argv[4]); + const int offsetx = atoi(argv[5]); + const int offsety = atoi(argv[6]); + + const unsigned int Dimension = 2; + typedef float PixelType; + typedef otb::Image<PixelType, Dimension> ImageType; + typedef otb::ScalarImageToTexturesFilter + <ImageType,ImageType> TexturesFilterType; + typedef otb::ImageFileReader<ImageType> ReaderType; + typedef otb::ImageFileWriter<ImageType> WriterType; + typedef itk::MinimumMaximumImageCalculator + <ImageType> MinMaxCalculatorType; + + ReaderType::Pointer reader = ReaderType::New(); + TexturesFilterType::Pointer filter = TexturesFilterType::New(); + WriterType::Pointer writer = WriterType::New(); + + // Read image + reader->SetFileName(infname); + reader->Update(); + + // Build radius + TexturesFilterType::SizeType sradius; + sradius.Fill(radius); + + // Build offset + TexturesFilterType::OffsetType offset; + offset[0] = offsetx; + offset[1] = offsety; + + filter->SetInput(reader->GetOutput()); + filter->SetNumberOfBinsPerAxis(nbBins); + filter->SetRadius(sradius); + filter->SetOffset(offset); + + otb::StandardFilterWatcher watcher(filter,"Textures filter"); + + // Compute min/max + MinMaxCalculatorType::Pointer minMax = MinMaxCalculatorType::New(); + minMax->SetImage(reader->GetOutput()); + minMax->Compute(); + + filter->SetInputImageMinimum(minMax->GetMinimum()); + filter->SetInputImageMaximum(minMax->GetMaximum()); + filter->Update(); + + // Write outputs + itk::OStringStream oss; + + oss.str(""); + oss<<outprefix<<"Energy.tif"; + writer->SetInput(filter->GetEnergyOutput()); + writer->SetFileName(oss.str()); + + oss.str(""); + oss<<outprefix<<"Entropy.tif"; + writer->SetInput(filter->GetEntropyOutput()); + writer->SetFileName(oss.str()); + writer->Update(); + + oss.str(""); + oss<<outprefix<<"Correlation.tif"; + writer->SetInput(filter->GetCorrelationOutput()); + writer->SetFileName(oss.str()); + writer->Update(); + + oss.str(""); + oss<<outprefix<<"InverseDifferenceMoment.tif"; + writer->SetInput(filter->GetInverseDifferenceMomentOutput()); + writer->SetFileName(oss.str()); + writer->Update(); + + oss.str(""); + oss<<outprefix<<"Inertia.tif"; + writer->SetInput(filter->GetInertiaOutput()); + writer->SetFileName(oss.str()); + writer->Update(); + + oss.str(""); + oss<<outprefix<<"ClusterShade.tif"; + writer->SetInput(filter->GetClusterShadeOutput()); + writer->SetFileName(oss.str()); + writer->Update(); + + oss.str(""); + oss<<outprefix<<"ClusterProminence.tif"; + writer->SetInput(filter->GetClusterProminenceOutput()); + writer->SetFileName(oss.str()); + writer->Update(); + + oss.str(""); + oss<<outprefix<<"HaralickCorrelation.tif"; + writer->SetInput(filter->GetHaralickCorrelationOutput()); + writer->SetFileName(oss.str()); + writer->Update(); + + return EXIT_SUCCESS; +} diff --git a/Testing/Code/FeatureExtraction/otbScalarImageToTexturesFilterNew.cxx b/Testing/Code/FeatureExtraction/otbScalarImageToTexturesFilterNew.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0aefa067057358c0632ac42e3ae963f067abc438 --- /dev/null +++ b/Testing/Code/FeatureExtraction/otbScalarImageToTexturesFilterNew.cxx @@ -0,0 +1,33 @@ +/*========================================================================= + + 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 "itkExceptionObject.h" + +#include "otbScalarImageToTexturesFilter.h" +#include "otbImage.h" + +int otbScalarImageToTexturesFilterNew(int argc, char * argv[]) +{ + const unsigned int Dimension = 2; + typedef double PixelType; + typedef otb::Image<PixelType, Dimension> ImageType; + typedef otb::ScalarImageToTexturesFilter<ImageType,ImageType> FilterType; + + FilterType::Pointer filter = FilterType::New(); + + return EXIT_SUCCESS; +}