changeset 2235:6450fd850adf

added support for more types of DICOM SR
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sat, 26 Apr 2025 14:20:19 +0200 (5 weeks ago)
parents d9e4d135229b
children f276f465ff5a
files Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp OrthancStone/Sources/StoneEnumerations.cpp OrthancStone/Sources/StoneEnumerations.h OrthancStone/Sources/Toolbox/DicomStructuredReport.cpp
diffstat 4 files changed, 134 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Sat Apr 26 11:28:30 2025 +0200
+++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Sat Apr 26 14:20:19 2025 +0200
@@ -889,7 +889,7 @@
       std::string sopInstanceUid, sopClassUid;
       if (message.GetInstance(i).LookupStringValue(sopInstanceUid, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false) &&
           message.GetInstance(i).LookupStringValue(sopClassUid, Orthanc::DICOM_TAG_SOP_CLASS_UID, false) &&
-          OrthancStone::StringToSopClassUid(sopClassUid) == OrthancStone::SopClassUid_ComprehensiveSR)
+          OrthancStone::IsStructuredReport(OrthancStone::StringToSopClassUid(sopClassUid)))
       {
         std::unique_ptr<OrthancStone::ILoadersContext::ILock> lock(context_.Lock());
         lock->Schedule(
@@ -2860,7 +2860,7 @@
      **/
     
     bool isMonochrome1 = false;
-    if (instance.GetSopClassUid() != OrthancStone::SopClassUid_ComprehensiveSR)
+    if (!OrthancStone::IsStructuredReport(instance.GetSopClassUid()))
     {
       isMonochrome1 = (instance.GetImageInformation().GetPhotometricInterpretation() ==
                        Orthanc::PhotometricInterpretation_Monochrome1);
@@ -3027,7 +3027,7 @@
       {
         lock->RefreshCanvasSize();
 
-        if (instance.GetSopClassUid() == OrthancStone::SopClassUid_ComprehensiveSR)
+        if (OrthancStone::IsStructuredReport(instance.GetSopClassUid()))
         {
           // Fit to the width of the textual report
           scene.FitTopContent(lock->GetCompositor().GetCanvasWidth(), lock->GetCompositor().GetCanvasHeight(), 0.1);
@@ -3162,7 +3162,7 @@
         try
         {
           std::unique_ptr<Orthanc::ImageAccessor> frame;
-          if (instance.GetSopClassUid() == OrthancStone::SopClassUid_ComprehensiveSR)
+          if (OrthancStone::IsStructuredReport(instance.GetSopClassUid()))
           {
             OrthancStone::DicomStructuredReport report(const_cast<Orthanc::ParsedDicomFile&>(accessor->GetDicom()));
             frame.reset(report.Render(font_, GetHighlightedColorInternal(), GetAnnotationsColorInternal()));
--- a/OrthancStone/Sources/StoneEnumerations.cpp	Sat Apr 26 11:28:30 2025 +0200
+++ b/OrthancStone/Sources/StoneEnumerations.cpp	Sat Apr 26 14:20:19 2025 +0200
@@ -65,10 +65,78 @@
     {
       return SopClassUid_DicomSeg;
     }
+    else if (s == "1.2.840.10008.5.1.4.1.1.88.11")
+    {
+      return SopClassUid_BasicTextSR;
+    }
+    else if (s == "1.2.840.10008.5.1.4.1.1.88.22")
+    {
+      return SopClassUid_EnhancedSR;
+    }
     else if (s == "1.2.840.10008.5.1.4.1.1.88.33")
     {
       return SopClassUid_ComprehensiveSR;
     }
+    else if (s == "1.2.840.10008.5.1.4.1.1.88.34")
+    {
+      return SopClassUid_Comprehensive3DSR;
+    }
+    else if (s == "1.2.840.10008.5.1.4.1.1.88.35")
+    {
+      return SopClassUid_ExtensibleSR;
+    }
+    else if (s == "1.2.840.10008.5.1.4.1.1.88.50")
+    {
+      return SopClassUid_MammographyCADSR;
+    }
+    else if (s == "1.2.840.10008.5.1.4.1.1.88.65")
+    {
+      return SopClassUid_ChestCADSR;
+    }
+    else if (s == "1.2.840.10008.5.1.4.1.1.88.67")
+    {
+      return SopClassUid_XRayRadiationDoseSR;
+    }
+    else if (s == "1.2.840.10008.5.1.4.1.1.88.68")
+    {
+      return SopClassUid_RadiopharmaceuticalRadiationDoseSR;
+    }
+    else if (s == "1.2.840.10008.5.1.4.1.1.88.69")
+    {
+      return SopClassUid_ColonCADSR;
+    }
+    else if (s == "1.2.840.10008.5.1.4.1.1.88.70")
+    {
+      return SopClassUid_ImplantationPlanSR;
+    }
+    else if (s == "1.2.840.10008.5.​1.​4.​1.​1.​88.​71")
+    {
+      return SopClassUid_AcquisitionContextSR;
+    }
+    else if (s == "1.2.840.10008.5.​1.​4.​1.​1.​88.​72")
+    {
+      return SopClassUid_SimplifiedAdultEchoSR;
+    }
+    else if (s == "1.2.840.10008.5.​1.​4.​1.​1.​88.​73")
+    {
+      return SopClassUid_PatientRadiationDoseSR;
+    }
+    else if (s == "1.2.840.10008.5.​1.​4.​1.​1.​88.​74")
+    {
+      return SopClassUid_PlannedImagingAgentAdministrationSR;
+    }
+    else if (s == "1.2.840.10008.5.​1.​4.​1.​1.​88.​75")
+    {
+      return SopClassUid_PerformedImagingAgentAdministrationSR;
+    }
+    else if (s == "1.2.840.10008.5.​1.​4.​1.​1.​88.​76")
+    {
+      return SopClassUid_EnhancedXRayRadiationDoseSR;
+    }
+    else if (s == "1.2.840.10008.5.​1.​4.​1.​1.​88.​77")
+    {
+      return SopClassUid_WaveformAnnotationSR;
+    }
     else
     {
       //LOG(INFO) << "Other SOP class UID: " << source;
@@ -222,11 +290,40 @@
       case SopClassUid_VideoPhotographicImageStorage:
         return SeriesThumbnailType_Video;
 
-      case SopClassUid_ComprehensiveSR:
-        return SeriesThumbnailType_StructuredReport;
+      default:
+        break;
+    }
 
-      default:
-        return SeriesThumbnailType_Unsupported;
+    if (IsStructuredReport(sopClassUid))
+    {
+      return SeriesThumbnailType_StructuredReport;
+    }
+    else
+    {
+      return SeriesThumbnailType_Unsupported;
     }
   }
+
+
+  bool IsStructuredReport(SopClassUid sopClassUid)
+  {
+    return (sopClassUid == SopClassUid_BasicTextSR ||
+            sopClassUid == SopClassUid_EnhancedSR ||
+            sopClassUid == SopClassUid_ComprehensiveSR ||
+            sopClassUid == SopClassUid_Comprehensive3DSR ||
+            sopClassUid == SopClassUid_ExtensibleSR ||
+            sopClassUid == SopClassUid_MammographyCADSR ||
+            sopClassUid == SopClassUid_ChestCADSR ||
+            sopClassUid == SopClassUid_XRayRadiationDoseSR ||
+            sopClassUid == SopClassUid_RadiopharmaceuticalRadiationDoseSR ||
+            sopClassUid == SopClassUid_ColonCADSR ||
+            sopClassUid == SopClassUid_ImplantationPlanSR ||
+            sopClassUid == SopClassUid_AcquisitionContextSR ||
+            sopClassUid == SopClassUid_SimplifiedAdultEchoSR ||
+            sopClassUid == SopClassUid_PatientRadiationDoseSR ||
+            sopClassUid == SopClassUid_PlannedImagingAgentAdministrationSR ||
+            sopClassUid == SopClassUid_PerformedImagingAgentAdministrationSR ||
+            sopClassUid == SopClassUid_EnhancedXRayRadiationDoseSR ||
+            sopClassUid == SopClassUid_WaveformAnnotationSR);
+  }
 }
--- a/OrthancStone/Sources/StoneEnumerations.h	Sat Apr 26 11:28:30 2025 +0200
+++ b/OrthancStone/Sources/StoneEnumerations.h	Sat Apr 26 14:20:19 2025 +0200
@@ -106,6 +106,8 @@
     KeyboardKeys_F12 = 123,
   };
 
+
+  // https://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_b.5.html
   enum SopClassUid
   {
     SopClassUid_Other,
@@ -117,7 +119,26 @@
     SopClassUid_VideoMicroscopicImageStorage,
     SopClassUid_VideoPhotographicImageStorage,
     SopClassUid_DicomSeg,
-    SopClassUid_ComprehensiveSR
+
+    // All the possible DICOM-SR
+    SopClassUid_BasicTextSR,
+    SopClassUid_EnhancedSR,
+    SopClassUid_ComprehensiveSR,
+    SopClassUid_Comprehensive3DSR,
+    SopClassUid_ExtensibleSR,
+    SopClassUid_MammographyCADSR,
+    SopClassUid_ChestCADSR,
+    SopClassUid_XRayRadiationDoseSR,
+    SopClassUid_RadiopharmaceuticalRadiationDoseSR,
+    SopClassUid_ColonCADSR,
+    SopClassUid_ImplantationPlanSR,
+    SopClassUid_AcquisitionContextSR,
+    SopClassUid_SimplifiedAdultEchoSR,
+    SopClassUid_PatientRadiationDoseSR,
+    SopClassUid_PlannedImagingAgentAdministrationSR,
+    SopClassUid_PerformedImagingAgentAdministrationSR,
+    SopClassUid_EnhancedXRayRadiationDoseSR,
+    SopClassUid_WaveformAnnotationSR
   };
 
   enum SeriesThumbnailType
@@ -184,4 +205,6 @@
                                 unsigned int border = 0);
 
   SeriesThumbnailType GetSeriesThumbnailType(SopClassUid sopClassUid);
+
+  bool IsStructuredReport(SopClassUid sopClassUid);
 }
--- a/OrthancStone/Sources/Toolbox/DicomStructuredReport.cpp	Sat Apr 26 11:28:30 2025 +0200
+++ b/OrthancStone/Sources/Toolbox/DicomStructuredReport.cpp	Sat Apr 26 14:20:19 2025 +0200
@@ -651,8 +651,9 @@
     seriesInstanceUid_ = GetStringValue(dataset, DCM_SeriesInstanceUID);
     sopInstanceUid_ = GetStringValue(dataset, DCM_SOPInstanceUID);
 
-    SopClassUid sopClassUid = StringToSopClassUid(GetStringValue(dataset, DCM_SOPClassUID));
-    if (sopClassUid != SopClassUid_ComprehensiveSR)
+    std::string sopClassUidString = GetStringValue(dataset, DCM_SOPClassUID);
+    SopClassUid sopClassUid = StringToSopClassUid(sopClassUidString);
+    if (!IsStructuredReport(sopClassUid))
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
     }
@@ -674,7 +675,8 @@
 
     ReadTextualReport(textualReport_, dataset);
 
-    if (IsDicomConcept(dataset, "126000") /* Imaging measurement report */ &&
+    if (sopClassUid == SopClassUid_ComprehensiveSR &&
+        IsDicomConcept(dataset, "126000") /* Imaging measurement report */ &&
         IsDicomTemplate(dataset, "1500") &&
         dataset.tagExists(DCM_CurrentRequestedProcedureEvidenceSequence))
     {