From 43ae9e413aaa8249c9992819a56392ae77643c71 Mon Sep 17 00:00:00 2001
From: Valentin Genin <valentin.genin@cnes.fr>
Date: Tue, 10 Oct 2023 13:10:34 +0000
Subject: [PATCH] ENH: Adapt SARESD to otb V8

---
 app/CMakeLists.txt                            |   8 +-
 app/otbSARESD.cxx                             |  15 ++-
 .../otbSARDopplerCentroidFreqImageFilter.h    |   8 +-
 .../otbSARDopplerCentroidFreqImageFilter.txx  | 120 +++++++++---------
 ...eamingMeanPhaseAndAzimutShiftImageFilter.h |  13 +-
 5 files changed, 79 insertions(+), 85 deletions(-)

diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index e8cd2e3..33046d1 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -85,10 +85,10 @@ OTB_CREATE_APPLICATION(NAME SARDeramp
 #                        LINK_LIBRARIES ${${otb-module}_LIBRARIES}
 # )
 
-# OTB_CREATE_APPLICATION(NAME SARESD
-#                        SOURCES otbSARESD.cxx
-#                        LINK_LIBRARIES ${${otb-module}_LIBRARIES}
-# )
+OTB_CREATE_APPLICATION(NAME SARESD
+                       SOURCES otbSARESD.cxx
+                       LINK_LIBRARIES ${${otb-module}_LIBRARIES}
+)
 
 # OTB_CREATE_APPLICATION(NAME SARCorrelationRough
 #                        SOURCES otbSARCorrelationRough.cxx
diff --git a/app/otbSARESD.cxx b/app/otbSARESD.cxx
index 171a00c..7de4489 100644
--- a/app/otbSARESD.cxx
+++ b/app/otbSARESD.cxx
@@ -182,15 +182,15 @@ void DoExecute() override
     }  
 
   // Check invalid Pixel Key
-  const bool inputWithInvalidPixels1 = InterfUpPtr->GetImageKeywordlist().HasKey("support_data.invalid_pixels")
-    && InterfUpPtr->GetImageKeywordlist().GetMetadataByKey("support_data.invalid_pixels") == "yes";
-  const bool inputWithInvalidPixels2 = InterfLowPtr->GetImageKeywordlist().HasKey("support_data.invalid_pixels")
-    && InterfLowPtr->GetImageKeywordlist().GetMetadataByKey("support_data.invalid_pixels") == "yes";
+  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 support_data.invalid_pixels key).");
+      otbAppLogFATAL(<< "Incoherency between input images (for invalid_pixels key).");
     }
   
 
@@ -199,7 +199,7 @@ void DoExecute() override
   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")->GetImageKeywordlist(),
+  meanPhase->getOverlapLinesAndSamples(GetParameterComplexFloatImage("insar")->GetImageMetadata(),
 					    linesUp, linesLow, samplesUp, samplesLow, burstindex, 
 					    inputWithInvalidPixels1);
 
@@ -340,7 +340,8 @@ void DoExecute() override
 
   // //////////// ESD Filter ////////////
   esdFilter->SetPhaseDiffMean(meanPhase->GetMean());
-  double aziInterval = std::stod(InterfUpPtr->GetImageKeywordlist().GetMetadataByKey("support_data.line_time_interval"));
+  //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());
diff --git a/include/otbSARDopplerCentroidFreqImageFilter.h b/include/otbSARDopplerCentroidFreqImageFilter.h
index 0f20ca2..b3bff31 100644
--- a/include/otbSARDopplerCentroidFreqImageFilter.h
+++ b/include/otbSARDopplerCentroidFreqImageFilter.h
@@ -28,8 +28,8 @@
 #include "itkImageScanlineConstIterator.h"
 #include "itkImageScanlineIterator.h"
 
-#include "otbImageKeywordlist.h"
-#include "otbSarSensorModelAdapter.h"
+#include "otbImageMetadata.h"
+#include "otbSarSensorModel.h"
 
 #include "otbDateTime.h"
 
@@ -165,8 +165,8 @@ protected:
   void BeforeThreadedGenerateData() ITK_OVERRIDE;
   
 
