Mercurial > hg > orthanc
diff Core/Images/ImageProcessing.cpp @ 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 |
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); + } + } }