changeset 1206:f5b0207967bc

Fix issue #19 (YBR_FULL are decoded incorrectly)
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 03 Nov 2014 15:19:02 +0100
parents bb1ad2fbf914
children ddb5b6ed9736
files Core/DicomFormat/DicomImageInformation.cpp Core/DicomFormat/DicomImageInformation.h Core/DicomFormat/DicomMap.cpp Core/DicomFormat/DicomMap.h Core/Enumerations.cpp Core/Enumerations.h NEWS OrthancServer/Internals/DicomImageDecoder.cpp
diffstat 8 files changed, 179 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomFormat/DicomImageInformation.cpp	Mon Nov 03 13:40:14 2014 +0100
+++ b/Core/DicomFormat/DicomImageInformation.cpp	Mon Nov 03 15:19:02 2014 +0100
@@ -39,6 +39,7 @@
 #include "DicomImageInformation.h"
 
 #include "../OrthancException.h"
+#include "../Toolbox.h"
 #include <boost/lexical_cast.hpp>
 #include <limits>
 #include <cassert>
@@ -53,6 +54,66 @@
 
     try
     {
+      std::string p = values.GetValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION).AsString();
+      Toolbox::ToUpperCase(p);
+
+      if (p == "RGB")
+      {
+        photometric_ = PhotometricInterpretation_RGB;
+      }
+      else if (p == "MONOCHROME1")
+      {
+        photometric_ = PhotometricInterpretation_Monochrome1;
+      }
+      else if (p == "MONOCHROME2")
+      {
+        photometric_ = PhotometricInterpretation_Monochrome2;
+      }
+      else if (p == "PALETTE COLOR")
+      {
+        photometric_ = PhotometricInterpretation_Palette;
+      }
+      else if (p == "HSV")
+      {
+        photometric_ = PhotometricInterpretation_HSV;
+      }
+      else if (p == "ARGB")
+      {
+        photometric_ = PhotometricInterpretation_ARGB;
+      }
+      else if (p == "CMYK")
+      {
+        photometric_ = PhotometricInterpretation_CMYK;
+      }
+      else if (p == "YBR_FULL")
+      {
+        photometric_ = PhotometricInterpretation_YBRFull;
+      }
+      else if (p == "YBR_FULL_422")
+      {
+        photometric_ = PhotometricInterpretation_YBRFull422;
+      }
+      else if (p == "YBR_PARTIAL_420")
+      {
+        photometric_ = PhotometricInterpretation_YBRPartial420;
+      }
+      else if (p == "YBR_PARTIAL_422")
+      {
+        photometric_ = PhotometricInterpretation_YBRPartial422;
+      }
+      else if (p == "YBR_ICT")
+      {
+        photometric_ = PhotometricInterpretation_YBR_ICT;
+      }
+      else if (p == "YBR_RCT")
+      {
+        photometric_ = PhotometricInterpretation_YBR_RCT;
+      }
+      else
+      {
+        photometric_ = PhotometricInterpretation_Unknown;
+      }
+
       width_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_COLUMNS).AsString());
       height_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_ROWS).AsString());
       bitsAllocated_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_BITS_ALLOCATED).AsString());
