Mercurial > hg > orthanc-stone
annotate Framework/Toolbox/SubvoxelReader.h @ 976:3abc47e051c8
Added tag toa2019083101 for changeset e75fd08d6c75
author | Benjamin Golinvaux <bgo@osimis.io> |
---|---|
date | Sat, 31 Aug 2019 13:50:11 +0200 |
parents | b70e9be013e4 |
children | 2d8ab34c8c91 |
rev | line source |
---|---|
183 | 1 /** |
2 * Stone of Orthanc | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
439 | 5 * Copyright (C) 2017-2019 Osimis S.A., Belgium |
183 | 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 | |
212
5412adf19980
resort to OrthancFramework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
201
diff
changeset
|
27 #include <Core/Images/ImageTraits.h> |
183 | 28 |
29 #include <boost/noncopyable.hpp> | |
30 #include <cmath> | |
31 | |
32 namespace OrthancStone | |
33 { | |
34 namespace Internals | |
35 { | |
36 class SubvoxelReaderBase : public boost::noncopyable | |
37 { | |
38 private: | |
39 const ImageBuffer3D& source_; | |
40 unsigned int width_; | |
41 unsigned int height_; | |
42 unsigned int depth_; | |
43 | |
44 public: | |
45 SubvoxelReaderBase(const ImageBuffer3D& source) : | |
46 source_(source), | |
47 width_(source.GetWidth()), | |
48 height_(source.GetHeight()), | |
49 depth_(source.GetDepth()) | |
50 { | |
51 } | |
52 | |
53 ORTHANC_FORCE_INLINE | |
54 const Orthanc::ImageAccessor& GetSource() const | |
55 { | |
56 return source_.GetInternalImage(); | |
57 } | |
58 | |
59 ORTHANC_FORCE_INLINE | |
60 unsigned int GetWidth() const | |
61 { | |
62 return width_; | |
63 } | |
64 | |
65 ORTHANC_FORCE_INLINE | |
66 unsigned int GetHeight() const | |
67 { | |
68 return height_; | |
69 } | |
70 | |
71 ORTHANC_FORCE_INLINE | |
72 unsigned int GetDepth() const | |
73 { | |
74 return depth_; | |
75 } | |
76 | |
77 ORTHANC_FORCE_INLINE | |
78 unsigned int ComputeRow(unsigned int y, | |
79 unsigned int z) const | |
80 { | |
81 return z * height_ + y; | |
82 } | |
83 }; | |
84 } | |
85 | |
86 | |
87 template <Orthanc::PixelFormat Format, | |
88 ImageInterpolation Interpolation> | |
89 class SubvoxelReader; | |
90 | |
91 | |
92 template <Orthanc::PixelFormat Format> | |
93 class SubvoxelReader<Format, ImageInterpolation_Nearest> : | |
94 public Internals::SubvoxelReaderBase | |
95 { | |
96 public: | |
97 typedef Orthanc::PixelTraits<Format> Traits; | |
98 typedef typename Traits::PixelType PixelType; | |
99 | |
100 SubvoxelReader(const ImageBuffer3D& source) : | |
101 SubvoxelReaderBase(source) | |
102 { | |
103 } | |
104 | |
105 inline bool GetValue(PixelType& target, | |
106 float x, | |
107 float y, | |
108 float z) const; | |
109 | |
110 inline bool GetFloatValue(float& target, | |
111 float x, | |
112 float y, | |
113 float z) const; | |
114 }; | |
115 | |
116 | |
117 template <Orthanc::PixelFormat Format> | |
118 class SubvoxelReader<Format, ImageInterpolation_Bilinear> : | |
119 public Internals::SubvoxelReaderBase | |
120 { | |
121 public: | |
122 typedef Orthanc::PixelTraits<Format> Traits; | |
123 typedef typename Traits::PixelType PixelType; | |
124 | |
125 SubvoxelReader(const ImageBuffer3D& source) : | |
126 SubvoxelReaderBase(source) | |
127 { | |
128 } | |
129 | |
130 inline bool Sample(float& f00, | |
131 float& f01, | |
132 float& f10, | |
133 float& f11, | |
134 unsigned int ux, | |
135 unsigned int uy, | |
136 unsigned int uz) const; | |
137 | |
138 inline bool GetValue(PixelType& target, | |
139 float x, | |
140 float y, | |
141 float z) const; | |
142 | |
143 inline bool GetFloatValue(float& target, | |
144 float x, | |
145 float y, | |
146 float z) const; | |
147 }; | |
148 | |
149 | |
150 template <Orthanc::PixelFormat Format> | |
151 class SubvoxelReader<Format, ImageInterpolation_Trilinear> : | |
152 public Internals::SubvoxelReaderBase | |
153 { | |
154 private: | |
155 SubvoxelReader<Format, ImageInterpolation_Bilinear> bilinear_; | |
156 | |
157 public: | |
158 typedef Orthanc::PixelTraits<Format> Traits; | |
159 typedef typename Traits::PixelType PixelType; | |
160 | |
161 SubvoxelReader(const ImageBuffer3D& source) : | |
162 SubvoxelReaderBase(source), | |
163 bilinear_(source) | |
164 { | |
165 } | |
166 | |
167 inline bool GetValue(PixelType& target, | |
168 float x, | |
169 float y, | |
170 float z) const; | |
171 | |
172 inline bool GetFloatValue(float& target, | |
173 float x, | |
174 float y, | |
175 float z) const; | |
176 }; | |
177 | |
178 | |
179 | |
180 template <Orthanc::PixelFormat Format> | |
181 bool SubvoxelReader<Format, ImageInterpolation_Nearest>::GetValue(PixelType& target, | |
182 float x, | |
183 float y, | |
184 float z) const | |
185 { | |
186 if (x < 0 || | |
187 y < 0 || | |
188 z < 0) | |
189 { | |
190 return false; | |
191 } | |
192 else | |
193 { | |
194 unsigned int ux = static_cast<unsigned int>(std::floor(x)); | |
195 unsigned int uy = static_cast<unsigned int>(std::floor(y)); | |
196 unsigned int uz = static_cast<unsigned int>(std::floor(z)); | |
197 | |
198 if (ux < GetWidth() && | |
199 uy < GetHeight() && | |
200 uz < GetDepth()) | |
201 { | |
202 Orthanc::ImageTraits<Format>::GetPixel(target, GetSource(), ux, ComputeRow(uy, uz)); | |
203 return true; | |
204 } | |
205 else | |
206 { | |
207 return false; | |
208 } | |
209 } | |
210 } | |
211 | |
212 | |
213 template <Orthanc::PixelFormat Format> | |
214 bool SubvoxelReader<Format, ImageInterpolation_Nearest>::GetFloatValue(float& target, | |
215 float x, | |
216 float y, | |
217 float z) const | |
218 { | |
219 PixelType value; | |
220 | |
221 if (GetValue(value, x, y, z)) | |
222 { | |
223 target = Traits::PixelToFloat(value); | |
224 return true; | |
225 } | |
226 else | |
227 { | |
228 return false; | |
229 } | |
230 } | |
231 | |
232 | |
233 | |
234 template <Orthanc::PixelFormat Format> | |
235 bool SubvoxelReader<Format, ImageInterpolation_Bilinear>::Sample(float& f00, | |
236 float& f01, | |
237 float& f10, | |
238 float& f11, | |
239 unsigned int ux, | |
240 unsigned int uy, | |
241 unsigned int uz) const | |
242 { | |
243 if (ux < GetWidth() && | |
244 uy < GetHeight() && | |
245 uz < GetDepth()) | |
246 { | |
247 f00 = Orthanc::ImageTraits<Format>::GetFloatPixel(GetSource(), ux, ComputeRow(uy, uz)); | |
248 } | |
249 else | |
250 { | |
251 // Pixel is out of the volume | |
252 return false; | |
253 } | |
254 | |
255 if (ux + 1 < GetWidth()) | |
256 { | |
257 f01 = Orthanc::ImageTraits<Format>::GetFloatPixel(GetSource(), ux + 1, ComputeRow(uy, uz)); | |
258 } | |
259 else | |
260 { | |
261 f01 = f00; | |
262 } | |
263 | |
264 if (uy + 1 < GetHeight()) | |
265 { | |
266 f10 = Orthanc::ImageTraits<Format>::GetFloatPixel(GetSource(), ux, ComputeRow(uy + 1, uz)); | |
267 } | |
268 else | |
269 { | |
270 f10 = f00; | |
271 } | |
272 | |
273 if (ux + 1 < GetWidth() && | |
274 uy + 1 < GetHeight()) | |
275 { | |
276 f11 = Orthanc::ImageTraits<Format>::GetFloatPixel(GetSource(), ux + 1, ComputeRow(uy + 1, uz)); | |
277 } | |
278 else | |
279 { | |
280 f11 = f00; | |
281 } | |
282 | |
283 return true; | |
284 } | |
285 | |
286 | |
287 | |
288 template <Orthanc::PixelFormat Format> | |
289 bool SubvoxelReader<Format, ImageInterpolation_Bilinear>::GetFloatValue(float& target, | |
290 float x, | |
291 float y, | |
292 float z) const | |
293 { | |
294 x -= 0.5f; | |
295 y -= 0.5f; | |
296 | |
297 if (x < 0 || | |
298 y < 0 || | |
299 z < 0) | |
300 { | |
301 return false; | |
302 } | |
303 else | |
304 { | |
305 unsigned int ux = static_cast<unsigned int>(std::floor(x)); | |
306 unsigned int uy = static_cast<unsigned int>(std::floor(y)); | |
307 unsigned int uz = static_cast<unsigned int>(std::floor(z)); | |
308 | |
309 float f00, f01, f10, f11; | |
310 if (Sample(f00, f01, f10, f11, ux, uy, uz)) | |
311 { | |
312 float ax = x - static_cast<float>(ux); | |
313 float ay = y - static_cast<float>(uy); | |
314 | |
315 target = GeometryToolbox::ComputeBilinearInterpolationUnitSquare(ax, ay, f00, f01, f10, f11); | |
316 return true; | |
317 } | |
318 else | |
319 { | |
320 return false; | |
321 } | |
322 } | |
323 } | |
324 | |
325 | |
326 | |
327 template <Orthanc::PixelFormat Format> | |
328 bool SubvoxelReader<Format, ImageInterpolation_Bilinear>::GetValue(PixelType& target, | |
329 float x, | |
330 float y, | |
331 float z) const | |
332 { | |
333 float value; | |
334 | |
335 if (GetFloatValue(value, x, y, z)) | |
336 { | |
337 Traits::FloatToPixel(target, value); | |
338 return true; | |
339 } | |
340 else | |
341 { | |
342 return false; | |
343 } | |
344 } | |
345 | |
346 | |
347 | |
348 template <Orthanc::PixelFormat Format> | |
349 bool SubvoxelReader<Format, ImageInterpolation_Trilinear>::GetFloatValue(float& target, | |
350 float x, | |
351 float y, | |
352 float z) const | |
353 { | |
354 x -= 0.5f; | |
355 y -= 0.5f; | |
356 z -= 0.5f; | |
357 | |
358 if (x < 0 || | |
359 y < 0 || | |
360 z < 0) | |
361 { | |
362 return false; | |
363 } | |
364 else | |
365 { | |
366 unsigned int ux = static_cast<unsigned int>(std::floor(x)); | |
367 unsigned int uy = static_cast<unsigned int>(std::floor(y)); | |
368 unsigned int uz = static_cast<unsigned int>(std::floor(z)); | |
369 | |
370 float f000, f001, f010, f011; | |
371 if (bilinear_.Sample(f000, f001, f010, f011, ux, uy, uz)) | |
372 { | |
373 const float ax = x - static_cast<float>(ux); | |
374 const float ay = y - static_cast<float>(uy); | |
375 | |
376 float f100, f101, f110, f111; | |
377 | |
378 if (bilinear_.Sample(f100, f101, f110, f111, ux, uy, uz + 1)) | |
379 { | |
380 const float az = z - static_cast<float>(uz); | |
381 target = GeometryToolbox::ComputeTrilinearInterpolationUnitSquare | |
382 (ax, ay, az, f000, f001, f010, f011, f100, f101, f110, f111); | |
383 } | |
384 else | |
385 { | |
386 target = GeometryToolbox::ComputeBilinearInterpolationUnitSquare | |
387 (ax, ay, f000, f001, f010, f011); | |
388 } | |
389 | |
390 return true; | |
391 } | |
392 else | |
393 { | |
394 return false; | |
395 } | |
396 } | |
397 } | |
398 | |
399 | |
400 | |
401 template <Orthanc::PixelFormat Format> | |
402 bool SubvoxelReader<Format, ImageInterpolation_Trilinear>::GetValue(PixelType& target, | |
403 float x, | |
404 float y, | |
405 float z) const | |
406 { | |
407 float value; | |
408 | |
409 if (GetFloatValue(value, x, y, z)) | |
410 { | |
411 Traits::FloatToPixel(target, value); | |
412 return true; | |
413 } | |
414 else | |
415 { | |
416 return false; | |
417 } | |
418 } | |
419 } |