Mercurial > hg > orthanc-wsi
diff Applications/DicomToTiff.cpp @ 57:91fc9583b2de
big refactoring to support sparse tiling
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 24 Nov 2016 17:48:24 +0100 |
parents | 8e1dfd531335 |
children | 7a3853d51c45 |
line wrap: on
line diff
--- a/Applications/DicomToTiff.cpp Thu Nov 24 15:41:21 2016 +0100 +++ b/Applications/DicomToTiff.cpp Thu Nov 24 17:48:24 2016 +0100 @@ -21,6 +21,7 @@ #include "../Framework/DicomToolbox.h" #include "../Framework/ImageToolbox.h" #include "../Framework/Inputs/DicomPyramid.h" +#include "../Framework/Inputs/TiledPyramidStatistics.h" #include "../Framework/Messaging/CurlOrthancConnection.h" #include "../Framework/Orthanc/Core/Logging.h" #include "../Framework/Orthanc/Core/OrthancException.h" @@ -114,7 +115,8 @@ << std::endl << "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research." << std::endl << std::endl - << "Convert a DICOM for digital pathology stored in some Orthanc server as a standard hierarchical TIFF." + << "Convert a DICOM image for digital pathology stored in some Orthanc server as a" << std::endl + << "standard hierarchical TIFF (whose tiles are all encoded using JPEG)." << std::endl; std::cout << allWithoutHidden << "\n"; @@ -167,56 +169,8 @@ -static void RunTranscode(OrthancWSI::ITiledPyramid& source, - const boost::program_options::variables_map& options) -{ - OrthancWSI::HierarchicalTiffWriter target(options["output"].as<std::string>(), - source.GetPixelFormat(), - source.GetImageCompression(), - source.GetTileWidth(), - source.GetTileHeight()); - - std::auto_ptr<Orthanc::ImageAccessor> empty(CreateEmptyTile(target, options)); - - for (unsigned int level = 0; level < source.GetLevelCount(); level++) - { - LOG(WARNING) << "Creating level " << level << " of size " - << source.GetLevelWidth(level) << "x" << source.GetLevelHeight(level); - target.AddLevel(source.GetLevelWidth(level), source.GetLevelHeight(level)); - } - - for (unsigned int level = 0; level < source.GetLevelCount(); level++) - { - LOG(WARNING) << "Transcoding level " << level; - - unsigned int countX = OrthancWSI::CeilingDivision(source.GetLevelWidth(level), source.GetTileWidth()); - unsigned int countY = OrthancWSI::CeilingDivision(source.GetLevelHeight(level), source.GetTileHeight()); - - for (unsigned int tileY = 0; tileY < countY; tileY++) - { - for (unsigned int tileX = 0; tileX < countX; tileX++) - { - LOG(INFO) << "Dealing with tile (" << tileX << "," << tileY << ") at level " << level; - std::string tile; - - if (source.ReadRawTile(tile, level, tileX, tileY)) - { - target.WriteRawTile(tile, source.GetImageCompression(), level, tileX, tileY); - } - else - { - target.EncodeTile(*empty, level, tileX, tileY); - } - } - } - - target.Flush(); - } -} - - -static void RunReencode(OrthancWSI::ITiledPyramid& source, - const boost::program_options::variables_map& options) +static void Run(OrthancWSI::ITiledPyramid& source, + const boost::program_options::variables_map& options) { OrthancWSI::HierarchicalTiffWriter target(options["output"].as<std::string>(), source.GetPixelFormat(), @@ -224,6 +178,9 @@ source.GetTileWidth(), source.GetTileHeight()); + bool reencode = (options.count("reencode") && + options["reencode"].as<bool>()); + if (options.count("jpeg-quality")) { target.SetJpegQuality(options["jpeg-quality"].as<int>()); @@ -240,7 +197,7 @@ for (unsigned int level = 0; level < source.GetLevelCount(); level++) { - LOG(WARNING) << "Reencoding level " << level; + LOG(WARNING) << std::string(reencode ? "Reencoding" : "Transcoding") << " level " << level; unsigned int countX = OrthancWSI::CeilingDivision(source.GetLevelWidth(level), source.GetTileWidth()); unsigned int countY = OrthancWSI::CeilingDivision(source.GetLevelHeight(level), source.GetTileHeight()); @@ -251,14 +208,58 @@ { LOG(INFO) << "Dealing with tile (" << tileX << "," << tileY << ") at level " << level; - std::auto_ptr<Orthanc::ImageAccessor> tile(source.DecodeTile(level, tileX, tileY)); - if (tile.get() == NULL) + bool missing = false; + bool success = true; + + // Give a first try to get the raw tile + std::string tile; + OrthancWSI::ImageCompression compression; + if (source.ReadRawTile(tile, compression, level, tileX, tileY)) { - target.EncodeTile(*empty, level, tileX, tileY); + if (reencode || + compression == OrthancWSI::ImageCompression_Jpeg) + { + target.WriteRawTile(tile, compression, level, tileX, tileY); + } + else + { + success = false; // Re-encoding is mandatory + } } else { - target.EncodeTile(*tile, level, tileX, tileY); + // Give a second try to get the decoded tile + compression = OrthancWSI::ImageCompression_Unknown; + + std::auto_ptr<Orthanc::ImageAccessor> tile(source.DecodeTile(level, tileX, tileY)); + if (tile.get() == NULL) + { + // Unable to read the raw tile or to decode it: The tile is missing (sparse tiling) + missing = true; + } + else if (reencode) + { + target.EncodeTile(*empty, level, tileX, tileY); + } + else + { + success = false; // Re-encoding is mandatory + } + } + + if (!success) + { + LOG(WARNING) << "Cannot transcode a DICOM image that is not encoded using JPEG (it is " + << OrthancWSI::EnumerationToString(compression) + << "), please use the --reencode=1 option"; + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + if (missing) + { + LOG(WARNING) << "Sparse tiling: Using an empty image for missing tile (" + << tileX << "," << tileY << ") at level " << level; + target.EncodeTile(*empty, level, tileX, tileY); } } } @@ -300,15 +301,8 @@ OrthancWSI::CurlOrthancConnection orthanc(params); OrthancWSI::DicomPyramid source(orthanc, options["input"].as<std::string>()); - if (options.count("reencode") && - options["reencode"].as<bool>()) - { - RunReencode(source, options); - } - else - { - RunTranscode(source, options); - } + OrthancWSI::TiledPyramidStatistics stats(source); + Run(stats, options); } } catch (Orthanc::OrthancException& e)