-  void getAllCoefs(ImageKeywordlist  const& kwl, std::vector<FMRateRecordType> & FMRateRecords);
-  void getAllCoefs(ImageKeywordlist  const& kwl, std::vector<DCFRecordType> & DCFRecords);
+  void getAllCoefs(ImageMetadata  const& kwl, std::vector<FMRateRecordType> & FMRateRecords);
+  void getAllCoefs(ImageMetadata  const& kwl, std::vector<DCFRecordType> & DCFRecords);
 
   long double applyFMRateCoefs(double index_sample);
   long double applyDCFCoefs(double index_sample);
diff --git a/include/otbSARDopplerCentroidFreqImageFilter.txx b/include/otbSARDopplerCentroidFreqImageFilter.txx
index 5837319..62604d1 100644
--- a/include/otbSARDopplerCentroidFreqImageFilter.txx
+++ b/include/otbSARDopplerCentroidFreqImageFilter.txx
@@ -28,7 +28,7 @@
 #include "itkProgressReporter.h"
 #include "itkNumericTraitsPointPixel.h"
 
-#include "otbSarSensorModelAdapter.h"
+#include "otbSarSensorModel.h"
 
 #include <cmath>
 #include <algorithm>
@@ -70,12 +70,12 @@ namespace otb
   template<class TImage>
   void
   SARDopplerCentroidFreqImageFilter< TImage >
-  ::getAllCoefs(ImageKeywordlist  const& kwl, std::vector<FMRateRecordType> & FMRateRecords)
+  ::getAllCoefs(ImageMetadata  const& kwl, std::vector<FMRateRecordType> & FMRateRecords)
   {
     char fmRatePrefix_[1024];
     std::size_t nbLists(0);
     
-    nbLists = std::stoi(kwl.GetMetadataByKey("azimuthFmRate.azi_fm_rate_coef_nb_list"));
+    nbLists = std::stoi(kwl["azimuthFmRate.azi_fm_rate_coef_nb_list"]);
 
     std::string FM_PREFIX = "azimuthFmRate.azi_fm_rate_coef_list";
     
@@ -86,12 +86,12 @@ namespace otb
 	const std::string FMPrefix(fmRatePrefix_, pos);
 
 	FMRateRecordType fmRateRecord;
-	fmRateRecord.azimuthFMRateTime = otb::MetaData::ReadFormattedDate(kwl.GetMetadataByKey(FMPrefix+ 
-										      "azi_fm_rate_coef_time"));
-	fmRateRecord.coef0FMRate = std::stod(kwl.GetMetadataByKey(FMPrefix + "1.azi_fm_rate_coef"));
-	fmRateRecord.coef1FMRate = std::stod(kwl.GetMetadataByKey(FMPrefix + "2.azi_fm_rate_coef"));
-	fmRateRecord.coef2FMRate = std::stod(kwl.GetMetadataByKey(FMPrefix + "3.azi_fm_rate_coef"));
-	fmRateRecord.tau0FMRate = std::stod(kwl.GetMetadataByKey(FMPrefix + "slant_range_time"));
+	fmRateRecord.azimuthFMRateTime = otb::MetaData::ReadFormattedDate(kwl[FMPrefix+ 
+										      "azi_fm_rate_coef_time"]);
+	fmRateRecord.coef0FMRate = std::stod(kwl[FMPrefix + "1.azi_fm_rate_coef"]);
+	fmRateRecord.coef1FMRate = std::stod(kwl[FMPrefix + "2.azi_fm_rate_coef"]);
+	fmRateRecord.coef2FMRate = std::stod(kwl[FMPrefix + "3.azi_fm_rate_coef"]);
+	fmRateRecord.tau0FMRate = std::stod(kwl[FMPrefix + "slant_range_time"]);
 
 	FMRateRecords.push_back(fmRateRecord);
       }
@@ -100,12 +100,12 @@ namespace otb
   template<class TImage>
   void
   SARDopplerCentroidFreqImageFilter< TImage >
