Mercurial > hg > orthanc
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> + { };