diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 4de89d4f93954d2fa444d36e90750c5440a97bc6..220370d9b4f894d0242dcaad87fdcc2bcd298917 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -103,3 +103,8 @@ OTB_CREATE_APPLICATION(NAME SARCorrelationRough SOURCES otbSARCorrelationRough.cxx LINK_LIBRARIES ${${otb-module}_LIBRARIES} ) + +OTB_CREATE_APPLICATION(NAME SARCorrelationPrecise + SOURCES otbSARCorrelationPrecise.cxx + LINK_LIBRARIES ${${otb-module}_LIBRARIES} +) diff --git a/app/otbSARCorrelationPrecise.cxx b/app/otbSARCorrelationPrecise.cxx new file mode 100644 index 0000000000000000000000000000000000000000..15a0a6fb91df5f8499778695f21b7d35acdc24fd --- /dev/null +++ b/app/otbSARCorrelationPrecise.cxx @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2005-2018 Centre National d'Etudes Spatiales (CNES) + * + * This file is part of Orfeo Toolbox + * + * https://www.orfeo-toolbox.org/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "otbWrapperApplication.h" +#include "otbWrapperApplicationFactory.h" + +#include "itkFFTNormalizedCorrelationImageFilter.h" +#include "itkMinimumMaximumImageCalculator.h" + +#include "otbSARTemporalCorrelationGridImageFilter.h" + +#include <iostream> +#include <string> +#include <fstream> + +namespace otb +{ +namespace Wrapper +{ + +class SARCorrelationPrecise : public Application +{ +public: + typedef SARCorrelationPrecise Self; + typedef itk::SmartPointer<Self> Pointer; + + itkNewMacro(Self); + itkTypeMacro(SARCorrelationPrecise, otb::Wrapper::Application); + + // Filters + typedef itk::FFTNormalizedCorrelationImageFilter<FloatImageType, FloatImageType> CorFilterType; + typedef itk::MinimumMaximumImageCalculator< FloatImageType> MinMaxCalculatorType; + typedef otb::SARTemporalCorrelationGridImageFilter<FloatImageType, FloatVectorImageType> CorGridFilterType; + + +private: + void DoInit() override + { + SetName("SARCorrelationPrecise"); + SetDescription("Computes SAR correlation shift (into temporal domain)."); + + SetDocLongDescription("This application computes correlation shifts between two images : " + "shift in range and shift in azimut. " + "The inputs of this application are MultiLooked images (real images)."); + + //Optional descriptors + SetDocLimitations("Only Sentinel 1 products and Cosmo are supported for now."); + SetDocAuthors("OTB-Team"); + SetDocSeeAlso(" "); + AddDocTag(Tags::SAR); + + //Parameter declarations + AddParameter(ParameterType_InputImage, "inmaster", "Input Master image (real image)"); + SetParameterDescription("inmaster", "Master Image (real image)."); + + AddParameter(ParameterType_InputImage, "inslave", "Input Slave image (real image)"); + SetParameterDescription("inslave", "Slave Image (real image)."); + + AddParameter(ParameterType_Int, "mlran", "MultiLook factor on distance"); + SetParameterDescription("mlran","MultiLook factor on distance."); + SetDefaultParameterInt("mlran", 3); + SetMinimumParameterIntValue("mlran", 1); + MandatoryOff("mlran"); + + AddParameter(ParameterType_Int, "mlazi", "MultiLook factor on azimut"); + SetParameterDescription("mlazi","MultiLook factor on azimut."); + SetDefaultParameterInt("mlazi", 3); + SetMinimumParameterIntValue("mlazi", 1); + MandatoryOff("mlazi"); + + AddParameter(ParameterType_Int, "gridsteprange", "Grid step for range dimension (into SLC/SAR geometry)"); + SetParameterDescription("gridsteprange","Grid step for range dimension (into SLC/SAR geometry)."); + SetDefaultParameterInt("gridsteprange", 150); + SetMinimumParameterIntValue("gridsteprange", 1); + MandatoryOff("gridsteprange"); + + AddParameter(ParameterType_Int, "gridstepazimut", "Grid step for azimut dimension (into SLC/SAR geometry)"); + SetParameterDescription("gridstepazimut","Grid step for azimut dimension (into SLC/SAR geometry)."); + SetDefaultParameterInt("gridstepazimut", 150); + SetMinimumParameterIntValue("gridstepazimut", 1); + MandatoryOff("gridstepazimut"); + + // Parameter Output + AddParameter(ParameterType_OutputImage, "out", "Output Correlation grid (Vector Image)"); + SetParameterDescription("out","Output Correlation Grid Vector Image (Shift_ran, Shift_azi, Correlation_rate)."); + + AddRAMParameter(); + + SetDocExampleParameterValue("inmaster","s1a-s4-slc-vv-20160818t014650-20160818t014715-012648-013db1-002_ML.tiff"); + SetDocExampleParameterValue("inslave","s1b-s4-slc-vv-20160929t014610-20160929t014634-002277-003d71-002_ML.tiff"); + SetDocExampleParameterValue("out", "out_CorrelationGrid.tiff"); + } + + void DoUpdateParameters() override + { +// Nothing to do here : all parameters are independent + } + +void DoExecute() override +{ + // Get numeric parameters + int factorML_azi = GetParameterInt("mlazi"); + int factorML_ran = GetParameterInt("mlran"); + int grid_step_azi = GetParameterInt("gridstepazimut"); + int grid_step_ran = GetParameterInt("gridsteprange"); + + // Log information + otbAppLogINFO(<<"ML Factor on azimut :"<<factorML_azi); + otbAppLogINFO(<<"ML Factor on range : "<<factorML_ran); + otbAppLogINFO(<<"Grid Step for range : "<<grid_step_ran); + otbAppLogINFO(<<"Grid Step for azimut : "<<grid_step_azi); + + // Get master and slave image + FloatImageType::Pointer MasterPtr = GetParameterFloatImage("inmaster"); + FloatImageType::Pointer SlavePtr = GetParameterFloatImage("inslave"); + + + // Correlation Filter + CorFilterType::Pointer correlationFilter = CorFilterType::New(); + m_Ref.push_back(correlationFilter.GetPointer()); + correlationFilter->SetFixedImage(MasterPtr); + correlationFilter->SetMovingImage(SlavePtr); + correlationFilter->Update(); + + // Min/Max calculator + MinMaxCalculatorType::Pointer minMaxFilter = MinMaxCalculatorType::New(); + minMaxFilter->SetImage(correlationFilter->GetOutput()); + minMaxFilter->ComputeMaximum(); + + float shiftSLC_range = ((correlationFilter->GetOutput()->GetLargestPossibleRegion().GetSize()[0]/2)- + minMaxFilter->GetIndexOfMaximum()[0]) * static_cast<float>(factorML_ran); + float shiftSLC_azimut = ((correlationFilter->GetOutput()->GetLargestPossibleRegion().GetSize()[1]/2) + -minMaxFilter->GetIndexOfMaximum()[1]) * static_cast<float>(factorML_azi); + + float shiftML_range = ((correlationFilter->GetOutput()->GetLargestPossibleRegion().GetSize()[0]/2)- + minMaxFilter->GetIndexOfMaximum()[0]); + float shiftML_azimut = ((correlationFilter->GetOutput()->GetLargestPossibleRegion().GetSize()[1]/2) + -minMaxFilter->GetIndexOfMaximum()[1]); + + // Correlation Grid Filter + CorGridFilterType::Pointer filterCorrelationGrid = CorGridFilterType::New(); + m_Ref.push_back(filterCorrelationGrid.GetPointer()); + + // Configure CorrelationGrid Filter + filterCorrelationGrid->SetMLran(factorML_ran); + filterCorrelationGrid->SetMLazi(factorML_azi); + filterCorrelationGrid->SetGridStep(grid_step_ran, grid_step_azi); + filterCorrelationGrid->SetRoughShift_ran(shiftML_range); + filterCorrelationGrid->SetRoughShift_azi(shiftML_azimut); + + //filterCorrelationGrid->SetRoughShift_ran(42); + //filterCorrelationGrid->SetRoughShift_azi(692); + + // Define the main pipeline + filterCorrelationGrid->SetMasterInput(MasterPtr); + filterCorrelationGrid->SetSlaveInput(SlavePtr); + SetParameterOutputImage("out", filterCorrelationGrid->GetOutput()); +} + // Vector for filters + std::vector<itk::ProcessObject::Pointer> m_Ref; +}; + + +} + +} + +OTB_APPLICATION_EXPORT(otb::Wrapper::SARCorrelationPrecise) diff --git a/app/otbSARCorrelationRough.cxx b/app/otbSARCorrelationRough.cxx index 1011102bb967cb7b0d2fa9a715dfc8819bda1358..644fb89ee3046a13344f4b8e425f620afdbd7e37 100644 --- a/app/otbSARCorrelationRough.cxx +++ b/app/otbSARCorrelationRough.cxx @@ -82,15 +82,25 @@ private: MandatoryOff("mlazi"); // Parameter Output - AddParameter(ParameterType_Float,"shiftran","rough shift in range dimension (output of this application)"); - SetParameterDescription("shiftran", "rough shift in range."); - SetParameterRole("shiftran", Role_Output); - SetDefaultParameterFloat("shiftran", 0); - - AddParameter(ParameterType_Float,"shiftazi","rough shift in azimut dimension (output of this application)"); - SetParameterDescription("shiftazi", "rough shift in azimut."); - SetParameterRole("shiftazi", Role_Output); - SetDefaultParameterFloat("shiftazi", 0); + AddParameter(ParameterType_Float,"shiftranslc","rough shift in range dimension into SLC geometry (output of this application)"); + SetParameterDescription("shiftranslc", "rough shift in range into SLC geometry."); + SetParameterRole("shiftranslc", Role_Output); + SetDefaultParameterFloat("shiftranslc", 0); + + AddParameter(ParameterType_Float,"shiftazislc","rough shift in azimut dimension into SLC geometry (output of this application)"); + SetParameterDescription("shiftazislc", "rough shift in azimut into SLC geometry ."); + SetParameterRole("shiftazislc", Role_Output); + SetDefaultParameterFloat("shiftazislc", 0); + + AddParameter(ParameterType_Float,"shiftranml","rough shift in range dimension into ML geometry (output of this application)"); + SetParameterDescription("shiftranml", "rough shift in range into ML geometry."); + SetParameterRole("shiftranml", Role_Output); + SetDefaultParameterFloat("shiftranml", 0); + + AddParameter(ParameterType_Float,"shiftaziml","rough shift in azimut dimension into ML geometry (output of this application)"); + SetParameterDescription("shiftaziml", "rough shift in azimut into ML geometry ."); + SetParameterRole("shiftaziml", Role_Output); + SetDefaultParameterFloat("shiftaziml", 0); AddRAMParameter(); @@ -130,14 +140,22 @@ void DoExecute() override minMaxFilter->SetImage(correlationFilter->GetOutput()); minMaxFilter->ComputeMaximum(); - float shift_range = ((correlationFilter->GetOutput()->GetLargestPossibleRegion().GetSize()[0]/2)- + float shiftSLC_range = ((correlationFilter->GetOutput()->GetLargestPossibleRegion().GetSize()[0]/2)- minMaxFilter->GetIndexOfMaximum()[0]) * static_cast<float>(factorML_ran); - float shift_azimut = ((correlationFilter->GetOutput()->GetLargestPossibleRegion().GetSize()[1]/2) + float shiftSLC_azimut = ((correlationFilter->GetOutput()->GetLargestPossibleRegion().GetSize()[1]/2) -minMaxFilter->GetIndexOfMaximum()[1]) * static_cast<float>(factorML_azi); + float shiftML_range = ((correlationFilter->GetOutput()->GetLargestPossibleRegion().GetSize()[0]/2)- + minMaxFilter->GetIndexOfMaximum()[0]); + float shiftML_azimut = ((correlationFilter->GetOutput()->GetLargestPossibleRegion().GetSize()[1]/2) + -minMaxFilter->GetIndexOfMaximum()[1]); + // Assigne Outputs - SetParameterFloat("shiftran", shift_range); - SetParameterFloat("shiftazi", shift_azimut); + SetParameterFloat("shiftranslc", shiftSLC_range); + SetParameterFloat("shiftazislc", shiftSLC_azimut); + + SetParameterFloat("shiftranml", shiftML_range); + SetParameterFloat("shiftaziml", shiftML_azimut); } // Vector for filters std::vector<itk::ProcessObject::Pointer> m_Ref; diff --git a/include/otbSARTemporalCorrelationGridImageFilter.h b/include/otbSARTemporalCorrelationGridImageFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..f0085955f9b0275bbd3fe18e986da48925cfb9c0 --- /dev/null +++ b/include/otbSARTemporalCorrelationGridImageFilter.h @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2005-2018 Centre National d'Etudes Spatiales (CNES) + * + * This file is part of Orfeo Toolbox + * + * https://www.orfeo-toolbox.org/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef otbSARTemporalCorrelationGridImageFilter_h +#define otbSARTemporalCorrelationGridImageFilter_h + +#include "itkImageToImageFilter.h" +#include "itkSmartPointer.h" +#include "itkPoint.h" + +#include "otbImageKeywordlist.h" +#include "otbGenericRSTransform.h" +#include "itkMinimumMaximumImageCalculator.h" +#include "itkStatisticsImageFilter.h" +#include "itkRescaleIntensityImageFilter.h" + +#include "itkFFTWCommon.h" + +namespace otb +{ + /** \class SARTemporalCorrelationGridImageFilter + * \brief Estimates a deformation grid between two images (master and slave) for the azimut and range + * dimension. A correlation rate is also calculated. The correlation is estimed into the temporal domain + * + * This filter performs the estimation of deformations between two images (the images are reals). + * + * \ingroup DiapOTBModule + */ + + template <typename TImageIn, typename TImageOut> class ITK_EXPORT SARTemporalCorrelationGridImageFilter : + public itk::ImageToImageFilter<TImageIn,TImageOut> + { + public: + + // Standard class typedefs + typedef SARTemporalCorrelationGridImageFilter Self; + typedef itk::ImageToImageFilter<TImageIn,TImageOut> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + // Method for creation through object factory + itkNewMacro(Self); + // Run-time type information + itkTypeMacro(SARCorrelationGridFilter,ImageToImageFilter); + + /** Typedef to image input type : otb::Image for master and slave images */ + typedef TImageIn ImageInType; + /** Typedef to describe the inout image pointer type. */ + typedef typename ImageInType::Pointer ImageInPointer; + typedef typename ImageInType::ConstPointer ImageInConstPointer; + /** Typedef to describe the inout image region type. */ + typedef typename ImageInType::RegionType ImageInRegionType; + /** Typedef to describe the type of pixel and point for inout image. */ + typedef typename ImageInType::PixelType ImageInPixelType; + typedef typename ImageInType::PointType ImageInPointType; + /** Typedef to describe the image index, size types and spacing for inout image. */ + typedef typename ImageInType::IndexType ImageInIndexType; + typedef typename ImageInType::IndexValueType ImageInIndexValueType; + typedef typename ImageInType::SizeType ImageInSizeType; + typedef typename ImageInType::SizeValueType ImageInSizeValueType; + typedef typename ImageInType::SpacingType ImageInSpacingType; + typedef typename ImageInType::SpacingValueType ImageInSpacingValueType; + + /** Typedef to image output type : otb::VectorImage with three components (range deformations, + azimut deformations and correlation rate) */ + typedef TImageOut ImageOutType; + /** Typedef to describe the output image pointer type. */ + typedef typename ImageOutType::Pointer ImageOutPointer; + typedef typename ImageOutType::ConstPointer ImageOutConstPointer; + /** Typedef to describe the output image region type. */ + typedef typename ImageOutType::RegionType ImageOutRegionType; + /** Typedef to describe the type of pixel and point for output image. */ + typedef typename ImageOutType::PixelType ImageOutPixelType; + typedef typename ImageOutType::PointType ImageOutPointType; + /** Typedef to describe the image index, size types and spacing for output image. */ + typedef typename ImageOutType::IndexType ImageOutIndexType; + typedef typename ImageOutType::IndexValueType ImageOutIndexValueType; + typedef typename ImageOutType::SizeType ImageOutSizeType; + typedef typename ImageOutType::SizeValueType ImageOutSizeValueType; + typedef typename ImageOutType::SpacingType ImageOutSpacingType; + typedef typename ImageOutType::SpacingValueType ImageOutSpacingValueType; + + + // Define Point2DType and Point3DType + using Point2DType = itk::Point<double,2>; + using Point3DType = itk::Point<double,3>; + + + // Define Filter used here (ie : RSTRansform from Master to Slave) + typedef typename itk::MinimumMaximumImageCalculator< ImageInType> MinMaxCalculatorType; + typedef typename itk::RescaleIntensityImageFilter< ImageInType, ImageInType > RescaleFilterType; + + // ITK proxy to the fftw library + typedef typename itk::fftw::Proxy<ImageInPixelType> FFTWProxyType; + typedef typename FFTWProxyType::ComplexType FFTProxyComplexType; + typedef typename FFTWProxyType::PixelType FFTProxyPixelType; + typedef typename FFTWProxyType::PlanType FFTProxyPlanType; + + // Setter/Getter + itkSetMacro(RoughShift_ran, int); + itkGetMacro(RoughShift_ran, int); + itkSetMacro(RoughShift_azi, int); + itkGetMacro(RoughShift_azi, int); + + /** Set/Get fine coherency threshold */ + itkSetMacro(CorrelationThreshold, double); + itkGetMacro(CorrelationThreshold, double); + + /** Set/Get unsigned int grid step */ + void SetGridStep(unsigned int stepRange, unsigned int stepAzimut) + { + m_GridStep[0] = stepRange; + m_GridStep[1] = stepAzimut; + } + unsigned int GetGridStepRange() + { + return m_GridStep[0]; + } + unsigned int GetGridStepAzimut() + { + return m_GridStep[1]; + } + /** Set/Get ML factors */ + itkSetMacro(MLran, unsigned int); + itkGetMacro(MLran, unsigned int); + itkSetMacro(MLazi, unsigned int); + itkGetMacro(MLazi, unsigned int); + + + // Setter/Getter for master and slave images (inputs) + /** Connect one of the operands for registration */ + void SetMasterInput( const ImageInType* image); + + /** Connect one of the operands for registration */ + void SetSlaveInput(const ImageInType* image); + + /** Get the inputs */ + const ImageInType * GetMasterInput() const; + const ImageInType * GetSlaveInput() const; + + protected: + // Constructor + SARTemporalCorrelationGridImageFilter(); + + // Destructor + virtual ~SARTemporalCorrelationGridImageFilter() ITK_OVERRIDE {}; + + // Print + void PrintSelf(std::ostream & os, itk::Indent indent) const ITK_OVERRIDE; + + /** SARTemporalCorrelationGridImageFilter produces an vector image to indicate the deformation for the two dimensions + * and the correlation rate. The differences between output and input images are the size of images and the + * dimensions. The input images a classic images and the output is a otb::VectorImage with three components. + * As such, SARTemporalCorrelationGridImageFilter needs to provide an implementation for + * GenerateOutputInformation() in order to inform the pipeline execution model. + */ + virtual void GenerateOutputInformation() ITK_OVERRIDE; + + /** SARTemporalCorrelationGridImageFilter needs input requested regions (for master and slave images) that + * corresponds to the projection into the requested region of the deformation grid (our output requested + * region). + * As such, SARQuadraticAveragingImageFilter needs to provide an implementation for + * GenerateInputRequestedRegion() in order to inform the pipeline execution model. + * \sa ProcessObject::GenerateInputRequestedRegion() */ + virtual void GenerateInputRequestedRegion() ITK_OVERRIDE; + + /** + * OutputRegionToInputRegion assigne master and slave regions + */ + void OutputRegionToInputRegion(const ImageOutRegionType& outputRegion) const; + + /** SARTemporalCorrelationGridImageFilter 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 ThreadedGenerateData(const ImageOutRegionType& outputRegionForThread, + itk::ThreadIdType threadId ) override; + + + private: + SARTemporalCorrelationGridImageFilter(const Self&); // purposely not implemented + void operator=(const Self &); // purposely not + + /** Function to interpolate the best interger shift */ + void PIC(float TAB_PIC[3][3], float *DX, float *DY, float *VAL_MAX, int *CR) const; + + inline double Correlation(const std::vector<double>& master, + const std::vector<double>& slave) const; + + inline double CorrelationDiapason(const std::vector<double>& master, + const std::vector<double>& slave) const; + + /** Coarse correlation threshold */ + double m_CorrelationThreshold; + + /** Grid step */ + ImageInSizeType m_GridStep; + + /** Grid step into ML geometry */ + ImageInSizeType m_GridStep_ML; + + /** ML factors (in range and in azimut) */ + unsigned int m_MLran; + unsigned int m_MLazi; + + /** Input rough shifts */ + int m_RoughShift_ran; + int m_RoughShift_azi; + + /** Search Window around rough shifts (into ML geometry) */ + int m_WinAround_ShiftRan; + int m_WinAround_ShiftAzi; + + /** Window size to estimate correlation */ + int m_WinCor_ran; + int m_WinCor_azi; + + // Extract Parameters + ImageInPointer * m_masterExtractPieceTab; + ImageInPointer * m_slaveExtractPieceTab; + + }; + +} // End namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbSARTemporalCorrelationGridImageFilter.txx" +#endif + + + +#endif diff --git a/include/otbSARTemporalCorrelationGridImageFilter.txx b/include/otbSARTemporalCorrelationGridImageFilter.txx new file mode 100644 index 0000000000000000000000000000000000000000..d51e18eda9176506f8526ee8ba5a70b2dc14b1e0 --- /dev/null +++ b/include/otbSARTemporalCorrelationGridImageFilter.txx @@ -0,0 +1,797 @@ +/* + * Copyright (C) 2005-2018 Centre National d'Etudes Spatiales (CNES) + * + * This file is part of Orfeo Toolbox + * + * https://www.orfeo-toolbox.org/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef otbSARTemporalCorrelationGridImageFilter_txx +#define otbSARTemporalCorrelationGridImageFilter_txx + +#include "otbSARTemporalCorrelationGridImageFilter.h" + +#include "itkImageScanlineConstIterator.h" +#include "itkImageRegionIterator.h" +#include "itkImageRegionConstIterator.h" +#include "itkImageScanlineIterator.h" +#include "itkProgressReporter.h" +#include "itkNumericTraitsPointPixel.h" +#include "itkContinuousIndex.h" + +#include "otbDEMHandler.h" + +#include "itkFFTWCommon.h" +#include "itkFFTWGlobalConfiguration.h" + +#include <cmath> + + +namespace otb +{ + /** + * Constructor with default initialization + */ + template <class TImageIn, class TImageOut> + SARTemporalCorrelationGridImageFilter< TImageIn ,TImageOut >::SARTemporalCorrelationGridImageFilter() + { + this->SetNumberOfRequiredInputs(2); + + // Default window sizes + m_WinAround_ShiftRan = 10; + m_WinAround_ShiftAzi = 20; + m_WinCor_ran = 10; + m_WinCor_azi = 10; + + // Default rough shits (0) + m_RoughShift_ran = 0; + m_RoughShift_azi = 0; + + // Grid Step + m_GridStep.Fill(1); + m_GridStep_ML.Fill(1); + + m_CorrelationThreshold = 0.3; + + m_MLran = 3; + m_MLazi = 3; + } + + /** + * Set Master Image + */ + template <class TImageIn, class TImageOut> + void + SARTemporalCorrelationGridImageFilter< TImageIn ,TImageOut > + ::SetMasterInput(const ImageInType* image ) + { + // Process object is not const-correct so the const casting is required. + this->SetNthInput(0, const_cast<ImageInType *>(image)); + } + + /** + * Set Slave Image + */ + template <class TImageIn, class TImageOut> + void + SARTemporalCorrelationGridImageFilter< TImageIn ,TImageOut > + ::SetSlaveInput(const ImageInType* image) + { + // Process object is not const-correct so the const casting is required. + this->SetNthInput(1, const_cast<ImageInType *>(image)); + } + + /** + * Get Master Image + */ + template <class TImageIn, class TImageOut> + const typename SARTemporalCorrelationGridImageFilter< TImageIn ,TImageOut>::ImageInType * + SARTemporalCorrelationGridImageFilter< TImageIn ,TImageOut > + ::GetMasterInput() const + { + if (this->GetNumberOfInputs()<1) + { + return 0; + } + return static_cast<const ImageInType *>(this->itk::ProcessObject::GetInput(0)); + } + + /** + * Get Slave Image + */ + template <class TImageIn, class TImageOut> + const typename SARTemporalCorrelationGridImageFilter< TImageIn ,TImageOut>::ImageInType * + SARTemporalCorrelationGridImageFilter< TImageIn ,TImageOut > + ::GetSlaveInput() const + { + if (this->GetNumberOfInputs()<2) + { + return 0; + } + return static_cast<const ImageInType *>(this->itk::ProcessObject::GetInput(1)); + } + + /** + * Print + */ + template<class TImageIn, class TImageOut> + void + SARTemporalCorrelationGridImageFilter< TImageIn, TImageOut > + ::PrintSelf(std::ostream & os, itk::Indent indent) const + { + Superclass::PrintSelf(os, indent); + + os << indent << "ML range factor : " << m_MLran << std::endl; + os << indent << "ML azimut factor : " << m_MLazi << std::endl; + os << indent << "Step for the grid : " << m_GridStep[0] << ", " << m_GridStep[1] << std::endl; + } + + /** + * Method GenerateOutputInformaton() + **/ + template<class TImageIn, class TImageOut> + void + SARTemporalCorrelationGridImageFilter< TImageIn, TImageOut > + ::GenerateOutputInformation() + { + // Call superclass implementation + Superclass::GenerateOutputInformation(); + + // Get pointers to the input and output + ImageInType * masterPtr = const_cast<ImageInType * >(this->GetMasterInput()); + ImageInType * slavePtr = const_cast<ImageInType * >(this->GetSlaveInput()); + ImageOutPointer outputPtr = this->GetOutput(); + + // Check GridSteps (must be a multiple of ML Factors) + if (m_GridStep[0] % m_MLran) + { + itkExceptionMacro(<<"GridSteps range mot a multiple of MLRan."); + } + if (m_GridStep[1] % m_MLazi) + { + itkExceptionMacro(<<"GridSteps azimut mot a multiple of MLAzi."); + } + + m_GridStep_ML[0] = m_GridStep[0]/m_MLran; + m_GridStep_ML[1] = m_GridStep[1]/m_MLazi; + + ///////// Checks (with input keywordlists/metadata) ///////////// + // Check ML Factors (inputs of this filter with Master and Slave metadata) + // Get Master and Slave Keywordlist + ImageKeywordlist masterKWL = masterPtr->GetImageKeywordlist(); + ImageKeywordlist slaveKWL = slavePtr->GetImageKeywordlist(); + + if (masterKWL.HasKey("support_data.ml_ran") && masterKWL.HasKey("support_data.ml_azi")) + { + // Get Master ML Factors + unsigned int master_MLRan = atoi(masterKWL.GetMetadataByKey("support_data.ml_ran").c_str()); + unsigned int master_MLAzi = atoi(masterKWL.GetMetadataByKey("support_data.ml_azi").c_str()); + + if (slaveKWL.HasKey("support_data.ml_ran") && slaveKWL.HasKey("support_data.ml_azi")) + { + // Get Slave ML Factors + unsigned int slave_MLRan = atoi(slaveKWL.GetMetadataByKey("support_data.ml_ran").c_str()); + unsigned int slave_MLAzi = atoi(slaveKWL.GetMetadataByKey("support_data.ml_azi").c_str()); + + if ((slave_MLRan != master_MLRan) || (slave_MLAzi != master_MLAzi)) + { + itkExceptionMacro(<<"ML Factor betwwen master and slave are different."); + } + } + + if ((master_MLRan != m_MLran) || (master_MLAzi != m_MLazi)) + { + itkExceptionMacro(<<"ML Factor betwwen master and inputs of this application are different."); + } + } + else + { + if (slaveKWL.HasKey("support_data.ml_ran") && slaveKWL.HasKey("support_data.ml_azi")) + { + // Get Slave ML Factors + unsigned int slave_MLRan = atoi(slaveKWL.GetMetadataByKey("support_data.ml_ran").c_str()); + unsigned int slave_MLAzi = atoi(slaveKWL.GetMetadataByKey("support_data.ml_azi").c_str()); + + if ((slave_MLRan != m_MLran) || (slave_MLAzi != m_MLazi)) + { + itkExceptionMacro(<<"ML Factor betwwen slave and inputs of this application are different."); + } + } + } + + // Set the number of Components for the Output VectorImage + // 3 Components : + // _ range shift between Master and Slave + // _ azimut shift between Master and Slave + // _ correlation rate + outputPtr->SetNumberOfComponentsPerPixel(3); + + // Update size and spacing according to grid step + ImageOutRegionType largestRegion = static_cast<ImageOutRegionType>(masterPtr->GetLargestPossibleRegion()); + ImageOutSizeType outputSize = static_cast<ImageOutSizeType>(largestRegion.GetSize()); + ImageOutSpacingType outputSpacing = static_cast<ImageOutSpacingType>(masterPtr->GetSpacing()); + ImageOutPointType outputOrigin = static_cast<ImageOutPointType>(masterPtr->GetOrigin()); + + // First/Last Colunm and row + int firstC = std::max (1 + m_WinCor_ran, 1 + m_WinCor_ran - m_RoughShift_ran + m_WinAround_ShiftRan); + int firstL = std::max (1 + m_WinCor_azi, 1 + m_WinCor_azi - m_RoughShift_azi + m_WinAround_ShiftAzi); + int lastC = std::min(slavePtr->GetLargestPossibleRegion().GetSize()[0] - m_RoughShift_ran - + m_WinAround_ShiftRan - m_WinCor_ran, masterPtr->GetLargestPossibleRegion().GetSize()[0] + - m_WinCor_ran); + int lastL = std::min(slavePtr->GetLargestPossibleRegion().GetSize()[1] - m_RoughShift_azi - + m_WinAround_ShiftAzi- m_WinCor_azi, masterPtr->GetLargestPossibleRegion().GetSize()[1] + - m_WinCor_azi); + + outputSize[0]= lastC - firstC + 1; + outputSize[1] = lastL - firstL + 1; + + + for(unsigned int dim = 0; dim < ImageOutType::ImageDimension; ++dim) + { + outputSize[dim] = (outputSize[dim] - outputSize[dim]%m_GridStep_ML[dim]) / m_GridStep_ML[dim]; + outputSpacing[dim] *= m_GridStep_ML[dim]; + } + + // Set spacing + outputPtr->SetSpacing(outputSpacing); + + // Set origin + outputPtr->SetOrigin(outputOrigin); + + // Set largest region size + largestRegion.SetSize(outputSize); + outputPtr->SetLargestPossibleRegion(largestRegion); + + // Add GridSteps into KeyWordList + ImageKeywordlist outputKWL; + outputKWL.AddKey("support_data.gridstep.range", std::to_string(m_GridStep[0])); + outputKWL.AddKey("support_data.gridstep.azimut", std::to_string(m_GridStep[1])); + + outputPtr->SetImageKeywordList(outputKWL); + } + + /** + * Method OutputRegionToInputRegion for GenerateInputRequestedRegion + */ + template<class TImageIn, class TImageOut> + void + SARTemporalCorrelationGridImageFilter< TImageIn, TImageOut > + ::OutputRegionToInputRegion(const ImageOutRegionType& outputRegion) const + { + // Get pointers to inputs + ImageInType * masterPtr = const_cast<ImageInType * >(GetMasterInput()); + ImageInType * slavePtr = const_cast<ImageInType * >(GetSlaveInput()); + + int nbColSlave = slavePtr->GetLargestPossibleRegion().GetSize()[0]; + int nbLinesSlave = slavePtr->GetLargestPossibleRegion().GetSize()[1]; + + /////////////////////// Requested region for master //////////////////// + // Correlation grid is bonded to the master image => should represent with the + // m_Grid_step the output requested region + // get a copy of the master requested region (should equal the output + // requested region) + ImageInRegionType masterRequestedRegion, slaveRequestedRegion; + masterRequestedRegion = outputRegion; + + // Apply grid step + ImageInSizeType masterRequestedSize = masterRequestedRegion.GetSize(); + ImageInIndexType masterRequestedIndex = masterRequestedRegion.GetIndex(); + + for(unsigned int dim = 0; dim < ImageOutType::ImageDimension; ++dim) + { + masterRequestedSize [dim] *= m_GridStep_ML[dim]; + masterRequestedIndex[dim] *= m_GridStep_ML[dim]; + } + + int firstC_Grid = std::max (1 + m_WinCor_ran, 1 + m_WinCor_ran - m_RoughShift_ran + m_WinAround_ShiftRan); + int firstL_Grid = std::max (1 + m_WinCor_azi, 1 + m_WinCor_azi - m_RoughShift_azi + m_WinAround_ShiftAzi); + + // With correlation window and first row/colunm + masterRequestedIndex[0] -= (m_WinCor_ran - firstC_Grid); + masterRequestedIndex[1] -= (m_WinCor_azi - firstL_Grid); + masterRequestedSize[0] += (2*m_WinCor_ran+1) + firstC_Grid; + masterRequestedSize[1] += (2*m_WinCor_azi+1) + firstL_Grid; + + masterRequestedRegion.SetSize(masterRequestedSize); + masterRequestedRegion.SetIndex(masterRequestedIndex); + + masterPtr->SetRequestedRegion(masterRequestedRegion); + + // Crop the fixed region at the fixed's largest possible region (or buffered) + if ( masterRequestedRegion.Crop(masterPtr->GetLargestPossibleRegion())) + { + masterPtr->SetRequestedRegion( masterRequestedRegion ); + } + else + { + // Couldn't crop the region (requested region is outside the largest + // possible region). Throw an exception. + // store what we tried to request (prior to trying to crop) + masterPtr->SetRequestedRegion( masterRequestedRegion ); + + // Build an exception + itk::InvalidRequestedRegionError e(__FILE__, __LINE__); + std::ostringstream msg; + msg << this->GetNameOfClass() + << "::GenerateInputRequestedRegion()"; + e.SetLocation(msg.str().c_str()); + e.SetDescription("Requested region is (at least partially) outside the largest possible region of image 1."); + e.SetDataObject(masterPtr); + throw e; + } + + //////////////////// Requested region for slave //////////////////// + int firstL, firstC, lastL, lastC; + // Transform back into slave region index space with an maximum shift between master and slave + ImageInIndexType slaveIndex; + + // Find requested region + ImageInSizeType slaveSize; + + // Set the max_shift (margin) + firstL = masterRequestedIndex[1] - m_RoughShift_azi - m_WinAround_ShiftAzi - m_WinCor_azi; + firstC = masterRequestedIndex[0] - m_RoughShift_ran - m_WinAround_ShiftRan - m_WinCor_ran; + lastL = masterRequestedIndex[1] + masterRequestedSize[1] + m_RoughShift_azi + m_WinAround_ShiftAzi + + m_WinCor_azi; + lastC = masterRequestedIndex[0] + masterRequestedSize[0] + m_RoughShift_ran + m_WinAround_ShiftRan + m_WinCor_ran; + + // Check the limits + if (firstC < 0) + { + firstC = 0; + } + if (firstL < 0) + { + firstL = 0; + } + if (lastC > nbColSlave-1) + { + lastC = nbColSlave-1; + } + if (lastL > nbLinesSlave-1) + { + lastL = nbLinesSlave-1; + } + + + slaveIndex[0] = static_cast<ImageInIndexValueType>(firstC); + slaveIndex[1] = static_cast<ImageInIndexValueType>(firstL); + slaveSize[0] = static_cast<ImageInIndexValueType>(lastC - firstC)+1; + slaveSize[1] = static_cast<ImageInIndexValueType>(lastL - firstL)+1; + + slaveRequestedRegion.SetIndex(slaveIndex); + slaveRequestedRegion.SetSize(slaveSize); + + // crop the moving region at the moving's largest possible region + if ( slaveRequestedRegion.Crop(slavePtr->GetLargestPossibleRegion())) + { + slavePtr->SetRequestedRegion( slaveRequestedRegion ); + } + else + { + // Couldn't crop the region (requested region is outside the largest + // possible region). This case might happen so we do not throw any exception but + // request a null region instead + slaveSize.Fill(0); + slaveRequestedRegion.SetSize(slaveSize); + slaveIndex.Fill(0); + slaveRequestedRegion.SetIndex(slaveIndex); + + // store what we tried to request (prior to trying to crop) + slavePtr->SetRequestedRegion(slaveRequestedRegion); + } + } + + + /** + * Method GenerateInputRequestedRegion + */ + template<class TImageIn, class TImageOut> + void + SARTemporalCorrelationGridImageFilter< TImageIn, TImageOut > + ::GenerateInputRequestedRegion() + { + // Call the superclass' implementation of this method + Superclass::GenerateInputRequestedRegion(); + + ImageOutRegionType outputRequestedRegion = this->GetOutput()->GetRequestedRegion(); + this->OutputRegionToInputRegion(outputRequestedRegion); + } + + + /** + * Method BeforeThreadedGenerateData + */ + template<class TImageIn, class TImageOut> + void + SARTemporalCorrelationGridImageFilter< TImageIn, TImageOut > + ::ThreadedGenerateData(const ImageOutRegionType& outputRegionForThread, + itk::ThreadIdType threadId) + { + // Get pointers to inputs + const ImageInType * masterPtr = this->GetMasterInput(); + const ImageInType * slavePtr = this->GetSlaveInput(); + + // Typedef for iterators + typedef itk::ImageScanlineIterator< ImageOutType > OutputIterator; + typedef itk::ImageRegionConstIterator<ImageInType> MasterSlaveIt; + typedef itk::ImageRegionIterator<ImageInType> ExtractIt; + + // Iterator on output (Grid geometry) + OutputIterator OutIt(this->GetOutput(), outputRegionForThread); + OutIt.GoToBegin(); + + ImageOutPixelType pixelCorrelationGrid; + pixelCorrelationGrid.Reserve(3); + + // Support progress methods/callbacks + itk::ProgressReporter progress(this, threadId, this->GetOutput()->GetRequestedRegion().GetNumberOfPixels()); + + int nbColSlave = slavePtr->GetLargestPossibleRegion().GetSize()[0]; + int nbLinesSlave = slavePtr->GetLargestPossibleRegion().GetSize()[1]; + + // Array to store correlation rate for each pixel and each shift + double arrayRate [2*m_WinAround_ShiftAzi+1][2*m_WinAround_ShiftRan+1]; + float arrayPic[3][3]; + + float dx, dy, VAL_MAX; + int checkInterpolation; + + // Size for correlation estimation + ImageInSizeType masterSize; + masterSize[0] = 2*m_WinCor_ran+1; + masterSize[1] = 2*m_WinCor_azi+1; + + ImageInSizeType slaveSize; + slaveSize[0] = 2*m_WinCor_ran+1; + slaveSize[1] = 2*m_WinCor_azi+1; + + // vector master and slave + std::vector<double> master; + std::vector<double> slave; + + // First L/C for the grid + int firstC = std::max (1 + m_WinCor_ran, 1 + m_WinCor_ran - m_RoughShift_ran + m_WinAround_ShiftRan); + int firstL = std::max (1 + m_WinCor_azi, 1 + m_WinCor_azi - m_RoughShift_azi + m_WinAround_ShiftAzi); + + + // For each line of output + while ( !OutIt.IsAtEnd()) + { + OutIt.GoToBeginOfLine(); + + // For each colunm of the grid + while (!OutIt.IsAtEndOfLine()) + { + // Get index + ImageInIndexType masterIndex; + + for(unsigned int dim = 0; dim < ImageInType::ImageDimension; ++dim) + { + masterIndex[dim] = OutIt.GetIndex()[dim] * m_GridStep_ML[dim]; // Grid geometry + } + + // To center correlation estimation and shift to the first L/C + masterIndex[0] -= (m_WinCor_ran-firstC); + masterIndex[1] -= (m_WinCor_azi-firstL); + + // Build the master region (for correlation estimation) + ImageInRegionType masterCurrentRegion; + masterCurrentRegion.SetIndex(masterIndex); + masterCurrentRegion.SetSize(masterSize); + masterCurrentRegion.Crop(masterPtr->GetLargestPossibleRegion()); + + // Iterators on master Ptr + MasterSlaveIt masterIt(masterPtr, masterCurrentRegion); + masterIt.GoToBegin(); + + + // Fill master patch + master.clear(); + while( !masterIt.IsAtEnd()) + { + // Add to the master vector + double value = masterIt.Get(); + master.push_back(value); + + ++masterIt; + } + + // Best integer shifts and correlation rate + int bestShift_ran = 0; + int bestShift_azi = 0; + double bestRate = 0; + + // Loop on shift around rough ones + for (int l = -m_WinAround_ShiftAzi; l <= m_WinAround_ShiftAzi; l++) + { + for (int c = -m_WinAround_ShiftRan; c <= m_WinAround_ShiftRan; c++) + { + // Find slave index for current shifts + ImageInIndexType slaveIndex; + slaveIndex[0] = masterIndex[0] + c + m_RoughShift_ran; + slaveIndex[1] = masterIndex[1] + l + m_RoughShift_azi; + //slaveIndex[0] = masterIndex[0]; + //slaveIndex[1] = masterIndex[1]; + + // Check Index + if (slaveIndex[0] < 0) + { + slaveIndex[0] = 0; + } + if (slaveIndex[1] < 0) + { + slaveIndex[1] = 0; + } + if (slaveIndex[0] > (nbColSlave-(2*m_WinCor_ran))) + { + slaveIndex[0] = nbColSlave-2*m_WinCor_ran; + } + if (slaveIndex[1] > (nbLinesSlave-(2*m_WinCor_azi))) + { + slaveIndex[1] = nbLinesSlave-2*m_WinCor_azi; + } + + + // Build the slave region (for correlation estimation) + ImageInRegionType slaveCurrentRegion; + slaveCurrentRegion.SetIndex(slaveIndex); + slaveCurrentRegion.SetSize(slaveSize); + slaveCurrentRegion.Crop(slavePtr->GetLargestPossibleRegion()); + + // Iterators on slave Ptr + MasterSlaveIt slaveIt(slavePtr, slaveCurrentRegion); + slaveIt.GoToBegin(); + + // Fill slave patch + slave.clear(); + while (!slaveIt.IsAtEnd()) + { + // Add to the slave vector + double value = slaveIt.Get(); + slave.push_back(value); + + ++slaveIt; + } + + //arrayRate[l][c] = Correlation(master, slave); + + arrayRate[l + m_WinAround_ShiftAzi][c + m_WinAround_ShiftRan] = + CorrelationDiapason(master, slave); + + if (arrayRate[l+ m_WinAround_ShiftAzi][c+ m_WinAround_ShiftRan] > bestRate) + { + bestRate = arrayRate[l + m_WinAround_ShiftAzi][c + m_WinAround_ShiftRan]; + bestShift_ran = c; + bestShift_azi = l; + } + } + } + + + // Function PIC on the best shifts (interpolation) + if ((std::abs(bestShift_ran) < m_WinAround_ShiftRan) && + (std::abs(bestShift_azi) < m_WinAround_ShiftAzi) && + (bestRate >= m_CorrelationThreshold)) + { + // Built array_pic + for (int k=-1;k<2;k++) + for (int j=-1;j<2;j++) + arrayPic[k+1][j+1] = static_cast<float>(arrayRate[bestShift_azi + k + m_WinAround_ShiftAzi] + [bestShift_ran + j + m_WinAround_ShiftRan]); + + // Launch interpolation + PIC(arrayPic, &dx, &dy, &VAL_MAX, &checkInterpolation); + + pixelCorrelationGrid[0] = m_RoughShift_ran + bestShift_ran + dx; + pixelCorrelationGrid[1] = m_RoughShift_azi + bestShift_azi + dy; + pixelCorrelationGrid[2] = VAL_MAX; + + //std::cout << arrayPic[1][1] << " at " << bestShift_ran << " , " << bestShift_azi << std::endl; + + } + else + { + pixelCorrelationGrid[0] = m_RoughShift_ran + bestShift_ran; + pixelCorrelationGrid[1] = m_RoughShift_azi + bestShift_azi; + pixelCorrelationGrid[2] = 0; + } + + + // Correlation into SLC geometry and not ML geometry + pixelCorrelationGrid[0] *= m_MLran; + pixelCorrelationGrid[1] *= m_MLazi; + + // Assign Output + OutIt.Set(pixelCorrelationGrid); + progress.CompletedPixel(); + + // Next Colunm for output + ++OutIt; + } + + // Next Line for output + OutIt.NextLine(); + } + } + + + /** + * Method PIC + */ + template<class TImageIn, class TImageOut> + void + SARTemporalCorrelationGridImageFilter< TImageIn, TImageOut > + ::PIC(float TAB_PIC[3][3], float *DX, float *DY, float *VAL_MAX, int *CR) const + { + float TAB_COS[3]= {-0.5,1.,-0.5}; + float TAB_SIN[3]= {-0.8660254,0.,+0.8660254}; + float SXF,SYF,SF,N,A1,B1,SDXF,SDYF,A2,B2; + float AX, AY; + int i, j; + + // The method of least squares in cosinus + *CR = 1; + SF = 0.; + SXF = 0.; + SYF = 0.; + + for (i=-1;i<2;i++) + { + for (j=-1;j<2;j++) + { + SF = SF + TAB_PIC[i+1][j+1]; + SXF = SXF + TAB_PIC[i+1][j+1]*TAB_COS[j+1]; + SYF = SYF + TAB_PIC[i+1][j+1]*TAB_COS[i+1]; + } + } + + N = SF / 9.; + A1 = SXF/ 4.5; + B1 = SYF/ 4.5; + + // The method of least squares in sinus + SDXF = 0.; + SDYF = 0.; + + for (i=-1;i<2;i++) + { + for (j=-1;j<2;j++) + { + SDXF = SDXF + TAB_PIC[i+1][j+1]*TAB_SIN[j+1]; + SDYF = SDYF + TAB_PIC[i+1][j+1]*TAB_SIN[i+1]; + } + } + + A2 = SDXF/3.; // 4*.75 + B2 = SDYF/3.; // 4*.75 + + A2 = A2/1.5; + B2 = B2/1.5; + + // Max + AX = std::sqrt (A1*A1+A2*A2); + AY = std::sqrt (B1*B1+B2*B2); + + if (AX*AY == 0.) + { + *VAL_MAX = -1.; + *DX = 0.; + *DY = 0.; + return; + } + + *DX = std::atan2 (A2,A1) /(2*M_PI/3.); + *DY = std::atan2 (B2,B1) /(2*M_PI/3.); + + *VAL_MAX = N + (AX + AY)* 0.5; + *VAL_MAX = std::max(*VAL_MAX,TAB_PIC[1][1]); + *VAL_MAX = std::min(static_cast<float>(1.),*VAL_MAX); + + // Check values + if ((fabs((double)*DX)>.75) || (fabs((double)*DY)>.75)) + { + *VAL_MAX = -3.; + *DX = 0.; + *DY = 0.; + } + + return; + + } + + template<class TImageIn, class TImageOut> + double + SARTemporalCorrelationGridImageFilter< TImageIn, TImageOut > + ::Correlation(const std::vector<double>& master, const std::vector<double>& slave) const + { + double meanSlave = 0; + double meanMaster = 0; + double correlationValue = 0; + + // Compute means + for(unsigned int i = 0; i < master.size(); ++i) + { + meanSlave += slave[i]; + meanMaster += master[i]; + } + meanSlave /= slave.size(); + meanMaster /= master.size(); + + double crossProd = 0.; + double squareSumMaster = 0.; + double squareSumSlave = 0.; + + + // Compute correlation + for(unsigned int i = 0; i < master.size(); ++i) + { + crossProd += (slave[i]-meanSlave) * (master[i]-meanMaster); + squareSumSlave += (slave[i]-meanSlave) * (slave[i]-meanSlave); + squareSumMaster += (master[i]-meanMaster) * (master[i]-meanMaster); + } + + correlationValue = std::abs(crossProd/(std::sqrt(squareSumSlave)*std::sqrt(squareSumMaster))); + + return correlationValue; + } + + template<class TImageIn, class TImageOut> + double + SARTemporalCorrelationGridImageFilter< TImageIn, TImageOut > + ::CorrelationDiapason(const std::vector<double>& master, const std::vector<double>& slave) const + { + double sumSlave = 0; + double sumMaster = 0; + double sumMasterSlave = 0; + double sumSlaveSquare = 0; + double sumMasterSquare = 0; + + double correlationValue = 0; + + // Compute sum, sum square and cross prod + for(unsigned int i = 0; i < master.size(); ++i) + { + sumSlave += slave[i]; + sumMaster += master[i]; + sumMasterSlave += slave[i]*master[i]; + sumSlaveSquare += slave[i]*slave[i]; + sumMasterSquare += master[i]*master[i]; + } + + // Compute means + double meanMaster = sumMaster/master.size(); + double meanSlave = sumSlave/slave.size(); + + // Compute sigma and covariance + double sigmaMaster = sumMasterSquare/master.size() - (meanMaster*meanMaster); + double sigmaSlave = sumSlaveSquare/slave.size() - (meanSlave*meanSlave); + double covariance = sumMasterSlave/master.size(); + + + + if (sigmaMaster > 0 && sigmaSlave > 0) + { + correlationValue = (covariance - (meanMaster*meanSlave))/(std::sqrt(sigmaMaster*sigmaSlave)); + } + + return correlationValue; + } + + + +} /*namespace otb*/ + +#endif