Skip to content
Snippets Groups Projects
otbSARESD.cxx 15.4 KiB
Newer Older
/*
 * 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 "otbMultiToMonoChannelExtractROI.h"
#include "otbImageList.h"
#include "otbImageListToVectorImageFilter.h"
#include "itkSubtractImageFilter.h"
#include "otbSARStreamingMeanPhaseAndAzimutShiftImageFilter.h"
#include "otbSARESDOffsetsImageFilter.h"
#include "otbSARDopplerCentroidFreqImageFilter.h"

#include <iostream>
#include <string>
#include <fstream>

namespace otb
{
namespace Wrapper
{

class SARESD : public Application
{
public:
  typedef SARESD Self;
  typedef itk::SmartPointer<Self> Pointer; 

  itkNewMacro(Self);
  itkTypeMacro(SARESD, otb::Wrapper::Application);

  /** Filters typedef */
  typedef otb::SARStreamingMeanPhaseAndAzimutShiftImageFilter<FloatVectorImageType>   MeanFilter;;
  typedef otb::ImageList<FloatImageType>                                              ImageListType;
  typedef otb::ImageListToVectorImageFilter<ImageListType,
                                       FloatVectorImageType >                         ListConcatenerFilterType;
  typedef otb::MultiToMonoChannelExtractROI<FloatVectorImageType::InternalPixelType,
					    FloatImageType::PixelType>                ExtractROIFilterType;
  typedef itk::SubtractImageFilter <FloatImageType, FloatImageType, FloatImageType>   SubFilterType;

  typedef ObjectList<ExtractROIFilterType>                                            ExtractROIFilterListType;

  typedef otb::SARDopplerCentroidFreqImageFilter<FloatImageType>                      DCFFilterType;
  typedef otb::SARESDOffsetsImageFilter<FloatImageType>                               ESDFilterType;
  

private:
  void DoInit() override
  {
    SetName("SARESD");
    SetDescription("ESD processing to correct phase between two bursts.");

    SetDocLongDescription("This application applies esd processing on two consecutives bursts"
      " dimension.");

    //Optional descriptors
    SetDocLimitations("Only Sentinel 1 (IW and StripMap mode) and Cosmo products are supported for now.");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso(" ");
    AddDocTag(Tags::SAR);

    //Parameter declarations
    AddParameter(ParameterType_InputImage,  "ininterfup",   "First interferogram (Vector Image)");
    SetParameterDescription("ininterfup", "First interferogram.");

    AddParameter(ParameterType_InputImage,  "ininterflow",   "Second interferogram (Vector Image)");
    SetParameterDescription("ininterflow", "Second interferogram.");

    AddParameter(ParameterType_InputImage,  "insar",   "Input SAR  image (for metadata only");
    SetParameterDescription("insar", "SAR Image to extract SAR geometry.");

    AddParameter(ParameterType_Int,  "burstindex", "Index of first interferogram");
    SetParameterDescription("burstindex", "Index of first interferogram.");
    SetDefaultParameterInt("burstindex", 0);

    AddParameter(ParameterType_Float, "threshold", "Threshold for correlation rate");
    SetParameterDescription("threshold","Threshold for correlation rate.");
    SetDefaultParameterFloat("threshold", 0.3);
    SetMinimumParameterFloatValue("threshold", 0.0001);
    MandatoryOff("threshold");

    AddParameter(ParameterType_Int, "mlazi", "Averaging on azimut");
    SetParameterDescription("mlazi","Averaging on azimut");
    SetDefaultParameterInt("mlazi", 1);
    SetMinimumParameterIntValue("mlazi", 1);
    MandatoryOff("mlazi");
      
    AddParameter(ParameterType_OutputImage, "out", "Output Tmp");
    SetParameterDescription("out","Output Tmp.");

    AddParameter(ParameterType_Float,"azishift","Azimut shift to correct phase jump into two consecutive interferograms");
    SetParameterDescription("azishift", "Azimut shift to correct phase jump.");
    SetParameterRole("azishift", Role_Output);
    SetDefaultParameterFloat("azishift", 0);
 
    AddRAMParameter();

    SetDocExampleParameterValue("ininterfup","./interferogram_burst0.tiff");
    SetDocExampleParameterValue("ininterflow", "./interferogram_burst1.tiff");
    SetDocExampleParameterValue("insar","s1a-iw1-slc-vv-20150821t152433-20150821t152458-007363-00a1e0-004.tiff");
    SetDocExampleParameterValue("burstindex", "0");
    SetDocExampleParameterValue("out","phaseDiff.tif");
  }

  void DoUpdateParameters() override
  {
    // Nothing // TODO: o do here : all parameters are independent
  }

