comparison 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
comparison
equal deleted inserted replaced
2488:345725b9350c 2489:e91bab2d8c75
32 32
33 33
34 #include "../PrecompiledHeaders.h" 34 #include "../PrecompiledHeaders.h"
35 #include "ImageProcessing.h" 35 #include "ImageProcessing.h"
36 36
37 #include "../OrthancException.h" 37 #include "PixelTraits.h"
38 38
39 #include <boost/math/special_functions/round.hpp> 39 #include <boost/math/special_functions/round.hpp>
40 40
41 #include <cassert> 41 #include <cassert>
42 #include <string.h> 42 #include <string.h>
227 227
228 228
229 229
230 template <typename PixelType, 230 template <typename PixelType,
231 bool UseRound> 231 bool UseRound>
232 void MultiplyConstantInternal(ImageAccessor& image, 232 static void MultiplyConstantInternal(ImageAccessor& image,
233 float factor) 233 float factor)
234 { 234 {
235 if (std::abs(factor - 1.0f) <= std::numeric_limits<float>::epsilon()) 235 if (std::abs(factor - 1.0f) <= std::numeric_limits<float>::epsilon())
236 { 236 {
237 return; 237 return;
238 } 238 }
275 } 275 }
276 276
277 277
278 template <typename PixelType, 278 template <typename PixelType,
279 bool UseRound> 279 bool UseRound>
280 void ShiftScaleInternal(ImageAccessor& image, 280 static void ShiftScaleInternal(ImageAccessor& image,
281 float offset, 281 float offset,
282 float scaling) 282 float scaling)
283 { 283 {
284 const float minFloatValue = static_cast<float>(std::numeric_limits<PixelType>::min()); 284 const float minFloatValue = static_cast<float>(std::numeric_limits<PixelType>::min());
285 const float maxFloatValue = static_cast<float>(std::numeric_limits<PixelType>::max()); 285 const float maxFloatValue = static_cast<float>(std::numeric_limits<PixelType>::max());
286 const PixelType minPixelValue = std::numeric_limits<PixelType>::min(); 286 const PixelType minPixelValue = std::numeric_limits<PixelType>::min();
287 const PixelType maxPixelValue = std::numeric_limits<PixelType>::max(); 287 const PixelType maxPixelValue = std::numeric_limits<PixelType>::max();
925 925
926 default: 926 default:
927 throw OrthancException(ErrorCode_NotImplemented); 927 throw OrthancException(ErrorCode_NotImplemented);
928 } 928 }
929 } 929 }
930
931
932
933 namespace
934 {
935 template <Orthanc::PixelFormat Format>
936 class BresenhamPixelWriter
937 {
938 private:
939 typedef typename PixelTraits<Format>::PixelType PixelType;
940
941 Orthanc::ImageAccessor& image_;
942 PixelType value_;
943
944 void PlotLineLow(int x0,
945 int y0,
946 int x1,
947 int y1)
948 {
949 int dx = x1 - x0;
950 int dy = y1 - y0;
951 int yi = 1;
952
953 if (dy < 0)
954 {
955 yi = -1;
956 dy = -dy;
957 }
958
959 int d = 2 * dy - dx;
960 int y = y0;
961
962 for (int x = x0; x <= x1; x++)
963 {
964 Write(x, y);
965
966 if (d > 0)
967 {
968 y = y + yi;
969 d = d - 2 * dx;
970 }
971
972 d = d + 2*dy;
973 }
974 }
975
976 void PlotLineHigh(int x0,
977 int y0,
978 int x1,
979 int y1)
980 {
981 int dx = x1 - x0;
982 int dy = y1 - y0;
983 int xi = 1;
984
985 if (dx < 0)
986 {
987 xi = -1;
988 dx = -dx;
989 }
990
991 int d = 2 * dx - dy;
992 int x = x0;
993
994 for (int y = y0; y <= y1; y++)
995 {
996 Write(x, y);
997
998 if (d > 0)
999 {
1000 x = x + xi;
1001 d = d - 2 * dy;
1002 }
1003
1004 d = d + 2 * dx;
1005 }
1006 }
1007
1008 public:
1009 BresenhamPixelWriter(Orthanc::ImageAccessor& image,
1010 int64_t value) :
1011 image_(image),
1012 value_(PixelTraits<Format>::IntegerToPixel(value))
1013 {
1014 }
1015
1016 BresenhamPixelWriter(Orthanc::ImageAccessor& image,
1017 const PixelType& value) :
1018 image_(image),
1019 value_(value)
1020 {
1021 }
1022
1023 void Write(int x,
1024 int y)
1025 {
1026 if (x >= 0 &&
1027 y >= 0 &&
1028 static_cast<unsigned int>(x) < image_.GetWidth() &&
1029 static_cast<unsigned int>(y) < image_.GetHeight())
1030 {
1031 PixelType* p = reinterpret_cast<PixelType*>(image_.GetRow(y));
1032 p[x] = value_;
1033 }
1034 }
1035
1036 void DrawSegment(int x0,
1037 int y0,
1038 int x1,
1039 int y1)
1040 {
1041 // This is an implementation of Bresenham's line algorithm
1042 // https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#All_cases
1043
1044 if (abs(y1 - y0) < abs(x1 - x0))
1045 {
1046 if (x0 > x1)
1047 {
1048 PlotLineLow(x1, y1, x0, y0);
1049 }
1050 else
1051 {
1052 PlotLineLow(x0, y0, x1, y1);
1053 }
1054 }
1055 else
1056 {
1057 if (y0 > y1)
1058 {
1059 PlotLineHigh(x1, y1, x0, y0);
1060 }
1061 else
1062 {
1063 PlotLineHigh(x0, y0, x1, y1);
1064 }
1065 }
1066 }
1067 };
1068 }
1069
1070
1071 void ImageProcessing::DrawLineSegment(ImageAccessor& image,
1072 int x0,
1073 int y0,
1074 int x1,
1075 int y1,
1076 int64_t value)
1077 {
1078 switch (image.GetFormat())
1079 {
1080 case Orthanc::PixelFormat_Grayscale8:
1081 {
1082 BresenhamPixelWriter<Orthanc::PixelFormat_Grayscale8> writer(image, value);
1083 writer.DrawSegment(x0, y0, x1, y1);
1084 break;
1085 }
1086
1087 case Orthanc::PixelFormat_Grayscale16:
1088 {
1089 BresenhamPixelWriter<Orthanc::PixelFormat_Grayscale16> writer(image, value);
1090 writer.DrawSegment(x0, y0, x1, y1);
1091 break;
1092 }
1093
1094 case Orthanc::PixelFormat_SignedGrayscale16:
1095 {
1096 BresenhamPixelWriter<Orthanc::PixelFormat_SignedGrayscale16> writer(image, value);
1097 writer.DrawSegment(x0, y0, x1, y1);
1098 break;
1099 }
1100
1101 default:
1102 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
1103 }
1104 }
1105
1106
1107 void ImageProcessing::DrawLineSegment(ImageAccessor& image,
1108 int x0,
1109 int y0,
1110 int x1,
1111 int y1,
1112 uint8_t red,
1113 uint8_t green,
1114 uint8_t blue,
1115 uint8_t alpha)
1116 {
1117 switch (image.GetFormat())
1118 {
1119 case Orthanc::PixelFormat_BGRA32:
1120 {
1121 PixelTraits<Orthanc::PixelFormat_BGRA32>::PixelType pixel;
1122 pixel.red_ = red;
1123 pixel.green_ = green;
1124 pixel.blue_ = blue;
1125 pixel.alpha_ = alpha;
1126
1127 BresenhamPixelWriter<Orthanc::PixelFormat_BGRA32> writer(image, pixel);
1128 writer.DrawSegment(x0, y0, x1, y1);
1129 break;
1130 }
1131
1132 case Orthanc::PixelFormat_RGB24:
1133 {
1134 PixelTraits<Orthanc::PixelFormat_RGB24>::PixelType pixel;
1135 pixel.red_ = red;
1136 pixel.green_ = green;
1137 pixel.blue_ = blue;
1138
1139 BresenhamPixelWriter<Orthanc::PixelFormat_RGB24> writer(image, pixel);
1140 writer.DrawSegment(x0, y0, x1, y1);
1141 break;
1142 }
1143
1144 default:
1145 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
1146 }
1147 }
930 } 1148 }