comparison Framework/Toolbox/FiniteProjectiveCamera.cpp @ 192:371da7fe2c0e wasm

FiniteProjectiveCamera::ApplyRaytracer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 16 Mar 2018 17:11:11 +0100
parents 964118e7e6de
children e9c7a78a3e77
comparison
equal deleted inserted replaced
191:46cb2eedc2e0 192:371da7fe2c0e
20 20
21 21
22 #include "FiniteProjectiveCamera.h" 22 #include "FiniteProjectiveCamera.h"
23 23
24 #include "GeometryToolbox.h" 24 #include "GeometryToolbox.h"
25 #include "SubpixelReader.h"
25 26
26 #include <Core/Logging.h> 27 #include <Core/Logging.h>
27 #include <Core/OrthancException.h> 28 #include <Core/OrthancException.h>
29 #include <Core/Images/Image.h>
30 #include <Core/Images/ImageProcessing.h>
28 31
29 namespace OrthancStone 32 namespace OrthancStone
30 { 33 {
31 void FiniteProjectiveCamera::ComputeMInverse() 34 void FiniteProjectiveCamera::ComputeMInverse()
32 { 35 {
286 { 289 {
287 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); 290 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
288 } 291 }
289 } 292 }
290 } 293 }
294
295
296 template <Orthanc::PixelFormat TargetFormat,
297 Orthanc::PixelFormat SourceFormat,
298 bool MIP>
299 static void ApplyRaytracerInternal(Orthanc::ImageAccessor& target,
300 const FiniteProjectiveCamera& camera,
301 const ImageBuffer3D& source,
302 VolumeProjection projection)
303 {
304 if (source.GetFormat() != SourceFormat ||
305 target.GetFormat() != TargetFormat ||
306 !std::numeric_limits<float>::is_iec559 ||
307 sizeof(float) != 4)
308 {
309 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
310 }
311
312 LOG(WARNING) << "Input volume size: " << source.GetWidth() << "x"
313 << source.GetHeight() << "x" << source.GetDepth();
314 LOG(WARNING) << "Input pixel format: " << Orthanc::EnumerationToString(source.GetFormat());
315 LOG(WARNING) << "Output image size: " << target.GetWidth() << "x" << target.GetHeight();
316 LOG(WARNING) << "Output pixel format: " << Orthanc::EnumerationToString(target.GetFormat());
317
318 std::auto_ptr<OrthancStone::ParallelSlices> slices(source.GetGeometry(projection));
319 const OrthancStone::Vector pixelSpacing = source.GetVoxelDimensions(projection);
320 const unsigned int targetWidth = target.GetWidth();
321 const unsigned int targetHeight = target.GetHeight();
322
323 Orthanc::Image accumulator(Orthanc::PixelFormat_Float32, targetWidth, targetHeight, false);
324 Orthanc::Image counter(Orthanc::PixelFormat_Grayscale16, targetWidth, targetHeight, false);
325 Orthanc::ImageProcessing::Set(accumulator, 0);
326 Orthanc::ImageProcessing::Set(counter, 0);
327
328 typedef SubpixelReader<SourceFormat, ImageInterpolation_Nearest> SourceReader;
329
330 for (size_t z = 0; z < slices->GetSliceCount(); z++)
331 {
332 LOG(INFO) << "Applying raytracer on slice: " << z << "/" << slices->GetSliceCount();
333
334 const OrthancStone::CoordinateSystem3D& slice = slices->GetSlice(z);
335 OrthancStone::ImageBuffer3D::SliceReader sliceReader(source, projection, z);
336
337 SourceReader pixelReader(sliceReader.GetAccessor());
338
339 for (unsigned int y = 0; y < targetHeight; y++)
340 {
341 float *qacc = reinterpret_cast<float*>(accumulator.GetRow(y));
342 uint16_t *qcount = reinterpret_cast<uint16_t*>(counter.GetRow(y));
343
344 for (unsigned int x = 0; x < targetWidth; x++)
345 {
346 // Backproject the ray originating from the center of the target pixel
347 OrthancStone::Vector direction = camera.GetRayDirection(static_cast<double>(x + 0.5),
348 static_cast<double>(y + 0.5));
349
350 // Compute the 3D intersection of the ray with the slice plane
351 OrthancStone::Vector p;
352 if (slice.IntersectLine(p, camera.GetCenter(), direction))
353 {
354 // Compute the 2D coordinates of the intersections, in slice coordinates
355 double ix, iy;
356 slice.ProjectPoint(ix, iy, p);
357
358 ix /= pixelSpacing[0];
359 iy /= pixelSpacing[1];
360
361 // Read and accumulate the value of the pixel
362 float pixel;
363 if (pixelReader.GetFloatValue(pixel, ix, iy))
364 {
365 if (MIP)
366 {
367 // MIP rendering
368 if (*qcount == 0)
369 {
370 (*qacc) = pixel;
371 (*qcount) = 1;
372 }
373 else if (pixel > *qacc)
374 {
375 (*qacc) = pixel;
376 }
377 }
378 else
379 {
380 // Mean intensity
381 (*qacc) += pixel;
382 (*qcount) ++;
383 }
384 }
385 }
386
387 qacc++;
388 qcount++;
389 }
390 }
391 }
392
393
394 typedef Orthanc::PixelTraits<TargetFormat> TargetTraits;
395
396 // "Flatten" the accumulator image to create the target image
397 for (unsigned int y = 0; y < targetHeight; y++)
398 {
399 const float *qacc = reinterpret_cast<const float*>(accumulator.GetConstRow(y));
400 const uint16_t *qcount = reinterpret_cast<const uint16_t*>(counter.GetConstRow(y));
401 typename TargetTraits::PixelType *p = reinterpret_cast<typename TargetTraits::PixelType*>(target.GetRow(y));
402
403 for (unsigned int x = 0; x < targetWidth; x++)
404 {
405 if (*qcount == 0)
406 {
407 TargetTraits::SetZero(*p);
408 }
409 else
410 {
411 TargetTraits::FloatToPixel(*p, *qacc / static_cast<float>(*qcount));
412 }
413
414 p++;
415 qacc++;
416 qcount++;
417 }
418 }
419 }
420
421
422 Orthanc::ImageAccessor*
423 FiniteProjectiveCamera::ApplyRaytracer(const ImageBuffer3D& source,
424 Orthanc::PixelFormat targetFormat,
425 unsigned int targetWidth,
426 unsigned int targetHeight,
427 bool mip) const
428 {
429 // TODO - We consider the axial projection of the volume, but we
430 // should choose the projection that is the "most perpendicular"
431 // to the line joining the camera center and the principal point
432 const VolumeProjection projection = VolumeProjection_Axial;
433
434 std::auto_ptr<Orthanc::ImageAccessor> target
435 (new Orthanc::Image(targetFormat, targetWidth, targetHeight, false));
436
437 if (targetFormat == Orthanc::PixelFormat_Grayscale16 &&
438 source.GetFormat() == Orthanc::PixelFormat_Grayscale16 && mip)
439 {
440 ApplyRaytracerInternal<Orthanc::PixelFormat_Grayscale16,
441 Orthanc::PixelFormat_Grayscale16, true>
442 (*target, *this, source, projection);
443 }
444 else if (targetFormat == Orthanc::PixelFormat_Grayscale16 &&
445 source.GetFormat() == Orthanc::PixelFormat_Grayscale16 && !mip)
446 {
447 ApplyRaytracerInternal<Orthanc::PixelFormat_Grayscale16,
448 Orthanc::PixelFormat_Grayscale16, false>
449 (*target, *this, source, projection);
450 }
451 else
452 {
453 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
454 }
455
456 return target.release();
457 }
291 } 458 }