@@ -159,30 +220,37 @@
 
   bool DicomImageInformation::ExtractPixelFormat(PixelFormat& format) const
   {
-    if (GetBitsStored() == 8 && GetChannelCount() == 1 && !IsSigned())
+    if (photometric_ == PhotometricInterpretation_Monochrome1 ||
+        photometric_ == PhotometricInterpretation_Monochrome2)
     {
-      format = PixelFormat_Grayscale8;
-      return true;
+      if (GetBitsStored() == 8 && GetChannelCount() == 1 && !IsSigned())
+      {
+        format = PixelFormat_Grayscale8;
+        return true;
+      }
+      
+      if (GetBitsAllocated() == 16 && GetChannelCount() == 1 && !IsSigned())
+      {
+        format = PixelFormat_Grayscale16;
+        return true;
+      }
+
+      if (GetBitsAllocated() == 16 && GetChannelCount() == 1 && IsSigned())
+      {
+        format = PixelFormat_SignedGrayscale16;
+        return true;
+      }
     }
 
-    if (GetBitsStored() == 8 && GetChannelCount() == 3 && !IsSigned())
+    if (GetBitsStored() == 8 && 
+        GetChannelCount() == 3 && 
+        !IsSigned() &&
+        photometric_ == PhotometricInterpretation_RGB)
     {
       format = PixelFormat_RGB24;
       return true;
     }
 
-    if (GetBitsAllocated() == 16 && GetChannelCount() == 1 && !IsSigned())
-    {
-      format = PixelFormat_Grayscale16;
-      return true;
-    }
-
-    if (GetBitsAllocated() == 16 && GetChannelCount() == 1 && IsSigned())
-    {
-      format = PixelFormat_SignedGrayscale16;
-      return true;
-    }
-
     return false;
   }
 }
--- a/Core/DicomFormat/DicomImageInformation.h	Mon Nov 03 13:40:14 2014 +0100
+++ b/Core/DicomFormat/DicomImageInformation.h	Mon Nov 03 15:19:02 2014 +0100
@@ -54,6 +54,8 @@
     unsigned int bitsStored_;
     unsigned int highBit_;
 
+    PhotometricInterpretation  photometric_;
+
   public:
     DicomImageInformation(const DicomMap& values);
 
@@ -112,6 +114,11 @@
       return highBit_ + 1 - bitsStored_;
     }
 
+    PhotometricInterpretation GetPhotometricInterpretation() const
+    {
+      return photometric_;
+    }
+
     bool ExtractPixelFormat(PixelFormat& format) const;
   };
 }
--- a/Core/DicomFormat/DicomMap.cpp	Mon Nov 03 13:40:14 2014 +0100
+++ b/Core/DicomFormat/DicomMap.cpp	Mon Nov 03 15:19:02 2014 +0100
@@ -36,6 +36,7 @@
 #include <stdio.h>
 #include <memory>
 #include "DicomString.h"
+#include "DicomArray.h"
 #include "../OrthancException.h"
 
 
@@ -387,4 +388,11 @@
     GetMainDicomTagsInternal(result, ResourceType_Series);
     GetMainDicomTagsInternal(result, ResourceType_Instance);
   }
+
+
+  void DicomMap::Print(FILE* fp) const
+  {
+    DicomArray a(*this);
+    a.Print(fp);
+  }
 }
--- a/Core/DicomFormat/DicomMap.h	Mon Nov 03 13:40:14 2014 +0100
+++ b/Core/DicomFormat/DicomMap.h	Mon Nov 03 15:19:02 2014 +0100
@@ -160,5 +160,7 @@
     static void GetMainDicomTags(std::set<DicomTag>& result, ResourceType level);
 
     static void GetMainDicomTags(std::set<DicomTag>& result);
+
+    void Print(FILE* fp) const;
   };
 }
--- a/Core/Enumerations.cpp	Mon Nov 03 13:40:14 2014 +0100
+++ b/Core/Enumerations.cpp	Mon Nov 03 15:19:02 2014 +0100
@@ -313,6 +313,58 @@
   }
 
 
