changeset 2489:e91bab2d8c75

Bresenham's line algorithm
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 13 Mar 2018 21:14:21 +0100
parents 345725b9350c
children 0cacb38297a9
files Core/Images/ImageProcessing.cpp Core/Images/ImageProcessing.h Core/Images/PixelTraits.h
diffstat 3 files changed, 332 insertions(+), 129 deletions(-) [+]
line wrap: on
line diff
--- a/Core/Images/ImageProcessing.cpp	Tue Mar 13 17:02:30 2018 +0100
+++ b/Core/Images/ImageProcessing.cpp	Tue Mar 13 21:14:21 2018 +0100
@@ -34,7 +34,7 @@
 #include "../PrecompiledHeaders.h"
 #include "ImageProcessing.h"
 
-#include "../OrthancException.h"
+#include "PixelTraits.h"
 
 #include <boost/math/special_functions/round.hpp>
 
@@ -229,8 +229,8 @@
 
   template <typename PixelType,
             bool UseRound>
-  void MultiplyConstantInternal(ImageAccessor& image,
-                                float factor)
+  static void MultiplyConstantInternal(ImageAccessor& image,
+                                       float factor)
   {
     if (std::abs(factor - 1.0f) <= std::numeric_limits<float>::epsilon())
     {
@@ -277,9 +277,9 @@
 
   template <typename PixelType,
             bool UseRound>
-  void ShiftScaleInternal(ImageAccessor& image,
-                          float offset,
-                          float scaling)
+  static void ShiftScaleInternal(ImageAccessor& image,
+                                 float offset,
+                                 float scaling)
   {
     const float minFloatValue = static_cast<float>(std::numeric_limits<PixelType>::min());
     const float maxFloatValue = static_cast<float>(std::numeric_limits<PixelType>::max());
@@ -927,4 +927,222 @@
         throw OrthancException(ErrorCode_NotImplemented);
     }   
   }
+
+
+
+  namespace
+  {
+    template <Orthanc::PixelFormat Format>
+    class BresenhamPixelWriter
+    {
+    private:
+      typedef typename PixelTraits<Format>::PixelType  PixelType;
+    
+      Orthanc::ImageAccessor&  image_;
+      PixelType                value_;
+
+      void PlotLineLow(int x0,
+                       int y0,
+                       int x1,
+                       int y1)
+      {
+        int dx = x1 - x0;
+        int dy = y1 - y0;
+        int yi = 1;
+
+        if (dy < 0)
+        {
+          yi = -1;
+          dy = -dy;
+        }
+
+        int d = 2 * dy - dx;
+        int y = y0;
+
+        for (int x = x0; x <= x1; x++)
+        {
+          Write(x, y);
+          
+          if (d > 0)
+          {
+            y = y + yi;
+            d = d - 2 * dx;
+          }
+      
+          d = d + 2*dy;
+        }
+      }
+      
+      void PlotLineHigh(int x0,
+                        int y0,
+                        int x1,
+                        int y1)
+      {
+        int dx = x1 - x0;
+        int dy = y1 - y0;
+        int xi = 1;
+    
+        if (dx < 0)
+        {
+          xi = -1;
+          dx = -dx;
+        }
+    
+        int d = 2 * dx - dy;
+        int x = x0;
+
+        for (int y = y0; y <= y1; y++)
+        {
+          Write(x, y);
+          
+          if (d > 0)
+          {
+            x = x + xi;
+            d = d - 2 * dy;
+          }
+      
+          d = d + 2 * dx;
+        }
+      }
+
+    public:
+      BresenhamPixelWriter(Orthanc::ImageAccessor& image,
+                           int64_t value) :
+        image_(image),
+        value_(PixelTraits<Format>::IntegerToPixel(value))
+      {
+      }
+
+      BresenhamPixelWriter(Orthanc::ImageAccessor& image,
+                           const PixelType& value) :
+        image_(image),
+        value_(value)
+      {
+      }
+
+      void Write(int x,
+                 int y)
+      {
+        if (x >= 0 &&
+            y >= 0 &&
+            static_cast<unsigned int>(x) < image_.GetWidth() &&
+            static_cast<unsigned int>(y) < image_.GetHeight())
+        {
+          PixelType* p = reinterpret_cast<PixelType*>(image_.GetRow(y));
+          p[x] = value_;
+        }
+      }
+
+      void DrawSegment(int x0,
+                       int y0,
+                       int x1,
+                       int y1)
+      {
+        // This is an implementation of Bresenham's line algorithm
+        // https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#All_cases
+    
+        if (abs(y1 - y0) < abs(x1 - x0))
+        {
+          if (x0 > x1)
+          {
+            PlotLineLow(x1, y1, x0, y0);
+          }
+          else
+          {
+            PlotLineLow(x0, y0, x1, y1);
+          }
+        }
+        else
+        {
+          if (y0 > y1)
+          {
+            PlotLineHigh(x1, y1, x0, y0);
+          }
+          else
+          {
+            PlotLineHigh(x0, y0, x1, y1);
+          }
+        }
+      }
+    };
+  }
+
+  
+  void ImageProcessing::DrawLineSegment(ImageAccessor& image,
+                                        int x0,
+                                        int y0,
+                                        int x1,
+                                        int y1,
+                                        int64_t value)
+  {
+    switch (image.GetFormat())
+    {       
+      case Orthanc::PixelFormat_Grayscale8:
+      {
+        BresenhamPixelWriter<Orthanc::PixelFormat_Grayscale8> writer(image, value);
+        writer.DrawSegment(x0, y0, x1, y1);
+        break;
+      }
+
+      case Orthanc::PixelFormat_Grayscale16:
+      {
+        BresenhamPixelWriter<Orthanc::PixelFormat_Grayscale16> writer(image, value);
+        writer.DrawSegment(x0, y0, x1, y1);
+        break;
+      }
+
+      case Orthanc::PixelFormat_SignedGrayscale16:
+      {
+        BresenhamPixelWriter<Orthanc::PixelFormat_SignedGrayscale16> writer(image, value);
+        writer.DrawSegment(x0, y0, x1, y1);
+        break;
+      }
+        
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+    }
+  }
+
+  
+  void ImageProcessing::DrawLineSegment(ImageAccessor& image,
+                                        int x0,
+                                        int y0,
+                                        int x1,
+                                        int y1,
+                                        uint8_t red,
+                                        uint8_t green,
+                                        uint8_t blue,
+                                        uint8_t alpha)
+  {
+    switch (image.GetFormat())
+    {
+      case Orthanc::PixelFormat_BGRA32:
+      {
+        PixelTraits<Orthanc::PixelFormat_BGRA32>::PixelType pixel;
+        pixel.red_ = red;
+        pixel.green_ = green;
+        pixel.blue_ = blue;
+        pixel.alpha_ = alpha;
+
+        BresenhamPixelWriter<Orthanc::PixelFormat_BGRA32> writer(image, pixel);
+        writer.DrawSegment(x0, y0, x1, y1);
+        break;
+      }
+        
+      case Orthanc::PixelFormat_RGB24:
+      {
+        PixelTraits<Orthanc::PixelFormat_RGB24>::PixelType pixel;
+        pixel.red_ = red;
+        pixel.green_ = green;
+        pixel.blue_ = blue;
+
+        BresenhamPixelWriter<Orthanc::PixelFormat_RGB24> writer(image, pixel);
+        writer.DrawSegment(x0, y0, x1, y1);
+        break;
+      }
+        
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+    }
+  }
 }
