Commit d844d1b6 authored by Cédric Traizet's avatar Cédric Traizet

Merge branch '2024_GeomMetadataSupplier' into 'develop'

Reading the metadata from the geom files without OSSIM

Closes #2106

See merge request !759
parents d0ca3aec fcca4d70
Pipeline #6076 passed with stages
in 116 minutes and 24 seconds
bias_error : 0
ce90_absolute : 0
ce90_relative : 0
current_adjustment : 0
height_off : 242
height_scale : 500
image_id : 02APR01105228-P1BS-000000128955_01_P001
lat_off : 43.5668
lat_scale : 0.0881
line_off : 14522
line_scale : 14767
adjustment_0.adj_param_0.center : 0
adjustment_0.adj_param_0.description : intrack_offset
adjustment_0.adj_param_0.lock_flag : 0
adjustment_0.adj_param_0.parameter : 0
adjustment_0.adj_param_0.sigma : 50
adjustment_0.adj_param_0.units : pixel
adjustment_0.adj_param_1.center : 0
adjustment_0.adj_param_1.description : crtrack_offset
adjustment_0.adj_param_1.lock_flag : 0
adjustment_0.adj_param_1.parameter : 0
adjustment_0.adj_param_1.sigma : 50
adjustment_0.adj_param_1.units : pixel
adjustment_0.adj_param_2.center : 0
adjustment_0.adj_param_2.description : intrack_scale
adjustment_0.adj_param_2.lock_flag : 0
adjustment_0.adj_param_2.parameter : 0
adjustment_0.adj_param_2.sigma : 50
adjustment_0.adj_param_2.units : unknown
adjustment_0.adj_param_3.center : 0
adjustment_0.adj_param_3.description : crtrack_scale
adjustment_0.adj_param_3.lock_flag : 0
adjustment_0.adj_param_3.parameter : 0
adjustment_0.adj_param_3.sigma : 50
adjustment_0.adj_param_3.units : unknown
adjustment_0.adj_param_4.center : 0
adjustment_0.adj_param_4.description : map_rotation
adjustment_0.adj_param_4.lock_flag : 0
adjustment_0.adj_param_4.parameter : 0
adjustment_0.adj_param_4.sigma : 0.1
adjustment_0.adj_param_4.units : degrees
{"LineOffset": "14522",
"SampleOffset": "13779",
"LatOffset": "43.5668",
"LonOffset": "1.4635",
"HeightOffset": "242",
"LineScale": "14767",
"SampleScale": "13799",
"LatScale": "0.0881",
"LonScale": "0.1095",
"HeightScale": "500",
"LineNum": [ "-0.00139825", "0.00153793", "-0.986303", "0.0160753", "3.45261e-05", "-1.10444e-06", "0.00025058", "-0.000783885", "0.00210043", "-5.89713e-06", "-8.42682e-07", "5.24613e-08", "2.93096e-05", "0", "-8.65437e-06", "-4.4754e-05", "-1.0574e-05", "4.18275e-07", "-4.687e-06", "1.93054e-07", ],
"LineDen": [ "1", "3.82226e-05", "0.000565666", "0.00027757", "1.71173e-05", "-4.27783e-07", "-2.03092e-06", "6.16391e-06", "-2.06465e-05", "1.08768e-05", "4.17567e-08", "5.94172e-08", "-4.37271e-06", "0", "3.06573e-08", "0.00043593", "7.99703e-08", "0", "-1.43435e-05", "2.29249e-08", ],
"SampleNum": [ "-0.00263535", "1.00384", "0.0034115", "0.000261524", "-0.00232656", "0.000620898", "-0.000415032", "0.00128362", "-0.00119353", "7.47621e-06", "2.39993e-06", "-2.14036e-05", "-4.92957e-05", "-1.14876e-05", "8.27706e-05", "-7.63615e-05", "-2.79215e-07", "3.04261e-07", "7.00103e-06", "-2.55119e-08", ],
"SampleDen": [ "1", "0.00136456", "0.00234838", "-0.000621177", "-5.99001e-05", "1.56209e-06", "-1.88818e-06", "-4.23341e-06", "3.14449e-05", "-1.20077e-05", "-1.56497e-07", "-7.45329e-08", "1.97967e-06", "0", "-1.26249e-07", "-1.4791e-06", "-5.68974e-08", "3.27442e-08", "1.06612e-07", "1.69648e-08", ],
}
......@@ -151,7 +151,7 @@ support_data.R_band_absCalFactor: 0.0126735
support_data.TDI_level: 13
support_data.azimuth_angle: 154.8
support_data.band_id: Multi
support_data.band_name_list: B G R N
support_data.band_name_list: X Y
support_data.bits_per_pixel: 16
support_data.elevation_angle: 48.6
support_data.generation_date: 2004-05-25T19:49:03.000000Z
......
......@@ -147,7 +147,7 @@ sensor: WV02
support_data.TDI_level: 0
support_data.azimuth_angle: 0
support_data.band_id: Unknown
support_data.band_name_list: Unknown
support_data.band_name_list: B1 B2
support_data.bits_per_pixel: 0
support_data.elevation_angle: 0
support_data.generation_date: Unknown
......
......@@ -145,7 +145,7 @@ samp_off: 20750
samp_scale: 20749.5
sensor: PHR 1A
support_data.azimuth_angle: """80.2522912450309 79.9972007995515 79.7424588085454 """
support_data.band_name_list: """P """
support_data.band_name_list: """P Q R"""
support_data.elevation_angle: """70.6794398393405 70.6639265028018 70.6478415472195 """
support_data.image_date: 2012-07-19T15:34:14.1Z
support_data.image_id: 565234101-001
......@@ -156,7 +156,7 @@ support_data.instrument_index: 1A
support_data.line_period: 0
support_data.ll_ground_point: 18.474937683268 -72.4019514529938 0 WGE
support_data.lr_ground_point: 18.4745584022313 -72.2113475033199 0 WGE
support_data.number_bands: 1
support_data.number_bands: 3
support_data.number_of_azimuth_angle: 3
support_data.number_of_elevation_angle: 3
support_data.number_of_incident_angle: 3
......
......@@ -61,9 +61,9 @@ otb_test_application(NAME apTvUtDynamicConvertExtendedFilename_readerGEOM
APP DynamicConvert
OPTIONS -in ${INPUTDATA}/ToulouseExtract_WithGeom.tif?&geom=${INPUTDATA}/ToulouseExtract_ModifiedGeom.geom
-out ${TEMP}/apTvUtGeomExtendedFilename.tif
VALID --compare-ascii ${EPSILON_7}
${INPUTDATA}/ToulouseExtract_ModifiedGeom.geom
${TEMP}/apTvUtGeomExtendedFilename.geom)
VALID --compare-metadata ${NOTOL}
${INPUTDATA}/ToulouseExtract_ModifiedMetadata.tif
${TEMP}/apTvUtGeomExtendedFilename.tif)
otb_test_application(NAME apTvUtDynamicConvertLog2
APP DynamicConvert
......
/*
* Copyright (C) 2005-2020 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.
*/
#ifndef otbGeomMetadataSupplier_h
#define otbGeomMetadataSupplier_h
#include <boost/any.hpp>
#include "OTBMetadataExport.h"
#include "otbMetadataSupplierInterface.h"
#include "otbImageMetadata.h"
namespace otb
{
/** \class GeomMetadataSupplier
*
* \brief Class to access metadata information in a Geom file
*
* \ingroup OTBMetadata
*/
class OTBMetadata_EXPORT GeomMetadataSupplier
: public MetadataSupplierInterface
{
public:
using DictType = std::map<std::string, std::string>;
GeomMetadataSupplier(const std::string &);
GeomMetadataSupplier(const GeomMetadataSupplier &) = delete;
GeomMetadataSupplier& operator=(const GeomMetadataSupplier&) = delete;
~GeomMetadataSupplier() = default;
/**
* @brief Get the metadata value corresponding to a given path
*
* @param path The path to look for
* @param hasValue True if path is found
* @param band not used
* @return The value corresponding to path. Empty string if not found.
*/
std::string GetMetadataValue(std::string const& path, bool& hasValue, int band=1) const override;
std::string GetResourceFile(std::string const& s="") const override;
int GetNbBands() const override;
/**
* @brief Fill the ImageMetadata with the data from the geom file
*
* @param imd The ImageMetadata to fill
*/
const boost::any& FetchRPC(ImageMetadata & imd);
/**
* @brief Writes the content of the Geom file into a string
*
* @return A std::string
*/
std::string PrintSelf() const;
protected:
/**
* @brief Parse a Geom file and fill the internal map
*/
void ReadGeomFile();
private:
/** List of resource files */
std::string m_FileName;
/** Dictionary containing the metadata */
DictType m_MetadataDic;
};
} // end namespace otb
#endif
......@@ -24,10 +24,9 @@
#include "OTBMetadataExport.h"
#include <vector>
#include <string>
#include "otbStringUtils.h"
#include "otbMacro.h"
#include "otbStringUtilities.h"
#include "otbStringUtils.h"
#include "otbStringUtilities.h"
namespace otb
{
......@@ -48,7 +47,7 @@ public:
class OTBMetadata_EXPORT MetadataSupplierInterface
{
public:
virtual std::string GetResourceFile(std::string="") const = 0;
virtual std::string GetResourceFile(std::string const& ="") const = 0;
virtual std::vector<std::string> GetResourceFiles() const
{
return std::vector<std::string>{this->GetResourceFile()};
......@@ -59,14 +58,14 @@ public:
* depends on the specific implementation. Returns empty string when path is not found,
* and hasValue is set to False.
* If band >= 0, the metadata value is looked in the specified band*/
virtual std::string GetMetadataValue(const std::string path, bool& hasValue, int band=-1) const = 0;
virtual std::string GetMetadataValue(std::string const& path, bool& hasValue, int band=-1) const = 0;
bool HasValue(std::string path, int band=-1);
bool HasValue(std::string const& path, int band=-1);
virtual int GetNbBands() const = 0;
// utility functions
template <typename T> T GetAs(std::string path, int band=-1) const
template <typename T> T GetAs(std::string const& path, int band=-1) const
{
bool hasValue;
std::string ret = GetMetadataValue(path, hasValue, band);
......@@ -87,7 +86,7 @@ public:
/** Parse a metadata value to a std::vector,
* If size>=0, then the final std::vector size is checked and an exception
* is raised if it doesn't match the given size.*/
template < typename T> std::vector<T> GetAsVector(std::string path, const char sep=' ', int size=-1, int band=-1) const
template < typename T> std::vector<T> GetAsVector(std::string const& path, char sep=' ', int size=-1, int band=-1) const
{
bool hasValue;
std::string ret = GetMetadataValue(path, hasValue, band);
......
......@@ -54,7 +54,7 @@ public:
* @param band not used
* @return The value corresponding to path. Empty string if not found.
*/
std::string GetMetadataValue(const std::string path, bool& hasValue, int band=1) const override;
std::string GetMetadataValue(std::string const& path, bool& hasValue, int band=1) const override;
/**
* @brief Get the first metadata value corresponding to a given path
......@@ -63,7 +63,7 @@ public:
* @param hasValue True if path is found
* @return The value corresponding to path. Empty string if not found.
*/
std::string GetFirstMetadataValue(const std::string paths, bool& hasValue) const;
std::string GetFirstMetadataValue(std::string const& paths, bool& hasValue) const;
/**
* @brief Get the metadata value corresponding to a given path
......@@ -80,7 +80,7 @@ public:
* @return The value corresponding to path.
* @raises otb::Error if path not found
*/
template <typename T> T GetFirstAs(const std::string &path) const
template <typename T> T GetFirstAs(std::string const& path) const
{
bool hasValue;
std::string ret = GetFirstMetadataValue(path, hasValue);
......@@ -98,7 +98,7 @@ public:
}
}
std::string GetResourceFile(std::string="") const override;
std::string GetResourceFile(std::string const& s="") const override;
int GetNbBands() const override;
......
......@@ -72,6 +72,7 @@ set(OTBMetadata_SRC
otbImageMetadata.cxx
otbGeometryMetadata.cxx
otbGeomMetadataSupplier.cxx
otbXMLMetadataSupplier.cxx
otbMetadataStorageInterface.cxx
......
/*
* Copyright (C) 2005-2020 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 <iomanip>
#include <iostream>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include "otbGeomMetadataSupplier.h"
#include "otbMetaDataKey.h"
#include "otbGeometryMetadata.h"
#include "otbStringUtils.h"
namespace otb
{
GeomMetadataSupplier::GeomMetadataSupplier(std::string const& fileName)
: m_FileName(fileName)
{
this->ReadGeomFile();
}
std::string GeomMetadataSupplier::GetMetadataValue(std::string const& path, bool& hasValue, int band) const
{
auto value = this->m_MetadataDic.find(path);
if(value != this->m_MetadataDic.end())
{
hasValue = true;
return value->second;
}
hasValue = false;
return "";
}
std::string GeomMetadataSupplier::GetResourceFile(std::string const& s) const
{
return this->m_FileName;
}
int GeomMetadataSupplier::GetNbBands() const
{
bool hasValue;
std::string ret = this->GetMetadataValue("support_data.number_bands", hasValue);
if (hasValue)
{
boost::algorithm::trim_if(ret, boost::algorithm::is_any_of("\" "));
return std::stoi(ret);
}
ret = this->GetMetadataValue("support_data.band_name_list", hasValue);
boost::algorithm::trim_if(ret, boost::algorithm::is_any_of("\" "));
if (!hasValue)
otbGenericExceptionMacro(MissingMetadataException,<<"Missing metadata 'support_data.band_name_list'")
std::vector<std::string> ret_vect;
otb::Utils::ConvertStringToVector(ret, ret_vect, "band name");
return ret_vect.size();
}
const boost::any& GeomMetadataSupplier::FetchRPC(ImageMetadata & imd)
{
Projection::RPCParam rpcStruct;
rpcStruct.LineOffset = this->GetAs<double>("line_off");
rpcStruct.SampleOffset = this->GetAs<double>("samp_off");
rpcStruct.LatOffset = this->GetAs<double>("lat_off");
rpcStruct.LonOffset = this->GetAs<double>("long_off");
rpcStruct.HeightOffset = this->GetAs<double>("height_off");
rpcStruct.LineScale = this->GetAs<double>("line_scale");
rpcStruct.SampleScale = this->GetAs<double>("samp_scale");
rpcStruct.LatScale = this->GetAs<double>("lat_scale");
rpcStruct.LonScale = this->GetAs<double>("long_scale");
rpcStruct.HeightScale = this->GetAs<double>("height_scale");
std::vector<double> coeffs;
int loop = 0;
std::stringstream path;
for (auto & coeff : rpcStruct.LineNum)
{
path.str("");
path << "line_num_coeff_" << std::setfill('0') << std::setw(2) << loop++;
coeff = this->GetAs<double>(path.str());
}
loop = 0;
for (auto & coeff : rpcStruct.LineDen)
{
path.str("");
path << "line_den_coeff_" << std::setfill('0') << std::setw(2) << loop++;
coeff = this->GetAs<double>(path.str());
}
loop = 0;
for (auto & coeff : rpcStruct.SampleNum)
{
path.str("");
path << "samp_num_coeff_" << std::setfill('0') << std::setw(2) << loop++;
coeff = this->GetAs<double>(path.str());
}
loop = 0;
for (auto & coeff : rpcStruct.SampleDen)
{
path.str("");
path << "samp_den_coeff_" << std::setfill('0') << std::setw(2) << loop++;
coeff = this->GetAs<double>(path.str());
}
imd.Add(MDGeom::RPC, rpcStruct);
return imd[MDGeom::RPC];
}
std::string GeomMetadataSupplier::PrintSelf() const
{
std::ostringstream oss;
oss << "GeomMetadataSupplier: " << this->m_FileName << '\n';
for (const auto& kv : this->m_MetadataDic)
oss << kv.first << " : " << kv.second << '\n';
return oss.str();
}
void GeomMetadataSupplier::ReadGeomFile()
{
std::ifstream inputFile(this->m_FileName);
std::string line;
std::vector< std::string > keyVal;
while (std::getline(inputFile, line))
{
boost::split(keyVal, line, [](char c){return c == ':';});
boost::trim(keyVal[0]);
boost::trim(keyVal[1]);
this->m_MetadataDic[keyVal[0]] = keyVal[1];
}
}
} // end namespace otb
......@@ -23,7 +23,7 @@
namespace otb
{
bool MetadataSupplierInterface::HasValue(const std::string path, int band)
bool MetadataSupplierInterface::HasValue(std::string const& path, int band)
{
bool hasValue;
const std::string ret = GetMetadataValue(path, hasValue, band);
......
......@@ -36,7 +36,7 @@ XMLMetadataSupplier::XMLMetadataSupplier(const std::string & fileName)
CPLDestroyXMLNode(psNode);
}
std::string XMLMetadataSupplier::GetMetadataValue(const std::string path, bool& hasValue, int band) const
std::string XMLMetadataSupplier::GetMetadataValue(std::string const& path, bool& hasValue, int band) const
{
const char * ret = CSLFetchNameValue(m_MetadataDic, path.c_str());
if (ret)
......@@ -49,7 +49,7 @@ std::string XMLMetadataSupplier::GetMetadataValue(const std::string path, bool&
return std::string(ret);
}
std::string XMLMetadataSupplier::GetFirstMetadataValue(const std::string path, bool& hasValue) const
std::string XMLMetadataSupplier::GetFirstMetadataValue(std::string const& path, bool& hasValue) const
{
// Search for the first joker
std::size_t found = path.find("_#");
......@@ -83,7 +83,7 @@ std::string XMLMetadataSupplier::GetFirstMetadataValue(const std::string path, b
}
}
std::string XMLMetadataSupplier::GetResourceFile(std::string) const
std::string XMLMetadataSupplier::GetResourceFile(std::string const& s) const
{
return m_FileName;
}
......
......@@ -33,6 +33,7 @@ otbImageMetadataInterfaceTest2.cxx
otbNoDataHelperTest.cxx
otbSarCalibrationLookupDataTest.cxx
otbImageMetadataTest.cxx
otbGeomMetadataSupplierTest.cxx
otbXMLMetadataSupplierTest.cxx
)
......@@ -422,6 +423,14 @@ otb_add_test(NAME ioTuImageMetadataToFromKeywordlistTest COMMAND otbMetadataTest
${TEMP}/ioTuImageMetadataToFromKeywordlistTest.txt
)
otb_add_test(NAME ioTuotbGeomMetadataSupplierTest COMMAND otbMetadataTestDriver
--compare-ascii ${NOTOL} ${BASELINE_FILES}/ioTuotbGeomMetadataSupplierTest.txt
${TEMP}/ioTuotbGeomMetadataSupplierTest.txt
otbGeomMetadataSupplierTest
${INPUTDATA}/QB/qb-1.geom
${TEMP}/ioTuotbGeomMetadataSupplierTest.txt
)
otb_add_test(NAME ioTuotbXMLMetadataSupplierTest COMMAND otbMetadataTestDriver
--compare-ascii ${NOTOL} ${BASELINE_FILES}/ioTuotbXMLMetadataSupplierTest.txt
${TEMP}/ioTuotbXMLMetadataSupplierTest.txt
......
/*
* Copyright (C) 2020 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 "otbGeomMetadataSupplier.h"
int otbGeomMetadataSupplierTest(int itkNotUsed(argc), char* argv[])
{
// Verify the number of parameters in the command line
const char* fileName = argv[1];
const char* outputFilename = argv[2];
// List of simple keys
std::vector<std::string> simpleKeys =
{"bias_error", "ce90_absolute", "ce90_relative", "current_adjustment", "height_off",
"height_scale", "image_id", "lat_off", "lat_scale", "line_off", "line_scale"};
// List of adjustment keys
std::vector<std::string> adjustmentKeys =
{"center", "description", "lock_flag", "parameter", "sigma", "units"};
// Instantiate the supplier
otb::GeomMetadataSupplier mds(fileName);
bool hasValue;
std::ofstream file;
file.open(outputFilename);
for(auto const& val : simpleKeys)
file << val << " : " << mds.GetMetadataValue(val, hasValue) << "\n";
std::ostringstream key;
std::ostringstream key2;
for(unsigned int loop = 0 ; loop < 5 ; ++loop)
{
key.str("");
key << "adjustment_0.adj_param_" << loop << ".";
for (auto const& val : adjustmentKeys)
{
key2.str("");
key2 << key.str() << val;
file << key2.str() << " : " << mds.GetMetadataValue(key2.str(), hasValue) << "\n";
}
}
file << '\n';
otb::ImageMetadata imd;
mds.FetchRPC(imd);
file << boost::any_cast<otb::Projection::RPCParam>(imd[otb::MDGeom::RPC]).ToJSON(true) << '\n';
file.close();
return EXIT_SUCCESS;
}
......@@ -33,5 +33,6 @@ void RegisterTests()
REGISTER_TEST(otbNoDataHelperTest);
REGISTER_TEST(otbSarCalibrationLookupDataTest);
REGISTER_TEST(otbImageMetadataTest);
REGISTER_TEST(otbGeomMetadataSupplierTest);
REGISTER_TEST(otbXMLMetadataSupplierTest);
}
......@@ -118,15 +118,16 @@ otb_add_test(NAME ioTvImageFileReaderExtendedFileName_GEOM COMMAND otbExtendedFi
${TEMP}/ioImageFileReaderWithExternalGEOMFile_pr.txt
)
otb_add_test(NAME ioTvImageFileWriterExtendedFileName_GEOM COMMAND otbExtendedFilenameTestDriver
--ignore-order --compare-ascii ${NOTOL}
${INPUTDATA}/ToulouseExtract_WithGeom.geom
${TEMP}/ioImageFileWriterExtendedFileName_GEOM.geom
--ignore-lines-with 2 ce90_absolute ce90_relative
otbImageFileWriterWithExtendedFilename
${INPUTDATA}/ToulouseExtract_WithGeom.tif
${TEMP}/ioImageFileWriterExtendedFileName_GEOM.tif?&writegeom=ON
)
# TODO: This test needs to be removed when the extended filename writegeom is replaced by writeMetadata
#otb_add_test(NAME ioTvImageFileWriterExtendedFileName_GEOM COMMAND otbExtendedFilenameTestDriver
# --ignore-order --compare-ascii ${NOTOL}
# ${INPUTDATA}/ToulouseExtract_WithGeom.geom
# ${TEMP}/ioImageFileWriterExtendedFileName_GEOM.geom
# --ignore-lines-with 2 ce90_absolute ce90_relative
# otbImageFileWriterWithExtendedFilename
# ${INPUTDATA}/ToulouseExtract_WithGeom.tif
# ${TEMP}/ioImageFileWriterExtendedFileName_GEOM.tif?&writegeom=ON
# )