diff OrthancServer/Internals/DicomImageDecoder.cpp @ 863:3c0d0836f704 jpeg

refactoring
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 10 Jun 2014 17:20:33 +0200
parents a546b05a43da
children 87791ebc1f50
line wrap: on
line diff
--- a/OrthancServer/Internals/DicomImageDecoder.cpp	Sat Jun 07 10:51:28 2014 +0200
+++ b/OrthancServer/Internals/DicomImageDecoder.cpp	Tue Jun 10 17:20:33 2014 +0200
@@ -42,38 +42,38 @@
   Program: GDCM (Grassroots DICOM). A DICOM library
   Module:  http://gdcm.sourceforge.net/Copyright.html
 
-Copyright (c) 2006-2011 Mathieu Malaterre
-Copyright (c) 1993-2005 CREATIS
-(CREATIS = Centre de Recherche et d'Applications en Traitement de l'Image)
-All rights reserved.
+  Copyright (c) 2006-2011 Mathieu Malaterre
+  Copyright (c) 1993-2005 CREATIS
+  (CREATIS = Centre de Recherche et d'Applications en Traitement de l'Image)
+  All rights reserved.
 
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
 
- * Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
+  * Redistributions of source code must retain the above copyright notice,
+  this list of conditions and the following disclaimer.
 
- * Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
+  * Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
 
- * Neither name of Mathieu Malaterre, or CREATIS, nor the names of any
-   contributors (CNRS, INSERM, UCB, Universite Lyon I), may be used to
-   endorse or promote products derived from this software without specific
-   prior written permission.
+  * Neither name of Mathieu Malaterre, or CREATIS, nor the names of any
+  contributors (CNRS, INSERM, UCB, Universite Lyon I), may be used to
+  endorse or promote products derived from this software without specific
+  prior written permission.
 
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
+  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-=========================================================================*/
+  =========================================================================*/
 
 
 
@@ -426,7 +426,8 @@
 
     bool fastVersionSuccess = false;
     PixelFormat sourceFormat;
-    if (info.ExtractPixelFormat(sourceFormat))
+    if (!info.IsPlanar() &&
+        info.ExtractPixelFormat(sourceFormat))
     {
       try
       {
@@ -460,19 +461,19 @@
         case PixelFormat_RGB24:
         case PixelFormat_RGBA32:
         case PixelFormat_Grayscale8:
-        CopyPixels<uint8_t>(targetAccessor, source.GetAccessor());
-        break;
+          CopyPixels<uint8_t>(targetAccessor, source.GetAccessor());
+          break;
         
         case PixelFormat_Grayscale16:
-        CopyPixels<uint16_t>(targetAccessor, source.GetAccessor());
-        break;
+          CopyPixels<uint16_t>(targetAccessor, source.GetAccessor());
+          break;
 
         case PixelFormat_SignedGrayscale16:
-        CopyPixels<int16_t>(targetAccessor, source.GetAccessor());
-        break;
+          CopyPixels<int16_t>(targetAccessor, source.GetAccessor());
+          break;
 
         default:
-        throw OrthancException(ErrorCode_InternalError);
+          throw OrthancException(ErrorCode_InternalError);
       }
     }
   }
@@ -584,53 +585,97 @@
   }
 
 
-  bool DicomImageDecoder::Decode(ImageBuffer& target,
-                                 DcmDataset& dataset,
-                                 unsigned int frame,
-                                 PixelFormat format,
-                                 Mode mode)
+  bool DicomImageDecoder::DecodeAndTruncate(ImageBuffer& target,
+                                            DcmDataset& dataset,
+                                            unsigned int frame,
+                                            PixelFormat format)
   {
-    // TODO OPTIMIZE THIS (avoid unnecessary image copies) !!!
+    // TODO Special case for uncompressed images
+    
+    ImageBuffer source;
+    if (!Decode(source, dataset, frame))
+    {
+      return false;
+    }
+
+    if (source.GetFormat() == format)
+    {
+      // No conversion is required, return the temporary image
+      target.AcquireOwnership(source);
+      return true;
+    }
 
-    ImageBuffer tmp;
-    if (!Decode(tmp, dataset, frame))
+    target.SetFormat(format);
+    target.SetWidth(source.GetWidth());
+    target.SetHeight(source.GetHeight());
+
+    ImageAccessor targetAccessor(target.GetAccessor());
+    ImageAccessor sourceAccessor(source.GetAccessor());
+    ImageProcessing::Convert(targetAccessor, sourceAccessor);
+
+    return true;
+  }
+
+
+  bool DicomImageDecoder::DecodePreview(ImageBuffer& target,
+                                        DcmDataset& dataset,
+                                        unsigned int frame)
+  {
+    // TODO Special case for uncompressed images
+    
+    ImageBuffer source;
+    if (!Decode(source, dataset, frame))
     {
       return false;
     }
 
-    if (!IsUncompressedImage(dataset) && !IsJpegLossless(dataset))
+    switch (source.GetFormat())
     {
-      printf("ICI\n");
-      PngWriter w;
-      ImageAccessor b(tmp.GetConstAccessor());
-      w.WriteToFile("toto.png", b);
-    }
-
-    target.SetFormat(format);
-    target.SetWidth(tmp.GetWidth());
-    target.SetHeight(tmp.GetHeight());
-
-    switch (mode)
-    {
-      case Mode_Truncate:
+      case PixelFormat_RGB24:
       {
-        if (!IsUncompressedImage(dataset) && !IsJpegLossless(dataset))
-        {
-          printf("%d => %d\n", tmp.GetFormat(), target.GetFormat());
-        }
-        ImageAccessor a(target.GetAccessor());
-        ImageAccessor b(tmp.GetConstAccessor());
-        ImageProcessing::Convert(a, b);
+        // Directly return color images (RGB)
+        target.AcquireOwnership(source);
         return true;
       }
 
+      case PixelFormat_Grayscale8:
+      case PixelFormat_Grayscale16:
+      case PixelFormat_SignedGrayscale16:
+      {
+        // Grayscale image: Stretch its dynamics to the [0,255] range
+        target.SetFormat(PixelFormat_Grayscale8);
+        target.SetWidth(source.GetWidth());
+        target.SetHeight(source.GetHeight());
+
+        ImageAccessor targetAccessor(target.GetAccessor());
+        ImageAccessor sourceAccessor(source.GetAccessor());
+
+        int64_t a, b;
+        ImageProcessing::GetMinMaxValue(a, b, sourceAccessor);
+        
+        if (a == b)
+        {
+          ImageProcessing::Set(targetAccessor, 0);
+        }
+        else
+        {
+          ImageProcessing::ShiftScale(sourceAccessor, -a, 255.0f / static_cast<float>(b - a));
+
+          if (source.GetFormat() == PixelFormat_Grayscale8)
+          {
+            target.AcquireOwnership(source);
+          }
+          else
+          {
+            ImageProcessing::Convert(targetAccessor, sourceAccessor);
+          }
+        }
+
+        return true;
+      }
+      
       default:
         throw OrthancException(ErrorCode_NotImplemented);
     }
-
-    return false;
   }
-
-
-
 }