changeset 1677:51bab5188a13

start multiple preset windowings
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 23 Nov 2020 19:24:18 +0100
parents 5e76d5e8167a
children 1393e3393a0b
files Applications/StoneWebViewer/WebApplication/app.js Applications/StoneWebViewer/WebApplication/index.html Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp OrthancStone/Sources/Loaders/SeriesFramesLoader.cpp OrthancStone/Sources/Toolbox/DicomInstanceParameters.cpp OrthancStone/Sources/Toolbox/DicomInstanceParameters.h
diffstat 6 files changed, 113 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/StoneWebViewer/WebApplication/app.js	Mon Nov 23 18:49:42 2020 +0100
+++ b/Applications/StoneWebViewer/WebApplication/app.js	Mon Nov 23 19:24:18 2020 +0100
@@ -623,10 +623,10 @@
       }
     },
 
-    SetDefaultWindowing: function() {
+    SetPresetWindowing: function() {
       var canvas = this.GetActiveCanvas();
       if (canvas != '') {
-        stone.SetDefaultWindowing(canvas);
+        stone.SetPresetWindowing(canvas);
       }
     },
 
--- a/Applications/StoneWebViewer/WebApplication/index.html	Mon Nov 23 18:49:42 2020 +0100
+++ b/Applications/StoneWebViewer/WebApplication/index.html	Mon Nov 23 19:24:18 2020 +0100
@@ -478,8 +478,8 @@
 
       <ul class="wvToolbar__windowingPresetList">
         <li class="wvToolbar__windowingPresetListItem">
-          <a href="#" onclick="app.SetDefaultWindowing()">
-            Default
+          <a href="#" onclick="app.SetPresetWindowing()">
+            Preset
           </a>
         </li>
         <li class="wvToolbar__windowingPresetListItem">
--- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Mon Nov 23 18:49:42 2020 +0100
+++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Mon Nov 23 19:24:18 2020 +0100
@@ -1102,20 +1102,21 @@
       {
         OrthancStone::DicomInstanceParameters params(dicom);
 
-        if (params.HasDefaultWindowing())
+        // TODO - WINDOWING
+        if (params.GetPresetWindowingsCount() > 0)
         {
-          GetViewport().defaultWindowingCenter_ = params.GetDefaultWindowingCenter();
-          GetViewport().defaultWindowingWidth_ = params.GetDefaultWindowingWidth();
-          LOG(INFO) << "Default windowing: " << params.GetDefaultWindowingCenter()
-                    << "," << params.GetDefaultWindowingWidth();
-
-          GetViewport().windowingCenter_ = params.GetDefaultWindowingCenter();
-          GetViewport().windowingWidth_ = params.GetDefaultWindowingWidth();
+          GetViewport().presetWindowingCenter_ = params.GetPresetWindowingCenter(0);
+          GetViewport().presetWindowingWidth_ = params.GetPresetWindowingWidth(0);
+          LOG(INFO) << "Preset windowing: " << params.GetPresetWindowingCenter(0)
+                    << "," << params.GetPresetWindowingWidth(0);
+
+          GetViewport().windowingCenter_ = params.GetPresetWindowingCenter(0);
+          GetViewport().windowingWidth_ = params.GetPresetWindowingWidth(0);
         }
         else
         {
-          LOG(INFO) << "No default windowing";
-          GetViewport().ResetDefaultWindowing();
+          LOG(INFO) << "No preset windowing";
+          GetViewport().ResetPresetWindowing();
         }
       }
 
@@ -1361,8 +1362,8 @@
   std::unique_ptr<SeriesCursor>                cursor_;
   float                                        windowingCenter_;
   float                                        windowingWidth_;
-  float                                        defaultWindowingCenter_;
-  float                                        defaultWindowingWidth_;
+  float                                        presetWindowingCenter_;
+  float                                        presetWindowingWidth_;
   unsigned int                                 cineRate_;
   bool                                         inverted_;
   bool                                         flipX_;
@@ -1410,13 +1411,13 @@
   }
   
   
-  void ResetDefaultWindowing()
+  void ResetPresetWindowing()
   {
-    defaultWindowingCenter_ = 128;
-    defaultWindowingWidth_ = 256;
-
-    windowingCenter_ = defaultWindowingCenter_;
-    windowingWidth_ = defaultWindowingWidth_;
+    presetWindowingCenter_ = 128;
+    presetWindowingWidth_ = 256;
+
+    windowingCenter_ = presetWindowingCenter_;
+    windowingWidth_ = presetWindowingWidth_;
 
     inverted_ = false;
   }