--- a/Core/Images/ImageProcessing.h	Tue Mar 13 17:02:30 2018 +0100
+++ b/Core/Images/ImageProcessing.h	Tue Mar 13 21:14:21 2018 +0100
@@ -39,49 +39,65 @@
 
 namespace Orthanc
 {
-  class ImageProcessing
+  namespace ImageProcessing
   {
-  public:
-    static void Copy(ImageAccessor& target,
-                     const ImageAccessor& source);
+    void Copy(ImageAccessor& target,
+              const ImageAccessor& source);
 
-    static void Convert(ImageAccessor& target,
-                        const ImageAccessor& source);
+    void Convert(ImageAccessor& target,
+                 const ImageAccessor& source);
 
-    static void Set(ImageAccessor& image,
-                    int64_t value);
+    void Set(ImageAccessor& image,
+             int64_t value);
 
-    static void Set(ImageAccessor& image,
-                    uint8_t red,
-                    uint8_t green,
-                    uint8_t blue,
-                    uint8_t alpha);
+    void Set(ImageAccessor& image,
+             uint8_t red,
+             uint8_t green,
+             uint8_t blue,
+             uint8_t alpha);
 
-    static void ShiftRight(ImageAccessor& target,
-                           unsigned int shift);
+    void ShiftRight(ImageAccessor& target,
+                    unsigned int shift);
 
-    static void GetMinMaxIntegerValue(int64_t& minValue,
-                                      int64_t& maxValue,
-                                      const ImageAccessor& image);
+    void GetMinMaxIntegerValue(int64_t& minValue,
+                               int64_t& maxValue,
+                               const ImageAccessor& image);
 
-    static void GetMinMaxFloatValue(float& minValue,
-                                    float& maxValue,
-                                    const ImageAccessor& image);
+    void GetMinMaxFloatValue(float& minValue,
+                             float& maxValue,
+                             const ImageAccessor& image);
 
-    static void AddConstant(ImageAccessor& image,
-                            int64_t value);
+    void AddConstant(ImageAccessor& image,
+                     int64_t value);
 
     // "useRound" is expensive
-    static void MultiplyConstant(ImageAccessor& image,
-                                 float factor,
-                                 bool useRound);
+    void MultiplyConstant(ImageAccessor& image,
+                          float factor,
+                          bool useRound);
 
     // "useRound" is expensive
-    static void ShiftScale(ImageAccessor& image,
-                           float offset,
-                           float scaling,
-                           bool useRound);
+    void ShiftScale(ImageAccessor& image,
+                    float offset,
+                    float scaling,
+                    bool useRound);
+
+    void Invert(ImageAccessor& image);
 
-    static void Invert(ImageAccessor& image);
+    void DrawLineSegment(ImageAccessor& image,
+                         int x0,
+                         int y0,
+                         int x1,
+                         int y1,
+                         int64_t value);
+
+    void DrawLineSegment(ImageAccessor& image,
+                         int x0,
+                         int y0,
+                         int x1,
+                         int y1,
+                         uint8_t red,
+                         uint8_t green,
+                         uint8_t blue,
+                         uint8_t alpha);
   };
 }
