Mercurial > hg > orthanc
comparison Core/Images/ImageProcessing.cpp @ 3525:8c66c9c2257b
fix ImageProcessing::ShiftScale() on float images
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 25 Sep 2019 17:16:54 +0200 |
parents | b2d4dd16dae8 |
children | 551945086617 |
comparison
equal
deleted
inserted
replaced
3524:d96379a965de | 3525:8c66c9c2257b |
---|---|
58 | 58 |
59 template <typename TargetType, typename SourceType> | 59 template <typename TargetType, typename SourceType> |
60 static void ConvertInternal(ImageAccessor& target, | 60 static void ConvertInternal(ImageAccessor& target, |
61 const ImageAccessor& source) | 61 const ImageAccessor& source) |
62 { | 62 { |
63 // WARNING - "::min()" should be replaced by "::lowest()" if | |
64 // dealing with float or double (which is not the case so far) | |
65 assert(sizeof(TargetType) <= 2); // Safeguard to remember about "float/double" | |
63 const TargetType minValue = std::numeric_limits<TargetType>::min(); | 66 const TargetType minValue = std::numeric_limits<TargetType>::min(); |
64 const TargetType maxValue = std::numeric_limits<TargetType>::max(); | 67 const TargetType maxValue = std::numeric_limits<TargetType>::max(); |
65 | 68 |
66 const unsigned int width = source.GetWidth(); | 69 const unsigned int width = source.GetWidth(); |
67 const unsigned int height = source.GetHeight(); | 70 const unsigned int height = source.GetHeight(); |
140 static void ConvertColorToGrayscale(ImageAccessor& target, | 143 static void ConvertColorToGrayscale(ImageAccessor& target, |
141 const ImageAccessor& source) | 144 const ImageAccessor& source) |
142 { | 145 { |
143 assert(source.GetFormat() == PixelFormat_RGB24); | 146 assert(source.GetFormat() == PixelFormat_RGB24); |
144 | 147 |
148 // WARNING - "::min()" should be replaced by "::lowest()" if | |
149 // dealing with float or double (which is not the case so far) | |
150 assert(sizeof(TargetType) <= 2); // Safeguard to remember about "float/double" | |
145 const TargetType minValue = std::numeric_limits<TargetType>::min(); | 151 const TargetType minValue = std::numeric_limits<TargetType>::min(); |
146 const TargetType maxValue = std::numeric_limits<TargetType>::max(); | 152 const TargetType maxValue = std::numeric_limits<TargetType>::max(); |
147 | 153 |
148 const unsigned int width = source.GetWidth(); | 154 const unsigned int width = source.GetWidth(); |
149 const unsigned int height = source.GetHeight(); | 155 const unsigned int height = source.GetHeight(); |
225 | 231 |
226 | 232 |
227 template <typename PixelType> | 233 template <typename PixelType> |
228 static void GetMinMaxValueInternal(PixelType& minValue, | 234 static void GetMinMaxValueInternal(PixelType& minValue, |
229 PixelType& maxValue, | 235 PixelType& maxValue, |
230 const ImageAccessor& source) | 236 const ImageAccessor& source, |
237 const PixelType LowestValue = std::numeric_limits<PixelType>::min()) | |
231 { | 238 { |
232 // Deal with the special case of empty image | 239 // Deal with the special case of empty image |
233 if (source.GetWidth() == 0 || | 240 if (source.GetWidth() == 0 || |
234 source.GetHeight() == 0) | 241 source.GetHeight() == 0) |
235 { | 242 { |
237 maxValue = 0; | 244 maxValue = 0; |
238 return; | 245 return; |
239 } | 246 } |
240 | 247 |
241 minValue = std::numeric_limits<PixelType>::max(); | 248 minValue = std::numeric_limits<PixelType>::max(); |
242 maxValue = std::numeric_limits<PixelType>::min(); | 249 maxValue = LowestValue; |
243 | 250 |
244 const unsigned int height = source.GetHeight(); | 251 const unsigned int height = source.GetHeight(); |
245 const unsigned int width = source.GetWidth(); | 252 const unsigned int width = source.GetWidth(); |
246 | 253 |
247 for (unsigned int y = 0; y < height; y++) | 254 for (unsigned int y = 0; y < height; y++) |
272 if (constant == 0) | 279 if (constant == 0) |
273 { | 280 { |
274 return; | 281 return; |
275 } | 282 } |
276 | 283 |
284 // WARNING - "::min()" should be replaced by "::lowest()" if | |
285 // dealing with float or double (which is not the case so far) | |
286 assert(sizeof(PixelType) <= 2); // Safeguard to remember about "float/double" | |
277 const int64_t minValue = std::numeric_limits<PixelType>::min(); | 287 const int64_t minValue = std::numeric_limits<PixelType>::min(); |
278 const int64_t maxValue = std::numeric_limits<PixelType>::max(); | 288 const int64_t maxValue = std::numeric_limits<PixelType>::max(); |
279 | 289 |
280 const unsigned int width = image.GetWidth(); | 290 const unsigned int width = image.GetWidth(); |
281 const unsigned int height = image.GetHeight(); | 291 const unsigned int height = image.GetHeight(); |
314 if (std::abs(factor - 1.0f) <= std::numeric_limits<float>::epsilon()) | 324 if (std::abs(factor - 1.0f) <= std::numeric_limits<float>::epsilon()) |
315 { | 325 { |
316 return; | 326 return; |
317 } | 327 } |
318 | 328 |
329 // WARNING - "::min()" should be replaced by "::lowest()" if | |
330 // dealing with float or double (which is not the case so far) | |
331 assert(sizeof(PixelType) <= 2); // Safeguard to remember about "float/double" | |
319 const int64_t minValue = std::numeric_limits<PixelType>::min(); | 332 const int64_t minValue = std::numeric_limits<PixelType>::min(); |
320 const int64_t maxValue = std::numeric_limits<PixelType>::max(); | 333 const int64_t maxValue = std::numeric_limits<PixelType>::max(); |
321 | 334 |
322 const unsigned int width = image.GetWidth(); | 335 const unsigned int width = image.GetWidth(); |
323 const unsigned int height = image.GetHeight(); | 336 const unsigned int height = image.GetHeight(); |
358 | 371 |
359 template <typename PixelType, | 372 template <typename PixelType, |
360 bool UseRound> | 373 bool UseRound> |
361 static void ShiftScaleInternal(ImageAccessor& image, | 374 static void ShiftScaleInternal(ImageAccessor& image, |
362 float offset, | 375 float offset, |
363 float scaling) | 376 float scaling, |
364 { | 377 const PixelType LowestValue = std::numeric_limits<PixelType>::min()) |
365 const float minFloatValue = static_cast<float>(std::numeric_limits<PixelType>::min()); | 378 { |
366 const float maxFloatValue = static_cast<float>(std::numeric_limits<PixelType>::max()); | 379 const PixelType minPixelValue = LowestValue; |
367 const PixelType minPixelValue = std::numeric_limits<PixelType>::min(); | |
368 const PixelType maxPixelValue = std::numeric_limits<PixelType>::max(); | 380 const PixelType maxPixelValue = std::numeric_limits<PixelType>::max(); |
381 const float minFloatValue = static_cast<float>(LowestValue); | |
382 const float maxFloatValue = static_cast<float>(maxPixelValue); | |
369 | 383 |
370 const unsigned int height = image.GetHeight(); | 384 const unsigned int height = image.GetHeight(); |
371 const unsigned int width = image.GetWidth(); | 385 const unsigned int width = image.GetWidth(); |
372 | 386 |
373 for (unsigned int y = 0; y < height; y++) | 387 for (unsigned int y = 0; y < height; y++) |
967 { | 981 { |
968 case PixelFormat_Float32: | 982 case PixelFormat_Float32: |
969 { | 983 { |
970 assert(sizeof(float) == 4); | 984 assert(sizeof(float) == 4); |
971 float a, b; | 985 float a, b; |
972 GetMinMaxValueInternal<float>(a, b, image); | 986 |
987 /** | |
988 * WARNING - On floating-point types, the minimal value is | |
989 * "-FLT_MAX" (as implemented by "::lowest()"), not "FLT_MIN" | |
990 * (as implemented by "::min()") | |
991 * https://en.cppreference.com/w/cpp/types/numeric_limits | |
992 **/ | |
993 GetMinMaxValueInternal<float>(a, b, image, -std::numeric_limits<float>::max()); | |
973 minValue = a; | 994 minValue = a; |
974 maxValue = b; | 995 maxValue = b; |
975 break; | 996 break; |
976 } | 997 } |
977 | 998 |
1091 return; | 1112 return; |
1092 | 1113 |
1093 case PixelFormat_Float32: | 1114 case PixelFormat_Float32: |
1094 if (useRound) | 1115 if (useRound) |
1095 { | 1116 { |
1096 ShiftScaleInternal<float, true>(image, offset, scaling); | 1117 ShiftScaleInternal<float, true>(image, offset, scaling, -std::numeric_limits<float>::max()); |
1097 } | 1118 } |
1098 else | 1119 else |
1099 { | 1120 { |
1100 ShiftScaleInternal<float, false>(image, offset, scaling); | 1121 ShiftScaleInternal<float, false>(image, offset, scaling, -std::numeric_limits<float>::max()); |
1101 } | 1122 } |
1102 return; | 1123 return; |
1103 | 1124 |
1104 default: | 1125 default: |
1105 throw OrthancException(ErrorCode_NotImplemented); | 1126 throw OrthancException(ErrorCode_NotImplemented); |
1830 size_t horizontalAnchor, | 1851 size_t horizontalAnchor, |
1831 const std::vector<float>& vertical, | 1852 const std::vector<float>& vertical, |
1832 size_t verticalAnchor, | 1853 size_t verticalAnchor, |
1833 float normalization) | 1854 float normalization) |
1834 { | 1855 { |
1856 // WARNING - "::min()" should be replaced by "::lowest()" if | |
1857 // dealing with float or double (which is not the case so far) | |
1858 assert(sizeof(RawPixel) <= 2); // Safeguard to remember about "float/double" | |
1859 | |
1835 const unsigned int width = image.GetWidth(); | 1860 const unsigned int width = image.GetWidth(); |
1836 const unsigned int height = image.GetHeight(); | 1861 const unsigned int height = image.GetHeight(); |
1837 | 1862 |
1838 | 1863 |
1839 /** | 1864 /** |