-  ::getAllCoefs(ImageKeywordlist  const& kwl, std::vector<DCFRecordType> & DCFRecords)
+  ::getAllCoefs(ImageMetadata  const& kwl, std::vector<DCFRecordType> & DCFRecords)
   {
      char dcfPrefix_[1024];
     std::size_t nbLists(0);
     
-    nbLists = std::stoi(kwl.GetMetadataByKey("dopplerCentroid.dop_coef_nb_list"));
+    nbLists = std::stoi(kwl["dopplerCentroid.dop_coef_nb_list"]);
 
     std::string DCF_PREFIX = "dopplerCentroid.dop_coef_list";
     
@@ -116,12 +116,12 @@ namespace otb
 	const std::string DCFPrefix(dcfPrefix_, pos);
 
 	DCFRecordType dcfRecord;
-	dcfRecord.azimuthDCFTime = otb::MetaData::ReadFormattedDate(kwl.GetMetadataByKey(DCFPrefix + 
-									      "dop_coef_time"));
-	dcfRecord.coef0DCF = std::stod(kwl.GetMetadataByKey(DCFPrefix + "1.dop_coef"));
-	dcfRecord.coef1DCF = std::stod(kwl.GetMetadataByKey(DCFPrefix + "2.dop_coef"));
-	dcfRecord.coef2DCF = std::stod(kwl.GetMetadataByKey(DCFPrefix + "3.dop_coef"));
-	dcfRecord.tau0DCF = std::stod(kwl.GetMetadataByKey(DCFPrefix + "slant_range_time"));
+	dcfRecord.azimuthDCFTime = otb::MetaData::ReadFormattedDate(kwl[DCFPrefix + 
+									      "dop_coef_time"]);
+	dcfRecord.coef0DCF = std::stod(kwl[DCFPrefix + "1.dop_coef"]);
+	dcfRecord.coef1DCF = std::stod(kwl[DCFPrefix + "2.dop_coef"]);
+	dcfRecord.coef2DCF = std::stod(kwl[DCFPrefix + "3.dop_coef"]);
+	dcfRecord.tau0DCF = std::stod(kwl[DCFPrefix + "slant_range_time"]);
 
 	 DCFRecords.push_back(dcfRecord);
       }
@@ -139,27 +139,28 @@ namespace otb
     ImagePointer inputPtr = const_cast< ImageType * >( this->GetInput() );
 
      // Retrieve all polynomials
-    std::vector<FMRateRecordType> FMRateRecords;
+    std::vector<otb::AzimuthFmRate> FMRateRecords;
 
-    ImageKeywordlist inputKWL = inputPtr->GetImageKeywordlist();
+    ImageMetadata inputKWL = inputPtr->GetImageMetadata();
     
-    this->getAllCoefs(inputKWL, FMRateRecords);
+    //this->getAllCoefs(inputKWL, FMRateRecords);
+    FMRateRecords = boost::any_cast<const otb::SARParam&>(inputKWL[otb::MDGeom::SAR]).azimuthFmRates;
 
-    DurationType diffAziTimeMin(0);
+    DurationType diffAziTimeMin;
     unsigned int polySelected = 0;
     
     // Select one polynomial (with m_MidAziTime)
     for (unsigned int i = 0; i < FMRateRecords.size(); i++)
       {
 	// Difference between midAziTime and aziTime of the current polynomial
-	DurationType diffAziTime(0);
-	if (m_MidAziTime > FMRateRecords[i].azimuthFMRateTime)
+	DurationType diffAziTime;
+	if (m_MidAziTime > FMRateRecords[i].azimuthTime)
 	  {
-	    diffAziTime = DurationType(m_MidAziTime - FMRateRecords[i].azimuthFMRateTime);
+	    diffAziTime = DurationType(m_MidAziTime - FMRateRecords[i].azimuthTime);
 	  }
 	else
 	  {
-	    diffAziTime = DurationType(FMRateRecords[i].azimuthFMRateTime - m_MidAziTime);
+	    diffAziTime = DurationType(FMRateRecords[i].azimuthTime - m_MidAziTime);
 	  }
 	
 	if (diffAziTime < diffAziTimeMin || i == 0)
@@ -170,10 +171,10 @@ namespace otb
       }
 
     // Assign m_FM_C0, m_FM_C1, m_FM_C2, m_FM_Tau0
-    m_FM_C0 = FMRateRecords[polySelected].coef0FMRate;
-    m_FM_C1 = FMRateRecords[polySelected].coef1FMRate;
-    m_FM_C2 = FMRateRecords[polySelected].coef2FMRate;
-    m_FM_Tau0 = FMRateRecords[polySelected].tau0FMRate;
+    m_FM_C0 = FMRateRecords[polySelected].azimuthFmRatePolynomial[0];
+    m_FM_C1 = FMRateRecords[polySelected].azimuthFmRatePolynomial[1];
+    m_FM_C2 = FMRateRecords[polySelected].azimuthFmRatePolynomial[2];
+    m_FM_Tau0 = FMRateRecords[polySelected].t0;
    
     return true;
   }