--- a/Core/Images/PixelTraits.h	Tue Mar 13 17:02:30 2018 +0100
+++ b/Core/Images/PixelTraits.h	Tue Mar 13 21:14:21 2018 +0100
@@ -34,23 +34,36 @@
 #pragma once
 
 #include "../Enumerations.h"
+#include "../OrthancException.h"
 
+#include <limits>
 
 namespace Orthanc
 {
-  template <PixelFormat Format>
-  struct PixelTraits;
-
-
-  template <>
-  struct PixelTraits<PixelFormat_Grayscale8>
+  template <PixelFormat format,
+            typename _PixelType>
+  struct IntegerPixelTraits
   {
-    typedef uint8_t   PixelType;
+    typedef _PixelType  PixelType;
 
     ORTHANC_FORCE_INLINE
     static PixelFormat GetPixelFormat()
     {
-      return PixelFormat_Grayscale8;
+      return format;
+    }
+
+    ORTHANC_FORCE_INLINE
+    static PixelType IntegerToPixel(int64_t value)
+    {
+      if (value < static_cast<int64_t>(std::numeric_limits<PixelType>::min()) ||
+          value > static_cast<int64_t>(std::numeric_limits<PixelType>::max()))
+      {
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+      }
+      else
+      {
+        return static_cast<PixelType>(value);
+      }
     }
 
     ORTHANC_FORCE_INLINE
@@ -60,6 +73,18 @@
     }
 
     ORTHANC_FORCE_INLINE
+    static void SetMinValue(PixelType& target)
+    {
+      target = std::numeric_limits<PixelType>::min();
+    }
+
+    ORTHANC_FORCE_INLINE
+    static void SetMaxValue(PixelType& target)
+    {
+      target = std::numeric_limits<PixelType>::max();
+    }
+
+    ORTHANC_FORCE_INLINE
     static void Copy(PixelType& target,
                      const PixelType& source)
     {
@@ -76,7 +101,18 @@
     static void FloatToPixel(PixelType& target,
                              float value)
     {
-      target = static_cast<uint8_t>(value);
+      if (value < static_cast<float>(std::numeric_limits<PixelType>::min()))
+      {
+        target = std::numeric_limits<PixelType>::min();
+      }
+      else if (value > static_cast<float>(std::numeric_limits<PixelType>::max()))
+      {
+        target = std::numeric_limits<PixelType>::max();
+      }
+      else
+      {
+        target = static_cast<PixelType>(value);
+      }
     }
 
     ORTHANC_FORCE_INLINE
@@ -88,95 +124,28 @@
   };
 
 
-  template <>
-  struct PixelTraits<PixelFormat_Grayscale16>
-  {
-    typedef uint16_t   PixelType;
-
-    ORTHANC_FORCE_INLINE
-    static PixelFormat GetPixelFormat()
-    {
-      return PixelFormat_Grayscale16;
-    }
-
-    ORTHANC_FORCE_INLINE
-    static void SetZero(PixelType& target)
-    {
-      target = 0;
-    }
-
-    ORTHANC_FORCE_INLINE
-    static void Copy(PixelType& target,
-                     const PixelType& source)
-    {
-      target = source;
-    }
-
-    ORTHANC_FORCE_INLINE
-    static float PixelToFloat(const PixelType& source)
-    {
-      return static_cast<float>(source);
-    }
-
-    ORTHANC_FORCE_INLINE
-    static void FloatToPixel(PixelType& target,
-                             float value)
-    {
-      target = static_cast<uint16_t>(value);
-    }
-
-    ORTHANC_FORCE_INLINE
-    static bool IsEqual(const PixelType& a,
-                        const PixelType& b)
-    {
-      return a == b;
-    }
-  };
+  template <PixelFormat Format>
+  struct PixelTraits;
 
 
   template <>
-  struct PixelTraits<PixelFormat_SignedGrayscale16>
+  struct PixelTraits<PixelFormat_Grayscale8> :
+    public IntegerPixelTraits<PixelFormat_Grayscale8, uint8_t>
   {
-    typedef int16_t   PixelType;
-
-    ORTHANC_FORCE_INLINE
-    static PixelFormat GetPixelFormat()
-    {
-      return PixelFormat_SignedGrayscale16;
-    }
-
-    ORTHANC_FORCE_INLINE
-    static void SetZero(PixelType& target)
-    {
-      target = 0;
-    }
+  };
 
-    ORTHANC_FORCE_INLINE
-    static void Copy(PixelType& target,
-                     const PixelType& source)
-    {
-      target = source;
-    }
-
-    ORTHANC_FORCE_INLINE
-    static float PixelToFloat(const PixelType& source)
-    {
-      return static_cast<float>(source);
-    }
+  
+  template <>
+  struct PixelTraits<PixelFormat_Grayscale16> :
+    public IntegerPixelTraits<PixelFormat_Grayscale16, uint16_t>
+  {
+  };
 
-    ORTHANC_FORCE_INLINE
-    static void FloatToPixel(PixelType& target,
-                             float value)
-    {
-      target = static_cast<int16_t>(value);
-    }
-
-    ORTHANC_FORCE_INLINE
-    static bool IsEqual(const PixelType& a,
-                        const PixelType& b)
-    {
-      return a == b;
-    }
+  
+  template <>
+  struct PixelTraits<PixelFormat_SignedGrayscale16> :
+    public IntegerPixelTraits<PixelFormat_SignedGrayscale16, int16_t>
+  {
   };