changeset 166:f0dac1e8f736

access to photometric interpretation of source pyramids
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 12 Jul 2019 09:06:54 +0200
parents 8c279c5b28a3
children 605247fc8758
files Applications/Dicomizer.cpp Framework/Inputs/DecodedTiledPyramid.h Framework/Inputs/DicomPyramid.cpp Framework/Inputs/DicomPyramid.h Framework/Inputs/DicomPyramidInstance.cpp Framework/Inputs/DicomPyramidInstance.h Framework/Inputs/HierarchicalTiff.cpp Framework/Inputs/HierarchicalTiff.h Framework/Inputs/ITiledPyramid.h Framework/Inputs/TiledPyramidStatistics.h Framework/Outputs/InMemoryTiledImage.cpp Framework/Outputs/InMemoryTiledImage.h Framework/Outputs/TruncatedPyramidWriter.cpp Framework/Outputs/TruncatedPyramidWriter.h
diffstat 14 files changed, 89 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Dicomizer.cpp	Fri Feb 22 14:28:40 2019 +0100
+++ b/Applications/Dicomizer.cpp	Fri Jul 12 09:06:54 2019 +0200
@@ -132,7 +132,7 @@
   if (lowerLevelsCount != levelsCount)
   {
     LOG(WARNING) << "Constructing the " << lowerLevelsCount << " lower levels of the pyramid";
-    OrthancWSI::TruncatedPyramidWriter truncated(target, lowerLevelsCount);
+    OrthancWSI::TruncatedPyramidWriter truncated(target, lowerLevelsCount, source.GetPhotometricInterpretation());
     OrthancWSI::ReconstructPyramidCommand::PrepareBagOfTasks
       (tasks, truncated, source, lowerLevelsCount + 1, 0, parameters);
     OrthancWSI::ApplicationToolbox::Execute(tasks, parameters.GetThreadsCount());
--- a/Framework/Inputs/DecodedTiledPyramid.h	Fri Feb 22 14:28:40 2019 +0100
+++ b/Framework/Inputs/DecodedTiledPyramid.h	Fri Jul 12 09:06:54 2019 +0200
@@ -68,5 +68,10 @@
     {
       return false;   // No access to the raw tiles
     }
+
+    virtual Orthanc::PhotometricInterpretation GetPhotometricInterpretation() const
+    {
+      return Orthanc::PhotometricInterpretation_RGB;
+    }
   };
 }
--- a/Framework/Inputs/DicomPyramid.cpp	Fri Feb 22 14:28:40 2019 +0100
+++ b/Framework/Inputs/DicomPyramid.cpp	Fri Jul 12 09:06:54 2019 +0200
@@ -235,4 +235,11 @@
     assert(!instances_.empty() && instances_[0] != NULL);
     return instances_[0]->GetPixelFormat();
   }
+
+  
+  Orthanc::PhotometricInterpretation DicomPyramid::GetPhotometricInterpretation() const
+  {
+    assert(!instances_.empty() && instances_[0] != NULL);
+    return instances_[0]->GetPhotometricInterpretation();
+  }
 }
--- a/Framework/Inputs/DicomPyramid.h	Fri Feb 22 14:28:40 2019 +0100
+++ b/Framework/Inputs/DicomPyramid.h	Fri Jul 12 09:06:54 2019 +0200
@@ -81,5 +81,7 @@
                              unsigned int tileY);
 
     virtual Orthanc::PixelFormat GetPixelFormat() const;
+
+    virtual Orthanc::PhotometricInterpretation GetPhotometricInterpretation() const;
   };
 }
--- a/Framework/Inputs/DicomPyramidInstance.cpp	Fri Feb 22 14:28:40 2019 +0100
+++ b/Framework/Inputs/DicomPyramidInstance.cpp	Fri Jul 12 09:06:54 2019 +0200
@@ -69,17 +69,21 @@
   }
 
 
