diff --git a/Modules/Filtering/ImageManipulation/include/otbChangeInformationImageFilter.h b/Modules/Filtering/ImageManipulation/include/otbChangeInformationImageFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..f92b2c20656c832253b695b6f5845a93465635b1 --- /dev/null +++ b/Modules/Filtering/ImageManipulation/include/otbChangeInformationImageFilter.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 __otbChangeInformationImageFilter_h +#define __otbChangeInformationImageFilter_h + +#include "itkChangeInformationImageFilter.h" +#include "otbMetaDataKey.h" + +namespace otb +{ + +/** + * \class ChangeInformationImageFilter + * \brief Filter to modify image metadata + * + * The base class is itk::ChangeInformationImageFilter that allows to + * modifiy origin, spacing, direction and buffered region. This deriving + * filter adds the support of MetaDataDictionary. + * + * \ingroup OTBImageManipulation + */ +template< typename TInputImage > +class ChangeInformationImageFilter: + public itk::ChangeInformationImageFilter< TInputImage > +{ +public: + /** Standard class typedefs. */ + typedef ChangeInformationImageFilter Self; + typedef itk::ChangeInformationImageFilter<TInputImage> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Creation through object factory macro */ + itkTypeMacro(ChangeInformationImageFilter, itk::ChangeInformationImageFilter); + + /** Set key names to change */ + void SetChangeMetaData(const char *keyname, bool flag); + + /** Ask if a metadata will be changed */ + bool GetChangeMetaData(const char *keyname); + + /** Set output values for metadata, passing a NULL value will remove the + * metadata from output. If not set for a key name in the change list, + * the metadata will also be set. + */ + template<typename T> + void SetOutputMetaData(const char *keyname, const T * value); + +protected: + ChangeInformationImageFilter() {} + virtual ~ChangeInformationImageFilter() {} + + /** Apply changes to the output image metadata. */ + virtual void GenerateOutputInformation(); + +private: + ChangeInformationImageFilter(const Self &); //purposely not implemented + void operator =(const Self&); //purposely not implemented + + /** Removes a field from a metadata dictionary + * After ITK 4.6, an Erase() method has been added to + * itk::MetaDataDictionary, so this function could be tagged as deprecated */ + bool RemoveKeyFromDictionary(itk::MetaDataDictionary & dict, const std::string & key); + + /** List of metadata keys to change */ + std::set<std::string> m_ChangedKeys; + +}; + +} // End of namespace OTB + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbChangeInformationImageFilter.txx" +#endif + +#endif diff --git a/Modules/Filtering/ImageManipulation/include/otbChangeInformationImageFilter.txx b/Modules/Filtering/ImageManipulation/include/otbChangeInformationImageFilter.txx new file mode 100644 index 0000000000000000000000000000000000000000..319684064c4caf4a83c8be8b7fd460cae13d920d --- /dev/null +++ b/Modules/Filtering/ImageManipulation/include/otbChangeInformationImageFilter.txx @@ -0,0 +1,150 @@ +/*========================================================================= + + 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 __otbChangeInformationImageFilter_txx +#define __otbChangeInformationImageFilter_txx + +#include "otbChangeInformationImageFilter.h" +#include "itkMetaDataObject.h" + +namespace otb +{ + +template< typename TInputImage > +void +ChangeInformationImageFilter<TInputImage> +::SetChangeMetaData(const char *keyname, bool flag) +{ + std::string key(keyname); + if (! key.empty()) + { + if (flag) + { + m_ChangedKeys.insert(key); + } + else + { + std::set<std::string>::iterator pos = m_ChangedKeys.find(key); + if (pos != m_ChangedKeys.end()) + { + m_ChangedKeys.erase(pos); + } + } + } +} + +template< typename TInputImage > +bool +ChangeInformationImageFilter<TInputImage> +::GetChangeMetaData(const char *keyname) +{ + std::string key(keyname); + if (! key.empty()) + { + if (m_ChangedKeys.find(key) != m_ChangedKeys.end()) + { + return true; + } + } + return false; +} + +template< typename TInputImage > +template<typename T> +void +ChangeInformationImageFilter<TInputImage> +::SetOutputMetaData(const char *keyname, const T * value) +{ + std::string key(keyname); + if (! key.empty()) + { + // enable this key for metadata change + m_ChangedKeys.insert(key); + itk::MetaDataDictionary &dict = this->GetMetaDataDictionary(); + if (value == NULL) + { + // Remove meta-data from dictionary + this->RemoveKeyFromDictionary(dict,key); + } + else + { + // Set metadata in dictionary + const T &valueRef = (*value); + itk::EncapsulateMetaData<T>(dict,key,valueRef); + } + } +} + +template< typename TInputImage > +void +ChangeInformationImageFilter<TInputImage> +::GenerateOutputInformation() +{ + Superclass::GenerateOutputInformation(); + + // Process the metadatas to be changed + itk::MetaDataDictionary &dict = this->GetMetaDataDictionary(); + itk::MetaDataDictionary &outputDict = this->GetOutput()->GetMetaDataDictionary(); + std::set<std::string>::iterator it = m_ChangedKeys.begin(); + for ( ; it != m_ChangedKeys.end() ; ++it) + { + if (dict.HasKey(*it)) + { + // Replace metadata in output dictionary + outputDict[*it] = dict[*it]; + } + else + { + // Remove metadata from output dictionary + this->RemoveKeyFromDictionary(outputDict,*it); + } + } +} + +template< typename TInputImage > +bool +ChangeInformationImageFilter<TInputImage> +::RemoveKeyFromDictionary(itk::MetaDataDictionary & dict, const std::string & key) +{ + std::vector<std::string> keyList = dict.GetKeys(); + std::vector<std::string>::iterator pos = keyList.begin(); + while (pos != keyList.end()) + { + if (key.compare(*pos) == 0) + { + break; + } + ++pos; + } + if (pos != keyList.end()) + { + itk::MetaDataDictionary copyDict; + keyList.erase(pos); + pos = keyList.begin(); + for ( ; pos != keyList.end();++pos) + { + copyDict.Set(*pos, const_cast<itk::MetaDataObjectBase*>(dict.Get(*pos))); + } + dict = copyDict; + return true; + } + return false; +} + +} // End of namespace OTB + +#endif diff --git a/Modules/Filtering/ImageManipulation/test/CMakeLists.txt b/Modules/Filtering/ImageManipulation/test/CMakeLists.txt index 86e9cd72c67dca156fc4fd293c9b220ff186fc21..3019412f1434a6242298ef6d9fc9eff55aa520d2 100644 --- a/Modules/Filtering/ImageManipulation/test/CMakeLists.txt +++ b/Modules/Filtering/ImageManipulation/test/CMakeLists.txt @@ -75,6 +75,7 @@ otbOneRIBandImageToOneComplexBandImage.cxx otbTwoNRIBandsImageToNComplexBandsImage.cxx otbChangeNoDataValueFilter.cxx otbImageToNoDataMaskFilter.cxx +otbChangeInformationImageFilter.cxx ) add_executable(otbImageManipulationTestDriver ${OTBImageManipulationTests}) @@ -710,3 +711,8 @@ otb_add_test(NAME filteringImageManipulationChangeNoDataValueFilter COMMAND otbI otb_add_test(NAME filteringImageManipulationImageToNoDataMaskFilter COMMAND otbImageManipulationTestDriver otbImageToNoDataMaskFilter) + +otb_add_test(NAME bfTvChangeInformationImageFilter COMMAND otbImageManipulationTestDriver + otbChangeInformationImageFilter + ${INPUTDATA}/WV2_PAN_ROI_1000_100.tif + ) diff --git a/Modules/Filtering/ImageManipulation/test/otbChangeInformationImageFilter.cxx b/Modules/Filtering/ImageManipulation/test/otbChangeInformationImageFilter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..2a6a7e2a904cee67cfa8d15e7bf7d3be65126ece --- /dev/null +++ b/Modules/Filtering/ImageManipulation/test/otbChangeInformationImageFilter.cxx @@ -0,0 +1,66 @@ +/*========================================================================= + + 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. + +=========================================================================*/ +#include "otbChangeInformationImageFilter.h" +#include "otbImageFileReader.h" +#include "otbImage.h" + +int otbChangeInformationImageFilter(int itkNotUsed(argc), char * argv[]) +{ + const char *inputFilename(argv[1]); + + typedef otb::Image<float,2> ImageType; + typedef otb::ChangeInformationImageFilter<ImageType> FilterType; + typedef otb::ImageFileReader<ImageType> ReaderType; + + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(inputFilename); + + FilterType::Pointer filter = FilterType::New(); + filter->SetInput(reader->GetOutput()); + // try to set a different ProjRef + std::string newProj("Fake ProjRef"); + filter->SetOutputMetaData<std::string>(otb::MetaDataKey::ProjectionRefKey,&newProj); + // erase that choice + filter->SetOutputMetaData<std::string>(otb::MetaDataKey::ProjectionRefKey,NULL); + // add a no data to the image + std::vector<bool> flags; + flags.push_back(true); + std::vector<double> nodata; + nodata.push_back(0.0); + filter->SetOutputMetaData<std::vector<bool> >(otb::MetaDataKey::NoDataValueAvailable,&flags); + filter->SetOutputMetaData<std::vector<double> >(otb::MetaDataKey::NoDataValue,&nodata); + filter->UpdateOutputInformation(); + + ImageType::Pointer outImage = filter->GetOutput(); + if (! outImage->GetProjectionRef().empty()) + { + std::cout << "Projection is supposed to be removed but is still present !" << std::endl; + return EXIT_FAILURE; + } + + itk::MetaDataDictionary &dict = outImage->GetMetaDataDictionary(); + if (!dict.HasKey(otb::MetaDataKey::NoDataValueAvailable) || + !dict.HasKey(otb::MetaDataKey::NoDataValue)) + { + std::cout << "Missing no data metadata !" << std::endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + diff --git a/Modules/Filtering/ImageManipulation/test/otbImageManipulationTestDriver.cxx b/Modules/Filtering/ImageManipulation/test/otbImageManipulationTestDriver.cxx index f732d0d2a493a927ccfd34f1f5633d85b3508cf3..299f6744511b2d781a1f5a0d973b4c122c44674b 100644 --- a/Modules/Filtering/ImageManipulation/test/otbImageManipulationTestDriver.cxx +++ b/Modules/Filtering/ImageManipulation/test/otbImageManipulationTestDriver.cxx @@ -81,4 +81,5 @@ void RegisterTests() REGISTER_TEST(otbTwoNRIBandsImageToNComplexBandsImage); REGISTER_TEST(otbChangeNoDataValueFilter); REGISTER_TEST(otbImageToNoDataMaskFilter); + REGISTER_TEST(otbChangeInformationImageFilter); }