+  const char* EnumerationToString(PhotometricInterpretation photometric)
+  {
+    switch (photometric)
+    {
+      case PhotometricInterpretation_RGB:
+        return "RGB";
+
+      case PhotometricInterpretation_Monochrome1:
+        return "Monochrome1";
+
+      case PhotometricInterpretation_Monochrome2:
+        return "Monochrome2";
+
+      case PhotometricInterpretation_ARGB:
+        return "ARGB";
+
+      case PhotometricInterpretation_CMYK:
+        return "CMYK";
+
+      case PhotometricInterpretation_HSV:
+        return "HSV";
+
+      case PhotometricInterpretation_Palette:
+        return "Palette color";
+
+      case PhotometricInterpretation_YBRFull:
+        return "YBR full";
+
+      case PhotometricInterpretation_YBRFull422:
+        return "YBR full 422";
+
+      case PhotometricInterpretation_YBRPartial420:
+        return "YBR partial 420"; 
+
+      case PhotometricInterpretation_YBRPartial422:
+        return "YBR partial 422"; 
+
+      case PhotometricInterpretation_YBR_ICT:
+        return "YBR ICT"; 
+
+      case PhotometricInterpretation_YBR_RCT:
+        return "YBR RCT"; 
+
+      case PhotometricInterpretation_Unknown:
+        return "Unknown";
+
+      default:
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
   Encoding StringToEncoding(const char* encoding)
   {
     std::string s(encoding);
--- a/Core/Enumerations.h	Mon Nov 03 13:40:14 2014 +0100
+++ b/Core/Enumerations.h	Mon Nov 03 15:19:02 2014 +0100
@@ -254,6 +254,26 @@
   };
 
 
+  // https://www.dabsoft.ch/dicom/3/C.7.6.3.1.2/
+  enum PhotometricInterpretation
+  {
+    PhotometricInterpretation_ARGB,  // Retired
+    PhotometricInterpretation_CMYK,  // Retired
+    PhotometricInterpretation_HSV,   // Retired
+    PhotometricInterpretation_Monochrome1,
+    PhotometricInterpretation_Monochrome2,
+    PhotometricInterpretation_Palette,
+    PhotometricInterpretation_RGB,
+    PhotometricInterpretation_YBRFull,
+    PhotometricInterpretation_YBRFull422,
+    PhotometricInterpretation_YBRPartial420,
+    PhotometricInterpretation_YBRPartial422,
+    PhotometricInterpretation_YBR_ICT,
+    PhotometricInterpretation_YBR_RCT,
+    PhotometricInterpretation_Unknown
+  };
+
+
   /**
    * WARNING: Do not change the explicit values in the enumerations
    * below this point. This would result in incompatible databases
@@ -298,6 +318,8 @@
 
   const char* EnumerationToString(Encoding encoding);
 
+  const char* EnumerationToString(PhotometricInterpretation photometric);
+
   Encoding StringToEncoding(const char* encoding);
 
   ResourceType StringToResourceType(const char* type);
--- a/NEWS	Mon Nov 03 13:40:14 2014 +0100
+++ b/NEWS	Mon Nov 03 15:19:02 2014 +0100
@@ -3,6 +3,7 @@
 
 * Download ZIP + DICOMDIR from Orthanc Explorer
 * Sample plugin framework to serve static resources
+* Fix issue 19 (YBR_FULL are decoded incorrectly)
 * Fix issue 21 (Microsoft Visual Studio precompiled headers)
 * Fix issue 22 (Error decoding multi-frame instances)
 * Fix issue 24 (Build fails on OSX when directory has .DS_Store files)
--- a/OrthancServer/Internals/DicomImageDecoder.cpp	Mon Nov 03 13:40:14 2014 +0100
+++ b/OrthancServer/Internals/DicomImageDecoder.cpp	Mon Nov 03 15:19:02 2014 +0100
@@ -318,7 +318,9 @@
       LOG(WARNING) << "Unsupported DICOM image: " << info.GetBitsStored() 
                    << "bpp, " << info.GetChannelCount() << " channels, " 
                    << (info.IsSigned() ? "signed" : "unsigned")
-                   << (info.IsPlanar() ? ", planar" : ", non-planar");
+                   << (info.IsPlanar() ? ", planar, " : ", non-planar, ")
+                   << EnumerationToString(info.GetPhotometricInterpretation())
+                   << " photometric interpretation";
       throw OrthancException(ErrorCode_NotImplemented);
     }