-  static Orthanc::PixelFormat DetectPixelFormat(OrthancPlugins::DicomDatasetReader& reader)
+  static void DetectPixelFormat(Orthanc::PixelFormat& format,
+                                Orthanc::PhotometricInterpretation& photometric,
+                                OrthancPlugins::DicomDatasetReader& reader)
   {
     using namespace OrthancPlugins;
 
-    std::string photometric = Orthanc::Toolbox::StripSpaces
+    std::string p = Orthanc::Toolbox::StripSpaces
       (reader.GetMandatoryStringValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION));
+    
+    photometric = Orthanc::StringToPhotometricInterpretation(p.c_str());
 
-    if (photometric == "PALETTE")
+    if (photometric == Orthanc::PhotometricInterpretation_Palette)
     {
-      LOG(ERROR) << "Unsupported photometric interpretation: " << photometric;
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented,
+                                      "Unsupported photometric interpretation: " + p);
     }
 
     unsigned int bitsStored, samplesPerPixel, tmp;
@@ -97,18 +101,17 @@
         samplesPerPixel == 1 &&
         !isSigned)
     {
-      return Orthanc::PixelFormat_Grayscale8;
+      format = Orthanc::PixelFormat_Grayscale8;
     }
     else if (bitsStored == 8 &&
              samplesPerPixel == 3 &&
              !isSigned)
     {
-      return Orthanc::PixelFormat_RGB24;
+      format = Orthanc::PixelFormat_RGB24;
     }
     else
     {
-      LOG(ERROR) << "Unsupported pixel format";
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented, "Unsupported pixel format");
     }
   }
 
@@ -149,7 +152,7 @@
     }
 
     hasCompression_ = false;
-    format_ = DetectPixelFormat(reader);
+    DetectPixelFormat(format_, photometric_, reader);
 
     unsigned int tmp;
     if (!reader.GetUnsignedIntegerValue(tileWidth_, DICOM_TAG_COLUMNS) ||
--- a/Framework/Inputs/DicomPyramidInstance.h	Fri Feb 22 14:28:40 2019 +0100
+++ b/Framework/Inputs/DicomPyramidInstance.h	Fri Jul 12 09:06:54 2019 +0200
@@ -43,6 +43,7 @@
     unsigned int                totalWidth_;
     unsigned int                totalHeight_;
     std::vector<FrameLocation>  frames_;
+    Orthanc::PhotometricInterpretation  photometric_;
 
     void Load(OrthancPlugins::IOrthancConnection&  orthanc,
               const std::string& instanceId);
@@ -66,6 +67,11 @@
       return format_;
     }
 
