/*========================================================================= Program: gapfilling Language: C++ Copyright (c) Jordi Inglada. All rights reserved. See LICENSE 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 _TEMPORALGAPFILLING_H_ #define _TEMPORALGAPFILLING_H_ #include "otbVectorImage.h" #include "otbImageFileReader.h" #include "otbImageFileWriter.h" #include "otbStandardFilterWatcher.h" #include "itkBinaryFunctorImageFilter.h" #include #include #include #include #include #include #include "otbDateUtils.h" namespace GapFilling { template inline itk::VariableLengthVector vectorToPixel(const VectorType& v) { itk::VariableLengthVector p(v.size()); for(auto i=0; i inline itk::VariableLengthVector vectorToPixel(const std::vector& v) { itk::VariableLengthVector p(v.size()); for(size_t i=0; i class ITK_EXPORT BinaryFunctorImageFilterWithNBands : public itk::BinaryFunctorImageFilter< TInputImage1, TInputImage2, TOutputImage, TFunctor > { public: typedef BinaryFunctorImageFilterWithNBands Self; typedef itk::BinaryFunctorImageFilter< TInputImage1, TInputImage2, TOutputImage, TFunctor > Superclass; typedef itk::SmartPointer Pointer; typedef itk::SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Macro defining the type*/ itkTypeMacro(BinaryFunctorImageFilterWithNBands, SuperClass); /** Accessors for the number of bands*/ itkSetMacro(NumberOfOutputBands, unsigned int); itkGetConstMacro(NumberOfOutputBands, unsigned int); protected: BinaryFunctorImageFilterWithNBands() {} virtual ~BinaryFunctorImageFilterWithNBands() {} virtual void GenerateOutputInformation() { Superclass::GenerateOutputInformation(); this->GetOutput()->SetNumberOfComponentsPerPixel( m_NumberOfOutputBands ); } private: BinaryFunctorImageFilterWithNBands(const Self &); //purposely not implemented void operator =(const Self&); //purposely not implemented unsigned int m_NumberOfOutputBands; }; /** Return 2 vectors containing, for each date, the position of the * last (resp next) valid date and a bool which is true if there are no * valid dates */ template inline std::tuple, std::vector, bool> find_valid_bounds(const PixelType mask, int nbDates, typename PixelType::ValueType valid_value) { using PValueType = typename PixelType::ValueType; using PVectorType = typename std::vector; PVectorType l_valid(nbDates,0); PVectorType n_valid(nbDates,0); int lv{-1}; int nv{nbDates}; for(auto i=0; i inline std::tuple create_tmp_data_interlace_dates(const PixelType pix, const PixelType mask, const PixelType idv, const PixelType odv, typename PixelType::ValueType valid_value) { if(idv == odv) return std::make_tuple(pix, mask, odv); unsigned int nbDates = idv.GetSize() + odv.GetSize(); PixelType opix{nbDates}; PixelType omask{nbDates}; PixelType dv{nbDates}; unsigned int dcount = 0; unsigned int icount = 0; unsigned int ocount = 0; while(dcount < nbDates) { if(icount < idv.GetSize() && (ocount == odv.GetSize() || //ouput dates consumed idv[icount] <= odv[ocount])) { opix[dcount] = pix[icount]; omask[dcount] = mask[icount]; dv[dcount] = idv[icount]; icount++; } else { opix[dcount] = typename PixelType::ValueType{0}; omask[dcount] = valid_value+1; dv[dcount] = odv[ocount]; ocount++; } dcount++; } return std::make_tuple(opix, omask, dv); } /*** Return a pixel with only the output dates. dv contains all dates * and only those contained in odv are kept. */ template inline PixelType extract_output_dates(const PixelType pix, const PixelType dv, const PixelType odv) { if(dv == odv) return pix; unsigned int nbDates = odv.GetSize(); unsigned int nbInDates = dv.GetSize(); if(nbDates > nbInDates) throw std::invalid_argument("There are more output dates than input dates\n"); PixelType result{nbDates}; unsigned int in_count = 0; unsigned int out_count = 0; while(in_count < dv.GetSize() && out_count < nbDates) { if(dv[in_count] == odv[out_count]) { result[out_count] = pix[in_count]; ++out_count; } ++in_count; } return result; } template class IdentityGapFillingFunctor { public: IdentityGapFillingFunctor() = default; IdentityGapFillingFunctor(const PixelType& d) : dv{d} {} PixelType operator()(PixelType pix, PixelType mask) const { if(pix.GetSize() != mask.GetSize()) throw std::invalid_argument("Pixel and mask have different sizes\n"); return pix; } bool operator!=(const IdentityGapFillingFunctor a) const { return (this->dates != a.dates) || (this->dv != a.dv) ; } bool operator==(const IdentityGapFillingFunctor a) const { return !(*this != a); } protected: PixelType dv; }; template class LinearGapFillingFunctor { public: using ValueType = typename PixelType::ValueType; using VectorType = typename std::vector; ValueType valid_value = ValueType{0}; ValueType invalid_pixel_return_value = ValueType{0}; LinearGapFillingFunctor() = default; /// Constructor with a vector of input dates LinearGapFillingFunctor(const PixelType& d) : dv{d} {} /// Constructor with vectors of input and output dates LinearGapFillingFunctor(const PixelType& d, const PixelType& od) : dv{d}, odv{od} {} // valid pixel has a mask==0 PixelType operator()(PixelType pix, PixelType mask) const { auto local_dv(dv); auto local_odv(odv); unsigned int nbDates = local_dv.GetSize(); if(nbDates == 0) nbDates = pix.GetSize(); if(nbDates != mask.GetSize()) throw std::invalid_argument("Pixel and mask have different sizes\n"); if(local_dv.GetSize()!=0 && nbDates != local_dv.GetSize()) { std::stringstream errmessg; errmessg << "Pixel and date vector have different sizes: " << nbDates << " vs " << local_dv.GetSize() << "\n"; throw std::invalid_argument(errmessg.str()); } if(local_dv.GetSize()==0) { local_dv = pix; for(unsigned i=0; iinterpolate(tmp_pix, tmp_mask, tmp_dates, last_valid, next_valid), tmp_dates, local_odv); } bool operator!=(const LinearGapFillingFunctor a) const { return (this->dv != a.dv) ; } bool operator==(const LinearGapFillingFunctor a) const { return !(*this != a); } protected: inline PixelType interpolate(const PixelType& p, const PixelType& m, const PixelType& d, const VectorType& lv, const VectorType& nv) const { unsigned int nbDates = p.GetSize(); PixelType result(nbDates); for(size_t i=0; i class SplineGapFillingFunctor { public: using ValueType = typename PixelType::ValueType; using VectorType = typename std::vector; ValueType valid_value = ValueType{0}; ValueType invalid_pixel_return_value = ValueType{0}; SplineGapFillingFunctor() = default; SplineGapFillingFunctor(const PixelType& d) : dv{d} {} /// Constructor with vectors of input and output dates SplineGapFillingFunctor(const PixelType& d, const PixelType& od) : dv{d}, odv{od} {} // valid pixel has a mask==0 PixelType operator()(PixelType pix, PixelType mask) const { auto local_dv(dv); auto local_odv(odv); unsigned int nbDates = local_dv.GetSize(); if(nbDates == 0) nbDates = pix.GetSize(); if(nbDates != mask.GetSize()) throw std::invalid_argument("Pixel and mask have different sizes\n"); if(local_dv.GetSize()!=0 && nbDates != local_dv.GetSize()) { std::stringstream errmessg; errmessg << "Pixel and date vector have different sizes: " << nbDates << " vs " << local_dv.GetSize() << "\n"; throw std::invalid_argument(errmessg.str()); } if(local_dv.GetSize()==0) { local_dv = pix; for(size_t i=0; iinterpolate(tmp_pix, tmp_mask, tmp_dates, last_valid, next_valid), tmp_dates, local_odv); } bool operator!=(const SplineGapFillingFunctor a) const { return (this->dv != a.dv) ; } bool operator==(const SplineGapFillingFunctor a) const { return !(*this != a); } protected: inline PixelType interpolate(const PixelType& p, const PixelType& m, const PixelType& d, const VectorType& lv, const VectorType& nv) const { unsigned int nbDates = p.GetSize(); // Prepare the data for gsl double* x = new double[nbDates]; double* y = new double[nbDates]; std::size_t nbValidDates{0}; for(size_t i = 0; i < nbDates; i++) { if(m[i]==valid_value) { x[nbValidDates] = d[i]; //Ensure that the dates are strictly increasing if(nbValidDates>0 && (x[nbValidDates]-x[nbValidDates-1])::epsilon()) { //1 epsilon is not enough for gsl x[nbValidDates] = x[nbValidDates-1] + 0.1; } y[nbValidDates] = p[i]; nbValidDates++; } } if(nbValidDates < 2) { return p; } gsl_interp_accel* acc = gsl_interp_accel_alloc(); gsl_spline* spline = select_spline_type(nbValidDates); if(spline == nullptr) return p; gsl_spline_init(spline, x, y, nbValidDates); // the real interpolation PixelType result(nbDates); for(size_t i=0; i struct MultiComponentTimeSeriesFunctorAdaptor { MultiComponentTimeSeriesFunctorAdaptor() : m_NumberOfComponentsPerDate(1), m_MaxNumberOfOutputDates(20){}; PixelType operator()(PixelType p1, PixelType p2) const { const auto nbComponents = p1.GetSize(); const auto nbDates = nbComponents/m_NumberOfComponentsPerDate; CheckSizes(p1, p2); // Due to date interlacing, we don't know here the size of the // output pixel. This is only known when we receive the result // from the functor. The worst case is all dates are dulicated PixelType result(nbComponents*m_MaxNumberOfOutputDates); unsigned int outNbDates{0}; for(size_t band=0; band result.GetSize()) { std::stringstream errmessg; errmessg << "The result pixel has too many components: " << outNbDates << " instead of expected max of " << result.GetSize() << std::endl; throw std::invalid_argument(errmessg.str()); } for(size_t date=0; date) and on the interpolating functor. */ template > void gapfill_time_series(typename ImageType::Pointer inIma, typename ImageType::Pointer maskIma, typename BinaryFunctorImageFilterWithNBands::Pointer filter, typename BinaryFunctorImageFilterWithNBands::Pointer filter_mc, size_t components_per_date = 1, typename ImageType::PixelType dv= typename ImageType::PixelType{}, typename ImageType::PixelType odv= typename ImageType::PixelType{}) { inIma->UpdateOutputInformation(); maskIma->UpdateOutputInformation(); using TPixel = typename ImageType::PixelType; auto number_of_input_components = inIma->GetNumberOfComponentsPerPixel(); unsigned int number_of_output_components{number_of_input_components}; if(dv != TPixel{}) { number_of_output_components = components_per_date*dv.GetSize(); } if(odv != TPixel{}) { number_of_output_components = components_per_date*odv.GetSize(); } filter->SetNumberOfOutputBands(number_of_output_components); filter_mc->SetNumberOfOutputBands(number_of_output_components); if(components_per_date==1) { if(odv != TPixel{}) filter->SetFunctor(FunctorType(dv, odv)); else if(dv != TPixel{}) filter->SetFunctor(FunctorType(dv)); filter->SetInput(0, inIma); filter->SetInput(1, maskIma); filter->UpdateOutputInformation(); } else { if(odv != TPixel{}) { (filter_mc->GetFunctor()).SetFunctor(FunctorType(dv, odv)); (filter_mc->GetFunctor()).SetMaxNumberOfOutputDates(odv.GetSize()); } else if(dv != TPixel{}) (filter_mc->GetFunctor()).SetFunctor(FunctorType(dv)); (filter_mc->GetFunctor()).SetNumberOfComponentsPerDate(components_per_date); filter_mc->SetInput(0, inIma); filter_mc->SetInput(1, maskIma); filter_mc->UpdateOutputInformation(); } } }//GapFilling namespace #endif