@@ -1789,7 +1790,7 @@
     emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, false, OnKey);
     emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, false, OnKey);
 
-    ResetDefaultWindowing();
+    ResetPresetWindowing();
   }
 
   static EM_BOOL OnKey(int eventType,
@@ -1897,7 +1898,7 @@
 
     LOG(INFO) << "Number of frames in series: " << frames_->GetFramesCount();
 
-    ResetDefaultWindowing();
+    ResetPresetWindowing();
     ClearViewport();
     prefetchQueue_.clear();
 
@@ -2126,9 +2127,9 @@
   }
 
 
-  void SetDefaultWindowing()
+  void SetPresetWindowing()
   {
-    SetWindowing(defaultWindowingCenter_, defaultWindowingWidth_);
+    SetWindowing(presetWindowingCenter_, presetWindowingWidth_);
   }
 
   void SetWindowing(float windowingCenter,
@@ -2817,11 +2818,11 @@
 
 
   EMSCRIPTEN_KEEPALIVE
-  void SetDefaultWindowing(const char* canvas)
+  void SetPresetWindowing(const char* canvas)
   {
     try
     {
-      GetViewport(canvas)->SetDefaultWindowing();
+      GetViewport(canvas)->SetPresetWindowing();
     }
     EXTERN_CATCH_EXCEPTIONS;
   }  
--- a/OrthancStone/Sources/Loaders/SeriesFramesLoader.cpp	Mon Nov 23 18:49:42 2020 +0100
+++ b/OrthancStone/Sources/Loaders/SeriesFramesLoader.cpp	Mon Nov 23 19:24:18 2020 +0100
@@ -307,6 +307,16 @@
   }
 
 
+  static void GetBounds(float& low,
+                        float& high,
+                        double center,  // in
+                        double width)   // in
+  {
+    low = static_cast<float>(center - width / 2.0);
+    high = static_cast<float>(center + width / 2.0);
+  }
+  
+  
   void SeriesFramesLoader::GetPreviewWindowing(float& center,
                                                float& width,
                                                size_t index) const
@@ -314,11 +324,39 @@
     const Orthanc::DicomMap& instance = frames_.GetInstance(index);
     const DicomInstanceParameters& parameters = frames_.GetInstanceParameters(index);
 
-    if (parameters.HasDefaultWindowing())
+    size_t s = parameters.GetPresetWindowingsCount();
+
+    if (s > 0)
     {
-      // TODO - Handle multiple presets (take the largest width)
-      center = parameters.GetDefaultWindowingCenter();
-      width = parameters.GetDefaultWindowingWidth();
+      // Use the largest windowing given all the preset windowings
+      // that are available in the DICOM tags
+      float low, high;
+      GetBounds(low, high, parameters.GetPresetWindowingCenter(0),
+                parameters.GetPresetWindowingWidth(0));
+
+      for (size_t i = 1; i < s; i++)
+      {
+        float a, b;
+        GetBounds(a, b, parameters.GetPresetWindowingCenter(i),
+                  parameters.GetPresetWindowingWidth(i));
+        low = std::min(low, a);
+        high = std::max(high, b);
+      }
+
+      assert(low <= high);
+
+      if (LinearAlgebra::IsNear(low, high))
+      {
+        // Cannot infer a suitable windowing from the available tags
+        center = 128.0f;
+        width = 256.0f;
+      }
+      else
+      {
+        center = (low + high) / 2.0f;
+        width = (high - low);
+        printf(">> %f %f\n", center, width);
+      }
     }
     else
     {
--- a/OrthancStone/Sources/Toolbox/DicomInstanceParameters.cpp	Mon Nov 23 18:49:42 2020 +0100
+++ b/OrthancStone/Sources/Toolbox/DicomInstanceParameters.cpp	Mon Nov 23 19:24:18 2020 +0100
@@ -180,22 +180,28 @@
       }
     }
 
-    Vector c, w;
-    if (LinearAlgebra::ParseVector(c, dicom, Orthanc::DICOM_TAG_WINDOW_CENTER) &&
-        LinearAlgebra::ParseVector(w, dicom, Orthanc::DICOM_TAG_WINDOW_WIDTH) &&
-        c.size() > 0 && 
-        w.size() > 0)
+    bool ok = false;
+    
+    if (LinearAlgebra::ParseVector(presetWindowingCenters_, dicom, Orthanc::DICOM_TAG_WINDOW_CENTER) &&
+        LinearAlgebra::ParseVector(presetWindowingWidths_, dicom, Orthanc::DICOM_TAG_WINDOW_WIDTH))
     {
-      hasDefaultWindowing_ = true;
-      defaultWindowingCenter_ = static_cast<float>(c[0]);
-      defaultWindowingWidth_ = static_cast<float>(w[0]);
+      if (presetWindowingCenters_.size() == presetWindowingWidths_.size())
+      {
+        ok = true;
+      }
+      else
+      {
+        LOG(ERROR) << "Mismatch in the number of preset windowing widths/centers, ignoring this";
+        ok = false;
+      }
     }