+    Orthanc::PhotometricInterpretation GetPhotometricInterpretation() const
+    {
+      return photometric_;
+    }
+
     unsigned int GetTotalWidth() const
     {
       return totalWidth_;
--- a/Framework/Inputs/HierarchicalTiff.cpp	Fri Feb 22 14:28:40 2019 +0100
+++ b/Framework/Inputs/HierarchicalTiff.cpp	Fri Jul 12 09:06:54 2019 +0200
@@ -123,14 +123,15 @@
 
 
   bool HierarchicalTiff::GetCurrentPixelFormat(Orthanc::PixelFormat& pixelFormat,
+                                               Orthanc::PhotometricInterpretation& photometric,
                                                ImageCompression compression)
   {
     // http://www.awaresystems.be/imaging/tiff/tifftags/baseline.html
 
-    uint16_t channels, photometric, bpp, planar;
+    uint16_t channels, photometricTiff, bpp, planar;
     if (!TIFFGetField(tiff_, TIFFTAG_SAMPLESPERPIXEL, &channels) ||
         channels == 0 ||
-        !TIFFGetField(tiff_, TIFFTAG_PHOTOMETRIC, &photometric) ||
+        !TIFFGetField(tiff_, TIFFTAG_PHOTOMETRIC, &photometricTiff) ||
         !TIFFGetField(tiff_, TIFFTAG_BITSPERSAMPLE, &bpp) ||
         !TIFFGetField(tiff_, TIFFTAG_PLANARCONFIG, &planar))
     {
@@ -140,10 +141,24 @@
     if (compression == ImageCompression_Jpeg &&
         channels == 3 &&     // This is a color image
         bpp == 8 &&
-        photometric == PHOTOMETRIC_YCBCR &&
         planar == PLANARCONFIG_CONTIG)  // This is interleaved RGB
     {
       pixelFormat = Orthanc::PixelFormat_RGB24;
+
+      switch (photometricTiff)
+      {
+        case PHOTOMETRIC_YCBCR:
+          photometric = Orthanc::PhotometricInterpretation_YBRFull422;
+          return true;
+          
+        case PHOTOMETRIC_RGB:
+          photometric = Orthanc::PhotometricInterpretation_RGB;
+          return true;
+
+        default:
+          LOG(ERROR) << "Unknown photometric interpretation in TIFF: " << photometricTiff;
+          return false;
+      }
     }
     else
     {
@@ -164,6 +179,7 @@
       uint32_t w, h, tw, th;
       ImageCompression compression;
       Orthanc::PixelFormat pixelFormat;
+      Orthanc::PhotometricInterpretation photometric;
 
       if (TIFFSetDirectory(tiff_, pos) &&
           TIFFGetField(tiff_, TIFFTAG_IMAGEWIDTH, &w) &&
@@ -175,7 +191,7 @@
           tw > 0 &&
           th > 0 &&
           GetCurrentCompression(compression) &&
-          GetCurrentPixelFormat(pixelFormat, compression))
+          GetCurrentPixelFormat(pixelFormat, photometric, compression))
       {
         if (first)
         {
@@ -183,12 +199,14 @@
           tileHeight_ = th;
           compression_ = compression;
           pixelFormat_ = pixelFormat;
+          photometric_ = photometric;
           first = false;
         }
         else if (tw != tileWidth_ ||
                  th != tileHeight_ ||
                  compression_ != compression ||
-                 pixelFormat_ != pixelFormat)
+                 pixelFormat_ != pixelFormat ||
+                 photometric_ != photometric)
         {
           LOG(ERROR) << "The tile size or compression of the TIFF file varies along levels, this is not supported";
           return false;
--- a/Framework/Inputs/HierarchicalTiff.h	Fri Feb 22 14:28:40 2019 +0100
+++ b/Framework/Inputs/HierarchicalTiff.h	Fri Jul 12 09:06:54 2019 +0200
@@ -55,6 +55,7 @@
     unsigned int          tileWidth_;
     unsigned int          tileHeight_;
     std::vector<Level>    levels_;
+    Orthanc::PhotometricInterpretation  photometric_;
 
     void Finalize();
 
@@ -63,6 +64,7 @@
     bool GetCurrentCompression(ImageCompression& compression);
 
     bool GetCurrentPixelFormat(Orthanc::PixelFormat& pixelFormat,
+                               Orthanc::PhotometricInterpretation& photometric,
                                ImageCompression compression);
 
     bool Initialize();
@@ -105,6 +107,11 @@
       return pixelFormat_;
     }
 
+    virtual Orthanc::PhotometricInterpretation GetPhotometricInterpretation() const
+    {
+      return photometric_;
+    }
+
     ImageCompression GetImageCompression()
     {
       return compression_;
--- a/Framework/Inputs/ITiledPyramid.h	Fri Feb 22 14:28:40 2019 +0100
+++ b/Framework/Inputs/ITiledPyramid.h	Fri Jul 12 09:06:54 2019 +0200
@@ -63,5 +63,7 @@
                                                unsigned int tileY) = 0;
 
     virtual Orthanc::PixelFormat GetPixelFormat() const = 0;
+
+    virtual Orthanc::PhotometricInterpretation GetPhotometricInterpretation() const = 0;
   };
 }
--- a/Framework/Inputs/TiledPyramidStatistics.h	Fri Feb 22 14:28:40 2019 +0100
+++ b/Framework/Inputs/TiledPyramidStatistics.h	Fri Jul 12 09:06:54 2019 +0200
@@ -79,5 +79,10 @@
     virtual Orthanc::ImageAccessor* DecodeTile(unsigned int level,
                                                unsigned int tileX,
                                                unsigned int tileY);
+
+    virtual Orthanc::PhotometricInterpretation GetPhotometricInterpretation() const
+    {
+      return source_.GetPhotometricInterpretation();
+    }
   };
 }
