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