-    else
+
+    if (!ok)
     {
-      hasDefaultWindowing_ = false;
-      defaultWindowingCenter_ = 0;
-      defaultWindowingWidth_  = 0;
-    }
+      // Don't use "Vector::clear()", as it has not the same meaning as "std::vector::clear()"
+      presetWindowingCenters_.resize(0);
+      presetWindowingWidths_.resize(0);
+    }      
 
     // This computes the "IndexInSeries" metadata from Orthanc (check
     // out "Orthanc::ServerIndex::Store()")
@@ -391,34 +397,39 @@
   }
 
 
-  float DicomInstanceParameters::GetDefaultWindowingCenter() const
+  size_t DicomInstanceParameters::GetPresetWindowingsCount() const
   {
-    if (data_.hasDefaultWindowing_)
+    assert(data_.presetWindowingCenters_.size() == data_.presetWindowingWidths_.size());
+    return data_.presetWindowingCenters_.size();
+  }
+  
+
+  float DicomInstanceParameters::GetPresetWindowingCenter(size_t i) const
+  {
+    if (i < GetPresetWindowingsCount())
     {
-      return data_.defaultWindowingCenter_;
+      return static_cast<float>(data_.presetWindowingCenters_[i]);
     }
     else
     {
-      LOG(ERROR) << "DicomInstanceParameters::GetDefaultWindowingCenter(): no default windowing";
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
   }
 
 
-  float DicomInstanceParameters::GetDefaultWindowingWidth() const
+  float DicomInstanceParameters::GetPresetWindowingWidth(size_t i) const
   {
-    if (data_.hasDefaultWindowing_)
+    if (i < GetPresetWindowingsCount())
     {
-      return data_.defaultWindowingWidth_;
+      return static_cast<float>(data_.presetWindowingWidths_[i]);
     }
     else
     {
-      LOG(ERROR) << "DicomInstanceParameters::GetDefaultWindowingWidth(): no default windowing";
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
   }
 
-
+  
   Orthanc::ImageAccessor* DicomInstanceParameters::ConvertToFloat(const Orthanc::ImageAccessor& pixelData) const
   {
     std::unique_ptr<Orthanc::Image> converted(new Orthanc::Image(Orthanc::PixelFormat_Float32, 
@@ -483,10 +494,9 @@
         texture.reset(new FloatTextureSceneLayer(*converted));
       }
 
-      if (data_.hasDefaultWindowing_)
+      if (GetPresetWindowingsCount() > 0)
       {
-        texture->SetCustomWindowing(data_.defaultWindowingCenter_,
-                                    data_.defaultWindowingWidth_);
+        texture->SetCustomWindowing(GetPresetWindowingCenter(0), GetPresetWindowingWidth(0));
       }
       
       switch (GetImageInformation().GetPhotometricInterpretation())
--- a/OrthancStone/Sources/Toolbox/DicomInstanceParameters.h	Mon Nov 23 18:49:42 2020 +0100
+++ b/OrthancStone/Sources/Toolbox/DicomInstanceParameters.h	Mon Nov 23 19:24:18 2020 +0100
@@ -55,9 +55,8 @@
       bool                hasRescale_;
       double              rescaleIntercept_;
       double              rescaleSlope_;
-      bool                hasDefaultWindowing_;
-      float               defaultWindowingCenter_;
-      float               defaultWindowingWidth_;
+      Vector              presetWindowingCenters_;
+      Vector              presetWindowingWidths_;
       bool                hasIndexInSeries_;
       unsigned int        indexInSeries_;
       std::string         doseUnits_;
@@ -182,14 +181,11 @@
 
     double GetRescaleSlope() const;
 
-    bool HasDefaultWindowing() const
-    {
-      return data_.hasDefaultWindowing_;
-    }
+    size_t GetPresetWindowingsCount() const;
 
-    float GetDefaultWindowingCenter() const;
+    float GetPresetWindowingCenter(size_t i) const;
 
-    float GetDefaultWindowingWidth() const;
+    float GetPresetWindowingWidth(size_t i) const;
 
     Orthanc::PixelFormat GetExpectedPixelFormat() const;