Skip to content
Snippets Groups Projects

Use SAR metadata in SarRadiometricCalibrationToImageFilter

Merged Julien Osman requested to merge 2159 into develop

Rationale

Fix #2159 (closed)

Copyright

The copyright owner is CNES and has signed the ORFEO ToolBox Contributor License Agreement.


Check before merging:

  • All discussions are resolved
  • At least 2 👍 votes from core developers, no 👎 vote.
  • The feature branch is (reasonably) up-to-date with the base branch
  • Dashboard is green
  • Copyright owner has signed the ORFEO ToolBox Contributor License Agreement
  • Optionally, run git diff develop... -U0 --no-color | clang-format-diff.py -p1 -i on latest changes and commit
Edited by Julien Osman

Merge request reports

Loading
Loading

Activity

Filter activity
  • Approvals
  • Assignees & reviewers
  • Comments (from bots)
  • Comments (from users)
  • Commits & branches
  • Edits
  • Labels
  • Lock status
  • Mentions
  • Merge request status
  • Tracking
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21 #ifndef otbSarSensorModel_h
22 #define otbSarSensorModel_h
23
24 #include "otbImageMetadata.h"
25
26
27 #include "itkPoint.h"
28
29 namespace otb
30 {
31
32 class SarSensorModel
  • Luc Hermitte
    Luc Hermitte @lhermitte started a thread on commit fb4d22f4
  • 230 229
    231 230 virtual bool CanRead() const {return false;}
    232 231
    233 virtual void Parse(const MetadataSupplierInterface &)
    234 {
    232 void SupplierCheck() const
    233 {
    234 if (m_MetadataSupplierInterface == nullptr)
  • Luc Hermitte
    Luc Hermitte @lhermitte started a thread on commit fb4d22f4
  • 296 296
    297 297 }
    298 298
    299 std::vector<Orbit> CosmoImageMetadataInterface::getOrbits(const MetadataSupplierInterface & mds, const std::string & reference_UTC)
    299 std::vector<Orbit> CosmoImageMetadataInterface::getOrbits(const std::string & reference_UTC)
  • Luc Hermitte
    Luc Hermitte @lhermitte started a thread on commit fb4d22f4
  • 347 347 return orbitVector ;
    348 348 }
    349 349
    350 void CosmoImageMetadataInterface::ParseGdal(const MetadataSupplierInterface & mds)
    350 void CosmoImageMetadataInterface::ParseGdal(ImageMetadata & imd)
    351 351 {
    352 352 // Check acquisition mode and product type
    353 Fetch(MDStr::Mode, mds, "Acquisition_Mode");
    354 if((m_Imd[MDStr::Mode] != "HIMAGE") &&
    355 (m_Imd[MDStr::Mode] != "SPOTLIGHT") &&
    356 (m_Imd[MDStr::Mode] != "ENHANCED SPOTLIGHT"))
    353 Fetch(MDStr::Mode, imd, "Acquisition_Mode");
    354 if((imd[MDStr::Mode] != "HIMAGE") &&
    • Looks like a std::none_of()

    • Author Maintainer

      Yes but imd is not iterable, and it contains many other keys, so I don't see how we could use std::any. I could instantiate a map containing the 3 keys and expected values and call none_of with a lambda fetching and comparing, but I'm not sure it's worth it.

    • {"HIMAGE", "SPOTLIGHT"...} is iterable. I've bugged on the complex expression of the test that spawns on 3 lines with increased indentation everytime.

      I haven't used the right algorithm given the test, but this is the idea. https://quick-bench.com/q/3oJTX53iQqKc1r6YM8TIhx9T-AM

      Then the test could become

      if (otb::not_in(m_Imd[MDStr::Mode], {"HIMAGE", "SPOTLIGHT", "ENHANCED SPOTLIGHT"})
      // for instance

      BTW, I see it's duplicated elsewhere as well. It'd be best to factorize the duplications of these 3 cases.

    • Please register or sign in to reply
  • Luc Hermitte
    Luc Hermitte @lhermitte started a thread on commit fb4d22f4
  • 230 229
    231 230 virtual bool CanRead() const {return false;}
    232 231
    233 virtual void Parse(const MetadataSupplierInterface &)
    234 {
    232 void SupplierCheck() const
    233 {
    234 if (m_MetadataSupplierInterface == nullptr)
    235 throw std::runtime_error("In ImageMetadataInterface, the MetadataSupplier needs to be set before calling the Parse function.");
    236 }
    237
    238 virtual void Parse(ImageMetadata &)
  • Luc Hermitte
    Luc Hermitte @lhermitte started a thread on commit 52fac90e
  • 96 96 double GetCenterIncidenceAngle() const override;
    97 97
    98 98 /*get lookup data for calculating backscatter */
    99 void CreateCalibrationLookupData(const short type) override;
    99 const LookupDataPointerType CreateCalibrationLookupData(const short type) const override;
  • Julien Osman added 3 commits

    added 3 commits

    • 15574bbb - BUG: Add a specific GetAs<bool> function
    • 3b560507 - Merge branch '2159' of gitlab.orfeo-toolbox.org:orfeotoolbox/otb into 2159
    • 5786bf0c - BUG: Set the CalibrationLookupData generation for Sentinel1

    Compare with previous version

  • Julien Osman added 15 commits

    added 15 commits

    • db1fe22b - REFAC: Created a new SARSensorModel class SarSensorModel as a replacement of SarSensorModelAdapter
    • d2284d21 - REFAC: use itk::Point instead of individual coordinates in Orbit parameters
    • fd671c4a - BUG: update expat version in Superbuild (security issue)
    • 9cfd44d1 - REFAC: implement WorldToLineSample (adapted from ossim plugins)
    • 2adf8cba - TEST: validate SAR inverse transform using product GCPs
    • ba383d3b - REFAC: add support for cosmo-skymed products in SarSensorModel
    • 5b625e3d - FIX: Update Baseline for ioTuMetaDataKeyTest
    • 193b4f06 - BUG: Fix key paths in Sentinel1IMI
    • f22b8204 - BUG: Update baseline with SARCalib
    • fc0f84b3 - ENH: Add GetNumberOf function to MetadataSupplierInterface
    • 3367d6e5 - WIP: Parse Calibration metadata for TerrasarX
    • 4a3140d3 - BUG: correct date formatting when time components have only one digit
    • f6b41eb0 - Merge branch '2160-SarSensorModel' into 2159
    • fc1b5242 - ENH: Add GetJulianDay and GetModifiedJulian functions to MetaData::Time
    • 5217bf98 - BUG: Parse Calibration metadata for TerrasarX

    Compare with previous version

  • Julien Osman marked this merge request as draft from 3367d6e5

    marked this merge request as draft from 3367d6e5

  • Julien Osman added 20 commits

    added 20 commits

    Compare with previous version

  • Julien Osman added 1 commit

    added 1 commit

    Compare with previous version

  • Julien Osman added 1 commit

    added 1 commit

    • 86261af7 - ENH: Implement CreateCalibrationLookupData for Radarsat2ImageMetadataInterface

    Compare with previous version

  • Julien Osman added 2 commits

    added 2 commits

    • 1973b2db - BUG: Correctly set the Radarsat2 calibration test
    • d395d481 - BUG: Correct the tests for SarIMI

    Compare with previous version

  • Julien Osman added 1 commit

    added 1 commit

    Compare with previous version

  • Julien Osman added 1 commit

    added 1 commit

    • 6a2321f7 - BUG: Add definition of GetAs<bool>

    Compare with previous version

  • Julien Osman added 1 commit

    added 1 commit

    • 28e07a0c - BUG: Deal with SARCalib metadata stored in bands

    Compare with previous version

  • Luc Hermitte
    Luc Hermitte @lhermitte started a thread on commit ae97a181
  • 383 389 line = (timeSinceStart/m_SarParam.azimuthTimeInterval) + currentBurst->startLine;
    384 390 }
    385 391
    392 void SarSensorModel::SlantRangeToGroundRange(const double & slantRange, const TimeType & azimuthTime, double & groundRange) const
    393 {
    394 ApplyCoordinateConversion(slantRange, azimuthTime, m_SarParam.slantRangeToGroundRangeRecords , groundRange);
    395 }
    396
    397 void SarSensorModel::ApplyCoordinateConversion(const double & in,
    398 const TimeType& azimuthTime,
    399 const std::vector<CoordinateConversionRecord> & records,
    400 double & out) const
    401 {
    • All these loops can be replaced with something more concise (and I guess the other as well). In SRGR case I already did the work in an unpublished branch

      Note that we don't need to copy the coef vector ( srgrRecord = records.back(); x 2), but as I left this optimization in comments I guess the difference wasn't perceptible -- I my benchs most of the time was lost in the use of MAT library (too many allocations)

         void ossimSarSensorModel::applyCoordinateConversion(const double & in, const TimeType& azimuthTime, const std::vector<CoordinateConversionRecordType> & records, double & out) const
         {
            assert(!records.empty()&&"The records vector is empty.");
            // std::clog << "conv coord(" << in << ", az="<<azimuthTime<<")\n";
      
            // First, we need to find the correct pair of records for interpolation
            auto it = records.begin();
      
            CoordinateConversionRecordType srgrRecord;
            auto nextRecord = std::find_if(std::begin(records), std::end(records),
                  [azimuthTime](auto const& record) { return azimuthTime < record.azimuthTime; }
                  );
            // Note: I did try with upper_bound instead of find_if (as the elements are sorted, but there aren't enough elements to make a perceptible difference
      
      
            assert(nextRecord == records.end() || nextRecord->azimuthTime > azimuthTime);
            if (nextRecord == records.end())
            {
               srgrRecord = records.back(); // ### don't copy the coefs vector
               // auto const& ref = records.back();
               // srgrRecord.azimuthTime = ref.azimuthTime;
               // srgrRecord.rg0         = ref.rg0        ;
            }
            else if (nextRecord == records.begin())
            {
               assert(azimuthTime < nextRecord->azimuthTime);
               srgrRecord = records.front(); // ### don't copy the coefs vector
               // auto const& ref = records.front();
               // srgrRecord.azimuthTime = ref.azimuthTime;
               // srgrRecord.rg0         = ref.rg0        ;
            }
            else
            {
               auto previousRecord = nextRecord - 1;
               assert(previousRecord->azimuthTime <= azimuthTime);
               assert(azimuthTime < nextRecord->azimuthTime);
               assert(nextRecord != records.end());
               assert(!previousRecord->coefs.empty()&&"previousRecord coefficients vector is empty.");
               assert(!nextRecord->coefs.empty()&&"nextRecord coefficients vector is empty.");
      
               // If azimuth time is between 2 records, interpolate
               const double interp
                  = DurationType(azimuthTime - previousRecord->azimuthTime)
                  / (nextRecord->azimuthTime - previousRecord->azimuthTime)
                  ;
               // std::clog << "interp: " << interp << " ="
               // << " (" << azimuthTime             << " - " << previousRecord->azimuthTime << " (="<< (azimuthTime             - previousRecord->azimuthTime)<< ") )"
               // << "/(" << nextRecord->azimuthTime << " - " << previousRecord->azimuthTime << " (="<< (nextRecord->azimuthTime - previousRecord->azimuthTime)<< ") )"
               // << "\n";
      
               srgrRecord.rg0 = (1.0-interp) * previousRecord->rg0 + interp*nextRecord->rg0;
      
               srgrRecord.coefs.clear();
               auto pIt = previousRecord->coefs.begin();
               auto nIt = nextRecord->coefs.begin();
      
               srgrRecord.coefs.reserve(std::min(previousRecord->coefs.size(), nextRecord->coefs.size()));
               for(;pIt != previousRecord->coefs.end() && nIt != nextRecord->coefs.end();++pIt,++nIt)
               {
                  srgrRecord.coefs.push_back(interp*(*nIt)+(1.0-interp)*(*pIt));
               }
      
               assert(!srgrRecord.coefs.empty()&&"Slant range to ground range interpolated coefficients vector is empty.");
            }
      
            // Now that we have the interpolated coefs, compute ground range
            // from slant range
            const double sr_minus_sr0 =  in-srgrRecord.rg0;
      
            assert(!srgrRecord.coefs.empty()&&"Slant range to ground range coefficients vector is empty.");
      
            double rout = 0.0; // avoid aliasing in loop
      
            for(auto cIt = srgrRecord.coefs.rbegin();cIt!=srgrRecord.coefs.rend();++cIt)
            {
               rout = *cIt + sr_minus_sr0*rout;
            }
            out = rout;
         }
    • I my benchs most of the time was lost in the use of MAT library (too many allocations)

      I plan on using itk fixed size matrices (itk::Matrix) and vectors (itk::Vector) to replace the NEWMAT objets in the inverse SAR transform. This should reduce the number of allocations.

    • If I'm not mistaken, ITK have started using eigen. It'll be nice to rely on this library for all the transformations.

    • Eigen3 has been integrated into ITK release 5.0.0. Quoting the ITK release notes:

      Eigen, a C++ library for linear algebra, was integrated in ITK and gradual transition from VXL to Eigen for Linear algebra is planned

      It looks like a long term goal of ITK is to replace uses of VXL by Eigen (e.g. use vectors from Eigen in itk::VariableLengthVector). See for example https://discourse.itk.org/t/add-internal-third-party-module-eigen3/1429

      Not that in current release (5.2.1), vnl objects are still used as internal type of ITK vector and matrix objects.

    • Please register or sign in to reply
  • Julien Osman added 8 commits

    added 8 commits

    • 7235f699 - REFAC: add support for TerraSAR-X products in SarSensorModel
    • 009b2b90 - TEST: add a test for SarSensorModel using a TerraSAR-X product
    • d4f3ba79 - ENH: read noise range LUT in S1 products generated by IPF version > 2.90
    • ae97a181 - ENH: add support for GRD and multi-burst products
    • 23517628 - COMP: merge 2159 into 2160-SarSensorModel
    • f8eeec26 - BUG: Read noise metadata for TerrasarX
    • 5ec85f33 - WIP: Read band-dependant metadata
    • ab26cbd3 - Merge branch '2160-SarSensorModel' into 2159

    Compare with previous version

  • Luc Hermitte
    Luc Hermitte @lhermitte started a thread on commit 0965c370
  • 53 54 Point3DType& sensorPos,
    54 55 Vector3DType& sensorVel) const;
    55 56
    57 void LineSampleHeightToWorld(const Point2DType& imPt,
    58 const double & heightAboveEllipsoid,
  • Luc Hermitte
    Luc Hermitte @lhermitte started a thread on commit 0965c370
  • 509 double minDistance = std::numeric_limits<double>::max();
    510
    511 for (const auto & elem : gcpParam.GCPs)
    512 {
    513 auto currentDistance = squaredDistance(imPt, elem);
    514 if (currentDistance < minDistance)
    515 {
    516 minDistance = currentDistance;
    517 closest = &elem;
    518 }
    519 }
    520
    521 return *closest;
    522 }
    523
    524 void SarSensorModel::projToSurface(const GCP & gcp, const Point2DType& imPt, double heightAboveEllipsoid, Point3DType & ecefPoint) const
  • Luc Hermitte
    Luc Hermitte @lhermitte started a thread on commit 0965c370
  • 134 134
    135 135 }
    136 136
    137 void SarSensorModel::LineSampleHeightToWorld(const Point2DType& imPt,
    138 const double & heightAboveEllipsoid,
    139 Point3DType& worldPt) const
    140 {
    141 assert(m_Imd.Has(MDGeom::GCP));
    142
    143 const auto gcp = findClosestGCP(imPt, m_Imd.GetGCPParam());
  • Julien Osman added 1 commit

    added 1 commit

    • d19fd426 - BUG: Read band-dependant metadata

    Compare with previous version

  • Julien Osman added 1 commit

    added 1 commit

    • 4a1fbad6 - BUG: Correctly read noise LUT

    Compare with previous version

  • Julien Osman added 3 commits

    added 3 commits

    • c8745333 - BUG: Set baseline for Radarsat2 metadata reading
    • 25dacd1c - BUG: Read Sentinel1 metadata without band
    • c1292f74 - BUG: Avoid exception when some metadata are not available for TerrasarX

    Compare with previous version

  • Julien Osman added 4 commits

    added 4 commits

    • 55fea8c4 - BUG: Manage the case when metadata contains one layer
    • 670398b8 - ENH: Add SpatialReference::FromGeogCS
    • 684814b1 - BUG: Consider the case of only one matching key in XMLMetadataSupplier::GetNumberOf
    • c874430e - BUG: Don't rely on GDAL to read TerrasarX GCP

    Compare with previous version

  • Cédric Traizet added 2 commits

    added 2 commits

    • cab506d8 - ENH: Parse number of lines and columns for TSX products
    • 85bf0e10 - BUG: fix inverted coordinates in SarParametricMapFunction

    Compare with previous version

  • added 1 commit

    • a93d1b69 - REFAC: read gcp times in ReadGeorefGCP

    Compare with previous version

  • Julien Osman added 2 commits

    added 2 commits

    • 85ce82c7 - BUG: correctly read sentinel1 metadata, including GDC, without GDAL
    • c22373ad - Merge branch '2159' of gitlab.orfeo-toolbox.org:orfeotoolbox/otb into 2159

    Compare with previous version

  • Cédric Traizet added 2 commits

    added 2 commits

    • 32e44e1b - BUG: fix uninitialized variable calibrationLookupFlag
    • 81be5e99 - Merge branch '2159' of https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb into 2159

    Compare with previous version

  • Julien Osman added 1 commit

    added 1 commit

    • ba18f577 - BUG: Read terrasar's polarization later prevents surcharging polarization for other sensors

    Compare with previous version

  • Julien Osman added 1 commit

    added 1 commit

    • 8b32a001 - BUG: Correctly read sentinel1's instrument metadata

    Compare with previous version

  • Cédric Traizet added 8 commits

    added 8 commits

    • 0965c370 - ENH: implements LineSampleHeightToWorld in SarSensorModel
    • 9cd225f3 - Merge remote-tracking branch 'origin/2159' into 2160-SarSensorModel
    • cfb3932d - PERF: copy input doubles instead of using const references
    • 791a115f - ENH: various optimizations (code review)
    • fb6e996b - ENH: add test for the forward sensor model
    • 08a2be01 - ENH: add a test for Sentinel1 SLC geom product
    • 7d467b7d - Merge remote-tracking branch 'origin/2160-SarSensorModel' into 2159
    • b631f032 - REFAC: use mono-band (scalar or complex) products in SarSensorModel

    Compare with previous version

  • Julien Osman added 4 commits

    added 4 commits

    • fa883c0b - ENH: Read NumberOfLines and NumberOfColumns from geom files for terrasar
    • 61114a07 - Merge branch '2159' of gitlab.orfeo-toolbox.org:orfeotoolbox/otb into 2159
    • bbdec105 - TEST: Use Sentinel1 image instead of directory as input
    • 6eb85934 - TEST: Update baseline with metadata in corect order

    Compare with previous version

  • added 1 commit

    • dff9aad5 - BUG: handle old geoms when reading burst informations

    Compare with previous version

  • added 1 commit

    • 08e6d26f - BUG: throw a MissingMetadataException for invalidd Cosmo product types

    Compare with previous version

  • Julien Osman added 3 commits

    added 3 commits

    • 62d8e08b - ENH: Allow GeomMetadataSupplier to keep trace of the image file
    • 83b769af - BUG: Remove multiband from Radarsat2 IMI
    • 462218b7 - Merge branch '2159' of gitlab.orfeo-toolbox.org:orfeotoolbox/otb into 2159

    Compare with previous version

  • Julien Osman added 1 commit

    added 1 commit

    • 4420544c - BUG: Correctly construct GeomMetadataSupplier

    Compare with previous version

  • Julien Osman added 1 commit

    added 1 commit

    • 0472472b - BUG: Allow to read Radarsat2 gcp

    Compare with previous version

  • Julien Osman added 1 commit

    added 1 commit

    • 9e6d6b18 - BUG: Read the correct LUTs for Radarsat2

    Compare with previous version

  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Please register or sign in to reply
    Loading