diff --git a/Modules/Fusion/PanSharpening/include/otbSimpleRcsPanSharpeningFusionImageFilter.h b/Modules/Fusion/PanSharpening/include/otbSimpleRcsPanSharpeningFusionImageFilter.h index 25e1470de639d4b87a9a068e705dbc1281b31b13..822db14618dfa82479b480167892fc781b60b72d 100644 --- a/Modules/Fusion/PanSharpening/include/otbSimpleRcsPanSharpeningFusionImageFilter.h +++ b/Modules/Fusion/PanSharpening/include/otbSimpleRcsPanSharpeningFusionImageFilter.h @@ -110,8 +110,8 @@ private: * This functor applies the * \f[ \frac{XS}{\mathrm{Filtered}(PAN)}PAN \f] * operation. It is intended for internal use only. - * - * \ingroup OTBPanSharpening + * + * \ingroup OTBPanSharpening */ class FusionFunctor { @@ -142,6 +142,83 @@ private: } }; + + /** \class NoDataFusionFunctor + * This functor applies the following operation if there is no data : + * \f[ \frac{XS}{\mathrm{Filtered}(PAN)}PAN \f] + * It is intended for internal use only. + * + * \ingroup OTBPanSharpening + */ + class NoDataFusionFunctor + { + public: + // Implement the fusion as a three arguments operator + typename TOutputImageType::PixelType operator()(const typename TXsImageType::PixelType& xsPixel, + const TInternalPrecision& smoothPanchroPixel, + const typename TPanImageType::PixelType& sharpPanchroPixel) const + { + // Build output pixel + typename TOutputImageType::PixelType output(xsPixel.Size()); + + // Check for no data Pan value + if( m_NoDataValuePanAvailable && sharpPanchroPixel == m_NoDataValuePan ) + { + for ( unsigned int i = 0; i < xsPixel.Size(); ++i ) + { + output[i] = static_cast<typename TOutputImageType::InternalPixelType>( m_NoDataValuesXs[i] ); + } + return output; + } + + TInternalPrecision scale = 1.; + + if(vcl_abs(smoothPanchroPixel) > 1e-10) + { + scale = sharpPanchroPixel/smoothPanchroPixel; + } + + // Perform fusion for each band with appropriate casting + for(unsigned int i = 0; i < xsPixel.Size(); ++i) + { + output[i] = ( m_NoDataValuesXsAvailable[i] && (xsPixel[i] == m_NoDataValuesXs[i]) ) ? + static_cast<typename TOutputImageType::InternalPixelType>( xsPixel[i] ) : + static_cast<typename TOutputImageType::InternalPixelType>( xsPixel[i] * scale ); + } + // Returns the output pixel + return output; + } + + void SetNoDataValuePanAvailable(bool noDataAvailable) { + m_NoDataValuePanAvailable = noDataAvailable; + } + + void SetNoDataValuePan(typename TPanImageType::PixelType noDataValue) { + m_NoDataValuePan = noDataValue; + } + + void SetNoDataValuesXsAvailable(std::vector<bool> noDataValuesAvailable) { + m_NoDataValuesXsAvailable = noDataValuesAvailable; + } + + void SetNoDataValuesXs(std::vector<typename TXsImageType::InternalPixelType> noDataValues) { + m_NoDataValuesXs = noDataValues; + } + + + private: + /** No data flags and values for APN image */ + bool m_NoDataValuePanAvailable; + typename TPanImageType::InternalPixelType m_NoDataValuePan; + + /** No data flags and values for XS image */ + std::vector<bool> m_NoDataValuesXsAvailable; + std::vector<typename TXsImageType::InternalPixelType> m_NoDataValuesXs; + + + }; + + /** * Typedef of the TernaryFunctorImageFilter applying the fusion functor to * p, p_smooth and xs. @@ -152,6 +229,16 @@ private: TOutputImageType, FusionFunctor> FusionFilterType; + /** + * Typedef of the TernaryFunctorImageFilter applying the no data fusion functor to + * p, p_smooth and xs. + */ + typedef itk::TernaryFunctorImageFilter<TXsImageType, + InternalImageType, + TPanImageType, + TOutputImageType, + NoDataFusionFunctor> NoDataFusionFilterType; + /** Typedef of the convolution filter performing smoothing */ typedef otb::ConvolutionImageFilter <TPanImageType, @@ -160,10 +247,16 @@ private: TInternalPrecision> ConvolutionFilterType; /** Pointer to the internal convolution filter */ - typename ConvolutionFilterType::Pointer m_ConvolutionFilter; + typename ConvolutionFilterType::Pointer m_ConvolutionFilter; /** Pointer to the fusion filter */ - typename FusionFilterType::Pointer m_FusionFilter; + typename FusionFilterType::Pointer m_FusionFilter; + + /** Pointer to the fusion filter */ + typename NoDataFusionFilterType::Pointer m_NoDataFusionFilter; + + /** Boolean used for no data */ + bool m_UseNoData; /** Radius used for the smoothing filter */ RadiusType m_Radius; diff --git a/Modules/Fusion/PanSharpening/include/otbSimpleRcsPanSharpeningFusionImageFilter.txx b/Modules/Fusion/PanSharpening/include/otbSimpleRcsPanSharpeningFusionImageFilter.txx index 4ddbe4831764bef8a4b72abe65c251009b9f6670..f849204758ffaf98aad467666968dfe68080ab4d 100644 --- a/Modules/Fusion/PanSharpening/include/otbSimpleRcsPanSharpeningFusionImageFilter.txx +++ b/Modules/Fusion/PanSharpening/include/otbSimpleRcsPanSharpeningFusionImageFilter.txx @@ -32,6 +32,7 @@ SimpleRcsPanSharpeningFusionImageFilter { // Fix number of required inputs this->SetNumberOfRequiredInputs(2); + this->m_UseNoData = false; // Instantiate convolution filter m_ConvolutionFilter = ConvolutionFilterType::New(); @@ -42,15 +43,6 @@ SimpleRcsPanSharpeningFusionImageFilter m_Filter.SetSize(7 * 7); m_Filter.Fill(1); - // Instantiate fusion filter - m_FusionFilter = FusionFilterType::New(); - m_FusionFilter->SetInput2(m_ConvolutionFilter->GetOutput()); - - // Set-up progress reporting - m_ProgressAccumulator = itk::ProgressAccumulator::New(); - m_ProgressAccumulator->SetMiniPipelineFilter(this); - m_ProgressAccumulator->RegisterInternalFilter(m_ConvolutionFilter, 0.9); - m_ProgressAccumulator->RegisterInternalFilter(m_FusionFilter, 0.1); } template <class TPanImageType, class TXsImageType, class TOutputImageType, class TInternalPrecision> @@ -127,18 +119,89 @@ SimpleRcsPanSharpeningFusionImageFilter itkExceptionMacro(<< "SimpleRcsPanSharpeningFusionImageFilter: Wrong Pan/Xs size"); } - //Process the fusion + // Set-up progress reporting + m_ProgressAccumulator = itk::ProgressAccumulator::New(); + m_ProgressAccumulator->SetMiniPipelineFilter(this); + m_ProgressAccumulator->RegisterInternalFilter(m_ConvolutionFilter, 0.9); + m_ConvolutionFilter->SetInput(this->GetPanInput()); m_ConvolutionFilter->SetRadius(this->m_Radius); m_ConvolutionFilter->SetFilter(this->m_Filter); - m_FusionFilter->SetInput1(this->GetXsInput()); - m_FusionFilter->SetInput3(this->GetPanInput()); + typedef typename TPanImageType::InternalPixelType PanPixelType; + typedef typename TXsImageType::InternalPixelType XsPixelType; + + // Write no-data flags for Pan image + std::vector<bool> tmpNoDataValuePanAvailable; + std::vector<double> tmpNoDataValuePan; + bool noDataValuePanAvailable = false; + PanPixelType noDataValuePan = 0; + + bool retPan = itk::ExposeMetaData<std::vector<bool> >( this->GetPanInput()->GetMetaDataDictionary(), MetaDataKey::NoDataValueAvailable, tmpNoDataValuePanAvailable ); + retPan &= itk::ExposeMetaData<std::vector<double> >( this->GetPanInput()->GetMetaDataDictionary(), MetaDataKey::NoDataValue, tmpNoDataValuePan ); + + if(retPan && tmpNoDataValuePanAvailable.size() > 0 && tmpNoDataValuePan.size() > 0) + { + noDataValuePanAvailable = tmpNoDataValuePanAvailable[0] && retPan; + noDataValuePan = static_cast<PanPixelType>( tmpNoDataValuePan[0] ); + } + + + // Write no-data flags for Xs image + std::vector<bool> noDataValuesXsAvailable; + std::vector<double> tmpNoDataValuesXs; + std::vector<XsPixelType> noDataValuesXs; + + bool retXs = itk::ExposeMetaData<std::vector<bool> >( this->GetXsInput()->GetMetaDataDictionary(), MetaDataKey::NoDataValueAvailable, noDataValuesXsAvailable ); + retXs &= itk::ExposeMetaData<std::vector<double> >( this->GetXsInput()->GetMetaDataDictionary(), MetaDataKey::NoDataValue, tmpNoDataValuesXs ); + + // Check if noData is needed and update noDataValuesAvailable with return function value + if ( retPan || retXs ) + { + m_UseNoData = noDataValuePanAvailable; + for ( unsigned int i = 0; i < tmpNoDataValuesXs.size() && i < noDataValuesXsAvailable.size(); ++i ) + { + noDataValuesXs.push_back( static_cast<XsPixelType>(tmpNoDataValuesXs[i]) ); + m_UseNoData |= (noDataValuesXsAvailable[i] = (noDataValuesXsAvailable[i] && retXs)); + } + } + + // Instantiate fusion filter + if ( m_UseNoData ) + { + m_NoDataFusionFilter = NoDataFusionFilterType::New(); + m_ProgressAccumulator->RegisterInternalFilter( m_NoDataFusionFilter, 0.1 ); + + m_NoDataFusionFilter->SetInput2( m_ConvolutionFilter->GetOutput() ); + m_NoDataFusionFilter->GetFunctor().SetNoDataValuesXsAvailable( noDataValuesXsAvailable ); + m_NoDataFusionFilter->GetFunctor().SetNoDataValuePanAvailable( noDataValuePanAvailable ); + m_NoDataFusionFilter->GetFunctor().SetNoDataValuePan( noDataValuePan ); + m_NoDataFusionFilter->GetFunctor().SetNoDataValuesXs( noDataValuesXs ); + + m_NoDataFusionFilter->SetInput1( this->GetXsInput() ); + m_NoDataFusionFilter->SetInput2( m_ConvolutionFilter->GetOutput() ); + m_NoDataFusionFilter->SetInput3( this->GetPanInput() ); + + // Wire composite filter + m_NoDataFusionFilter->GraftOutput( this->GetOutput() ); + m_NoDataFusionFilter->Update(); + this->GraftOutput( m_NoDataFusionFilter->GetOutput() ); + } + else + { + m_FusionFilter = FusionFilterType::New(); + m_ProgressAccumulator->RegisterInternalFilter( m_FusionFilter, 0.1 ); + + m_FusionFilter->SetInput1( this->GetXsInput() ); + m_FusionFilter->SetInput2( m_ConvolutionFilter->GetOutput() ); + m_FusionFilter->SetInput3( this->GetPanInput() ); + + // Wire composite filter + m_FusionFilter->GraftOutput( this->GetOutput() ); + m_FusionFilter->Update(); + this->GraftOutput( m_FusionFilter->GetOutput() ); + } - // Wire composite filter - m_FusionFilter->GraftOutput(this->GetOutput()); - m_FusionFilter->Update(); - this->GraftOutput(m_FusionFilter->GetOutput()); } template <class TPanImageType, class TXsImageType, class TOutputImageType, class TInternalPrecision>