--- a/Framework/Outputs/InMemoryTiledImage.cpp	Fri Feb 22 14:28:40 2019 +0100
+++ b/Framework/Outputs/InMemoryTiledImage.cpp	Fri Jul 12 09:06:54 2019 +0200
@@ -41,12 +41,14 @@
                                          unsigned int countTilesX,
                                          unsigned int countTilesY,
                                          unsigned int tileWidth,
-                                         unsigned int tileHeight) :
+                                         unsigned int tileHeight,
+                                         Orthanc::PhotometricInterpretation photometric) :
     format_(format),
     countTilesX_(countTilesX),
     countTilesY_(countTilesY),
     tileWidth_(tileWidth),
-    tileHeight_(tileHeight)
+    tileHeight_(tileHeight),
+    photometric_(photometric)
   {
   }
 
--- a/Framework/Outputs/InMemoryTiledImage.h	Fri Feb 22 14:28:40 2019 +0100
+++ b/Framework/Outputs/InMemoryTiledImage.h	Fri Jul 12 09:06:54 2019 +0200
@@ -44,13 +44,15 @@
     unsigned int          tileWidth_;
     unsigned int          tileHeight_;
     Tiles                 tiles_;
+    Orthanc::PhotometricInterpretation  photometric_;
 
   public:
     InMemoryTiledImage(Orthanc::PixelFormat format,
                        unsigned int countTilesX,
                        unsigned int countTilesY,
                        unsigned int tileWidth,
-                       unsigned int tileHeight);
+                       unsigned int tileHeight,
+                       Orthanc::PhotometricInterpretation photometric);
 
     virtual ~InMemoryTiledImage();
 
@@ -102,5 +104,10 @@
                             unsigned int level,
                             unsigned int tileX,
                             unsigned int tileY);
+
+    virtual Orthanc::PhotometricInterpretation GetPhotometricInterpretation() const
+    {
+      return photometric_;
+    }
   };
 }
--- a/Framework/Outputs/TruncatedPyramidWriter.cpp	Fri Feb 22 14:28:40 2019 +0100
+++ b/Framework/Outputs/TruncatedPyramidWriter.cpp	Fri Jul 12 09:06:54 2019 +0200
@@ -27,13 +27,15 @@
 namespace OrthancWSI
 {
   TruncatedPyramidWriter::TruncatedPyramidWriter(IPyramidWriter& lower,
-                                                 unsigned int upperLevelIndex) :
+                                                 unsigned int upperLevelIndex,
+                                                 Orthanc::PhotometricInterpretation photometric) :
     lowerLevels_(lower),
     upperLevel_(lower.GetPixelFormat(),
                 lower.GetCountTilesX(upperLevelIndex),
                 lower.GetCountTilesY(upperLevelIndex),
                 lower.GetTileWidth(),
-                lower.GetTileHeight()),
+                lower.GetTileHeight(),
+                photometric),
     upperLevelIndex_(upperLevelIndex)
   {
     if (upperLevelIndex > lower.GetLevelCount())
--- a/Framework/Outputs/TruncatedPyramidWriter.h	Fri Feb 22 14:28:40 2019 +0100
+++ b/Framework/Outputs/TruncatedPyramidWriter.h	Fri Jul 12 09:06:54 2019 +0200
@@ -34,7 +34,8 @@
     
   public:
     TruncatedPyramidWriter(IPyramidWriter& lower,
-                           unsigned int upperLevelIndex);
+                           unsigned int upperLevelIndex,
+                           Orthanc::PhotometricInterpretation photometric);
 
     virtual unsigned int GetLevelCount() const
     {