comparison Framework/Volumes/VolumeReslicer.cpp @ 183:98da3a8d4820 wasm

SubvoxelReader
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 15 Mar 2018 15:19:24 +0100
parents 4da803580da9
children 9523ce4f44cc
comparison
equal deleted inserted replaced
182:2cbfb08f3a95 183:98da3a8d4820
1 #include "VolumeReslicer.h" 1 #include "VolumeReslicer.h"
2 2
3 #include "../Toolbox/GeometryToolbox.h" 3 #include "../Toolbox/GeometryToolbox.h"
4 #include "../Toolbox/SubvoxelReader.h"
4 5
5 #include <Core/Images/ImageTraits.h> 6 #include <Core/Images/ImageTraits.h>
6 #include <Core/Logging.h> 7 #include <Core/Logging.h>
7 #include <Core/OrthancException.h> 8 #include <Core/OrthancException.h>
8 9
110 ORTHANC_FORCE_INLINE 111 ORTHANC_FORCE_INLINE
111 void SetValue(OutputPixelType* pixel, 112 void SetValue(OutputPixelType* pixel,
112 const InputPixelType& value) const 113 const InputPixelType& value) const
113 { 114 {
114 SetValueInternal<InputPixelType>(pixel, value); 115 SetValueInternal<InputPixelType>(pixel, value);
115 }
116 };
117
118
119
120 class VoxelReaderBase : public boost::noncopyable
121 {
122 private:
123 const Orthanc::ImageAccessor& image_;
124 unsigned int width_;
125 unsigned int height_;
126 unsigned int depth_;
127 float widthFloat_;
128 float heightFloat_;
129 float depthFloat_;
130
131 public:
132 VoxelReaderBase(const ImageBuffer3D& image) :
133 image_(image.GetInternalImage()),
134 width_(image.GetWidth()),
135 height_(image.GetHeight()),
136 depth_(image.GetDepth()),
137 widthFloat_(static_cast<float>(image.GetWidth())),
138 heightFloat_(static_cast<float>(image.GetHeight())),
139 depthFloat_(static_cast<float>(image.GetDepth()))
140 {
141 }
142
143 const Orthanc::ImageAccessor& GetImage() const
144 {
145 return image_;
146 }
147
148 const unsigned int GetImageWidth() const
149 {
150 return width_;
151 }
152
153 const unsigned int GetImageHeight() const
154 {
155 return height_;
156 }
157
158 const unsigned int GetImageDepth() const
159 {
160 return depth_;
161 }
162
163 bool GetNearestCoordinates(unsigned int& imageX,
164 unsigned int& imageY,
165 unsigned int& imageZ,
166 float& fractionalX,
167 float& fractionalY,
168 float& fractionalZ,
169 float volumeX,
170 float volumeY,
171 float volumeZ) const
172 {
173 if (volumeX >= 0 &&
174 volumeY >= 0 &&
175 volumeZ >= 0)
176 {
177 const float x = volumeX * widthFloat_;
178 const float y = volumeY * heightFloat_;
179 const float z = volumeZ * depthFloat_;
180
181 imageX = static_cast<unsigned int>(std::floor(x));
182 imageY = static_cast<unsigned int>(std::floor(y));
183 imageZ = static_cast<unsigned int>(std::floor(z));
184
185 if (imageX < width_ &&
186 imageY < height_ &&
187 imageZ < depth_)
188 {
189 fractionalX = x - static_cast<float>(imageX);
190 fractionalY = y - static_cast<float>(imageY);
191 fractionalZ = z - static_cast<float>(imageZ);
192 return true;
193 }
194 else
195 {
196 return false;
197 }
198 }
199 else
200 {
201 return false;
202 }
203 }
204 };
205
206
207 template <Orthanc::PixelFormat InputFormat,
208 ImageInterpolation Interpolation>
209 class VoxelReader;
210
211
212 template <Orthanc::PixelFormat InputFormat>
213 class VoxelReader<InputFormat, ImageInterpolation_Nearest> :
214 public VoxelReaderBase
215 {
216 public:
217 typedef typename Orthanc::PixelTraits<InputFormat>::PixelType InputPixelType;
218
219 VoxelReader(const ImageBuffer3D& image) :
220 VoxelReaderBase(image)
221 {
222 }
223
224 ORTHANC_FORCE_INLINE
225 float GetFloatValue(float volumeX,
226 float volumeY,
227 float volumeZ) const
228 {
229 InputPixelType value;
230 GetValue(value, volumeX, volumeY, volumeZ);
231 return static_cast<float>(value);
232 }
233
234 ORTHANC_FORCE_INLINE
235 void GetValue(InputPixelType& target,
236 float volumeX,
237 float volumeY,
238 float volumeZ) const
239 {
240 unsigned int imageX, imageY, imageZ;
241 float fractionalX, fractionalY, fractionalZ; // unused
242
243 if (GetNearestCoordinates(imageX, imageY, imageZ,
244 fractionalX, fractionalY, fractionalZ,
245 volumeX, volumeY, volumeZ))
246 {
247 Orthanc::ImageTraits<InputFormat>::GetPixel(target, GetImage(), imageX,
248 imageY + imageZ * GetImageHeight());
249 }
250 else
251 {
252 target = std::numeric_limits<InputPixelType>::min();
253 }
254 }
255 };
256
257
258 template <Orthanc::PixelFormat InputFormat>
259 class VoxelReader<InputFormat, ImageInterpolation_Bilinear> :
260 public VoxelReaderBase
261 {
262 private:
263 float outOfVolume_;
264
265 public:
266 VoxelReader(const ImageBuffer3D& image) :
267 VoxelReaderBase(image)
268 {
269 typedef typename Orthanc::PixelTraits<InputFormat>::PixelType Pixel;
270 outOfVolume_ = static_cast<float>(std::numeric_limits<Pixel>::min());
271 }
272
273 void SampleVoxels(float& f00,
274 float& f01,
275 float& f10,
276 float& f11,
277 unsigned int imageX,
278 unsigned int imageY,
279 unsigned int imageZ) const
280 {
281 f00 = Orthanc::ImageTraits<InputFormat>::GetFloatPixel
282 (GetImage(), imageX, imageY + imageZ * GetImageHeight());
283
284 if (imageX + 1 < GetImageWidth())
285 {
286 f01 = Orthanc::ImageTraits<InputFormat>::GetFloatPixel
287 (GetImage(), imageX + 1, imageY + imageZ * GetImageHeight());
288 }
289 else
290 {
291 f01 = f00;
292 }
293
294 if (imageY + 1 < GetImageWidth())
295 {
296 f10 = Orthanc::ImageTraits<InputFormat>::GetFloatPixel
297 (GetImage(), imageX, imageY + 1 + imageZ * GetImageHeight());
298 }
299 else
300 {
301 f10 = f00;
302 }
303
304 if (imageX + 1 < GetImageWidth() &&
305 imageY + 1 < GetImageHeight())
306 {
307 f11 = Orthanc::ImageTraits<InputFormat>::GetFloatPixel
308 (GetImage(), imageX + 1, imageY + 1 + imageZ * GetImageHeight());
309 }
310 else
311 {
312 f11 = f00;
313 }
314 }
315
316 float GetOutOfVolume() const
317 {
318 return outOfVolume_;
319 }
320
321 float GetFloatValue(float volumeX,
322 float volumeY,
323 float volumeZ) const
324 {
325 unsigned int imageX, imageY, imageZ;
326 float fractionalX, fractionalY, fractionalZ;
327
328 if (GetNearestCoordinates(imageX, imageY, imageZ,
329 fractionalX, fractionalY, fractionalZ,
330 volumeX, volumeY, volumeZ))
331 {
332 float f00, f01, f10, f11;
333 SampleVoxels(f00, f01, f10, f11, imageX, imageY, imageZ);
334 return GeometryToolbox::ComputeBilinearInterpolationUnitSquare
335 (fractionalX, fractionalY, f00, f01, f10, f11);
336 }
337 else
338 {
339 return outOfVolume_;
340 }
341 }
342 };
343
344
345 template <Orthanc::PixelFormat InputFormat>
346 class VoxelReader<InputFormat, ImageInterpolation_Trilinear> :
347 public VoxelReaderBase
348 {
349 private:
350 typedef VoxelReader<InputFormat, ImageInterpolation_Bilinear> Bilinear;
351
352 Bilinear bilinear_;
353 unsigned int imageDepth_;
354
355 public:
356 VoxelReader(const ImageBuffer3D& image) :
357 VoxelReaderBase(image),
358 bilinear_(image),
359 imageDepth_(image.GetDepth())
360 {
361 }
362
363 float GetFloatValue(float volumeX,
364 float volumeY,
365 float volumeZ) const
366 {
367 unsigned int imageX, imageY, imageZ;
368 float fractionalX, fractionalY, fractionalZ;
369
370 if (GetNearestCoordinates(imageX, imageY, imageZ,
371 fractionalX, fractionalY, fractionalZ,
372 volumeX, volumeY, volumeZ))
373 {
374 float f000, f001, f010, f011;
375 bilinear_.SampleVoxels(f000, f001, f010, f011, imageX, imageY, imageZ);
376
377 if (imageZ + 1 < imageDepth_)
378 {
379 float f100, f101, f110, f111;
380 bilinear_.SampleVoxels(f100, f101, f110, f111, imageX, imageY, imageZ + 1);
381 return GeometryToolbox::ComputeTrilinearInterpolationUnitSquare
382 (fractionalX, fractionalY, fractionalZ,
383 f000, f001, f010, f011, f100, f101, f110, f111);
384 }
385 else
386 {
387 return GeometryToolbox::ComputeBilinearInterpolationUnitSquare
388 (fractionalX, fractionalY, f000, f001, f010, f011);
389 }
390 }
391 else
392 {
393 return bilinear_.GetOutOfVolume();
394 }
395 } 116 }
396 }; 117 };
397 118
398 119
399 template <typename VoxelReader, 120 template <typename VoxelReader,
422 void Apply(typename PixelWriter::OutputPixelType* pixel, 143 void Apply(typename PixelWriter::OutputPixelType* pixel,
423 float volumeX, 144 float volumeX,
424 float volumeY, 145 float volumeY,
425 float volumeZ) 146 float volumeZ)
426 { 147 {
427 typename VoxelReader::InputPixelType image; 148 typename VoxelReader::PixelType value;
428 reader_.GetValue(image, volumeX, volumeY, volumeZ); 149
429 writer_.SetValue(pixel, image); 150 if (!reader_.GetValue(value, volumeX, volumeY, volumeZ))
151 {
152 VoxelReader::Traits::SetMinValue(value);
153 }
154
155 writer_.SetValue(pixel, value);
430 } 156 }
431 }; 157 };
432 158
433 159
434 template <typename VoxelReader, 160 template <typename VoxelReader,
436 class PixelShader<VoxelReader, PixelWriter, TransferFunction_Float> 162 class PixelShader<VoxelReader, PixelWriter, TransferFunction_Float>
437 { 163 {
438 private: 164 private:
439 VoxelReader reader_; 165 VoxelReader reader_;
440 PixelWriter writer_; 166 PixelWriter writer_;
167 float outOfVolume_;
441 168
442 public: 169 public:
443 PixelShader(const ImageBuffer3D& image, 170 PixelShader(const ImageBuffer3D& image,
444 float /* scaling */, 171 float /* scaling */,
445 float /* offset */) : 172 float /* offset */) :
446 reader_(image) 173 reader_(image),
174 outOfVolume_(static_cast<float>(std::numeric_limits<typename VoxelReader::PixelType>::min()))
447 { 175 {
448 } 176 }
449 177
450 ORTHANC_FORCE_INLINE 178 ORTHANC_FORCE_INLINE
451 void Apply(typename PixelWriter::OutputPixelType* pixel, 179 void Apply(typename PixelWriter::OutputPixelType* pixel,
452 float volumeX, 180 float volumeX,
453 float volumeY, 181 float volumeY,
454 float volumeZ) 182 float volumeZ)
455 { 183 {
456 writer_.SetFloatValue(pixel, reader_.GetFloatValue(volumeX, volumeY, volumeZ)); 184 float value;
457 } 185
186 if (!reader_.GetFloatValue(value, volumeX, volumeY, volumeZ))
187 {
188 value = outOfVolume_;
189 }
190
191 writer_.SetFloatValue(pixel, value);
192 }
458 }; 193 };
459 194
460 195
461 template <typename VoxelReader, 196 template <typename VoxelReader,
462 typename PixelWriter> 197 typename PixelWriter>
465 private: 200 private:
466 VoxelReader reader_; 201 VoxelReader reader_;
467 PixelWriter writer_; 202 PixelWriter writer_;
468 float scaling_; 203 float scaling_;
469 float offset_; 204 float offset_;
205 float outOfVolume_;
470 206
471 public: 207 public:
472 PixelShader(const ImageBuffer3D& image, 208 PixelShader(const ImageBuffer3D& image,
473 float scaling, 209 float scaling,
474 float offset) : 210 float offset) :
475 reader_(image), 211 reader_(image),
476 scaling_(scaling), 212 scaling_(scaling),
477 offset_(offset) 213 offset_(offset),
214 outOfVolume_(static_cast<float>(std::numeric_limits<typename VoxelReader::PixelType>::min()))
478 { 215 {
479 } 216 }
480 217
481 ORTHANC_FORCE_INLINE 218 ORTHANC_FORCE_INLINE
482 void Apply(typename PixelWriter::OutputPixelType* pixel, 219 void Apply(typename PixelWriter::OutputPixelType* pixel,
483 float volumeX, 220 float volumeX,
484 float volumeY, 221 float volumeY,
485 float volumeZ) 222 float volumeZ)
486 { 223 {
487 writer_.SetFloatValue(pixel, scaling_ * reader_.GetFloatValue(volumeX, volumeY, volumeZ) + offset_); 224 float value;
225
226 if (reader_.GetFloatValue(value, volumeX, volumeY, volumeZ))
227 {
228 value = scaling_ * value + offset_;
229 }
230 else
231 {
232 value = outOfVolume_;
233 }
234
235 writer_.SetFloatValue(pixel, value);
488 } 236 }
489 }; 237 };
490 238
491 239
492 240
614 const CoordinateSystem3D& plane, 362 const CoordinateSystem3D& plane,
615 const OrientedBoundingBox& box, 363 const OrientedBoundingBox& box,
616 float scaling, 364 float scaling,
617 float offset) 365 float offset)
618 { 366 {
619 typedef VoxelReader<InputFormat, Interpolation> Reader; 367 typedef SubvoxelReader<InputFormat, Interpolation> Reader;
620 typedef PixelWriter<InputFormat, OutputFormat> Writer; 368 typedef PixelWriter<InputFormat, OutputFormat> Writer;
621 typedef PixelShader<Reader, Writer, Function> Shader; 369 typedef PixelShader<Reader, Writer, Function> Shader;
622 370
623 const unsigned int outputWidth = slice.GetWidth(); 371 const unsigned int outputWidth = slice.GetWidth();
624 const unsigned int outputHeight = slice.GetHeight(); 372 const unsigned int outputHeight = slice.GetHeight();
625 373
374 const float sourceWidth = static_cast<float>(source.GetWidth());
375 const float sourceHeight = static_cast<float>(source.GetHeight());
376 const float sourceDepth = static_cast<float>(source.GetDepth());
377
626 Shader shader(source, scaling, offset); 378 Shader shader(source, scaling, offset);
627 379
628 for (unsigned int y = 0; y < outputHeight; y++) 380 for (unsigned int y = 0; y < outputHeight; y++)
629 { 381 {
630 typename Writer::OutputPixelType* p = 382 typename Writer::OutputPixelType* p =
634 386
635 for (unsigned int x = 0; x < outputWidth; x++, p++) 387 for (unsigned int x = 0; x < outputWidth; x++, p++)
636 { 388 {
637 float volumeX, volumeY, volumeZ; 389 float volumeX, volumeY, volumeZ;
638 it.GetVolumeCoordinates(volumeX, volumeY, volumeZ); 390 it.GetVolumeCoordinates(volumeX, volumeY, volumeZ);
639 shader.Apply(p, volumeX, volumeY, volumeZ); 391
392 shader.Apply(p,
393 volumeX * sourceWidth,
394 volumeY * sourceHeight,
395 volumeZ * sourceDepth);
640 it.Next(); 396 it.Next();
641 } 397 }
642 } 398 }
643 } 399 }
644 400