@@ -190,27 +191,28 @@ namespace otb
     ImagePointer inputPtr = const_cast< ImageType * >( this->GetInput() );
 
      // Retrieve all polynomials
-    std::vector<DCFRecordType> DCFRecords;
+    std::vector<otb::DopplerCentroid> DCFRecords;
     
-    ImageKeywordlist inputKWL = inputPtr->GetImageKeywordlist();
+    ImageMetadata inputKWL = inputPtr->GetImageMetadata();
     
-    this->getAllCoefs(inputKWL, DCFRecords);
+    // this->getAllCoefs(inputKWL, DCFRecords);
+    DCFRecords = boost::any_cast<const otb::SARParam&>(inputKWL[otb::MDGeom::SAR]).dopplerCentroids;
 
-    DurationType diffAziTimeMin(0);
+    DurationType diffAziTimeMin;
     unsigned int polySelected = 0;
     
     // Select one polynomial (with m_MidAziTime)
     for (unsigned int i = 0; i < DCFRecords.size(); i++)
       {
 	// Difference between midAziTime and aziTime of the current polynomial
-	DurationType diffAziTime(0);
-	if (m_MidAziTime > DCFRecords[i].azimuthDCFTime)
+	DurationType diffAziTime;
+	if (m_MidAziTime > DCFRecords[i].azimuthTime)
 	  {
-	    diffAziTime = DurationType(m_MidAziTime - DCFRecords[i].azimuthDCFTime);
+	    diffAziTime = DurationType(m_MidAziTime - DCFRecords[i].azimuthTime);
 	  }
 	else
 	  {
-	    diffAziTime = DurationType(DCFRecords[i].azimuthDCFTime - m_MidAziTime);
+	    diffAziTime = DurationType(DCFRecords[i].azimuthTime - m_MidAziTime);
 	  }
 	
 	if (diffAziTime < diffAziTimeMin || i == 0)
@@ -221,10 +223,10 @@ namespace otb
       }
 
     // Assign m_FM_C0, m_FM_C1, m_FM_C2, m_FM_Tau0
-    m_DCF_C0 = DCFRecords[polySelected].coef0DCF;
-    m_DCF_C1 = DCFRecords[polySelected].coef1DCF;
-    m_DCF_C2 = DCFRecords[polySelected].coef2DCF;
-    m_DCF_Tau0 = DCFRecords[polySelected].tau0DCF;
+    m_DCF_C0 = DCFRecords[polySelected].dopCoef[0];
+    m_DCF_C1 = DCFRecords[polySelected].dopCoef[1];
+    m_DCF_C2 = DCFRecords[polySelected].dopCoef[2];
+    m_DCF_Tau0 = DCFRecords[polySelected].t0;
 
     return true;
   }
@@ -292,42 +294,38 @@ namespace otb
 
 	// Get input
 	ImagePointer inputPtr = const_cast< ImageType * >( this->GetInput() );
-	// Choose KeyWordList
-	ImageKeywordlist inputKWL = inputPtr->GetImageKeywordlist();
+	// Choose Metadata
+	ImageMetadata inputKWL = inputPtr->GetImageMetadata();
 	
 	// Check version of header/kwl (at least 3)
-	int headerVersion = std::stoi(inputKWL.GetMetadataByKey("header.version"));
+	// int headerVersion = std::stoi(inputKWL.GetMetadataByKey("header.version"));
 
-	if (headerVersion < 3)
-	  {
-	    itkExceptionMacro(<<"Header version is inferior to 3. Please Upgrade your geom file");
-	  }
+	// if (headerVersion < 3)
+	//   {
+	//     itkExceptionMacro(<<"Header version is inferior to 3. Please Upgrade your geom file");
+	//   }
 
 	// Get some metadata
-	double aziSteeringRate = std::stod(inputKWL.GetMetadataByKey("support_data.azimuth_steering_rate"));
+  double aziSteeringRate = boost::any_cast<const otb::SARParam&>(inputKWL[otb::MDGeom::SAR]).azimuthSteeringRate;
 	// Conversion to radians per seconds
 	aziSteeringRate *= (M_PI/180); 
 
-	m_FirstAziTime = otb::MetaData::ReadFormattedDate((inputKWL.GetMetadataByKey("support_data.first_line_time")));
-	m_FirstRangeTime = std::stod(inputKWL.GetMetadataByKey("support_data.slant_range_to_first_pixel"));
+  m_FirstAziTime = inputKWL[MDTime::AcquisitionStartTime];
+  m_FirstRangeTime = boost::any_cast<const otb::SARParam&>(inputKWL[otb::MDGeom::SAR]).nearRangeTime;
 
