From 1aa2339f0b2fb723cf17c60039170cf22578c162 Mon Sep 17 00:00:00 2001
From: Valentin Genin <valentin.genin.external@cnes.fr>
Date: Tue, 14 Nov 2023 11:16:37 +0000
Subject: [PATCH] Otb sar metadata correction v8

---
 app/CMakeLists.txt               |   8 +-
 app/otbSARMetadataCorrection.cxx | 310 ++++++++++++-------------------
 2 files changed, 125 insertions(+), 193 deletions(-)

diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index 6422711..c180364 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -96,10 +96,10 @@ OTB_CREATE_APPLICATION(NAME SARCorrelationRough
 )
 
 
-# OTB_CREATE_APPLICATION(NAME SARMetadataCorrection
-#                        SOURCES otbSARMetadataCorrection.cxx
-#                        LINK_LIBRARIES ${${otb-module}_LIBRARIES}
-# )
+OTB_CREATE_APPLICATION(NAME SARMetadataCorrection
+                       SOURCES otbSARMetadataCorrection.cxx
+                       LINK_LIBRARIES ${${otb-module}_LIBRARIES}
+)
 
 OTB_CREATE_APPLICATION(NAME SARAltAmbig
                        SOURCES otbSARAltAmbig.cxx
diff --git a/app/otbSARMetadataCorrection.cxx b/app/otbSARMetadataCorrection.cxx
index 21e50b9..afe71bf 100644
--- a/app/otbSARMetadataCorrection.cxx
+++ b/app/otbSARMetadataCorrection.cxx
@@ -37,6 +37,7 @@
 #include "itksys/SystemTools.hxx"
 
 #include "otbDateTime.h"
+#include "date.h"
 
 enum
 {
@@ -51,7 +52,7 @@ enum
 using TimeType = otb::MetaData::TimePoint;
 using DurationType = otb::MetaData::Duration;
 
-// Keys for ImageKeywordlist
+// Keys for ImageMetadata
 // Gcp keys
 const std::string keyAzimuthTime      = "azimuthTime";
 const std::string keySlantRangeTime   = "slant_range_time";
@@ -77,22 +78,22 @@ const std::string keyVelZ             = "z_vel";
 
 ///// Functions to handle metadata //////
 // Get the four corners and estimate all useful info //
-void getCorners(otb::ImageKeywordlist imgKWL, std::vector<double *>* vector_lonlat,
+void getCorners(otb::ImageMetadata imgMD, std::vector<double *>* vector_lonlat,
 		std::vector<int *>* vector_colrow, std::vector<int> & vector_ind,
 		std::vector<TimeType> &  vector_aziTime,
 		std::vector<double> & vector_ranTime)
 {
   // Always the same order to fill all vector : ul, ur, lr and center
 
-  // Retrieve lon and lat for the four corners from imgKWL
-  double ullat = std::atof(imgKWL.GetMetadataByKey("ul_lat").c_str());
-  double ullon = std::atof(imgKWL.GetMetadataByKey("ul_lon").c_str());
-  double urlat = std::atof(imgKWL.GetMetadataByKey("ur_lat").c_str());
-  double urlon = std::atof(imgKWL.GetMetadataByKey("ur_lon").c_str());
-  double lrlat = std::atof(imgKWL.GetMetadataByKey("lr_lat").c_str());
-  double lrlon = std::atof(imgKWL.GetMetadataByKey("lr_lon").c_str());
-  double lllat = std::atof(imgKWL.GetMetadataByKey("ll_lat").c_str());
-  double lllon = std::atof(imgKWL.GetMetadataByKey("ll_lon").c_str());
+  // Retrieve lon and lat for the four corners from imgMD
+  double ullat = imgMD.GetSARParam().ulSceneCoord.latitude;
+  double ullon = imgMD.GetSARParam().ulSceneCoord.longitude;
+  double urlat = imgMD.GetSARParam().urSceneCoord.latitude;
+  double urlon = imgMD.GetSARParam().urSceneCoord.longitude;
+  double lrlat = imgMD.GetSARParam().lrSceneCoord.latitude;
+  double lrlon = imgMD.GetSARParam().lrSceneCoord.longitude;
+  double lllat = imgMD.GetSARParam().llSceneCoord.latitude;
+  double lllon = imgMD.GetSARParam().llSceneCoord.longitude;
 
   // Create center lon lat
   double centerlat = 0.25 * (ullat + urlat + lrlat + lllat);
@@ -129,8 +130,8 @@ void getCorners(otb::ImageKeywordlist imgKWL, std::vector<double *>* vector_lonl
   vector_ind.push_back(4);
 
   // col row
-  int nbRows = std::atoi(imgKWL.GetMetadataByKey("number_lines").c_str());
-  int nbCols = std::atoi(imgKWL.GetMetadataByKey("number_samples").c_str());
+  int nbRows = std::atoi(imgMD["NumberOfLines"].c_str());
+  int nbCols = std::atoi(imgMD["NumberOfColumns"].c_str());
   int * ul_cl = new int[2];
   int * ur_cl = new int[2];
   int * ll_cl = new int[2];
@@ -153,30 +154,21 @@ void getCorners(otb::ImageKeywordlist imgKWL, std::vector<double *>* vector_lonl
   vector_colrow->push_back(center_cl);
 
   // azi and ran Time vectors
-  char prefixAziTime[1024];
-  sprintf(prefixAziTime, "%s%s", SUPPORT_DATA_PREFIX.c_str(), "first_line_time");
-  char prefixAziTimeInterval[1024];
-  sprintf(prefixAziTimeInterval, "%s%s", SUPPORT_DATA_PREFIX.c_str(), "line_time_interval");
-  char prefixRange[1024];
-  sprintf(prefixRange, "%s%s", SUPPORT_DATA_PREFIX.c_str(), "slant_range_to_first_pixel");
-  char prefixRangeRate[1024];
-  sprintf(prefixRangeRate, "%s%s", SUPPORT_DATA_PREFIX.c_str(), "range_sampling_rate");
-
-  std::string aziFirstTime = imgKWL.GetMetadataByKey(prefixAziTime);
-  std::string ranFirst = imgKWL.GetMetadataByKey(prefixRange);
-  std::string aziTimeInterval = imgKWL.GetMetadataByKey(prefixAziTimeInterval);
-  std::string ranRate = imgKWL.GetMetadataByKey(prefixRangeRate);
-
-  TimeType time_first_pixel_Date = otb::MetaData::ReadFormattedDate(aziFirstTime);
+  TimeType aziFirstTime = imgMD[otb::MDTime::AcquisitionStartTime];
+  double ranFirst = imgMD.GetSARParam().nearRangeTime;
+  double aziTimeInterval = imgMD.GetSARParam().azimuthTimeInterval.TotalSeconds();
+  double ranRate = imgMD.GetSARParam().rangeSamplingRate;
+
+  TimeType time_first_pixel_Date = aziFirstTime;
   // Estimate time_line for center and last : time_line = time_first_line + ind_line*aziTimeInterval
   TimeType center_Azitime = time_first_pixel_Date +
-    DurationType::Seconds(center_cl[1]*std::atof(aziTimeInterval.c_str()));
+    DurationType::Seconds(center_cl[1]*aziTimeInterval);
   TimeType last_Azitime = time_first_pixel_Date +
-    DurationType::Seconds(lr_cl[1]*std::atof(aziTimeInterval.c_str()));
+    DurationType::Seconds(lr_cl[1]*aziTimeInterval);
 
   // Estimate range distance for center and last : ran_dist = ran_first_dist + ind_col/ranRate
-  double center_ranDist = std::atof(ranFirst.c_str()) + center_cl[0]/(std::atof(ranRate.c_str()));
-  double last_ranDist = std::atof(ranFirst.c_str()) + lr_cl[0]/(std::atof(ranRate.c_str()));
+  double center_ranDist = ranFirst + center_cl[0]/ranRate;
+  double last_ranDist = ranFirst + lr_cl[0]/ranRate;
 
   vector_aziTime.push_back(time_first_pixel_Date);
   vector_aziTime.push_back(time_first_pixel_Date);
@@ -184,19 +176,20 @@ void getCorners(otb::ImageKeywordlist imgKWL, std::vector<double *>* vector_lonl
   vector_aziTime.push_back(last_Azitime);
   vector_aziTime.push_back(center_Azitime);
 
-  vector_ranTime.push_back(std::atof(ranFirst.c_str()));
+  vector_ranTime.push_back(ranFirst);
   vector_ranTime.push_back(last_ranDist);
-  vector_ranTime.push_back(std::atof(ranFirst.c_str()));
+  vector_ranTime.push_back(ranFirst);
   vector_ranTime.push_back(last_ranDist);
   vector_ranTime.push_back(center_ranDist);
 }
 
 // Get GCP //
-void getGCP(otb::ImageMetadataInterfaceBase::Pointer metadataInterface,
-	    int gcpcount, otb::ImageKeywordlist kwl,
+void getGCP(otb::Wrapper::ComplexFloatImageType::Pointer metadataInterface,
+	    int gcpcount, otb::ImageMetadata md,
 	    std::vector<double *>* vector_lonlat,
 	    std::vector<int *>* vector_colrow, std::vector<int> & vector_ind)
 {
+  // TODO : Check if it is still necessary to do this check or if we can just use the Metadata directly
   // Get the count of GCPs and check if metadataInterface is consistent
   // Sometimes (for S1 IW) metadataInterace is not updated
   int gcpcount_interface = metadataInterface->GetGCPCount();
@@ -224,23 +217,17 @@ void getGCP(otb::ImageMetadataInterfaceBase::Pointer metadataInterface,
 	  vector_colrow->push_back(gcpColRow);
 	}
     }
-  // else use the kwl
+  // else use the md
   else
     {
       // Loop on all GCPs
       for (int gcpIdx = 0; gcpIdx < gcpcount; ++gcpIdx)
 	{
-	  char prefix[1024];
-
-	  std::stringstream stream;
-
 	  // Fill our vectors
 	  // Lon lat
 	  double * gcpLonLat = new double[2];
-	  sprintf(prefix, "%s[%d].%s", GCP_PREFIX.c_str(), gcpIdx, keyWorldPtLon.c_str());
-	  gcpLonLat[0] = std::atof(kwl.GetMetadataByKey(prefix).c_str());
-	  sprintf(prefix, "%s[%d].%s", GCP_PREFIX.c_str(), gcpIdx, keyWorldPtLat.c_str());
-	  gcpLonLat[1] = std::atof(kwl.GetMetadataByKey(prefix).c_str());
+    gcpLonLat[0] = md.GetGCPParam().GCPs[gcpIdx].m_GCPX;
+    gcpLonLat[1] = md.GetGCPParam().GCPs[gcpIdx].m_GCPY;
 	  vector_lonlat->push_back(gcpLonLat);
 
 	  // idx
@@ -248,20 +235,18 @@ void getGCP(otb::ImageMetadataInterfaceBase::Pointer metadataInterface,
 
 	  // col row
 	  int * gcpColRow = new int[2];
-	  sprintf(prefix, "%s[%d].%s", GCP_PREFIX.c_str(), gcpIdx, keyImPtX.c_str());
-	  gcpColRow[0] = std::atoi(kwl.GetMetadataByKey(prefix).c_str());
-	  sprintf(prefix, "%s[%d].%s", GCP_PREFIX.c_str(), gcpIdx, keyImPtY.c_str());
-	  gcpColRow[1] = std::atoi(kwl.GetMetadataByKey(prefix).c_str());
+    gcpColRow[0] = md.GetGCPParam().GCPs[gcpIdx].m_GCPCol;
+    gcpColRow[0] = md.GetGCPParam().GCPs[gcpIdx].m_GCPRow;
 	  vector_colrow->push_back(gcpColRow);
 	}
     }
 }
 
-// Create new GCPs and update outKWL //
-int createGCPAndUpdateKWL(std::vector<double *>* vector_lonlat, std::vector<double> * vector_hgt,
+// Create new GCPs and update outMD //
+int createGCPAndUpdateMD(std::vector<double *>* vector_lonlat, std::vector<double> * vector_hgt,
 			  std::vector<int *>* vector_colrow, std::vector<int> vector_ind,
 			  std::vector<TimeType>  vector_aziTime,
-			  std::vector<double> vector_ranTime, otb::ImageKeywordlist & outKWL)
+			  std::vector<double> vector_ranTime, otb::ImageMetadata & outMD)
 {
   // Check size (same size for all vectors)
   unsigned int vecSize = vector_lonlat->size();
@@ -274,49 +259,36 @@ int createGCPAndUpdateKWL(std::vector<double *>* vector_lonlat, std::vector<doub
 
 
   std::string gcpCount = std::to_string(vecSize);
-  outKWL.AddKey(GCP_NUMBER_KEY, gcpCount);
+  outMD.Add(GCP_NUMBER_KEY, gcpCount);
+  otb::Projection::GCPParam gcpPrm;
+  std::unordered_map<std::string, otb::GCPTime> gcpTimes;
   // Create or update each GCP
   for (unsigned int i = 0; i < vecSize; i++)
     {
-      // Add the GCP to kwl
-      char prefix[1024];
-
-      std::stringstream stream;
-
-      sprintf(prefix, "%s[%d].%s", GCP_PREFIX.c_str(), i, keyAzimuthTime.c_str());
-      outKWL.AddKey(prefix, to_simple_string(vector_aziTime[i]));
-
-      sprintf(prefix, "%s[%d].%s", GCP_PREFIX.c_str(), i, keySlantRangeTime.c_str());
-      stream << std::fixed << std::setprecision(11) << vector_ranTime[i];
-      outKWL.AddKey(prefix, stream.str());
-
-      sprintf(prefix, "%s[%d].%s", GCP_PREFIX.c_str(), i, keyImPtX.c_str());
-      outKWL.AddKey(prefix, std::to_string(vector_colrow->at(i)[0]));
-
-      sprintf(prefix, "%s[%d].%s", GCP_PREFIX.c_str(), i, keyImPtY.c_str());
-      outKWL.AddKey(prefix, std::to_string(vector_colrow->at(i)[1]));
-
-      sprintf(prefix, "%s[%d].%s", GCP_PREFIX.c_str(), i, keyWorldPtLat.c_str());
-      stream.str("");
-      stream << std::fixed << std::setprecision(11) << vector_lonlat->at(i)[1];
-      outKWL.AddKey(prefix, stream.str());
-
-      sprintf(prefix, "%s[%d].%s", GCP_PREFIX.c_str(), i, keyWorldPtLon.c_str());
-      stream.str("");
-      stream << std::fixed << std::setprecision(11) << vector_lonlat->at(i)[0];
-      outKWL.AddKey(prefix, stream.str());
-
-      // only miss the heigth (form MNT)
-      sprintf(prefix, "%s[%d].%s", GCP_PREFIX.c_str(), i, keyWorldPtHgt.c_str());
-      stream.str("");
-      stream << std::fixed << std::setprecision(11) << vector_hgt->at(i);
-      outKWL.AddKey(prefix, stream.str());
+      // Add the GCP to md
+      gcpPrm.GCPs.emplace_back(std::to_string(i),                              // ID
+                               "",                                             // Comment
+                               vector_colrow->at(i)[0],                        // col
+                               vector_colrow->at(i)[1],                        // row
+                               vector_lonlat->at(i)[1],                        // px
+                               vector_lonlat->at(i)[0],                        // py
+                               vector_hgt->at(i));                             // pz
+      otb::GCPTime time;
+      time.slantRangeTime = vector_ranTime[i];
+      time.azimuthTime = vector_aziTime[i];
+      gcpTimes[std::to_string(i)] = time;
     }
+  gcpPrm.GCPProjection = otb::SpatialReference::FromWGS84().ToWkt();
+  outMD.Add(otb::MDGeom::GCP, gcpPrm);  // This step will erase the GCP read by GDAL if any.
+  auto sarParam = outMD.GetSARParam();
+  sarParam.gcpTimes = std::move(gcpTimes);
+  outMD.Add(otb::MDGeom::SAR, sarParam);
+
   return 0;
 }
 
-// Update only GCP height and KWL //
-int updateGCPAndKWL(std::vector<double> * vector_hgt, unsigned int gcpcount, otb::ImageKeywordlist & outKWL)
+// Update only GCP height and MD //
+int updateGCPAndMD(std::vector<double> * vector_hgt, unsigned int gcpcount, otb::ImageMetadata & outMD)
 {
   // Check vector size with gcp count
   if (vector_hgt->size() != gcpcount)
@@ -325,42 +297,36 @@ int updateGCPAndKWL(std::vector<double> * vector_hgt, unsigned int gcpcount, otb
       return 1;
     }
 
+  otb::Projection::GCPParam gcpPrm = outMD.GetGCPParam();
   // Create or update each GCP
   for (unsigned int i = 0; i < vector_hgt->size(); i++)
     {
-      // Add the GCP to kwl
-      char prefix[1024];
-
-      std::stringstream stream;
-
+      // Add the GCP to md
       // only update the keyWorldPtHgt
-      sprintf(prefix, "%s[%d].%s", GCP_PREFIX.c_str(), i, keyWorldPtHgt.c_str());
-      stream.str("");
-      stream << std::fixed << std::setprecision(11) << vector_hgt->at(i);
-      outKWL.AddKey(prefix, stream.str());
+      gcpPrm.GCPs[i].m_GCPZ = vector_hgt->at(i);
     }
-
+  outMD.Add(otb::MDGeom::GCP, gcpPrm);  // This step will erase the GCP read by GDAL if any.
   return 0;
 }
 
 // Selection for fine orbits (choose only orbits that fit with the image)
 int selectOrbits(std::vector<std::string> * vector_time,
-		 const otb::ImageKeywordlist inKWL, int & ind_first, int & ind_last)
+		 const otb::ImageMetadata inMD, int & ind_first, int & ind_last)
 {
   // Initialize indexes
   ind_first = 0;
   ind_last = vector_time->size() - 1;
 
-  // Get time for first and last original orbit states
-  int orbitCount = std::atoi(inKWL.GetMetadataByKey(ORBIT_NUMBER_KEY).c_str());
-
-  char prefix_first[1024];
-  sprintf(prefix_first, "%s[%d].%s", ORBIT_PREFIX.c_str(), 0, keyTime.c_str());
-  std::string UTC_first = inKWL.GetMetadataByKey(std::string (prefix_first));
+  std::stringstream stream;
 
-  char prefix_last[1024];
-  sprintf(prefix_last, "%s[%d].%s", ORBIT_PREFIX.c_str(), (orbitCount-1), keyTime.c_str());
-  std::string UTC_last = inKWL.GetMetadataByKey(std::string (prefix_last));
+  // Get time for first and last original orbit states
+  int orbitCount = inMD.GetSARParam().orbits.size();
+  stream.str("");
+  stream << inMD.GetSARParam().orbits[0].time;
+  std::string UTC_first = stream.str();
+  stream.str("");
+  stream << inMD.GetSARParam().orbits[orbitCount-1].time;
+  std::string UTC_last = stream.str();
 
   // Transform string to t_time (in seconds)
   std::tm tm1 ={};
@@ -401,16 +367,15 @@ int selectOrbits(std::vector<std::string> * vector_time,
 	  break;
 	}
     }
-
   return 0;
 }
 
 
-// Create new Orbits and update outKWL //
-int createOrbitsAndUpdateKWL(std::vector<double *>* vector_posvel,
+// Create new Orbits and update outMD //
+int createOrbitsAndUpdateMD(std::vector<double *>* vector_posvel,
 			     std::vector<std::string> * vector_time,
 			     int ind_first, int ind_last,
-			     otb::ImageKeywordlist & outKWL)
+			     otb::ImageMetadata & outMD)
 {
   // Check size (same size for all vectors)
   unsigned int vecSize = vector_posvel->size();
@@ -420,62 +385,42 @@ int createOrbitsAndUpdateKWL(std::vector<double *>* vector_posvel,
       return 1;
     }
 
-  int orbitCount = std::atoi(outKWL.GetMetadataByKey(ORBIT_NUMBER_KEY).c_str());
-
+  int orbitCount = outMD.GetSARParam().orbits.size();
   if (vecSize < static_cast<unsigned int>(orbitCount))
     {
       // Fine orbit are inferior to original => pb
       return 1;
     }
 
+  std::vector<otb::Orbit> orbitVector;
   std::string orbitFineCount = std::to_string(ind_last - ind_first + 1);
-  outKWL.AddKey(ORBIT_NUMBER_KEY, orbitFineCount);
+  outMD.Add(ORBIT_NUMBER_KEY, orbitFineCount);
 
   // Create or update each Orbit state
   for (unsigned int i = 0;
        i < static_cast<unsigned int>(std::atoi(orbitFineCount.c_str())); i++)
     {
-      // Add the orbit to kwl
-      char prefix[1024];
-
-      std::stringstream stream;
+      // Add the orbit to md
+      otb::Orbit orbit;
 
       // time
-      sprintf(prefix, "%s[%d].%s", ORBIT_PREFIX.c_str(), i, keyTime.c_str());
-      outKWL.AddKey(prefix, vector_time->at(ind_first + i));
+      orbit.time = otb::MetaData::ReadFormattedDate(vector_time->at(ind_first + i));
 
       // position
-      sprintf(prefix, "%s[%d].%s", ORBIT_PREFIX.c_str(), i, keyPosX.c_str());
-      stream.str("");
-      stream << std::fixed << std::setprecision(6) << vector_posvel->at(ind_first + i)[0];
-      outKWL.AddKey(prefix, stream.str());
-
-      sprintf(prefix, "%s[%d].%s", ORBIT_PREFIX.c_str(), i, keyPosY.c_str());
-      stream.str("");
-      stream << std::fixed << std::setprecision(6) << vector_posvel->at(ind_first + i)[1];
-      outKWL.AddKey(prefix, stream.str());
-
-      sprintf(prefix, "%s[%d].%s", ORBIT_PREFIX.c_str(), i, keyPosZ.c_str());
-      stream.str("");
-      stream << std::fixed << std::setprecision(6) << vector_posvel->at(ind_first + i)[2];
-      outKWL.AddKey(prefix, stream.str());
+      orbit.position[0] = vector_posvel->at(ind_first + i)[0];
+      orbit.position[1] = vector_posvel->at(ind_first + i)[1];
+      orbit.position[2] = vector_posvel->at(ind_first + i)[2];
 
       // velocity
-      sprintf(prefix, "%s[%d].%s", ORBIT_PREFIX.c_str(), i, keyVelX.c_str());
-      stream.str("");
-      stream << std::fixed << std::setprecision(6) << vector_posvel->at(ind_first + i)[3];
-      outKWL.AddKey(prefix, stream.str());
-
-      sprintf(prefix, "%s[%d].%s", ORBIT_PREFIX.c_str(), i, keyVelY.c_str());
-      stream.str("");
-      stream << std::fixed << std::setprecision(6) << vector_posvel->at(ind_first + i)[4];
-      outKWL.AddKey(prefix, stream.str());
-
-      sprintf(prefix, "%s[%d].%s", ORBIT_PREFIX.c_str(), i, keyVelZ.c_str());
-      stream.str("");
-      stream << std::fixed << std::setprecision(6) << vector_posvel->at(ind_first + i)[5];
-      outKWL.AddKey(prefix, stream.str());
+      orbit.velocity[0] = vector_posvel->at(ind_first + i)[3];
+      orbit.velocity[1] = vector_posvel->at(ind_first + i)[4];
+      orbit.velocity[2] = vector_posvel->at(ind_first + i)[5];
+
+      orbitVector.push_back(std::move(orbit));
     }
+  auto sarParam = outMD.GetSARParam();
+  sarParam.orbits = std::move(orbitVector);
+  outMD.Add(otb::MDGeom::SAR, sarParam);
   return 0;
 }
 
@@ -536,9 +481,9 @@ private:
                             "This mode allows you to automatically retrieve the fine orbits and to save into a new geom file");
 
 
-    AddParameter(ParameterType_OutputFilename, "outkwl", "Write the OSSIM keywordlist to a geom file");
-    SetParameterDescription("outkwl", "This option allows extracting the OSSIM keywordlist of the image into a geom file.");
-    MandatoryOff("outkwl");
+    AddParameter(ParameterType_OutputFilename, "outmd", "Write the OSSIM Metadata to a geom file");
+    SetParameterDescription("outmd", "This option allows extracting the OSSIM Metadata of the image into a geom file.");
+    MandatoryOff("outmd");
 
     AddRAMParameter();
 
@@ -555,33 +500,33 @@ private:
       case Mode_UserDefined:
 	{
 	  EnableParameter("indem");
-	  EnableParameter("outkwl");
+	  EnableParameter("outmd");
 	  DisableParameter("infineorbits");
 
 	  MandatoryOn("indem");
-	  MandatoryOff("outkwl");
+	  MandatoryOff("outmd");
 	  MandatoryOff("infineorbits");
 	}
       break;
       case Mode_GCP:
 	{
 	  EnableParameter("indem");
-	  EnableParameter("outkwl");
+	  EnableParameter("outmd");
 	  DisableParameter("infineorbits");
 
 	  MandatoryOn("indem");
-	  MandatoryOff("outkwl");
+	  MandatoryOff("outmd");
 	  MandatoryOff("infineorbits");
 	}
       break;
       case Mode_Orbits:
 	{
 	  DisableParameter("indem");
-	  EnableParameter("outkwl");
+	  EnableParameter("outmd");
 	  EnableParameter("infineorbits");
 
 	  MandatoryOff("indem");
-	  MandatoryOn("outkwl");
+	  MandatoryOn("outmd");
 	  MandatoryOn("infineorbits");
 	}
       break;
@@ -591,17 +536,10 @@ private:
   void DoExecute() override
   {
     std::ostringstream ossOutput;
-
-    ////// Get inputs and keywordlist /////
+    ////// Get inputs and Metadata /////
     ComplexFloatImageType::Pointer SARPtr = GetParameterComplexFloatImage("insar");
 
-    // Read information
-    typedef otb::ImageMetadataInterfaceBase ImageMetadataInterfaceType;
-    ImageMetadataInterfaceType::Pointer metadataInterface = ImageMetadataInterfaceFactory::CreateIMI(SARPtr->GetMetaDataDictionary());
-
-    SARPtr->UpdateOutputInformation();
-
-    ImageKeywordlist outputKWL = SARPtr->GetImageKeywordlist();
+    ImageMetadata outputMD = SARPtr->GetImageMetadata();
 
 
     // Get mode to adapt estimation according to user choice
@@ -632,14 +570,13 @@ private:
       {
 	FloatImageType::Pointer inputDEM =  GetParameterFloatImage("indem");
 	// Check with metadataInterface and keyword List
-	int gcpcount = metadataInterface->GetGCPCount();
-
+	int gcpcount = SARPtr->GetGCPCount();
 	if (gcpcount == 0)
 	  {
-	    int gcpcount_kwl = std::atoi(outputKWL.GetMetadataByKey(GCP_NUMBER_KEY).c_str());
-	    if (gcpcount_kwl > 5)
+	    int gcpcount_md = outputMD.GetGCPParam().GCPs.size();
+	    if (gcpcount_md > 5)
 	      {
-		gcpcount = gcpcount_kwl;
+		gcpcount = gcpcount_md;
 	      }
 	  }
 
@@ -648,7 +585,6 @@ private:
 	std::vector<int> vector_ind;
 	std::vector<TimeType>  vector_aziTime;
 	std::vector<double>  vector_ranTime;
-
 	// Build the input (vector_lonlat) for GetClosestMNTHeight filter
 	if (gcpcount == 0)
 	  {
@@ -656,7 +592,7 @@ private:
 	    // Get latitude and longitude for ur, ul, ll lr and center points
 	    try
 	      {
-		getCorners(metadataInterface->GetImageKeywordlist(), vector_lonlat,
+		getCorners(SARPtr->GetImageMetadata(), vector_lonlat,
 			   vector_colrow, vector_ind, vector_aziTime,
 			   vector_ranTime);
 	      }
@@ -668,7 +604,7 @@ private:
 	  {
 	    // If GCPs => Retrieve its
 	    // Get latitude and longitude for each of its
-	    getGCP(metadataInterface, gcpcount, outputKWL, vector_lonlat, vector_colrow, vector_ind);
+	    getGCP(SARPtr, gcpcount, outputMD, vector_lonlat, vector_colrow, vector_ind);
 	  }
 
 
@@ -693,19 +629,19 @@ private:
 	filterDEMClosestHgt->Update();
 	filterDEMClosestHgt->GetDEMHgt(vector_hgt);
 
-	// Add or update GCP into the output KWL (according to the sensor (GCPs already present or not))
+	// Add or update GCP into the output MD (according to the sensor (GCPs already present or not))
 	if (gcpcount == 0)
 	  {
 	    // Create GPCs with the four corners and center
-	    createGCPAndUpdateKWL(vector_lonlat, vector_hgt,
+	    createGCPAndUpdateMD(vector_lonlat, vector_hgt,
 				  vector_colrow, vector_ind,
 				  vector_aziTime,
-				  vector_ranTime, outputKWL);
+				  vector_ranTime, outputMD);
 	  }
 	else
 	  {
 	    // Just update heigths
-	    updateGCPAndKWL(vector_hgt, gcpcount, outputKWL);
+	    updateGCPAndMD(vector_hgt, gcpcount, outputMD);
 	  }
 
 
@@ -746,7 +682,6 @@ private:
 	// Add into SAR Image keyword list, the precise metadata
 	std::string inFile = GetParameterString("infineorbits");
 
-
 	// Check that the right extension is given : expected .EOF */
 	std::string extension = itksys::SystemTools::GetFilenameLastExtension(inFile);
 	if (itksys::SystemTools::LowerCase(extension) != ".eof")
@@ -765,7 +700,6 @@ private:
 
 	// Get root node
 	TiXmlElement* root = hDoc.FirstChildElement("Earth_Explorer_File").ToElement();
-
 	if (root)
 	  {
 	    // Init vectors
@@ -802,10 +736,8 @@ private:
 
 		++count_loop;
 	      }
-
 	    int ind_first, ind_last;
-	    selectOrbits(vector_time, outputKWL, ind_first, ind_last);
-
+	    selectOrbits(vector_time, outputMD, ind_first, ind_last);
 
 	    // Check coherency between the number of orbits
 	    if (count != count_loop)
@@ -814,8 +746,8 @@ private:
 	      }
 
 
-	    int ret = createOrbitsAndUpdateKWL(vector_posvel, vector_time, ind_first,
-					       ind_last, outputKWL);
+	    int ret = createOrbitsAndUpdateMD(vector_posvel, vector_time, ind_first,
+					       ind_last, outputMD);
 
 	    if (ret == 1)
 	      {
@@ -838,10 +770,10 @@ private:
 	  }
       }
 
-    /////// Write output keywordlist with correct gcp (correction on heigth) ///////
-    if (IsParameterEnabled("outkwl") && HasValue("outkwl"))
+    /////// Write output Metadata with correct gcp (correction on heigth) ///////
+    if (IsParameterEnabled("outmd") && HasValue("outmd"))
       {
-	WriteGeometry(outputKWL, GetParameterString("outkwl"));
+	WriteImageMetadataToGeomFile(outputMD, GetParameterString("outmd"));
       }
   }
 
-- 
GitLab