From ca20c963cbc1b400b25ddbcf9c9e38fc48a3013a Mon Sep 17 00:00:00 2001 From: Julien Michel <julien.michel@orfeo-toolbox.org> Date: Tue, 8 Jul 2014 16:27:52 +0200 Subject: [PATCH] ENH: Adding a helper class to hold duplicated code computing p/xs offset for Pleiades sensor bundles --- ...PleiadesPToXSAffineTransformCalculator.cxx | 155 ++++++++++++++++++ ...tbPleiadesPToXSAffineTransformCalculator.h | 94 +++++++++++ 2 files changed, 249 insertions(+) create mode 100644 Code/Projections/otbPleiadesPToXSAffineTransformCalculator.cxx create mode 100644 Code/Projections/otbPleiadesPToXSAffineTransformCalculator.h diff --git a/Code/Projections/otbPleiadesPToXSAffineTransformCalculator.cxx b/Code/Projections/otbPleiadesPToXSAffineTransformCalculator.cxx new file mode 100644 index 0000000000..3d51699ed2 --- /dev/null +++ b/Code/Projections/otbPleiadesPToXSAffineTransformCalculator.cxx @@ -0,0 +1,155 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.txt for details. + + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __otbPleiadesPToXSAffineTransformCalculator__cxx +#define __otbPleiadesPToXSAffineTransformCalculator__cxx + +#include "otbPleiadesPToXSAffineTransformCalculator.h" +#include "otbPleiadesImageMetadataInterface.h" +#include "otbDateTimeAdapter.h" +#include "otbImageKeywordlist.h" +#include "itkMetaDataObject.h" + +namespace otb { + +bool +PleiadesPToXSAffineTransformCalculator +::CanCompute(const itk::ImageBase<2> * panchromaticImage, const itk::ImageBase<2> * xsImage) +{ + bool isPanPHR = false; + bool isXSPHR = false; + + otb::PleiadesImageMetadataInterface::Pointer phrIMI = + otb::PleiadesImageMetadataInterface::New(); + phrIMI->SetMetaDataDictionary(panchromaticImage->GetMetaDataDictionary()); + isPanPHR = phrIMI->CanRead(); + + phrIMI->SetMetaDataDictionary(xsImage->GetMetaDataDictionary()); + isXSPHR = phrIMI->CanRead(); + + if (isPanPHR && isXSPHR) + { + ImageKeywordlist kwlPan; + ImageKeywordlist kwlXS; + + itk::ExposeMetaData<ImageKeywordlist>( + panchromaticImage->GetMetaDataDictionary(), + MetaDataKey::OSSIMKeywordlistKey, + kwlPan); + + itk::ExposeMetaData<ImageKeywordlist>( + xsImage->GetMetaDataDictionary(), + MetaDataKey::OSSIMKeywordlistKey, + kwlXS); + + // Get geometric processing + std::string panProcessing = kwlPan.GetMetadataByKey("support_data.processing_level"); + std::string xsProcessing = kwlXS.GetMetadataByKey("support_data.processing_level"); + + if (panProcessing.compare("SENSOR") == 0 && + xsProcessing.compare("SENSOR") == 0) + { + + std::string pid = kwlPan.GetMetadataByKey("image_id"); + std::string xsid = kwlXS.GetMetadataByKey("image_id"); + + pid = pid.substr(0,pid.size()-4); + xsid = xsid.substr(0,xsid.size()-4); + + if(pid == xsid) + { + return true; + } + } + } + return false; +} + +PleiadesPToXSAffineTransformCalculator +::TransformType::Pointer +PleiadesPToXSAffineTransformCalculator +::Compute(const itk::ImageBase<2> * panchromaticImage, const itk::ImageBase<2> * xsImage) +{ + if(!CanCompute(panchromaticImage,xsImage)) + { + itkGenericExceptionMacro("Can not compute affine transform between images, they do not correspond to Pleiades sensor bundle."); + } + + ImageKeywordlist kwlPan; + ImageKeywordlist kwlXS; + + itk::ExposeMetaData<ImageKeywordlist>( + panchromaticImage->GetMetaDataDictionary(), + MetaDataKey::OSSIMKeywordlistKey, + kwlPan); + + itk::ExposeMetaData<ImageKeywordlist>( + xsImage->GetMetaDataDictionary(), + MetaDataKey::OSSIMKeywordlistKey, + kwlXS); + + // Compute time delta + std::string strStartTimePan = kwlPan.GetMetadataByKey("support_data.time_range_start"); + std::string strStartTimeXS = kwlXS.GetMetadataByKey("support_data.time_range_start"); + + DateTimeAdapter::Pointer startTimePan = DateTimeAdapter::New(); + DateTimeAdapter::Pointer startTimeXS = DateTimeAdapter::New(); + + startTimePan->SetFromIso8601(strStartTimePan); + startTimeXS->SetFromIso8601(strStartTimeXS); + + double timeDelta = startTimeXS->GetDeltaInSeconds(startTimePan); + + // Retrieve line period in Pan + std::string tmpStr = kwlPan.GetMetadataByKey("support_data.line_period"); + double linePeriodPan = atof(tmpStr.c_str()); + + // Retrieve column start + tmpStr = kwlPan.GetMetadataByKey("support_data.swath_first_col"); + int colStartPan = atoi(tmpStr.c_str()); + tmpStr = kwlXS.GetMetadataByKey("support_data.swath_first_col"); + int colStartXS = atoi(tmpStr.c_str()); + + // Compute shift between MS and P (in Pan pixels) + // in order to keep the top left corners unchanged, apply an + // additional offset of (3/2) panchro pixels, or 0.375 xs pixels + int lineShift_MS_P =int(vcl_floor((timeDelta/(linePeriodPan/1000)) + 0.5)) + 0.375; + int colShift_MS_P = colStartXS*4 - colStartPan-4 + 0.375; + + // Apply the scaling + typedef itk::ScalableAffineTransform<double, 2> TransformType; + TransformType::Pointer transform = TransformType::New(); + transform->Scale(4.0); + + // Apply the offset + TransformType::OutputVectorType offset; + offset[0] = static_cast<double>(colShift_MS_P); + offset[1] = static_cast<double>(lineShift_MS_P); + transform->Translate(offset); + + // Invert the transform to get the P to XS transform + TransformType::Pointer realTransform = TransformType::New(); + transform->GetInverse(realTransform); + + return realTransform; + } + +} // End namespace otb + +#endif + + diff --git a/Code/Projections/otbPleiadesPToXSAffineTransformCalculator.h b/Code/Projections/otbPleiadesPToXSAffineTransformCalculator.h new file mode 100644 index 0000000000..aae59f0c9d --- /dev/null +++ b/Code/Projections/otbPleiadesPToXSAffineTransformCalculator.h @@ -0,0 +1,94 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.txt for details. + + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __otbPleiadesPToXSAffineTransformCalculator__h +#define __otbPleiadesPToXSAffineTransformCalculator__h + +#include "itkLightObject.h" +#include "itkObjectFactory.h" +#include "itkScalableAffineTransform.h" +#include "itkImageBase.h" + +namespace otb { +/** + * \class PleiadesPToXSAffineTransformCalculator + * \brief Compute the affine transform linking P and XS pixel position for Pleiades sensor bundles + * + * Pleiades sensor bundle are exactly homotetic, it is therefore + * possible to corregister the pancrhomatic and multispectral images + * with a simple affine transform without using any sensor + * modelling. This yelds a very accurate corregistration and avoid the + * use of a DSM which may cause registration errors due to height errors. + * + * This calculator is a helper class to build the affine transform. It + * consists in only two static methods: one to check if the transform + * calculation applies to the given pair of images, the other to + * actually estimate the transfrom. + * + * The estimated transform returned by the latter transforms + * pancrhomatic image positions to multispectral image positions. If + * the inverse transform is needed, one can call the GetInverse() + * method of the transform to retrieve it. + * + */ +class ITK_EXPORT PleiadesPToXSAffineTransformCalculator + : public itk::LightObject +{ +public: + typedef PleiadesPToXSAffineTransformCalculator Self; + typedef itk::LightObject Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + itkTypeMacro(PleiadesPToXSAffineTransformCalculator,itk::LightObject); + + typedef itk::ScalableAffineTransform<double,2> TransformType; + + /** + * This function checks if the transform calculation applies to the + * given pair of images. Checked items are: + * - Both images are sucessfully undertood by OTB as Pléiades images, + * - Both images processing level is SENSOR", + * - XS and Pan ids (except last 4 letters) are equal. + * \return True if the calculation applies + */ + static bool CanCompute(const itk::ImageBase<2> * panchromaticImage, const itk::ImageBase<2> * xsImage); + + + /** + * This function computes the transform for a pair of image. Note + * that the CanCompute() method is first called, and that an + * exception will be raised if computation can not be done. + * + * This function reads both images support data and builds a + * transform that will exactly coregister the images. + * + * \return The computed transform + */ + static TransformType::Pointer Compute(const itk::ImageBase<2> * panchromaticImage, const itk::ImageBase<2> * xsImage); + +private: + PleiadesPToXSAffineTransformCalculator(); // purposely not implemented + PleiadesPToXSAffineTransformCalculator(const Self &); // purposely not implemented + void operator =(const Self&); // purposely not implemented +}; + + +} // End namespace otb + + +#endif -- GitLab