diff OrthancServer/OrthancRestApi/OrthancRestResources.cpp @ 3600:4066998150ef

/instances/{id}/preview route now takes the windowing into account
author Alain Mazy <alain@mazy.be>
date Thu, 09 Jan 2020 18:54:40 +0100
parents 810772486249
children a77e7839012a
line wrap: on
line diff
--- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp	Tue Jan 07 10:53:32 2020 +0100
+++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp	Thu Jan 09 18:54:40 2020 +0100
@@ -39,6 +39,7 @@
 #include "../../Core/DicomParsing/FromDcmtkBridge.h"
 #include "../../Core/DicomParsing/Internals/DicomImageDecoder.h"
 #include "../../Core/HttpServer/HttpContentNegociation.h"
+#include "../../Core/Images/ImageProcessing.h"
 #include "../../Core/Logging.h"
 #include "../DefaultDicomImageDecoder.h"
 #include "../OrthancConfiguration.h"
@@ -502,6 +503,38 @@
   }
 
 
+  void LookupWindowingTags(const ParsedDicomFile& dicom, float& windowCenter, float& windowWidth, float& rescaleSlope, float& rescaleIntercept, bool& invert)
+  {
+    DicomMap dicomTags;
+    dicom.ExtractDicomSummary(dicomTags);
+
+
+    unsigned int bitsStored = boost::lexical_cast<unsigned int>(dicomTags.GetStringValue(Orthanc::DICOM_TAG_BITS_STORED, "8", false));
+    windowWidth = static_cast<float>(2 << (bitsStored - 1));
+    windowCenter = windowWidth / 2;
+    rescaleSlope = 1.0f;
+    rescaleIntercept = 0.0f;
+    invert = false;
+
+    if (dicomTags.HasTag(Orthanc::DICOM_TAG_WINDOW_CENTER) && dicomTags.HasTag(Orthanc::DICOM_TAG_WINDOW_WIDTH))
+    {
+      windowCenter = boost::lexical_cast<float>(dicomTags.GetStringValue(Orthanc::DICOM_TAG_WINDOW_CENTER, "", false));
+      windowWidth = boost::lexical_cast<float>(dicomTags.GetStringValue(Orthanc::DICOM_TAG_WINDOW_WIDTH, "", false));
+    }
+
+    if (dicomTags.HasTag(Orthanc::DICOM_TAG_RESCALE_SLOPE) && dicomTags.HasTag(Orthanc::DICOM_TAG_RESCALE_INTERCEPT))
+    {
+      rescaleSlope = boost::lexical_cast<float>(dicomTags.GetStringValue(Orthanc::DICOM_TAG_RESCALE_SLOPE, "", false));
+      rescaleIntercept = boost::lexical_cast<float>(dicomTags.GetStringValue(Orthanc::DICOM_TAG_RESCALE_INTERCEPT, "", false));
+    }
+
+    PhotometricInterpretation photometric;
+    if (dicom.LookupPhotometricInterpretation(photometric))
+    {
+      invert = (photometric == PhotometricInterpretation_Monochrome1);
+    }
+  }
+
   template <enum ImageExtractionMode mode>
   static void GetImage(RestApiGetCall& call)
   {
@@ -520,6 +553,11 @@
     }
 
     bool invert = false;
+    float windowCenter = 128.0f;
+    float windowWidth = 256.0f;
+    float rescaleSlope = 1.0f;
+    float rescaleIntercept = 0.0f;
+
     std::auto_ptr<ImageAccessor> decoded;
 
     try
@@ -549,11 +587,7 @@
           // twice the DICOM file
           ParsedDicomFile parsed(dicomContent);
           
-          PhotometricInterpretation photometric;
-          if (parsed.LookupPhotometricInterpretation(photometric))
-          {
-            invert = (photometric == PhotometricInterpretation_Monochrome1);
-          }
+          LookupWindowingTags(dicomContent, windowCenter, windowWidth, rescaleSlope, rescaleIntercept, invert);
         }
       }
 #endif
@@ -564,12 +598,11 @@
         // things on multi-frame images
         ServerContext::DicomCacheLocker locker(context, publicId);        
         decoded.reset(DicomImageDecoder::Decode(locker.GetDicom(), frame));
+        LookupWindowingTags(locker.GetDicom(), windowCenter, windowWidth, rescaleSlope, rescaleIntercept, invert);
 
-        PhotometricInterpretation photometric;
-        if (mode == ImageExtractionMode_Preview &&
-            locker.GetDicom().LookupPhotometricInterpretation(photometric))
+        if (mode != ImageExtractionMode_Preview)
         {
-          invert = (photometric == PhotometricInterpretation_Monochrome1);
+          invert = false;
         }
       }
     }
@@ -593,6 +626,13 @@
       return;
     }
 
+    if (mode == ImageExtractionMode_Preview
+        && (decoded->GetFormat() == Orthanc::PixelFormat_Grayscale8 || decoded->GetFormat() == Orthanc::PixelFormat_Grayscale16))
+    {
+      ImageProcessing::ApplyWindowing(*decoded, *decoded, windowCenter, windowWidth, rescaleSlope, rescaleIntercept, invert);
+      invert = false; // don't invert it later on when encoding it, it has been inverted in the ApplyWindowing function
+    }
+
     ImageToEncode image(decoded, mode, invert);
 
     HttpContentNegociation negociation;