comparison OrthancStone/Sources/Toolbox/SubvoxelReader.h @ 1512:244ad1e4e76a

reorganization of folders
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 07 Jul 2020 16:21:02 +0200
parents Framework/Toolbox/SubvoxelReader.h@7f16987131e1
children 85e117739eca
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
22 #pragma once
23
24 #include "../Volumes/ImageBuffer3D.h"
25 #include "GeometryToolbox.h"
26
27 #include <Images/ImageTraits.h>
28
29 #include <boost/noncopyable.hpp>
30 #include <cmath>
31
32 namespace OrthancStone
33 {
34 namespace Internals
35 {
36 /*
37 WARNING : the slice order is different between this class and ImageBuffer3D
38
39 See the comment above ImageBuffer3D declaration.
40
41 The slices are supposed to be stored in INCREASING z-order in this class!
42 */
43 class SubvoxelReaderBase : public boost::noncopyable
44 {
45 private:
46 const ImageBuffer3D& source_;
47 unsigned int width_;
48 unsigned int height_;
49 unsigned int depth_;
50
51 public:
52 SubvoxelReaderBase(const ImageBuffer3D& source) :
53 source_(source),
54 width_(source.GetWidth()),
55 height_(source.GetHeight()),
56 depth_(source.GetDepth())
57 {
58 }
59
60 ORTHANC_FORCE_INLINE
61 const Orthanc::ImageAccessor& GetSource() const
62 {
63 return source_.GetInternalImage();
64 }
65
66 ORTHANC_FORCE_INLINE
67 unsigned int GetWidth() const
68 {
69 return width_;
70 }
71
72 ORTHANC_FORCE_INLINE
73 unsigned int GetHeight() const
74 {
75 return height_;
76 }
77
78 ORTHANC_FORCE_INLINE
79 unsigned int GetDepth() const
80 {
81 return depth_;
82 }
83
84 ORTHANC_FORCE_INLINE
85 unsigned int ComputeRow(unsigned int y,
86 unsigned int z) const
87 {
88 return z * height_ + y;
89 }
90 };
91 }
92
93
94 /*
95 WARNING : the slice order is different between this class and ImageBuffer3D
96
97 See the comment above ImageBuffer3D declaration.
98
99 The slices are supposed to be stored in INCREASING z-order in this class!
100 */
101 template <Orthanc::PixelFormat Format,
102 ImageInterpolation Interpolation>
103 class SubvoxelReader;
104
105
106 /*
107 WARNING : the slice order is different between this class and ImageBuffer3D
108
109 See the comment above ImageBuffer3D declaration.
110
111 The slices are supposed to be stored in INCREASING z-order in this class!
112 */
113 template <Orthanc::PixelFormat Format>
114 class SubvoxelReader<Format, ImageInterpolation_Nearest> :
115 public Internals::SubvoxelReaderBase
116 {
117 public:
118 typedef Orthanc::PixelTraits<Format> Traits;
119 typedef typename Traits::PixelType PixelType;
120
121 SubvoxelReader(const ImageBuffer3D& source) :
122 SubvoxelReaderBase(source)
123 {
124 }
125
126 inline bool GetValue(PixelType& target,
127 float x,
128 float y,
129 float z) const;
130
131 inline bool GetFloatValue(float& target,
132 float x,
133 float y,
134 float z) const;
135 };
136
137
138 /*
139 WARNING : the slice order is different between this class and ImageBuffer3D
140
141 See the comment above ImageBuffer3D declaration.
142
143 The slices are supposed to be stored in INCREASING z-order in this class!
144 */
145 template <Orthanc::PixelFormat Format>
146 class SubvoxelReader<Format, ImageInterpolation_Bilinear> :
147 public Internals::SubvoxelReaderBase
148 {
149 public:
150 typedef Orthanc::PixelTraits<Format> Traits;
151 typedef typename Traits::PixelType PixelType;
152
153 SubvoxelReader(const ImageBuffer3D& source) :
154 SubvoxelReaderBase(source)
155 {
156 }
157
158 inline bool Sample(float& f00,
159 float& f01,
160 float& f10,
161 float& f11,
162 unsigned int ux,
163 unsigned int uy,
164 unsigned int uz) const;
165
166 inline bool GetValue(PixelType& target,
167 float x,
168 float y,
169 float z) const;
170
171 inline bool GetFloatValue(float& target,
172 float x,
173 float y,
174 float z) const;
175 };
176
177
178 /*
179 WARNING : the slice order is different between this class and ImageBuffer3D
180
181 See the comment above ImageBuffer3D declaration.
182
183 The slices are supposed to be stored in INCREASING z-order in this class!
184 */
185 template <Orthanc::PixelFormat Format>
186 class SubvoxelReader<Format, ImageInterpolation_Trilinear> :
187 public Internals::SubvoxelReaderBase
188 {
189 private:
190 SubvoxelReader<Format, ImageInterpolation_Bilinear> bilinear_;
191
192 public:
193 typedef Orthanc::PixelTraits<Format> Traits;
194 typedef typename Traits::PixelType PixelType;
195
196 SubvoxelReader(const ImageBuffer3D& source) :
197 SubvoxelReaderBase(source),
198 bilinear_(source)
199 {
200 }
201
202 inline bool GetValue(PixelType& target,
203 float x,
204 float y,
205 float z) const;
206
207 inline bool GetFloatValue(float& target,
208 float x,
209 float y,
210 float z) const;
211 };
212
213
214 /*
215 See important comment above
216 */
217
218 template <Orthanc::PixelFormat Format>
219 bool SubvoxelReader<Format, ImageInterpolation_Nearest>::GetValue(PixelType& target,
220 float x,
221 float y,
222 float z) const
223 {
224 if (x < 0 ||
225 y < 0 ||
226 z < 0)
227 {
228 return false;
229 }
230 else
231 {
232 unsigned int ux = static_cast<unsigned int>(std::floor(x));
233 unsigned int uy = static_cast<unsigned int>(std::floor(y));
234 unsigned int uz = static_cast<unsigned int>(std::floor(z));
235
236 if (ux < GetWidth() &&
237 uy < GetHeight() &&
238 uz < GetDepth())
239 {
240 Orthanc::ImageTraits<Format>::GetPixel(target, GetSource(), ux, ComputeRow(uy, uz));
241 return true;
242 }
243 else
244 {
245 return false;
246 }
247 }
248 }
249
250
251 template <Orthanc::PixelFormat Format>
252 bool SubvoxelReader<Format, ImageInterpolation_Nearest>::GetFloatValue(float& target,
253 float x,
254 float y,
255 float z) const
256 {
257 PixelType value;
258
259 if (GetValue(value, x, y, z))
260 {
261 target = Traits::PixelToFloat(value);
262 return true;
263 }
264 else
265 {
266 return false;
267 }
268 }
269
270
271 /*
272 See important comment above
273 */
274
275 template <Orthanc::PixelFormat Format>
276 bool SubvoxelReader<Format, ImageInterpolation_Bilinear>::Sample(float& f00,
277 float& f01,
278 float& f10,
279 float& f11,
280 unsigned int ux,
281 unsigned int uy,
282 unsigned int uz) const
283 {
284 if (ux < GetWidth() &&
285 uy < GetHeight() &&
286 uz < GetDepth())
287 {
288 f00 = Orthanc::ImageTraits<Format>::GetFloatPixel(GetSource(), ux, ComputeRow(uy, uz));
289 }
290 else
291 {
292 // Pixel is out of the volume
293 return false;
294 }
295
296 if (ux + 1 < GetWidth())
297 {
298 f01 = Orthanc::ImageTraits<Format>::GetFloatPixel(GetSource(), ux + 1, ComputeRow(uy, uz));
299 }
300 else
301 {
302 f01 = f00;
303 }
304
305 if (uy + 1 < GetHeight())
306 {
307 f10 = Orthanc::ImageTraits<Format>::GetFloatPixel(GetSource(), ux, ComputeRow(uy + 1, uz));
308 }
309 else
310 {
311 f10 = f00;
312 }
313
314 if (ux + 1 < GetWidth() &&
315 uy + 1 < GetHeight())
316 {
317 f11 = Orthanc::ImageTraits<Format>::GetFloatPixel(GetSource(), ux + 1, ComputeRow(uy + 1, uz));
318 }
319 else
320 {
321 f11 = f00;
322 }
323
324 return true;
325 }
326
327
328 /*
329 See important comment above
330 */
331
332 template <Orthanc::PixelFormat Format>
333 bool SubvoxelReader<Format, ImageInterpolation_Bilinear>::GetFloatValue(float& target,
334 float x,
335 float y,
336 float z) const
337 {
338 x -= 0.5f;
339 y -= 0.5f;
340
341 if (x < 0 ||
342 y < 0 ||
343 z < 0)
344 {
345 return false;
346 }
347 else
348 {
349 unsigned int ux = static_cast<unsigned int>(std::floor(x));
350 unsigned int uy = static_cast<unsigned int>(std::floor(y));
351 unsigned int uz = static_cast<unsigned int>(std::floor(z));
352
353 float f00, f01, f10, f11;
354 if (Sample(f00, f01, f10, f11, ux, uy, uz))
355 {
356 float ax = x - static_cast<float>(ux);
357 float ay = y - static_cast<float>(uy);
358
359 target = GeometryToolbox::ComputeBilinearInterpolationUnitSquare(ax, ay, f00, f01, f10, f11);
360 return true;
361 }
362 else
363 {
364 return false;
365 }
366 }
367 }
368
369
370 /*
371 See important comment above
372 */
373
374 template <Orthanc::PixelFormat Format>
375 bool SubvoxelReader<Format, ImageInterpolation_Bilinear>::GetValue(PixelType& target,
376 float x,
377 float y,
378 float z) const
379 {
380 float value;
381
382 if (GetFloatValue(value, x, y, z))
383 {
384 Traits::FloatToPixel(target, value);
385 return true;
386 }
387 else
388 {
389 return false;
390 }
391 }
392
393
394
395 template <Orthanc::PixelFormat Format>
396 bool SubvoxelReader<Format, ImageInterpolation_Trilinear>::GetFloatValue(float& target,
397 float x,
398 float y,
399 float z) const
400 {
401 x -= 0.5f;
402 y -= 0.5f;
403 z -= 0.5f;
404
405 if (x < 0 ||
406 y < 0 ||
407 z < 0)
408 {
409 return false;
410 }
411 else
412 {
413 unsigned int ux = static_cast<unsigned int>(std::floor(x));
414 unsigned int uy = static_cast<unsigned int>(std::floor(y));
415 unsigned int uz = static_cast<unsigned int>(std::floor(z));
416
417 float f000, f001, f010, f011;
418 if (bilinear_.Sample(f000, f001, f010, f011, ux, uy, uz))
419 {
420 const float ax = x - static_cast<float>(ux);
421 const float ay = y - static_cast<float>(uy);
422
423 float f100, f101, f110, f111;
424
425 if (bilinear_.Sample(f100, f101, f110, f111, ux, uy, uz + 1))
426 {
427 const float az = z - static_cast<float>(uz);
428 target = GeometryToolbox::ComputeTrilinearInterpolationUnitSquare
429 (ax, ay, az, f000, f001, f010, f011, f100, f101, f110, f111);
430 }
431 else
432 {
433 target = GeometryToolbox::ComputeBilinearInterpolationUnitSquare
434 (ax, ay, f000, f001, f010, f011);
435 }
436
437 return true;
438 }
439 else
440 {
441 return false;
442 }
443 }
444 }
445
446
447 /*
448 See important comment above
449 */
450
451
452 template <Orthanc::PixelFormat Format>
453 bool SubvoxelReader<Format, ImageInterpolation_Trilinear>::GetValue(PixelType& target,
454 float x,
455 float y,
456 float z) const
457 {
458 float value;
459
460 if (GetFloatValue(value, x, y, z))
461 {
462 Traits::FloatToPixel(target, value);
463 return true;
464 }
465 else
466 {
467 return false;
468 }
469 }
470 }