changeset 279:77afef2cf64b

automated extraction of the imaged volume if using OpenSlide
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 12 Jul 2023 18:06:34 +0200
parents 169f168ba07a
children 34b507959e32 b5b9719ef1c0
files Applications/Dicomizer.cpp Framework/ImagedVolumeParameters.cpp Framework/ImagedVolumeParameters.h Framework/Inputs/OpenSlidePyramid.cpp Framework/Inputs/OpenSlidePyramid.h NEWS
diffstat 6 files changed, 109 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Dicomizer.cpp	Wed Jul 12 17:12:10 2023 +0200
+++ b/Applications/Dicomizer.cpp	Wed Jul 12 18:06:34 2023 +0200
@@ -643,10 +643,10 @@
 
   boost::program_options::options_description volumeOptions("Description of the imaged volume");
   volumeOptions.add_options()
-    (OPTION_IMAGED_WIDTH, boost::program_options::value<float>()->default_value(15),
-     "Width of the specimen (in mm)")
-    (OPTION_IMAGED_HEIGHT, boost::program_options::value<float>()->default_value(15),
-     "Height of the specimen (in mm)")
+    (OPTION_IMAGED_WIDTH, boost::program_options::value<float>(),
+     "Width of the specimen (in mm), defaults to 15mm if missing")
+    (OPTION_IMAGED_HEIGHT, boost::program_options::value<float>(),
+     "Height of the specimen (in mm), defaults to 15mm if missing")
     (OPTION_IMAGED_DEPTH, boost::program_options::value<float>()->default_value(1),
      "Depth of the specimen (in mm)")
     (OPTION_OFFSET_X, boost::program_options::value<float>()->default_value(20), 
@@ -1010,6 +1010,7 @@
 
 
 OrthancWSI::ITiledPyramid* OpenInputPyramid(OrthancWSI::ImageCompression& sourceCompression,
+                                            OrthancWSI::ImagedVolumeParameters& volume,
                                             const std::string& path,
                                             const OrthancWSI::DicomizerParameters& parameters)
 {
@@ -1072,9 +1073,26 @@
   {
     LOG(WARNING) << "Trying to open the input pyramid with OpenSlide";
     sourceCompression = OrthancWSI::ImageCompression_Unknown;
-    return new OrthancWSI::OpenSlidePyramid(path, 
-                                            parameters.GetTargetTileWidth(512), 
-                                            parameters.GetTargetTileHeight(512));
+
+    std::unique_ptr<OrthancWSI::OpenSlidePyramid> openslide(
+      new OrthancWSI::OpenSlidePyramid(path, parameters.GetTargetTileWidth(512),
+                                       parameters.GetTargetTileHeight(512)));
+
+    float volumeWidth, volumeHeight;
+    if (openslide->LookupImagedVolumeSize(volumeWidth, volumeHeight))
+    {
+      if (!volume.HasWidth())
+      {
+        volume.SetWidth(volumeWidth);
+      }
+
+      if (!volume.HasHeight())
+      {
+        volume.SetHeight(volumeHeight);
+      }
+    }
+
+    return openslide.release();
   }
   catch (Orthanc::OrthancException&)
   {
@@ -1101,7 +1119,7 @@
       OrthancWSI::ImageCompression sourceCompression;
       std::unique_ptr<OrthancWSI::ITiledPyramid> source;
 
-      source.reset(OpenInputPyramid(sourceCompression, parameters.GetInputFile(), parameters));
+      source.reset(OpenInputPyramid(sourceCompression, volume, parameters.GetInputFile(), parameters));
       if (source.get() == NULL)
       {
         throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
--- a/Framework/ImagedVolumeParameters.cpp	Wed Jul 12 17:12:10 2023 +0200
+++ b/Framework/ImagedVolumeParameters.cpp	Wed Jul 12 18:06:34 2023 +0200
@@ -27,25 +27,54 @@
 
 namespace OrthancWSI
 {
-  ImagedVolumeParameters::ImagedVolumeParameters()
+  ImagedVolumeParameters::ImagedVolumeParameters() :
+    hasWidth_(false),
+    hasHeight_(false)
   {
-    // Typical parameters of a specimen millimeters
-    width_ = 15;
-    height_ = 15;
+    // Typical parameters for a specimen, in millimeters
     depth_ = 1;
     offsetX_ = 20;
     offsetY_ = 40;
   }
 
 
+  float ImagedVolumeParameters::GetWidth() const
+  {
+    if (hasWidth_)
+    {
+      return width_;
+    }
+    else
+    {
+      return 15;  // Typical width of a specimen
+    }
+  }
+
+
+  float ImagedVolumeParameters::GetHeight() const
+  {
+    if (hasHeight_)
+    {
+      return height_;
+    }
+    else
+    {
+      return 15;  // Typical height of a specimen
+    }
+  }
+
+
   void ImagedVolumeParameters::SetWidth(float width)
   {
     if (width <= 0)
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
-
-    width_ = width;
+    else
+    {
+      width_ = width;
+      hasWidth_ = true;
+    }
   }
     
 
@@ -55,8 +84,11 @@
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
-
-    height_ = height;
+    else
+    {
+      height_ = height;
+      hasHeight_ = true;
+    }
   }
 
     
--- a/Framework/ImagedVolumeParameters.h	Wed Jul 12 17:12:10 2023 +0200
+++ b/Framework/ImagedVolumeParameters.h	Wed Jul 12 18:06:34 2023 +0200
@@ -27,6 +27,8 @@
   class ImagedVolumeParameters
   {
   private:
+    bool   hasWidth_;
+    bool   hasHeight_;
     float  width_;
     float  height_;
     float  depth_;
@@ -36,15 +38,19 @@
   public:
     ImagedVolumeParameters();
 
-    float GetWidth() const
+    bool HasWidth() const
     {
-      return width_;
+      return hasWidth_;
+    }
+
+    bool HasHeight() const
+    {
+      return hasHeight_;
     }
     
-    float GetHeight() const
-    {
-      return height_;
-    }
+    float GetWidth() const;
+
+    float GetHeight() const;
     
     float GetDepth() const
     {
--- a/Framework/Inputs/OpenSlidePyramid.cpp	Wed Jul 12 17:12:10 2023 +0200
+++ b/Framework/Inputs/OpenSlidePyramid.cpp	Wed Jul 12 18:06:34 2023 +0200
@@ -26,6 +26,7 @@
 #include <Compatibility.h>  // For std::unique_ptr
 #include <Images/ImageProcessing.h>
 #include <OrthancException.h>
+#include <SerializationToolbox.h>
 #include <Logging.h>
 
 #include <memory>
@@ -50,4 +51,28 @@
     tileHeight_(tileHeight)
   {
   }
+
+
+  bool OpenSlidePyramid::LookupImagedVolumeSize(float& width,
+                                                float& height) const
+  {
+    std::string s;
+    double mppx;
+    double mppy;
+
+    if (image_.LookupProperty(s, "openslide.mpp-x") &&
+        Orthanc::SerializationToolbox::ParseDouble(mppx, s) &&
+        image_.LookupProperty(s, "openslide.mpp-y") &&
+        Orthanc::SerializationToolbox::ParseDouble(mppy, s))
+    {
+      // In the 2 lines below, remember to switch X/Y when going from physical to pixel coordinates!
+      width = mppy / 1000.0 * static_cast<double>(image_.GetLevelHeight(0));
+      height = mppx / 1000.0 * static_cast<double>(image_.GetLevelWidth(0));
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
 }
--- a/Framework/Inputs/OpenSlidePyramid.h	Wed Jul 12 17:12:10 2023 +0200
+++ b/Framework/Inputs/OpenSlidePyramid.h	Wed Jul 12 18:06:34 2023 +0200
@@ -79,5 +79,8 @@
     {
       return Orthanc::PhotometricInterpretation_RGB;
     }
+
+    bool LookupImagedVolumeSize(float& width,
+                                float& height) const;
   };
 }
--- a/NEWS	Wed Jul 12 17:12:10 2023 +0200
+++ b/NEWS	Wed Jul 12 18:06:34 2023 +0200
@@ -1,6 +1,9 @@
 Pending changes in the mainline
 ===============================
 
+* Automated extraction of the imaged volume if using OpenSlide
+
+
 Version 1.1 (2021-12-11)
 ========================