-	m_AziTimeInt = std::stod(inputKWL.GetMetadataByKey("support_data.line_time_interval"));
-	m_RangeSamplingRate = std::stod(inputKWL.GetMetadataByKey("support_data.range_sampling_rate"));
+  m_AziTimeInt = boost::any_cast<const otb::SARParam&>(inputKWL[otb::MDGeom::SAR]).azimuthTimeInterval.TotalSeconds();
+  m_RangeSamplingRate = boost::any_cast<const otb::SARParam&>(inputKWL[otb::MDGeom::SAR]).rangeSamplingRate;
 
-	double radarFrequency = std::stod(inputKWL.GetMetadataByKey("support_data.radar_frequency"));
+  double radarFrequency = inputKWL[MDNum::RadarFrequency];
 	
-	int nbLineBurst = std::stod(inputKWL.GetMetadataByKey("support_data.geom.bursts.number_lines_per_burst"));
-	int nbSampleBurst = std::stod(inputKWL.GetMetadataByKey("support_data.geom.bursts.number_samples_per_burst"));
+  int nbLineBurst = boost::any_cast<const otb::SARParam&>(inputKWL[otb::MDGeom::SAR]).numberOfLinesPerBurst;
+  int nbSampleBurst = boost::any_cast<const otb::SARParam&>(inputKWL[otb::MDGeom::SAR]).numberOfSamplesPerBurst;
 	// Estimation m_Ks
 	m_LineAtMidBurst = nbLineBurst/2.;
 	m_MidAziTime = m_FirstAziTime + DurationType::Seconds(m_AziTimeInt * m_LineAtMidBurst);
 	
 	// Try to create a SarSensorModelAdapter
-	SarSensorModelAdapter::Pointer sarSensorModel = SarSensorModelAdapter::New();
-	bool loadOk = sarSensorModel->LoadState(inputKWL);
-
-	if(!loadOk || !sarSensorModel->IsValidSensorModel())
-	  itkExceptionMacro(<<"Input image does not contain a valid SAR sensor model.");
+  SarSensorModel* sarSensorModel = new SarSensorModel(inputKWL);
 
 	Point3DType satpos, satvel;
  
diff --git a/include/otbSARStreamingMeanPhaseAndAzimutShiftImageFilter.h b/include/otbSARStreamingMeanPhaseAndAzimutShiftImageFilter.h
index 36b9ad7..9f8294d 100644
--- a/include/otbSARStreamingMeanPhaseAndAzimutShiftImageFilter.h
+++ b/include/otbSARStreamingMeanPhaseAndAzimutShiftImageFilter.h
@@ -27,8 +27,8 @@
 #include "itkSimpleDataObjectDecorator.h"
 #include "otbPersistentFilterStreamingDecorator.h"
 
-#include "otbSarSensorModelAdapter.h"
-#include "otbImageKeywordlist.h"
+#include "otbSarSensorModel.h"
+#include "otbImageMetadata.h"
 
 #include <complex>
 #include <cmath>
@@ -301,7 +301,7 @@ public:
     return mean; 
   }
 
-  bool getOverlapLinesAndSamples(ImageKeywordlist SLCImageKWL,
+  bool getOverlapLinesAndSamples(ImageMetadata SLCImageKWL,
 			    std::pair<unsigned long,unsigned long> & linesUp, 
 			    std::pair<unsigned long,unsigned long> & linesLow,
 			    std::pair<unsigned long,unsigned long> & samplesUp,
@@ -310,13 +310,8 @@ public:
 			    bool inputWithInvalidPixels)
     {
       // Try to create a SarSensorModelAdapter
-      SarSensorModelAdapter::Pointer sarSensorModel = SarSensorModelAdapter::New();
+      SarSensorModel* sarSensorModel = new SarSensorModel(SLCImageKWL);
 
-      bool loadOk = sarSensorModel->LoadState(SLCImageKWL);
-
-      if(!loadOk || !sarSensorModel->IsValidSensorModel())
-	itkExceptionMacro(<<"Input image does not contain a valid SAR sensor model.");
-    
       // Try to call the deburstAndConcatenate function
       bool deburstAndConcatenateOk = sarSensorModel->Overlap(linesUp, linesLow, 
 							     samplesUp, samplesLow,
-- 
GitLab