changeset 4945:6a59dc426f93

added ParsedDicomFile::DecodeOverlay()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sun, 20 Mar 2022 11:35:17 +0100
parents 47d734fa30f6
children 51e4947aa3b3
files OrthancFramework/Sources/DicomParsing/ParsedDicomFile.cpp OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h OrthancFramework/UnitTestsSources/FromDcmtkTests.cpp
diffstat 3 files changed, 102 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.cpp	Wed Mar 16 17:21:02 2022 +0100
+++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.cpp	Sun Mar 20 11:35:17 2022 +0100
@@ -76,6 +76,8 @@
 #include "Internals/DicomImageDecoder.h"
 #include "ToDcmtkBridge.h"
 
+#include "../Images/Image.h"
+#include "../Images/ImageProcessing.h"
 #include "../Images/PamReader.h"
 #include "../Logging.h"
 #include "../OrthancException.h"
@@ -1918,6 +1920,100 @@
   }
 
 
+  void ParsedDicomFile::ListOverlays(std::set<unsigned int>& groups) const
+  {
+    DcmDataset& dataset = *const_cast<ParsedDicomFile&>(*this).GetDcmtkObject().getDataset();
+
+    // "Repeating Groups shall only be allowed in the even Groups (6000-601E,eeee)"
+    // https://dicom.nema.org/medical/dicom/2021e/output/chtml/part05/sect_7.6.html
+
+    for (uint16_t group = 0x6000; group <= 0x601e; group += 2)
+    {
+      if (dataset.tagExists(DcmTagKey(group, 0x0010)))
+      {
+        groups.insert(group);
+      }
+    }
+  }
+
+
+  static unsigned int Ceiling(unsigned int a,
+                              unsigned int b)
+  {
+    if (a % b == 0)
+    {
+      return a / b;
+    }
+    else
+    {
+      return a / b + 1;
+    }
+  }
+  
+
+  ImageAccessor* ParsedDicomFile::DecodeOverlay(int& originX,
+                                                int& originY,
+                                                unsigned int group) const
+  {
+    // https://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.9.2.html
+
+    DcmDataset& dataset = *const_cast<ParsedDicomFile&>(*this).GetDcmtkObject().getDataset();
+
+    Uint16 rows, columns, bitsAllocated, bitPosition;
+    const Sint16* origin = NULL;
+    unsigned long originSize = 0;
+    const Uint8* overlayData = NULL;
+    unsigned long overlaySize = 0;
+    
+    if (dataset.findAndGetUint16(DcmTagKey(group, 0x0010), rows).good() &&
+        dataset.findAndGetUint16(DcmTagKey(group, 0x0011), columns).good() &&
+        dataset.findAndGetSint16Array(DcmTagKey(group, 0x0050), origin, &originSize).good() &&
+        origin != NULL &&
+        originSize == 2 &&
+        dataset.findAndGetUint16(DcmTagKey(group, 0x0100), bitsAllocated).good() &&
+        bitsAllocated == 1 &&
+        dataset.findAndGetUint16(DcmTagKey(group, 0x0102), bitPosition).good() &&
+        bitPosition == 0 &&
+        dataset.findAndGetUint8Array(DcmTagKey(group, 0x3000), overlayData, &overlaySize).good() &&
+        overlayData != NULL)
+    {
+      unsigned int expectedSize = Ceiling(rows * columns, 8);
+      if (overlaySize < expectedSize)
+      {
+        throw OrthancException(ErrorCode_CorruptedFile, "Overlay doesn't have a valid number of bits");
+      }
+      
+      originX = origin[1];
+      originY = origin[0];
+
+      std::unique_ptr<ImageAccessor> overlay(new Image(Orthanc::PixelFormat_Grayscale8, columns, rows, false));
+
+      unsigned int posBit = 0;
+      for (int y = 0; y < rows; y++)
+      {
+        uint8_t* target = reinterpret_cast<uint8_t*>(overlay->GetRow(y));
+        
+        for (int x = 0; x < columns; x++)
+        {
+          uint8_t source = overlayData[posBit / 8];
+          uint8_t mask = 1 << (posBit % 8);
+
+          *target = ((source & mask) ? 255 : 0);
+
+          target++;
+          posBit++;
+        }
+      }
+      
+      return overlay.release();
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_CorruptedFile, "Invalid overlay");
+    }
+  }
+
+  
 #if ORTHANC_BUILDING_FRAMEWORK_LIBRARY == 1
   // Alias for binary compatibility with Orthanc Framework 1.7.2 => don't use it anymore
   void ParsedDicomFile::DatasetToJson(Json::Value& target,
--- a/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h	Wed Mar 16 17:21:02 2022 +0100
+++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h	Sun Mar 20 11:35:17 2022 +0100
@@ -300,5 +300,11 @@
     void GetRescale(double& rescaleIntercept,
                     double& rescaleSlope,
                     unsigned int frame) const;
+
+    void ListOverlays(std::set<unsigned int>& groups) const;
+
+    ImageAccessor* DecodeOverlay(int& originX,
+                                 int& originY,
+                                 unsigned int group) const;
   };
 }
--- a/OrthancFramework/UnitTestsSources/FromDcmtkTests.cpp	Wed Mar 16 17:21:02 2022 +0100
+++ b/OrthancFramework/UnitTestsSources/FromDcmtkTests.cpp	Sun Mar 20 11:35:17 2022 +0100
@@ -49,7 +49,6 @@
 #include "../Sources/Images/ImageBuffer.h"
 #include "../Sources/Images/ImageProcessing.h"
 #include "../Sources/Images/PngReader.h"
-#include "../Sources/Images/PngWriter.h"
 #include "../Sources/Logging.h"
 #include "../Sources/OrthancException.h"