void DoExecute() override
{  
  ////////// Instanciate all filters //////////
  ExtractROIFilterType::Pointer extractorUp = ExtractROIFilterType::New();
  ExtractROIFilterType::Pointer extractorLow = ExtractROIFilterType::New();

  ExtractROIFilterType::Pointer extractorCohUp = ExtractROIFilterType::New();
  ExtractROIFilterType::Pointer extractorCohLow = ExtractROIFilterType::New();

  ExtractROIFilterType::Pointer extractorIsDataUp = ExtractROIFilterType::New();
  ExtractROIFilterType::Pointer extractorIsDataLow = ExtractROIFilterType::New();

  ExtractROIFilterType::Pointer extractorDcfUp = ExtractROIFilterType::New();
  ExtractROIFilterType::Pointer extractorDcfLow = ExtractROIFilterType::New();

  MeanFilter::Pointer meanPhase = MeanFilter::New();
  meanPhase->SetPhaseMean(true);
  
  MeanFilter::Pointer meanAziShift = MeanFilter::New();
  meanAziShift->SetPhaseMean(false);
    
  SubFilterType::Pointer subPhase = SubFilterType::New();

  ListConcatenerFilterType::Pointer m_Concatener = ListConcatenerFilterType::New();
  ImageListType::Pointer m_ImageList = ImageListType::New();

  ListConcatenerFilterType::Pointer m_Concatener1 = ListConcatenerFilterType::New();
  ImageListType::Pointer m_ImageList1 = ImageListType::New();
  
  DCFFilterType::Pointer dcfUp = DCFFilterType::New();
  DCFFilterType::Pointer dcfLow = DCFFilterType::New();

  ESDFilterType::Pointer esdFilter = ESDFilterType::New();
  
  ////////// Get and Check inputs //////////
  // Get Number of burst index
  float threshold = GetParameterFloat("threshold");
  int ml_azi = GetParameterInt("mlazi");
  int burstindex = GetParameterInt("burstindex");
  otbAppLogINFO(<< "burst index : " << burstindex);
  otbAppLogINFO(<< "ML factor for azimut dimension : " << ml_azi);
  otbAppLogINFO(<< "Threshold for phase difference : " << threshold);

  // Get input interferograms
  FloatVectorImageType::Pointer InterfUpPtr = GetParameterFloatVectorImage("ininterfup");
  FloatVectorImageType::Pointer InterfLowPtr = GetParameterFloatVectorImage("ininterflow");

  // Check number of components (at least three : modulus, phase and coherency)
  int nbComponentsUp = InterfUpPtr->GetNumberOfComponentsPerPixel();
  int nbComponentsLow = InterfLowPtr->GetNumberOfComponentsPerPixel();
  if (nbComponentsUp < 3 || nbComponentsLow < 3 || nbComponentsUp != nbComponentsLow)
    {
      otbAppLogFATAL(<< "Input interferograms have to contain at least three components");
    }  

  // Check invalid Pixel Key
  const bool inputWithInvalidPixels1 = InterfUpPtr->GetImageMetadata().Has("invalid_pixels")
    && InterfUpPtr->GetImageMetadata()["invalid_pixels"] == "yes";
  const bool inputWithInvalidPixels2 = InterfLowPtr->GetImageMetadata().Has("invalid_pixels")
    && InterfLowPtr->GetImageMetadata()["invalid_pixels"] == "yes";
  
  if (inputWithInvalidPixels1!= inputWithInvalidPixels2)
    {
      // Throw an execption
      otbAppLogFATAL(<< "Incoherency between input images (for invalid_pixels key).");
    }
  

  ////////// Determine overlap area between the two bursts //////////
  std::pair<unsigned long,unsigned long> linesUp;
  std::pair<unsigned long,unsigned long> linesLow;
  std::pair<unsigned long,unsigned long> samplesUp;
  std::pair<unsigned long,unsigned long> samplesLow;
  meanPhase->getOverlapLinesAndSamples(GetParameterComplexFloatImage("insar")->GetImageMetadata(),
					    linesUp, linesLow, samplesUp, samplesLow, burstindex, 
					    inputWithInvalidPixels1);

  
  // Check origin (msut have the whole burst/interferogram)
  InterfUpPtr->UpdateOutputInformation();
  InterfLowPtr->UpdateOutputInformation();
  unsigned long originOffset_samplesUp = static_cast<long>(InterfUpPtr->GetOrigin()[0]-0.5);
  unsigned long originOffset_linesUp = static_cast<long>(InterfUpPtr->GetOrigin()[1]-0.5);
  unsigned long originOffset_samplesLow = static_cast<long>(InterfLowPtr->GetOrigin()[0]-0.5);
  unsigned long originOffset_linesLow = static_cast<long>(InterfLowPtr->GetOrigin()[1]-0.5);

  if (originOffset_samplesLow != 0 || originOffset_linesLow != 0)
    {
      otbAppLogFATAL(<< "Input interferogram (Low) have not the expected origin (0,0)");
    }

  if (originOffset_samplesUp != 0 || originOffset_linesUp != 0)
    {
      otbAppLogFATAL(<< "Input interferogram (Up) have not the expected origin (0,0)");
    }

  // Retrieve start and size for each burst
  unsigned long minSamples_Up = std::min(samplesUp.second, 
					 static_cast<unsigned long>(InterfUpPtr->GetLargestPossibleRegion().GetSize()[0]-1));
  unsigned long minLines_Up = std::min(linesUp.second, 
				       static_cast<unsigned long>(InterfUpPtr->GetLargestPossibleRegion().GetSize()[1]-1));

  unsigned long minSamples_Low = std::min(samplesLow.second, 
					 static_cast<unsigned long>(InterfLowPtr->GetLargestPossibleRegion().GetSize()[0]-1));
  unsigned long minLines_Low = std::min(linesLow.second, 
				       static_cast<unsigned long>(InterfLowPtr->GetLargestPossibleRegion().GetSize()[1]-1));

  unsigned long startL_Up = linesUp.first;
  unsigned long sizeL_Up = minLines_Up - linesUp.first + 1;
  unsigned long startS_Up = samplesUp.first;
  unsigned long sizeS_Up = minSamples_Up - samplesUp.first + 1;

  unsigned long startL_Low = linesLow.first;
  unsigned long sizeL_Low = minLines_Low - linesLow.first + 1;
  unsigned long startS_Low = samplesLow.first;
  unsigned long sizeS_Low = minSamples_Low - samplesLow.first + 1;

  ////////// Extract Phase for overlap area //////////
  // Set the channel to extract : Phase = 2
  extractorUp->SetInput(InterfUpPtr);
  extractorUp->SetChannel(2);      
  extractorUp->SetStartX(startS_Up);
  extractorUp->SetStartY(startL_Up);
  extractorUp->SetSizeX(sizeS_Up);
  extractorUp->SetSizeY(sizeL_Up);
  extractorUp->UpdateOutputInformation();

  extractorLow->SetInput(InterfLowPtr);
  extractorLow->SetChannel(2);    
  extractorLow->SetStartX(startS_Low);
  extractorLow->SetStartY(startL_Low);
  extractorLow->SetSizeX(sizeS_Low);
  extractorLow->SetSizeY(sizeL_Low);
  extractorLow->UpdateOutputInformation();

  //////////// Subtract phase ////////////
  subPhase->SetCoordinateTolerance(10e08);
  subPhase->SetInput1(extractorUp->GetOutput());
  subPhase->SetInput2(extractorLow->GetOutput());

  //////////// Extract Coherency (Coherency = 3) ////////////
  extractorCohUp->SetInput(InterfUpPtr);
  extractorCohUp->SetChannel(3);      
  extractorCohUp->SetStartX(startS_Up);
  extractorCohUp->SetStartY(startL_Up);
  extractorCohUp->SetSizeX(sizeS_Up);
  extractorCohUp->SetSizeY(sizeL_Up);
  extractorCohUp->UpdateOutputInformation();

  extractorCohLow->SetInput(InterfLowPtr);
  extractorCohLow->SetChannel(3);    
  extractorCohLow->SetStartX(startS_Low);
  extractorCohLow->SetStartY(startL_Low);
  extractorCohLow->SetSizeX(sizeS_Low);
  extractorCohLow->SetSizeY(sizeL_Low);
  extractorCohLow->UpdateOutputInformation();

  //////////// Extract isData (isData Channel = 4) ////////////
  extractorIsDataUp->SetInput(InterfUpPtr);
  extractorIsDataUp->SetChannel(4);      
  extractorIsDataUp->SetStartX(startS_Up);
  extractorIsDataUp->SetStartY(startL_Up);
  extractorIsDataUp->SetSizeX(sizeS_Up);
  extractorIsDataUp->SetSizeY(sizeL_Up);
  extractorIsDataUp->UpdateOutputInformation();

  extractorIsDataLow->SetInput(InterfLowPtr);
  extractorIsDataLow->SetChannel(4);    
  extractorIsDataLow->SetStartX(startS_Low);
  extractorIsDataLow->SetStartY(startL_Low);
  extractorIsDataLow->SetSizeX(sizeS_Low);
  extractorIsDataLow->SetSizeY(sizeL_Low);
  extractorIsDataLow->UpdateOutputInformation();
  
  //////////// Concatenation of phase difference with coherency ////////////
  m_ImageList->PushBack( subPhase->GetOutput() );
  m_ImageList->PushBack( extractorCohUp->GetOutput() );
  m_ImageList->PushBack( extractorCohLow->GetOutput() );
  m_ImageList->PushBack( extractorIsDataUp->GetOutput() );
  m_ImageList->PushBack( extractorIsDataLow->GetOutput() );
  
  m_Concatener->SetInput( m_ImageList );
  
  ////////// Mean of phase difference //////////
  meanPhase->SetInput(m_Concatener->GetOutput());
  meanPhase->SetThreshold(threshold);
  // Adapt streaming with ram parameter (default 256 MB)
  meanPhase->GetStreamer()->SetAutomaticStrippedStreaming(GetParameterInt("ram"));
  meanPhase->Update();


  // Doppler Centroid Filter
  dcfUp->SetInput(extractorUp->GetOutput());
  dcfLow->SetInput(extractorLow->GetOutput());

  // Extract overlap area into Doppler Centroid outputs
  // extractorDcfUp->SetInput(dcfUp->GetOutput());
  // extractorDcfUp->SetChannel(1);      
  // extractorDcfUp->SetStartX(startS_Up);
  // extractorDcfUp->SetStartY(startL_Up);
  // extractorDcfUp->SetSizeX(sizeS_Up);
  // extractorDcfUp->SetSizeY(sizeL_Up);
  // extractorDcfUp->UpdateOutputInformation();

  // extractorDcfLow->SetInput(dcfLow->GetOutput());
  // extractorDcfLow->SetChannel(1);    
  // extractorDcfLow->SetStartX(startS_Low);
  // extractorDcfLow->SetStartY(startL_Low);
  // extractorDcfLow->SetSizeX(sizeS_Low);
  // extractorDcfLow->SetSizeY(sizeL_Low);
  // extractorDcfLow->UpdateOutputInformation();

  // //////////// ESD Filter ////////////
  esdFilter->SetPhaseDiffMean(meanPhase->GetMean());
  //double aziInterval = std::stod(InterfUpPtr->GetImageMetadata().GetMetadataByKey("line_time_interval"));
  double aziInterval = boost::any_cast<const otb::SARParam&>(InterfUpPtr->GetImageMetadata()[otb::MDGeom::SAR]).azimuthTimeInterval.TotalSeconds();
  esdFilter->SetAziTimeInt(aziInterval);
  //esdFilter->SetInput(subPhase->GetOutput());
  esdFilter->SetInput1(dcfUp->GetOutput());
  esdFilter->SetInput2(dcfLow->GetOutput());
  esdFilter->SetCoordinateTolerance(10e08);

  //////////// Concatenation with coherency ////////////
  m_ImageList1->PushBack( esdFilter->GetOutput() );
  m_ImageList1->PushBack( extractorCohUp->GetOutput() );
  m_ImageList1->PushBack( extractorCohLow->GetOutput() );
  
  m_Concatener1->SetInput( m_ImageList1 );

  ////////// Mean of azimut shift ///////////
  meanAziShift->SetInput(m_Concatener1->GetOutput());
  // Adapt streaming with ram parameter (default 256 MB)
  meanAziShift->GetStreamer()->SetAutomaticStrippedStreaming(GetParameterInt("ram"));
  meanAziShift->Update();

  ////////// Outputs : Image of azimut shift (for overlap area) and mean of azimut shift ////////////
  //SetParameterOutputImage("out", dcfLow->GetOutput());
  SetParameterOutputImage("out", subPhase->GetOutput());
  //SetParameterOutputImage("out", esdFilter->GetOutput());
  SetParameterFloat("azishift", meanAziShift->GetMean());
  RegisterPipeline();
}
   // Vector for filters 
  std::vector<itk::ProcessObject::Pointer> m_Ref;
};


}

}

OTB_APPLICATION_EXPORT(otb::Wrapper::SARESD)