diff --git a/Documentation/SoftwareGuide/Latex/OrthoRectification.tex b/Documentation/SoftwareGuide/Latex/OrthoRectification.tex index f372d4eb5269db49b1f96e341434f7b1a6ea4d55..6d1354cdfc839d926ef206bca9f715723da8cebb 100644 --- a/Documentation/SoftwareGuide/Latex/OrthoRectification.tex +++ b/Documentation/SoftwareGuide/Latex/OrthoRectification.tex @@ -158,20 +158,28 @@ OTB, through the use of the OSSIM library -- sensors either through a physical or an analytical approach. This is transparent for the user, since the geometrical model for a given image is instantiated using the information stored in its meta-data. The -search for a sensor model is not straightforward. It is done in 3 steps : +search for a sensor model is not straightforward. It is done in several steps : \begin{enumerate} + \item Load an external \code{.geom} file specified through extended filenames +(if present) + \item Load the \code{.geom} file attached with the input image (if present). +They share the same name, without extension. \item Search in the OSSIM plugin factory for a suitable model (\code{ossimplugins::ossimPluginProjectionFactory}). For instance, this factory contains Pl\'eiades and TerraSar sensor models. \item If no model was found, search in the OSSIM projection factory (\code{ossimProjectionFactoryRegistry}). For instance this factory contains Spot5, Landsat and Quickbird sensor models. - \item If still no model was found, search for a valid sensor model defined - in an external \code{.geom} file. If no model is found, check if there are -any RPC tags embedded within the image (GDAL is used to detect those RPC -tags). When the tags are present, an \code{ossimRpcModel} is created. + \item If no model was found, search any RPC tags in the input image. When the +tags are present, an \code{ossimRpcModel} is created. + \item If still no model was found, search for a valid sensor model in other +files attached to the current dataset. For instance, with a Sentinel-1 SAFE XML +product, it will inspect underlying \code{.tiff} files. With a VRT dataset, it +will inspect the files referenced by the VRT. \end{enumerate} +Note that the \code{.geom} metadata file can store any sensor model recognized +by OSSIM. \subsection{Using Sensor Models} \label{sec:UsingSensorModels} diff --git a/Modules/Core/ImageBase/include/otbImageIOBase.h b/Modules/Core/ImageBase/include/otbImageIOBase.h index ecadb4f00813fa85561d4f75962d3af413b89810..09303fb5bbce2b2fa2e704f38ac311a8e7eb5515 100644 --- a/Modules/Core/ImageBase/include/otbImageIOBase.h +++ b/Modules/Core/ImageBase/include/otbImageIOBase.h @@ -429,6 +429,9 @@ public: * conversion)*/ void DoMapBuffer(void* buffer, size_t numberOfPixels, std::vector<unsigned int>& bandList); + /** Returns a const ref to the list of attached files*/ + itkGetConstReferenceMacro(AttachedFileNames, std::vector<std::string> ); + protected: ImageIOBase(); ~ImageIOBase() override; @@ -550,6 +553,9 @@ protected: unsigned int numberOfActualSplits, const itk::ImageIORegion &pasteRegion) const; + /** List of files part of the same dataset as the input filename */ + std::vector<std::string> m_AttachedFileNames; + private: ImageIOBase(const Self&) = delete; void operator=(const Self&) = delete; diff --git a/Modules/IO/IOGDAL/src/otbGDALImageIO.cxx b/Modules/IO/IOGDAL/src/otbGDALImageIO.cxx index 439fd0e106ae427d7d082b496ca8828eff57916e..e800d8f4f0c47fc3e65c2eb1a4e89975c1904350 100644 --- a/Modules/IO/IOGDAL/src/otbGDALImageIO.cxx +++ b/Modules/IO/IOGDAL/src/otbGDALImageIO.cxx @@ -435,7 +435,7 @@ void GDALImageIO::InternalReadImageInformation() // supported gdal format using the m_DatasetNumber value // HDF4_SDS:UNKNOWN:"myfile.hdf":2 // and make m_Dataset point to it. - if (m_Dataset->GetDataSet()->GetRasterCount() == 0) + if (m_Dataset->GetDataSet()->GetRasterCount() == 0 || m_DatasetNumber > 0) { // this happen in the case of a hdf file with SUBDATASETS // Note: we assume that the datasets are in order @@ -659,6 +659,24 @@ void GDALImageIO::InternalReadImageInformation() } } + // get list of other files part of the same dataset + char** datasetFileList = dataset->GetFileList(); + m_AttachedFileNames.clear(); + if (datasetFileList != nullptr) + { + char** currentFile = datasetFileList; + while (*currentFile != nullptr) + { + if (m_FileName.compare(*currentFile) != 0) + { + m_AttachedFileNames.emplace_back(*currentFile); + otbLogMacro(Debug,<<"Found attached file : "<< *currentFile); + } + currentFile++; + } + CSLDestroy(datasetFileList); + } + /*----------------------------------------------------------------------*/ /*-------------------------- METADATA ----------------------------------*/ /*----------------------------------------------------------------------*/ diff --git a/Modules/IO/ImageIO/include/otbImageFileReader.hxx b/Modules/IO/ImageIO/include/otbImageFileReader.hxx index c26730b0058a322f728ad905c540c7e571796b5b..9e3215277e01a6b92d55cfe398fff4d95a28c9a6 100644 --- a/Modules/IO/ImageIO/include/otbImageFileReader.hxx +++ b/Modules/IO/ImageIO/include/otbImageFileReader.hxx @@ -433,7 +433,20 @@ ImageFileReader<TOutputImage, ConvertPixelTraits> } else { - otbLogMacro(Info,<< "No kwl metadata found in file "<<lFileNameOssimKeywordlist); + // Try attached files + for (const std::string& path : m_ImageIO->GetAttachedFileNames()) + { + otb_kwl = ReadGeometryFromImage(path,!m_FilenameHelper->GetSkipRpcTag()); + if(!otb_kwl.Empty()) + { + otbLogMacro(Info,<< "Loading kwl metadata in attached file "<<path); + break; + } + } + if (otb_kwl.Empty()) + { + otbLogMacro(Info,<< "No kwl metadata found in file "<<lFileNameOssimKeywordlist); + } } } diff --git a/Modules/IO/ImageIO/test/CMakeLists.txt b/Modules/IO/ImageIO/test/CMakeLists.txt index 59b02a6d60000b595ee5f3bbb6bf94356f40541c..f6cbe8fb68c8d9689ed167a1346198265da57de9 100644 --- a/Modules/IO/ImageIO/test/CMakeLists.txt +++ b/Modules/IO/ImageIO/test/CMakeLists.txt @@ -75,6 +75,7 @@ otbCompareWritingComplexImage.cxx otbImageFileReaderOptBandTest.cxx otbImageFileWriterOptBandTest.cxx otbMultiImageFileWriterTest.cxx +otbWriteGeomFile.cxx ) add_executable(otbImageIOTestDriver ${OTBImageIOTests}) @@ -1357,3 +1358,12 @@ otb_add_test(NAME ioTvMultiImageFileWriter_DiffSize ${TEMP}/ioTvMultiImageFileWriter_DiffSize1.tif ${TEMP}/ioTvMultiImageFileWriter_DiffSize2.tif 25) + +otb_add_test(NAME ioTvCompoundMetadataReaderTest + COMMAND otbImageIOTestDriver + --compare-ascii ${EPSILON_9} + ${INPUTDATA}/QB_Toulouse_SensorModel_labelImage.geom + ${TEMP}/ioTvCompoundMetadataReaderTest.geom + otbWriteGeomFile + ${INPUTDATA}/QB_Toulouse_combo.vrt + ${TEMP}/ioTvCompoundMetadataReaderTest.tif) diff --git a/Modules/IO/ImageIO/test/otbImageIOTestDriver.cxx b/Modules/IO/ImageIO/test/otbImageIOTestDriver.cxx index 0dab5832434baab0f12df11545fcd93e348858ac..1d59f88e8a8ba93e3616e1efd30f644bfe4ce0db 100644 --- a/Modules/IO/ImageIO/test/otbImageIOTestDriver.cxx +++ b/Modules/IO/ImageIO/test/otbImageIOTestDriver.cxx @@ -152,4 +152,5 @@ void RegisterTests() REGISTER_TEST(otbImageFileReaderOptBandTest); REGISTER_TEST(otbImageFileWriterOptBandTest); REGISTER_TEST(otbMultiImageFileWriterTest); + REGISTER_TEST(otbWriteGeomFile); } diff --git a/Modules/IO/ImageIO/test/otbWriteGeomFile.cxx b/Modules/IO/ImageIO/test/otbWriteGeomFile.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5ccf3cb985cb3a7eea1adcb64b9ae6a3108fc46b --- /dev/null +++ b/Modules/IO/ImageIO/test/otbWriteGeomFile.cxx @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2005-2017 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 "otbVectorImage.h" +#include "itkMacro.h" +#include <iostream> + +#include "otbImageFileReader.h" + +int otbWriteGeomFile(int itkNotUsed(argc), char* argv[]) +{ + + // Verify the number of parameters in the command line + std::string inputFilename(argv[1]); + std::string outputFilename(argv[2]); + + typedef double InputPixelType; + const unsigned int Dimension = 2; + + typedef otb::VectorImage<InputPixelType, Dimension> InputImageType; + typedef otb::ImageFileReader<InputImageType> ReaderType; + + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(inputFilename); + reader->UpdateOutputInformation(); + + otb::ImageKeywordlist otb_kwl; + itk::MetaDataDictionary &dict = reader->GetOutput()->GetMetaDataDictionary(); + itk::ExposeMetaData<otb::ImageKeywordlist>(dict, otb::MetaDataKey::OSSIMKeywordlistKey, otb_kwl); + if (otb_kwl.Empty()) + { + return EXIT_FAILURE; + } + + otb::WriteGeometry(otb_kwl, outputFilename); + + return EXIT_SUCCESS; +}