From 2bd206e2c57b3a36f9773e6837fce79f17310215 Mon Sep 17 00:00:00 2001 From: Guillaume Borrut <guillaume.borrut@c-s.fr> Date: Wed, 13 Aug 2008 08:24:25 +0000 Subject: [PATCH] Ajout des tests de syntheses de polarimetrie --- ...MultiChannelsPolarimetricSynthesisFilter.h | 194 +++++++++ ...ltiChannelsPolarimetricSynthesisFilter.txx | 403 ++++++++++++++++++ 2 files changed, 597 insertions(+) create mode 100755 Code/SARPolarimetry/otbMultiChannelsPolarimetricSynthesisFilter.h create mode 100755 Code/SARPolarimetry/otbMultiChannelsPolarimetricSynthesisFilter.txx diff --git a/Code/SARPolarimetry/otbMultiChannelsPolarimetricSynthesisFilter.h b/Code/SARPolarimetry/otbMultiChannelsPolarimetricSynthesisFilter.h new file mode 100755 index 0000000000..a8bda74e37 --- /dev/null +++ b/Code/SARPolarimetry/otbMultiChannelsPolarimetricSynthesisFilter.h @@ -0,0 +1,194 @@ +/*========================================================================= + + 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 __otbMultiChannelsPolarimetricSynthesisFilter_h +#define __otbMultiChannelsPolarimetricSynthesisFilter_h + +#include "itkInPlaceImageFilter.h" +#include "otbPolarimetricFunctor.h" +#include "itkFixedArray.h" +#include <complex> + +namespace otb +{ + +/** \class MultiChannelsPolarimetricSynthesisFilter + * \brief Implements + * + * This class is parameterized over the type of the input image and + * the type of the output image. It is also parameterized by the + * operation to be applied, using a Functor style. + * + */ + + +template <class TInputImage, class TOutputImage, + class TFunction = Functor::PolarimetricFunctor< + typename TInputImage::InternalPixelType, + typename TInputImage::InternalPixelType, + typename TInputImage::InternalPixelType, + typename TInputImage::InternalPixelType, + typename TOutputImage::PixelType> > +class ITK_EXPORT MultiChannelsPolarimetricSynthesisFilter : public itk::InPlaceImageFilter<TInputImage,TOutputImage> +{ +public: + /** Standard class typedefs. */ + typedef MultiChannelsPolarimetricSynthesisFilter Self; + typedef itk::InPlaceImageFilter<TInputImage,TOutputImage> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(MultiChannelsPolarimetricSynthesisFilter, InPlaceImageFilter); + + /** Some typedefs. */ + typedef TFunction FunctorType; + typedef TInputImage InputImageType; + typedef typename InputImageType::ConstPointer InputImagePointer; + typedef typename InputImageType::RegionType InputImageRegionType; + typedef typename InputImageType::PixelType InputImagePixelType; + typedef TOutputImage OutputImageType; + typedef typename OutputImageType::Pointer OutputImagePointer; + typedef typename OutputImageType::RegionType OutputImageRegionType; + typedef typename OutputImageType::PixelType OutputImagePixelType; + typedef typename std::complex <double> ComplexType; + typedef typename itk::FixedArray<ComplexType,2> ComplexArrayType; + + /** Get the functor object. The functor is returned by reference. + * (Functors do not have to derive from itk::LightObject, so they do + * not necessarily have a reference count. So we cannot return a + * SmartPointer.) */ + FunctorType& GetFunctor() { return m_Functor; }; + const FunctorType& GetFunctor() const { return m_Functor; }; + + + /** Set the functor object. This replaces the current Functor with a + * copy of the specified Functor. This allows the user to specify a + * functor that has ivars set differently than the default functor. + * This method requires an operator!=() be defined on the functor + * (or the compiler's default implementation of operator!=() being + * appropriate). */ + void SetFunctor(const FunctorType& functor) + { + if (m_Functor != functor) + { + m_Functor = functor; + this->Modified(); + } + } + + void SetEi(ComplexArrayType ei) + { + m_Ei = ei; + this->GetFunctor().SetEi(ei); + this->Modified(); + } + + void SetEr(ComplexArrayType er) + { + m_Er = er; + this->GetFunctor().SetEr(er); + this->Modified(); + } + + /** Set/Get PsiI */ + itkSetMacro(PsiI,double); + itkGetMacro(PsiI,double); + /** Set/Get TauI */ + itkSetMacro(TauI,double); + itkGetMacro(TauI,double); + /** Set/Get PsiR */ + itkSetMacro(PsiR,double); + itkGetMacro(PsiR,double); + /** Set/Get TauR */ + itkSetMacro(TauR,double); + itkGetMacro(TauR,double); + + +protected: + MultiChannelsPolarimetricSynthesisFilter(); + virtual ~MultiChannelsPolarimetricSynthesisFilter(){}; + + /** MultiChannelsPolarimetricSynthesisFilter can produce an image which is a different + * resolution than its input image. As such, MultiChannelsPolarimetricSynthesisFilter + * needs to provide an implementation for + * GenerateOutputInformation() in order to inform the pipeline + * execution model. The original documentation of this method is + * below. + * + * \sa ProcessObject::GenerateOutputInformaton() */ + virtual void GenerateOutputInformation(); + + virtual void BeforeThreadedGenerateData(); + + /** MultiChannelsPolarimetricSynthesisFilter 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 OutputImageRegionType& outputRegionForThread, + int threadId ); + + /** Computation of the electromagnetic fields Ei Er */ + void ComputeElectromagneticFields(); + + /** Verify and force the inputs, if only 2 or 3 channels are present */ + void VerifyAndForceInputs(); + + void PrintSelf(std::ostream& os, itk::Indent indent) const; + +private : + MultiChannelsPolarimetricSynthesisFilter(const Self&); //purposely not implemented + + /** Psi Incident */ + double m_PsiI; + /** Tau Incident */ + double m_TauI; + /** Psi Relechi */ + double m_PsiR; + /** Tau Relechi */ + double m_TauR; + + /** Champs Electromagnetic Incident */ + ComplexArrayType m_Ei; + /** Champs Electromagnetic Reflechi */ + ComplexArrayType m_Er; + + /** Conversion coefficient Degre To Radian */ + static const double m_DTOR=M_PI/180; + + /** Channel indexes 0 1 2 3 on verra */ + + FunctorType m_Functor; + +}; + +} // end namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbMultiChannelsPolarimetricSynthesisFilter.txx" +#endif + +#endif diff --git a/Code/SARPolarimetry/otbMultiChannelsPolarimetricSynthesisFilter.txx b/Code/SARPolarimetry/otbMultiChannelsPolarimetricSynthesisFilter.txx new file mode 100755 index 0000000000..4bb4242456 --- /dev/null +++ b/Code/SARPolarimetry/otbMultiChannelsPolarimetricSynthesisFilter.txx @@ -0,0 +1,403 @@ +/*========================================================================= + + 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 __otbMultiChannelsPolarimetricSynthesisFilter_txx +#define __otbMultiChannelsPolarimetricSynthesisFilter_txx + +#include "otbMultiChannelsPolarimetricSynthesisFilter.h" +#include "itkImageRegionIterator.h" +#include "itkImageRegionConstIterator.h" +#include "itkProgressReporter.h" +#include <complex> + +namespace otb +{ + +/** + * Constructor + */ +template <class TInputImage, class TOutputImage, class TFunction > +MultiChannelsPolarimetricSynthesisFilter<TInputImage,TOutputImage,TFunction> +::MultiChannelsPolarimetricSynthesisFilter() +{ + this->SetNumberOfRequiredInputs( 1 ); + //this->InPlaceOff(); +} + + /** PolarimetricSynthesisFilter + * + * + * \sa ProcessObject::GenerateOutputInformaton() + */ +template <class TInputImage, class TOutputImage, class TFunction> +void +MultiChannelsPolarimetricSynthesisFilter<TInputImage,TOutputImage,TFunction> +::GenerateOutputInformation() +{ + // do not call the superclass' implementation of this method since + // this filter allows the input the output to be of different dimensions + + // get pointers to the input and output + typename Superclass::OutputImagePointer outputPtr = this->GetOutput(); + typename Superclass::InputImageConstPointer inputPtr = this->GetInput(); + + if ( !outputPtr || !inputPtr) + { + return; + } + + // Set the output image largest possible region. Use a RegionCopier + // so that the input and output images can be different dimensions. + OutputImageRegionType outputLargestPossibleRegion; + this->CallCopyInputRegionToOutputRegion(outputLargestPossibleRegion, + inputPtr->GetLargestPossibleRegion()); + outputPtr->SetLargestPossibleRegion( outputLargestPossibleRegion ); + + // Set the output spacing and origin + const itk::ImageBase<Superclass::InputImageDimension> *phyData; + + phyData + = dynamic_cast<const itk::ImageBase<Superclass::InputImageDimension>*>(this->GetInput()); + + if (phyData) + { + // Copy what we can from the image from spacing and origin of the input + // This logic needs to be augmented with logic that select which + // dimensions to copy + unsigned int i, j; + const typename InputImageType::SpacingType& + inputSpacing = inputPtr->GetSpacing(); + const typename InputImageType::PointType& + inputOrigin = inputPtr->GetOrigin(); + const typename InputImageType::DirectionType& + inputDirection = inputPtr->GetDirection(); + + typename OutputImageType::SpacingType outputSpacing; + typename OutputImageType::PointType outputOrigin; + typename OutputImageType::DirectionType outputDirection; + + // copy the input to the output and fill the rest of the + // output with zeros. + for (i=0; i < Superclass::InputImageDimension; ++i) + { + outputSpacing[i] = inputSpacing[i]; + outputOrigin[i] = inputOrigin[i]; + for (j=0; j < Superclass::OutputImageDimension; j++) + { + if (j < Superclass::InputImageDimension) + { + outputDirection[j][i] = inputDirection[j][i]; + } + else + { + outputDirection[j][i] = 0.0; + } + } + } + for (; i < Superclass::OutputImageDimension; ++i) + { + outputSpacing[i] = 1.0; + outputOrigin[i] = 0.0; + for (j=0; j < Superclass::OutputImageDimension; j++) + { + if (j == i) + { + outputDirection[j][i] = 1.0; + } + else + { + outputDirection[j][i] = 0.0; + } + } + } + + // set the spacing and origin + outputPtr->SetSpacing( outputSpacing ); + outputPtr->SetOrigin( outputOrigin ); + outputPtr->SetDirection( outputDirection ); + + } + else + { + // pointer could not be cast back down + itkExceptionMacro(<< "otb::MultiChannelRAndNIRVegetationIndexImageFilter::GenerateOutputInformation " + << "cannot cast input to " + << typeid(itk::ImageBase<Superclass::InputImageDimension>*).name() ); + } +} + + +/** + * ThreadedGenerateData Performs the pixel-wise addition + */ +template <class TInputImage, class TOutputImage, class TFunction > +void +MultiChannelsPolarimetricSynthesisFilter<TInputImage,TOutputImage,TFunction> +::ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, + int threadId) +{ + InputImagePointer inputPtr = this->GetInput(); + OutputImagePointer outputPtr = this->GetOutput(0); + + // Define the portion of the input to walk for this thread, using + // the CallCopyOutputRegionToInputRegion method allows for the input + // and output images to be different dimensions + InputImageRegionType inputRegionForThread; + this->CallCopyOutputRegionToInputRegion(inputRegionForThread, outputRegionForThread); + + // Define the iterators + itk::ImageRegionConstIterator<TInputImage> inputIt(inputPtr, inputRegionForThread); + itk::ImageRegionIterator<TOutputImage> outputIt(outputPtr, outputRegionForThread); + + itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels()); + + inputIt.GoToBegin(); + outputIt.GoToBegin(); + + // Computation with 4 channels + if ( inputPtr->GetNumberOfComponentsPerPixel()==4 ) + { + while( !inputIt.IsAtEnd() ) + { + outputIt.Set( m_Functor( inputIt.Get()[0], inputIt.Get()[1], inputIt.Get()[2], inputIt.Get()[3] ) ); + ++inputIt; + ++outputIt; + progress.CompletedPixel(); // potential exception thrown here + } + } + +} + +/** + * Computation of the electromagnetic fields Ei Er + */ +template <class TInputImage, class TOutputImage, class TFunction > +void +MultiChannelsPolarimetricSynthesisFilter<TInputImage,TOutputImage,TFunction> +::ComputeElectromagneticFields() +{ + ComplexType Ei0,Ei1,Er0,Er1; + ComplexArrayType AEi, AEr; + + Ei0.real() = vcl_cos(m_DTOR*m_PsiI)*vcl_cos(m_DTOR*m_TauI); + Ei0.imag() = -vcl_sin(m_DTOR*m_PsiI)*vcl_sin(m_DTOR*m_TauI); + + Ei1.real() = vcl_sin(m_DTOR*m_PsiI)*vcl_cos(m_DTOR*m_TauI); + Ei1.imag() = vcl_cos(m_DTOR*m_PsiI)*vcl_sin(m_DTOR*m_TauI); + + Er0.real() = vcl_cos(m_DTOR*m_PsiR)*vcl_cos(m_DTOR*m_TauR); + Er0.imag() = -vcl_sin(m_DTOR*m_PsiR)*vcl_sin(m_DTOR*m_TauR); + + Er1.real() = vcl_sin(m_DTOR*m_PsiR)*vcl_cos(m_DTOR*m_TauR); + Er1.imag() = vcl_cos(m_DTOR*m_PsiR)*vcl_sin(m_DTOR*m_TauR); + + AEi[0]=Ei0; + AEi[1]=Ei1; + AEr[0]=Er0; + AEr[1]=Er1; + + this->SetEi(AEi); + this->SetEr(AEr); + + std::cout<<"PsiI: "<<m_PsiI<<std::endl; + std::cout<<"TauI: "<<m_TauI<<std::endl; + std::cout<<"PsiR: "<<m_PsiR<<std::endl; + std::cout<<"TauR: "<<m_TauR<<std::endl; + + std::cout<<"Ei0 im: "<<m_Ei[0].imag()<<std::endl; + std::cout<<"Ei0 re: "<<m_Ei[0].real()<<std::endl; + std::cout<<"Ei1 im: "<<m_Ei[1].imag()<<std::endl; + std::cout<<"Ei1 re: "<<m_Ei[1].real()<<std::endl; + + std::cout<<"Er0 im: "<<m_Er[0].imag()<<std::endl; + std::cout<<"Er0 re: "<<m_Er[0].real()<<std::endl; + std::cout<<"Er1 im: "<<m_Er[1].imag()<<std::endl; + std::cout<<"Er1 re: "<<m_Er[1].real()<<std::endl; + + std::cout<<"DTOR: "<<m_DTOR<<std::endl; +} + +/** + * Verify and force the inputs, if only 2 or 3 channels are present + */ +template <class TInputImage, class TOutputImage, class TFunction > +void +MultiChannelsPolarimetricSynthesisFilter<TInputImage,TOutputImage,TFunction> +::VerifyAndForceInputs() +{ +/* InputPixelType pix; + pix.imag()=0; + pix.real()=0; + + // With 3 channels : HH VH VV + if ( ( this->GetInput(0)!=0 && this->GetInput(1)==0 )&& + ( this->GetInput(2)!=0 && this->GetInput(3)!=0 ) ) + { + typename HVInputImageType::ConstPointer hvImage = dynamic_cast<const HVInputImageType*>((itk::ProcessObject::GetInput(2)));; + this->SetInputHV(hvImage); + std::cout<<"Case 3 channels !!"<<std::endl; + } + else + // With 3 channels : HH HV VV + if ( ( this->GetInput(0)!=0 && this->GetInput(1)!=0 )&& + ( this->GetInput(2)==0 && this->GetInput(3)!=0 ) ) + { + //this->SetInputVH(static_cast<typename HVInputImageType::Pointer>(this->GetInput(1))); + typename VHInputImageType::ConstPointer vhImage = dynamic_cast<const VHInputImageType*>((itk::ProcessObject::GetInput(1)));; + this->SetInputVH(vhImage); + std::cout<<"Case 3 channels !!"<<std::endl; + } + else + // Only VH and VV are present + if ( ( this->GetInput(0)==0 && this->GetInput(1)==0 ) && + ( this->GetInput(2)!=0 && this->GetInput(3)!=0 ) ) + { + + std::cout<<"Case VH VV present !!"<<std::endl; + // Forcing HH and HV to zero + typename HHInputImageType::Pointer inputHH = TInputImageHH::New(); + typename HVInputImageType::Pointer inputHV = TInputImageHV::New(); + + typename VHInputImageType::IndexType start; + start[0]=0; + start[1]=0; + + typename VHInputImageType::SizeType size; + typename VHInputImageType::ConstPointer vhImage = dynamic_cast<const VHInputImageType*>((itk::ProcessObject::GetInput(2))); + size = vhImage->GetLargestPossibleRegion().GetSize(); + + typename VHInputImageType::RegionType region; + region.SetSize(size); + region.SetIndex(start); + inputHH->SetRegions(region); + inputHH->Allocate(); + + inputHH->FillBuffer(pix); + + inputHV->SetRegions(region); + inputHV->Allocate(); + inputHV->FillBuffer(pix); + + this->SetInputHH(inputHH); + this->SetInputHV(inputHV); + + // Forcing TauI=0 PsiI=90 + this->SetTauI(0); + this->SetPsiI(90); + } + else + // Only HH and HV are present + if ( ( this->GetInput(0)!=0 && this->GetInput(1)!=0 ) && + ( this->GetInput(2)==0 && this->GetInput(3)==0 ) ) + { + std::cout<<"Case HH HV present !!"<<std::endl; + // Forcing HH and HV to zero + typename VVInputImageType::Pointer inputVV = TInputImageVV::New(); + typename VHInputImageType::Pointer inputVH = TInputImageVH::New(); + typename VHInputImageType::IndexType start; + start[0]=0; + start[1]=0; + typename VHInputImageType::SizeType size; + typename VHInputImageType::ConstPointer vhImage = dynamic_cast<const VHInputImageType*>((itk::ProcessObject::GetInput(1))); + + size = vhImage->GetLargestPossibleRegion().GetSize(); + + typename VHInputImageType::RegionType region; + region.SetSize(size); + region.SetIndex(start); + inputVV->SetRegions(region); + inputVV->Allocate(); + inputVV->FillBuffer(pix); + + inputVH->SetRegions(region); + inputVH->Allocate(); + inputVH->FillBuffer(pix); + + this->SetInputVV(inputVV); + this->SetInputVH(inputVH); + + // Forcing TauI=0 PsiI=0 + this->SetTauI(0); + this->SetPsiI(0); + } + else + // Only HH and VV are present + if ( ( this->GetInput(0)!=0 && this->GetInput(1)==0 )&& + ( this->GetInput(2)==0 && this->GetInput(3)!=0 ) ) + { + std::cout<<"Case HH VV present !!"<<std::endl; + itkExceptionMacro("Only the HH and VV channels are available : Polarimetric synthesis is impossible !"); + return; + } + std::cout<<"Fin VerifyAndForceInputs !!"<<std::endl; + + */ +} + +/** + * + */ +template <class TInputImage, class TOutputImage, class TFunction > +void +MultiChannelsPolarimetricSynthesisFilter<TInputImage,TOutputImage,TFunction> +::BeforeThreadedGenerateData() +{ + try{ + // First Part. Verify and force the inputs + VerifyAndForceInputs(); + + /* std::cout<<"image 1 "<<this->GetInput(0)<<std::endl; + std::cout<<"image 2 "<<this->GetInput(1)<<std::endl; + std::cout<<"image 3 "<<this->GetInput(2)<<std::endl; + std::cout<<"image 4 "<<this->GetInput(3)<<std::endl; + */ + // Second Part. Estimation of the incident field Ei and the reflected field Er + ComputeElectromagneticFields(); + } + catch( itk::ExceptionObject & err ) + { + std::cout << "Exception itk::ExceptionObject levee !" << std::endl; + std::cout << "Exception in PolarimetricSynthesisFilter class :"<< err << std::endl; + return; + } + catch (...) + { + // itkGenericExceptionMacro( <<"Unknown exception in PolarimetricSynthesisFilter class (catch(...)"); + std::cout << "Exception levee inconnue !" << std::endl; + return; + } + +} + +/** + * Printself + */ +template <class TInputImage, class TOutputImage, class TFunction > +void +MultiChannelsPolarimetricSynthesisFilter<TInputImage,TOutputImage,TFunction> +::PrintSelf(std::ostream& os, itk::Indent indent) const +{ + this->Superclass::PrintSelf(os,indent); + os << indent << "Psi I: "<<m_PsiI<<std::endl; + os << indent << "Tau I: "<<m_TauI<<std::endl; + os << indent << "Psi R: "<<m_PsiR<<std::endl; + os << indent << "Tau R: "<<m_TauR<<std::endl; +} + +} // end namespace otb + +#endif -- GitLab