comparison OrthancStone/Sources/Toolbox/ImageToolbox.cpp @ 1512:244ad1e4e76a

reorganization of folders
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 07 Jul 2020 16:21:02 +0200
parents Framework/Toolbox/ImageToolbox.cpp@121d01aa328e
children 4fb8fdf03314
comparison
equal deleted inserted replaced
1511:9dfeee74c1e6 1512:244ad1e4e76a
1 /**
2 * Stone of Orthanc
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Affero General Public License
9 * as published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20
21 #include "../OrthancStone.h"
22 #include "ImageToolbox.h"
23
24 #include "../StoneException.h"
25
26 #include <Images/ImageProcessing.h>
27 #include <Images/PixelTraits.h>
28
29 #include <Logging.h>
30 #include <OrthancException.h>
31
32 #include <boost/static_assert.hpp>
33 #include <boost/type_traits.hpp>
34
35 #include <vector>
36
37 #if !defined(ORTHANC_ENABLE_DCMTK)
38 # error ORTHANC_ENABLE_DCMTK is not defined
39 #endif
40
41 #if !defined(ORTHANC_ENABLE_DCMTK_JPEG)
42 # error ORTHANC_ENABLE_DCMTK_JPEG is not defined
43 #endif
44
45 #if !defined(ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS)
46 # error ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS is not defined
47 #endif
48
49
50 namespace OrthancStone
51 {
52 namespace
53 {
54 using Orthanc::PixelTraits;
55 using Orthanc::PixelFormat;
56 using Orthanc::ImageAccessor;
57 using Orthanc::PixelFormat;
58
59 template<typename Orthanc::PixelFormat Format>
60 class PixelBinner
61 {
62 // "PixelBinner requires an arithmetic (integer or floating-point) pixel format"
63 typedef typename Orthanc::PixelTraits<Format>::PixelType PixelType;
64 BOOST_STATIC_ASSERT(boost::is_arithmetic<PixelType>::value);
65
66 public:
67 PixelBinner(HistogramData& hd, double minValue, double maxValue)
68 : hd_(hd)
69 , minValue_(minValue)
70 , maxValue_(maxValue)
71 , division_(1.0 / hd_.binSize)
72 {
73 ORTHANC_ASSERT(hd_.bins.size() > 0);
74 ORTHANC_ASSERT(maxValue > minValue);
75 }
76
77 ORTHANC_FORCE_INLINE void AddPixel(PixelType p)
78 {
79 if (p <= minValue_)
80 {
81 hd_.bins[0] += 1;
82 }
83 else if (p >= maxValue_)
84 {
85 hd_.bins.back() += 1;
86 }
87 else
88 {
89 double distanceFromMin = p - minValue_;
90 size_t binIndex = static_cast<size_t>(
91 std::floor(distanceFromMin * division_));
92 if (binIndex >= hd_.bins.size())
93 binIndex = hd_.bins.size() - 1;
94 hd_.bins[binIndex] += 1;
95 }
96 }
97 private:
98 HistogramData& hd_;
99 double minValue_;
100 double maxValue_;
101 double division_;
102 };
103
104 template<PixelFormat Format>
105 struct Histogram
106 {
107 typedef typename PixelTraits<Format>::PixelType PixelType;
108
109 static void Apply(const Orthanc::ImageAccessor& img, HistogramData& hd,
110 double minValue = 0,
111 double maxValue = 0)
112 {
113 ORTHANC_ASSERT(Format == img.GetFormat(),
114 "Internal error. Wrong template histogram type");
115
116 const size_t height = img.GetHeight();
117 const size_t width = img.GetHeight();
118
119 if ((minValue == 0) && (maxValue == 0))
120 {
121 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
122 //ORTHANC_ASSERT(boost::is_integral<PixelType>::value,
123 // "Min and max values must be supplied for float-based histogram");
124 //
125 //PixelTraits<Format>::SetMinValue(minValue);
126 //PixelTraits<Format>::SetMaxValue(maxValue);
127 }
128
129 hd.minValue = minValue;
130
131 // the following code is not really pretty but ensures
132 size_t numBins = static_cast<size_t>(
133 std::ceil((maxValue - minValue) / hd.binSize));
134
135 hd.bins.resize(numBins);
136 std::fill(hd.bins.begin(), hd.bins.end(), 0);
137
138 PixelBinner<Format> binner(hd, minValue, maxValue);
139 for (uint32_t y = 0; y < height; ++y)
140 {
141 const PixelType* curPix = reinterpret_cast<const PixelType*>(
142 img.GetConstRow(y));
143
144 for (uint32_t x = 0; x < width; x++, curPix++)
145 {
146 binner.AddPixel(*curPix);
147 }
148 }
149 }
150 };
151
152
153 template<PixelFormat Format>
154 struct ComputeMinMax__
155 {
156 typedef typename PixelTraits<Format>::PixelType PixelType;
157
158 static void Apply(const Orthanc::ImageAccessor& img,
159 PixelType& minValue, PixelType& maxValue)
160 {
161 ORTHANC_ASSERT(Format == img.GetFormat(),
162 "Internal error. Wrong template histogram type");
163
164 const size_t height = img.GetHeight();
165 const size_t width = img.GetHeight();
166
167 if (height * width == 0)
168 {
169 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
170 }
171
172 // min and max are crossed below. Think about it. This is OK :)
173 PixelTraits<Format>::SetMaxValue(minValue);
174 PixelTraits<Format>::SetMinValue(maxValue);
175
176 for (uint32_t y = 0; y < height; ++y)
177 {
178 const PixelType* curPix = reinterpret_cast<const PixelType*>(
179 img.GetConstRow(y));
180
181 for (uint32_t x = 0; x < width; x++, curPix++)
182 {
183 if (*curPix <= minValue)
184 minValue = *curPix;
185 if (*curPix >= maxValue)
186 maxValue = *curPix;
187 }
188 }
189 }
190 };
191
192 template<PixelFormat Format>
193 void ComputeMinMax_(const Orthanc::ImageAccessor& img,
194 double& minValue, double& maxValue)
195 {
196 typedef typename PixelTraits<Format>::PixelType PixelType;
197 PixelType minValuePix = PixelType();
198 PixelType maxValuePix = PixelType();
199 ComputeMinMax__<Format>::Apply(img, minValuePix, maxValuePix);
200 minValue = static_cast<double>(minValuePix);
201 maxValue = static_cast<double>(maxValuePix);
202 }
203
204 template<PixelFormat Format>
205 void ComputeHistogram_(const Orthanc::ImageAccessor& img, HistogramData& hd)
206 {
207 typedef typename PixelTraits<Format>::PixelType PixelType;
208 PixelType minValue = PixelType();
209 PixelType maxValue = PixelType();
210 ComputeMinMax__<Format>::Apply(img, minValue, maxValue);
211
212 // make bins a little bigger to center integer pixel values
213 Histogram<Format>::Apply(img, hd,
214 static_cast<double>(minValue) - 0.5,
215 static_cast<double>(maxValue) + 0.5);
216 }
217 }
218
219 void ComputeHistogram(const Orthanc::ImageAccessor& img,
220 HistogramData& hd, double binSize)
221 {
222 using namespace Orthanc;
223
224 hd.binSize = binSize;
225
226 // dynamic/static bridge
227 switch (img.GetFormat())
228 {
229 case PixelFormat_Grayscale8:
230 ComputeHistogram_<PixelFormat_Grayscale8> (img, hd);
231 break;
232 case PixelFormat_Grayscale16:
233 ComputeHistogram_<PixelFormat_Grayscale16> (img, hd);
234 break;
235 case PixelFormat_SignedGrayscale16:
236 ComputeHistogram_<PixelFormat_SignedGrayscale16>(img, hd);
237 break;
238 case PixelFormat_Float32:
239 ComputeHistogram_<PixelFormat_Float32> (img, hd);
240 break;
241 case PixelFormat_Grayscale32:
242 ComputeHistogram_<PixelFormat_Grayscale32> (img, hd);
243 break;
244 case PixelFormat_Grayscale64:
245 ComputeHistogram_<PixelFormat_Grayscale64> (img, hd);
246 break;
247 default:
248 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
249 }
250 }
251
252 void ComputeMinMax(const Orthanc::ImageAccessor& img,
253 double& minValue, double& maxValue)
254 {
255 using namespace Orthanc;
256
257 // dynamic/static bridge
258 switch (img.GetFormat())
259 {
260 case PixelFormat_Grayscale8:
261 ComputeMinMax_<PixelFormat_Grayscale8> (img, minValue, maxValue);
262 break;
263 case PixelFormat_Grayscale16:
264 ComputeMinMax_<PixelFormat_Grayscale16> (img, minValue, maxValue);
265 break;
266 case PixelFormat_SignedGrayscale16:
267 ComputeMinMax_<PixelFormat_SignedGrayscale16>(img, minValue, maxValue);
268 break;
269 case PixelFormat_Float32:
270 ComputeMinMax_<PixelFormat_Float32> (img, minValue, maxValue);
271 break;
272 case PixelFormat_Grayscale32:
273 ComputeMinMax_<PixelFormat_Grayscale32> (img, minValue, maxValue);
274 break;
275 case PixelFormat_Grayscale64:
276 ComputeMinMax_<PixelFormat_Grayscale64> (img, minValue, maxValue);
277 break;
278 default:
279 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
280 }
281
282 }
283
284 void DumpHistogramResult(std::string& s, const HistogramData& hd)
285 {
286 std::stringstream ss;
287 ss << "Histogram:\n";
288 ss << "==========\n";
289 ss << "\n";
290 ss << "minValue : " << hd.minValue << "\n";
291 ss << "binSize : " << hd.binSize << "\n";
292 ss << "bins.size() : " << hd.bins.size() << "\n";
293 ss << "bins :\n";
294 double curBinStart = hd.minValue;
295 size_t pixCount = 0;
296 for (size_t i = 0; i < hd.bins.size(); ++i)
297 {
298 ss << "index: " << i << " (from " << curBinStart << " to "
299 << curBinStart + hd.binSize << ") : " << hd.bins[i] << " pixels\n";
300 curBinStart += hd.binSize;
301 pixCount += hd.bins[i];
302 }
303 ss << "total pix. count: " << pixCount << "\n";
304 s = ss.str();
305 }
306
307
308 bool ImageToolbox::IsDecodingSupported(Orthanc::DicomTransferSyntax& transferSyntax)
309 {
310 switch (transferSyntax)
311 {
312 case Orthanc::DicomTransferSyntax_LittleEndianImplicit:
313 case Orthanc::DicomTransferSyntax_LittleEndianExplicit:
314 case Orthanc::DicomTransferSyntax_DeflatedLittleEndianExplicit:
315 case Orthanc::DicomTransferSyntax_BigEndianExplicit:
316 case Orthanc::DicomTransferSyntax_RLELossless:
317 return true;
318
319 #if (ORTHANC_ENABLE_DCMTK == 1) && (ORTHANC_ENABLE_DCMTK_JPEG == 1)
320 case Orthanc::DicomTransferSyntax_JPEGProcess1:
321 case Orthanc::DicomTransferSyntax_JPEGProcess2_4:
322 case Orthanc::DicomTransferSyntax_JPEGProcess14:
323 case Orthanc::DicomTransferSyntax_JPEGProcess14SV1:
324 return true;
325 #endif
326
327 #if (ORTHANC_ENABLE_DCMTK == 1) && (ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1)
328 case Orthanc::DicomTransferSyntax_JPEGLSLossless:
329 case Orthanc::DicomTransferSyntax_JPEGLSLossy:
330 return true;
331 #endif
332
333 default:
334 return false;
335 }
336 }
337 }