From fb81ec608192a143e3c7aa9af2bbd5f8571e0052 Mon Sep 17 00:00:00 2001 From: Mickael Savinaud <mickael.savinaud@c-s.fr> Date: Tue, 22 Nov 2011 18:41:31 +0100 Subject: [PATCH] ENH: give the possibility to set the cache size of JPEG2000ImageIO::Read function and tests --- Code/IO/otbImageFileReader.txx | 2 + Code/IO/otbJPEG2000ImageIO.cxx | 95 +++++++++++++++++-- Code/IO/otbJPEG2000ImageIO.h | 7 ++ Testing/Code/IO/CMakeLists.txt | 42 +++++++- .../IO/otbGenerateClassicalQLWithJPEG2000.cxx | 65 +++++++++++++ Testing/Code/IO/otbIOTests13.cxx | 1 + 6 files changed, 205 insertions(+), 7 deletions(-) create mode 100644 Testing/Code/IO/otbGenerateClassicalQLWithJPEG2000.cxx diff --git a/Code/IO/otbImageFileReader.txx b/Code/IO/otbImageFileReader.txx index 397cb80774..9062633ae1 100644 --- a/Code/IO/otbImageFileReader.txx +++ b/Code/IO/otbImageFileReader.txx @@ -309,6 +309,8 @@ ImageFileReader<TOutputImage> // Pass the Resolution Factor imageIO->SetResolutionFactor(m_AdditionalNumber); + if (!imageIO->GetCacheSizeInByte()) + imageIO->SetCacheSizeInByte(135000000); // Useful for Pleiades Images 135Mb => 4tiles in cache } diff --git a/Code/IO/otbJPEG2000ImageIO.cxx b/Code/IO/otbJPEG2000ImageIO.cxx index c01e00c7f7..186d391fb7 100644 --- a/Code/IO/otbJPEG2000ImageIO.cxx +++ b/Code/IO/otbJPEG2000ImageIO.cxx @@ -395,7 +395,7 @@ public: typedef std::pair<unsigned int, opj_image_t *> CachedTileType; typedef std::deque<CachedTileType> TileCacheType; - /** Get a tile in cache, return null if cache does not cotain the + /** Get a tile in cache, return null if cache does not contain the tile */ opj_image_t * GetTile(unsigned int tileIndex); @@ -405,13 +405,59 @@ public: /** Clear the cache */ void Clear(); + /** Initialize some parameters linked to the cache size in memory*/ + void Initialize(unsigned int originalWidthTile, unsigned int originalHeightTile, + unsigned int nbComponent, + unsigned int precision, + unsigned int resolution) + { + this->EstimateTileCacheSize(originalWidthTile, originalHeightTile, + nbComponent, + precision, + resolution); + m_CacheSizeInByte = m_CacheSizeInTiles * m_TileCacheSizeInByte; + m_IsReady = true; + }; + + /** Set the size of the cache with in terms of number of tiles */ + void SetCacheSizeInTiles(unsigned int nbOfTiles) + { + if (nbOfTiles > 0 && m_IsReady) + { + m_CacheSizeInTiles = nbOfTiles; + m_CacheSizeInByte = m_CacheSizeInTiles * m_TileCacheSizeInByte; + } + }; + + /** Get the size of the cache in terms of number of tiles */ + unsigned int GetCacheSizeInTiles() {return m_CacheSizeInTiles;}; + + /** Set the size of the cache with in terms of Bytes */ + void SetCacheSizeInByte(unsigned int sizeInByte) + { + if (sizeInByte > 0 && m_IsReady) + { + m_CacheSizeInByte = sizeInByte; + m_CacheSizeInTiles = m_CacheSizeInByte / m_TileCacheSizeInByte; + } + }; + private: TileCacheType m_Cache; unsigned int m_CacheSizeInTiles; + unsigned int m_CacheSizeInByte; + unsigned int m_TileCacheSizeInByte; + bool m_IsReady; + + /** Estimate the size of a tile in memory*/ + void EstimateTileCacheSize(unsigned int originalWidthTile, unsigned int originalHeightTile, + unsigned int nbComponent, + unsigned int precision, + unsigned int resolution); }; -JPEG2000TileCache::JPEG2000TileCache() : m_Cache(), m_CacheSizeInTiles(4) +JPEG2000TileCache::JPEG2000TileCache() : m_Cache(), m_CacheSizeInTiles(4), m_CacheSizeInByte(0), m_IsReady(false) {} JPEG2000TileCache::~JPEG2000TileCache() @@ -419,6 +465,20 @@ JPEG2000TileCache::~JPEG2000TileCache() this->Clear(); } + +void JPEG2000TileCache::EstimateTileCacheSize(unsigned int originalWidthTile, unsigned int originalHeightTile, + unsigned int nbComponent, + unsigned int precision, + unsigned int resolution) +{ + this->m_TileCacheSizeInByte = originalWidthTile * originalHeightTile + * nbComponent + * precision + / vcl_pow(2, 2*static_cast<double>(resolution) ) ; + + otbMsgDevMacro( << "m_TileCacheSizeInByte = " << m_TileCacheSizeInByte ); +} + void JPEG2000TileCache::Clear() { for(TileCacheType::iterator it = m_Cache.begin(); @@ -434,6 +494,11 @@ void JPEG2000TileCache::Clear() erasedTile.second = NULL; } m_Cache.clear(); + + m_CacheSizeInTiles = 4; + m_CacheSizeInByte = 0; + + m_IsReady = false; } @@ -461,6 +526,7 @@ void JPEG2000TileCache::AddTile(unsigned int tileIndex, opj_image_t * tileData) return; } } + if(m_Cache.size() >= m_CacheSizeInTiles) { CachedTileType erasedTile = *m_Cache.begin(); @@ -474,6 +540,7 @@ void JPEG2000TileCache::AddTile(unsigned int tileIndex, opj_image_t * tileData) m_Cache.pop_front(); } + m_Cache.push_back(CachedTileType(tileIndex, tileData)); } @@ -503,6 +570,8 @@ JPEG2000ImageIO::JPEG2000ImageIO() m_BytePerPixel = 1; m_ResolutionFactor = 0; // Full resolution by default + + m_CacheSizeInByte = 0; // By default no cache } JPEG2000ImageIO::~JPEG2000ImageIO() @@ -708,11 +777,15 @@ void JPEG2000ImageIO::Read(void* buffer) } - // Now, do cache book-keeping - for (std::vector<JPEG2000TileCache::CachedTileType>::iterator itTile = toReadTiles.begin(); itTile < toReadTiles.end(); ++itTile) + // Now, do cache book-keeping if necessary + if (m_TileCache->GetCacheSizeInTiles() != 0) { - m_TileCache->AddTile(itTile->first, itTile->second); + for (std::vector<JPEG2000TileCache::CachedTileType>::iterator itTile = toReadTiles.begin(); itTile < toReadTiles.end(); ++itTile) + { + m_TileCache->AddTile(itTile->first, itTile->second); + } } + chrono.Stop(); otbMsgDevMacro( << "JPEG2000ImageIO::Read took " << chrono.GetTotal() << " sec"); @@ -953,7 +1026,6 @@ void JPEG2000ImageIO::ReadImageInformation() } } - m_Spacing[0] = 1.0 / vcl_pow(2.0, static_cast<double>(m_ResolutionFactor)); m_Spacing[1] = 1.0 / vcl_pow(2.0, static_cast<double>(m_ResolutionFactor)); @@ -1033,6 +1105,17 @@ void JPEG2000ImageIO::ReadImageInformation() this->SetPixelType(VECTOR); } + // Initialize some parameters of the tile cache + this->m_TileCache->Initialize(m_InternalReaders.front()->m_TileWidth, + m_InternalReaders.front()->m_TileHeight, + m_InternalReaders.front()->m_NbOfComponent, + m_BytePerPixel, + m_ResolutionFactor); + + // If available set the size of the cache + if (this->m_CacheSizeInByte) + this->m_TileCache->SetCacheSizeInByte(this->m_CacheSizeInByte); + otbMsgDebugMacro(<< "=========================="); otbMsgDebugMacro(<< "ReadImageInformation: "); otbMsgDebugMacro(<< "Tile size (WxH): " << m_InternalReaders.front()->m_TileWidth << " x " diff --git a/Code/IO/otbJPEG2000ImageIO.h b/Code/IO/otbJPEG2000ImageIO.h index 42cd747c4b..1115ddfd4e 100644 --- a/Code/IO/otbJPEG2000ImageIO.h +++ b/Code/IO/otbJPEG2000ImageIO.h @@ -105,6 +105,9 @@ public: itkSetMacro(ResolutionFactor, unsigned int); itkGetMacro(ResolutionFactor, unsigned int); + itkSetMacro(CacheSizeInByte, unsigned int); + itkGetMacro(CacheSizeInByte, unsigned int); + protected: /** Constructor.*/ JPEG2000ImageIO(); @@ -128,8 +131,12 @@ private: /** pixel nb of octets */ unsigned int m_BytePerPixel; + /** Resolution factor*/ unsigned int m_ResolutionFactor; + /** Size of the cache used to reduce number of decoding operations*/ + unsigned int m_CacheSizeInByte; + /** Load data from a tile into the buffer. 2nd argument is a * pointer to opj_image_t, hidden in void * to avoid forward declaration. */ void LoadTileData(void * buffer, void * tile); diff --git a/Testing/Code/IO/CMakeLists.txt b/Testing/Code/IO/CMakeLists.txt index 3230f5e155..03e6125b4b 100644 --- a/Testing/Code/IO/CMakeLists.txt +++ b/Testing/Code/IO/CMakeLists.txt @@ -2135,6 +2135,46 @@ ADD_TEST(ioTvMultiChannelROI_JPEG2000_2_TIF_PLEIADES_res5_FullQuicklook ${COMMON ) ENDIF(OTB_DATA_USE_LARGEINPUT) +# Test the possibility to modify the size of cache used to reduce the decoding operations +# O tile in the cache +ADD_TEST(ioTvJPEG2000ImageIO_CacheSize_500 ${IO_TESTS13} + --compare-image ${EPSILON_9} + ${BASELINE}/ioClassicalQLJPEG2K_bretagne.tif + ${TEMP}/ioClassicalQLJPEG2K_bretagne_500.tif + otbGenerateClassicalQLWithJPEG2000 + ${INPUTDATA}/bretagne.j2k + ${TEMP}/ioClassicalQLJPEG2K_bretagne_500.tif + 500) + +# 1 tile in the cache +ADD_TEST(ioTvJPEG2000ImageIO_CacheSize_1000 ${IO_TESTS13} + --compare-image ${EPSILON_9} + ${BASELINE}/ioClassicalQLJPEG2K_bretagne.tif + ${TEMP}/ioClassicalQLJPEG2K_bretagne_1000.tif + otbGenerateClassicalQLWithJPEG2000 + ${INPUTDATA}/bretagne.j2k + ${TEMP}/ioClassicalQLJPEG2K_bretagne_1000.tif + 1000) + +# 5 tiles in the cache +ADD_TEST(ioTvJPEG2000ImageIO_CacheSize_5000 ${IO_TESTS13} + --compare-image ${EPSILON_9} + ${BASELINE}/ioClassicalQLJPEG2K_bretagne.tif + ${TEMP}/ioClassicalQLJPEG2K_bretagne_5000.tif + otbGenerateClassicalQLWithJPEG2000 + ${INPUTDATA}/bretagne.j2k + ${TEMP}/ioClassicalQLJPEG2K_bretagne_5000.tif + 5000) + +# 135Mb in the cache +ADD_TEST(ioTvJPEG2000ImageIO_CacheSize_25000 ${IO_TESTS13} + --compare-image ${EPSILON_9} + ${BASELINE}/ioClassicalQLJPEG2K_bretagne.tif + ${TEMP}/ioClassicalQLJPEG2K_bretagne_25000.tif + otbGenerateClassicalQLWithJPEG2000 + ${INPUTDATA}/bretagne.j2k + ${TEMP}/ioClassicalQLJPEG2K_bretagne_25000.tif) + ENDIF(OTB_COMPILE_JPEG2000) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -3521,6 +3561,7 @@ otbJPEG2000ImageIOTestCanRead.cxx otbJPEG2000ImageIOTestCanWrite.cxx otbVectorImageTest.cxx otbMultiReadingInfo.cxx +otbGenerateClassicalQLWithJPEG2000.cxx ) ENDIF(OTB_COMPILE_JPEG2000) @@ -3665,7 +3706,6 @@ OTB_ADD_EXECUTABLE(otbIOTests10 "${BasicIO_SRCS10}" "OTBIO;OTBTesting") OTB_ADD_EXECUTABLE(otbIOTests11 "${BasicIO_SRCS11}" "OTBIO;OTBTesting") OTB_ADD_EXECUTABLE(otbIOTests12 "${BasicIO_SRCS12}" "OTBIO;OTBTesting") -# Case for releae 2.2.1 IF(OTB_COMPILE_JPEG2000) IF(NOT BUILD_SHARED_LIBS) ADD_DEFINITIONS(-DOPJ_STATIC) diff --git a/Testing/Code/IO/otbGenerateClassicalQLWithJPEG2000.cxx b/Testing/Code/IO/otbGenerateClassicalQLWithJPEG2000.cxx new file mode 100644 index 0000000000..9b7e184faa --- /dev/null +++ b/Testing/Code/IO/otbGenerateClassicalQLWithJPEG2000.cxx @@ -0,0 +1,65 @@ +/*========================================================================= + + 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 "otbImageFileReader.h" +#include "otbImageFileWriter.h" +#include "otbVectorImage.h" +#include "otbStreamingShrinkImageFilter.h" +#include "otbJPEG2000ImageIO.h" + +int otbGenerateClassicalQLWithJPEG2000(int argc, char * argv[]) +{ + char * inputFilename = argv[1]; + char * outputFilename = argv[2]; + unsigned int cacheSize = 0; + + if (argc == 4) + cacheSize = atoi(argv[3]) * 1000; + + const unsigned int Dimension = 2; + + typedef unsigned int PixelType; + typedef otb::VectorImage<PixelType, Dimension> ImageType; + typedef otb::ImageFileReader<ImageType> ReaderType; + typedef otb::ImageFileWriter<ImageType> WriterType; + typedef otb::StreamingShrinkImageFilter<ImageType, ImageType> ShrinkType; + + ReaderType::Pointer reader = ReaderType::New(); + ShrinkType::Pointer shrink = ShrinkType::New(); + WriterType::Pointer writer = WriterType::New(); + + reader->SetFileName(inputFilename); + + otb::JPEG2000ImageIO::Pointer imageIO = otb::JPEG2000ImageIO::New(); + reader->SetImageIO(imageIO); + + imageIO->SetCacheSizeInByte(cacheSize); + + reader->GenerateOutputInformation(); + + writer->SetFileName(outputFilename); + shrink->SetShrinkFactor(10); + + shrink->SetInput(reader->GetOutput()); + shrink->Update(); + + writer->SetInput(shrink->GetOutput()); + + writer->Update(); + + return EXIT_SUCCESS; +} diff --git a/Testing/Code/IO/otbIOTests13.cxx b/Testing/Code/IO/otbIOTests13.cxx index f5eb4e8d81..eb2d57286b 100644 --- a/Testing/Code/IO/otbIOTests13.cxx +++ b/Testing/Code/IO/otbIOTests13.cxx @@ -28,4 +28,5 @@ void RegisterTests() REGISTER_TEST(otbJPEG2000ImageIOTestCanWrite); REGISTER_TEST(otbMultiResolutionReadingInfo); REGISTER_TEST(otbVectorImageTest); + REGISTER_TEST(otbGenerateClassicalQLWithJPEG2000); } -- GitLab