Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
vtkMitkGPUVolumeRayCastMapper.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 /*=========================================================================
13 
14  Program: Visualization Toolkit
15  Module: $RCSfile: vtkMitkGPUVolumeRayCastMapper.cxx,v $
16 
17  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
18  All rights reserved.
19  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
20 
21  This software is distributed WITHOUT ANY WARRANTY; without even
22  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
23  PURPOSE. See the above copyright notice for more information.
24 
25 =========================================================================*/
26 
28 #include "vtkCamera.h"
29 #include "vtkCellData.h"
30 #include "vtkCommand.h" // for VolumeMapperRender{Start|End|Progress}Event
31 #include "vtkDataArray.h"
32 #include "vtkGPUInfo.h"
33 #include "vtkGPUInfoList.h"
34 #include "vtkImageData.h"
35 #include "vtkImageResample.h"
36 #include "vtkMultiThreader.h"
37 #include "vtkPointData.h"
38 #include "vtkRenderWindow.h"
39 #include "vtkRenderer.h"
40 #include "vtkRendererCollection.h"
41 #include "vtkTimerLog.h"
42 #include "vtkVolume.h"
43 #include "vtkVolumeProperty.h"
44 #include <cassert>
45 
46 vtkCxxSetObjectMacro(vtkMitkGPUVolumeRayCastMapper, MaskInput, vtkImageData);
47 vtkCxxSetObjectMacro(vtkMitkGPUVolumeRayCastMapper, TransformedInput, vtkImageData);
48 
50 {
51  this->AutoAdjustSampleDistances = 1;
52  this->ImageSampleDistance = 1.0;
53  this->MinimumImageSampleDistance = 1.0;
54  this->MaximumImageSampleDistance = 10.0;
55  this->SampleDistance = 1.0;
56  this->SmallVolumeRender = 0;
57  this->BigTimeToDraw = 0.0;
58  this->SmallTimeToDraw = 0.0;
59  this->FinalColorWindow = 1.0;
60  this->FinalColorLevel = 0.5;
61  this->GeneratingCanonicalView = 0;
62  this->CanonicalViewImageData = nullptr;
63 
64  this->MaskInput = nullptr;
65  this->MaskBlendFactor = 1.0f;
66 
67  this->AMRMode = 0;
68  this->ClippedCroppingRegionPlanes[0] = VTK_DOUBLE_MAX;
69  this->ClippedCroppingRegionPlanes[1] = VTK_DOUBLE_MIN;
70  this->ClippedCroppingRegionPlanes[2] = VTK_DOUBLE_MAX;
71  this->ClippedCroppingRegionPlanes[3] = VTK_DOUBLE_MIN;
72  this->ClippedCroppingRegionPlanes[4] = VTK_DOUBLE_MAX;
73  this->ClippedCroppingRegionPlanes[5] = VTK_DOUBLE_MIN;
74 
75  this->MaxMemoryInBytes = 0;
76  vtkGPUInfoList *l = vtkGPUInfoList::New();
77  l->Probe();
78  if (l->GetNumberOfGPUs() > 0)
79  {
80  vtkGPUInfo *info = l->GetGPUInfo(0);
81  this->MaxMemoryInBytes = info->GetDedicatedVideoMemory();
82  if (this->MaxMemoryInBytes == 0)
83  {
84  this->MaxMemoryInBytes = info->GetDedicatedSystemMemory();
85  }
86  // we ignore info->GetSharedSystemMemory(); as this is very slow.
87  }
88  l->Delete();
89 
90  if (this->MaxMemoryInBytes == 0) // use some default value: 128MB.
91  {
92  this->MaxMemoryInBytes = 128 * 1024 * 1024;
93  }
94 
95  this->MaxMemoryFraction = 0.75;
96 
97  this->ReportProgress = true;
98 
99  this->TransformedInput = nullptr;
100  this->LastInput = nullptr;
101 }
102 
103 // ----------------------------------------------------------------------------
105 {
106  this->SetMaskInput(nullptr);
107  this->SetTransformedInput(nullptr);
108  this->LastInput = nullptr;
109 }
110 
111 // ----------------------------------------------------------------------------
112 // The render method that is called from the volume. If this is a canonical
113 // view render, a specialized version of this method will be called instead.
114 // Otherwise we will
115 // - Invoke a start event
116 // - Start timing
117 // - Check that everything is OK for rendering
118 // - Render
119 // - Stop the timer and record results
120 // - Invoke an end event
121 // ----------------------------------------------------------------------------
122 void vtkMitkGPUVolumeRayCastMapper::Render(vtkRenderer *ren, vtkVolume *vol)
123 {
124  // Catch renders that are happening due to a canonical view render and
125  // handle them separately.
126  if (this->GeneratingCanonicalView)
127  {
128  this->CanonicalViewRender(ren, vol);
129  return;
130  }
131 
132  // Invoke a VolumeMapperRenderStartEvent
133  this->InvokeEvent(vtkCommand::VolumeMapperRenderStartEvent, nullptr);
134 
135  // Start the timer to time the length of this render
136  vtkTimerLog *timer = vtkTimerLog::New();
137  timer->StartTimer();
138 
139  // Make sure everything about this render is OK.
140  // This is where the input is updated.
141  if (this->ValidateRender(ren, vol))
142  {
143  // Everything is OK - so go ahead and really do the render
144  this->GPURender(ren, vol);
145  }
146 
147  // Stop the timer
148  timer->StopTimer();
149  double t = timer->GetElapsedTime();
150 
151  // cout << "Render Timer " << t << " seconds, " << 1.0/t << " frames per second" << endl;
152 
153  this->TimeToDraw = t;
154  timer->Delete();
155 
156  if (vol->GetAllocatedRenderTime() < 1.0)
157  {
158  this->SmallTimeToDraw = t;
159  }
160  else
161  {
162  this->BigTimeToDraw = t;
163  }
164 
165  // Invoke a VolumeMapperRenderEndEvent
166  this->InvokeEvent(vtkCommand::VolumeMapperRenderEndEvent, nullptr);
167 }
168 
169 // ----------------------------------------------------------------------------
170 // Special version for rendering a canonical view - we don't do things like
171 // invoke start or end events, and we don't capture the render time.
172 // ----------------------------------------------------------------------------
173 void vtkMitkGPUVolumeRayCastMapper::CanonicalViewRender(vtkRenderer *ren, vtkVolume *vol)
174 {
175  // Make sure everything about this render is OK
176  if (this->ValidateRender(ren, vol))
177  {
178  // Everything is OK - so go ahead and really do the render
179  this->GPURender(ren, vol);
180  }
181 }
182 
183 // ----------------------------------------------------------------------------
184 // This method us used by the render method to validate everything before
185 // attempting to render. This method returns 0 if something is not right -
186 // such as missing input, a null renderer or a null volume, no scalars, etc.
187 // In some cases it will produce a vtkErrorMacro message, and in others
188 // (for example, in the case of cropping planes that define a region with
189 // a volume or 0 or less) it will fail silently. If everything is OK, it will
190 // return with a value of 1.
191 // ----------------------------------------------------------------------------
192 int vtkMitkGPUVolumeRayCastMapper::ValidateRender(vtkRenderer *ren, vtkVolume *vol)
193 {
194  // Check that we have everything we need to render.
195  int goodSoFar = 1;
196 
197  // Check for a renderer - we MUST have one
198  if (!ren)
199  {
200  goodSoFar = 0;
201  vtkErrorMacro("Renderer cannot be null.");
202  }
203 
204  // Check for the volume - we MUST have one
205  if (goodSoFar && !vol)
206  {
207  goodSoFar = 0;
208  vtkErrorMacro("Volume cannot be null.");
209  }
210 
211  // Don't need to check if we have a volume property
212  // since the volume will create one if we don't. Also
213  // don't need to check for the scalar opacity function
214  // or the RGB transfer function since the property will
215  // create them if they do not yet exist.
216 
217  // However we must currently check that the number of
218  // color channels is 3
219  // TODO: lift this restriction - should work with
220  // gray functions as well. Right now turning off test
221  // because otherwise 4 component rendering isn't working.
222  // Will revisit.
223  if (goodSoFar && vol->GetProperty()->GetColorChannels() != 3)
224  {
225  // goodSoFar = 0;
226  // vtkErrorMacro("Must have a color transfer function.");
227  }
228 
229  // Check the cropping planes. If they are invalid, just silently
230  // fail. This will happen when an interactive widget is dragged
231  // such that it defines 0 or negative volume - this can happen
232  // and should just not render the volume.
233  // Check the cropping planes
234  if (goodSoFar && this->Cropping && (this->CroppingRegionPlanes[0] >= this->CroppingRegionPlanes[1] ||
235  this->CroppingRegionPlanes[2] >= this->CroppingRegionPlanes[3] ||
236  this->CroppingRegionPlanes[4] >= this->CroppingRegionPlanes[5]))
237  {
238  // No error message here - we want to be silent
239  goodSoFar = 0;
240  }
241 
242  // Check that we have input data
243  vtkImageData *input = this->GetInput();
244 
245  // If we have a timestamp change or data change then create a new clone.
246  if (input != this->LastInput || input->GetMTime() > this->TransformedInput->GetMTime())
247  {
248  this->LastInput = input;
249 
250  vtkImageData *clone;
251  if (!this->TransformedInput)
252  {
253  clone = vtkImageData::New();
254  this->SetTransformedInput(clone);
255  clone->Delete();
256  }
257  else
258  {
259  clone = this->TransformedInput;
260  }
261 
262  clone->ShallowCopy(input);
263 
264  // @TODO: This is the workaround to deal with GPUVolumeRayCastMapper
265  // not able to handle extents starting from non zero values.
266  // There is not a easy fix in the GPU volume ray cast mapper hence
267  // this fix has been introduced.
268 
269  // Get the current extents.
270  int extents[6], real_extents[6];
271  clone->GetExtent(extents);
272  clone->GetExtent(real_extents);
273 
274  // Get the current origin and spacing.
275  double origin[3], spacing[3];
276  clone->GetOrigin(origin);
277  clone->GetSpacing(spacing);
278 
279  for (int cc = 0; cc < 3; cc++)
280  {
281  // Transform the origin and the extents.
282  origin[cc] = origin[cc] + extents[2 * cc] * spacing[cc];
283  extents[2 * cc + 1] -= extents[2 * cc];
284  extents[2 * cc] -= extents[2 * cc];
285  }
286 
287  clone->SetOrigin(origin);
288  clone->SetExtent(extents);
289  }
290 
291  if (goodSoFar && !this->TransformedInput)
292  {
293  vtkErrorMacro("Input is nullptr but is required");
294  goodSoFar = 0;
295  }
296 
297  // Update the date then make sure we have scalars. Note
298  // that we must have point or cell scalars because field
299  // scalars are not supported.
300  vtkDataArray *scalars = nullptr;
301  if (goodSoFar)
302  {
303  // Here is where we update the input
304  // this->TransformedInput->UpdateInformation(); //VTK6_TODO
305  // this->TransformedInput->SetUpdateExtentToWholeExtent();
306  // this->TransformedInput->Update();
307 
308  // Now make sure we can find scalars
309  scalars = this->GetScalars(
310  this->TransformedInput, this->ScalarMode, this->ArrayAccessMode, this->ArrayId, this->ArrayName, this->CellFlag);
311 
312  // We couldn't find scalars
313  if (!scalars)
314  {
315  vtkErrorMacro("No scalars found on input.");
316  goodSoFar = 0;
317  }
318  // Even if we found scalars, if they are field data scalars that isn't good
319  else if (this->CellFlag == 2)
320  {
321  vtkErrorMacro("Only point or cell scalar support - found field scalars instead.");
322  goodSoFar = 0;
323  }
324  }
325 
326  // Make sure the scalar type is actually supported. This mappers supports
327  // almost all standard scalar types.
328  if (goodSoFar)
329  {
330  switch (scalars->GetDataType())
331  {
332  case VTK_CHAR:
333  vtkErrorMacro(<< "scalar of type VTK_CHAR is not supported "
334  << "because this type is platform dependent. "
335  << "Use VTK_SIGNED_CHAR or VTK_UNSIGNED_CHAR instead.");
336  goodSoFar = 0;
337  break;
338  case VTK_BIT:
339  vtkErrorMacro("scalar of type VTK_BIT is not supported by this mapper.");
340  goodSoFar = 0;
341  break;
342  case VTK_ID_TYPE:
343  vtkErrorMacro("scalar of type VTK_ID_TYPE is not supported by this mapper.");
344  goodSoFar = 0;
345  break;
346  case VTK_STRING:
347  vtkErrorMacro("scalar of type VTK_STRING is not supported by this mapper.");
348  goodSoFar = 0;
349  break;
350  default:
351  // Don't need to do anything here
352  break;
353  }
354  }
355 
356  // Check on the blending type - we support composite and min / max intensity
357  if (goodSoFar)
358  {
359  if (this->BlendMode != vtkVolumeMapper::COMPOSITE_BLEND &&
360  this->BlendMode != vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND &&
361  this->BlendMode != vtkVolumeMapper::MINIMUM_INTENSITY_BLEND)
362  {
363  goodSoFar = 0;
364  vtkErrorMacro(<< "Selected blend mode not supported. "
365  << "Only Composite and MIP and MinIP modes "
366  << "are supported by the current implementation.");
367  }
368  }
369 
370  // This mapper supports 1 component data, or 4 component if it is not independent
371  // component (i.e. the four components define RGBA)
372  int numberOfComponents = 0;
373  if (goodSoFar)
374  {
375  numberOfComponents = scalars->GetNumberOfComponents();
376  if (!(numberOfComponents == 1 || (numberOfComponents == 4 && vol->GetProperty()->GetIndependentComponents() == 0)))
377  {
378  goodSoFar = 0;
379  vtkErrorMacro(<< "Only one component scalars, or four "
380  << "component with non-independent components, "
381  << "are supported by this mapper.");
382  }
383  }
384 
385  // If this is four component data, then it better be unsigned char (RGBA).
386  if (goodSoFar && numberOfComponents == 4 && scalars->GetDataType() != VTK_UNSIGNED_CHAR)
387  {
388  goodSoFar = 0;
389  vtkErrorMacro("Only unsigned char is supported for 4-component scalars!");
390  }
391 
392  // return our status
393  return goodSoFar;
394 }
395 
396 // ----------------------------------------------------------------------------
397 // Description:
398 // Called by the AMR Volume Mapper.
399 // Set the flag that tells if the scalars are on point data (0) or
400 // cell data (1).
402 {
403  this->CellFlag = cellFlag;
404 }
405 
406 // ----------------------------------------------------------------------------
408  vtkVolume *volume,
409  vtkImageData *image,
410  int vtkNotUsed(blend_mode),
411  double viewDirection[3],
412  double viewUp[3])
413 {
414  this->GeneratingCanonicalView = 1;
415  int oldSwap = ren->GetRenderWindow()->GetSwapBuffers();
416  ren->GetRenderWindow()->SwapBuffersOff();
417 
418  int dim[3];
419  image->GetDimensions(dim);
420  int *size = ren->GetRenderWindow()->GetSize();
421 
422  vtkImageData *bigImage = vtkImageData::New();
423  bigImage->SetDimensions(size[0], size[1], 1);
424  bigImage->AllocateScalars(VTK_UNSIGNED_CHAR, 3);
425 
426  this->CanonicalViewImageData = bigImage;
427 
428  double scale[2];
429  scale[0] = dim[0] / static_cast<double>(size[0]);
430  scale[1] = dim[1] / static_cast<double>(size[1]);
431 
432  // Save the visibility flags of the renderers and set all to false except
433  // for the ren.
434  vtkRendererCollection *renderers = ren->GetRenderWindow()->GetRenderers();
435  int numberOfRenderers = renderers->GetNumberOfItems();
436 
437  auto rendererVisibilities = new bool[numberOfRenderers];
438  renderers->InitTraversal();
439  int i = 0;
440  while (i < numberOfRenderers)
441  {
442  vtkRenderer *r = renderers->GetNextItem();
443  rendererVisibilities[i] = r->GetDraw() == 1;
444  if (r != ren)
445  {
446  r->SetDraw(false);
447  }
448  ++i;
449  }
450 
451  // Save the visibility flags of the props and set all to false except
452  // for the volume.
453 
454  vtkPropCollection *props = ren->GetViewProps();
455  int numberOfProps = props->GetNumberOfItems();
456 
457  auto propVisibilities = new bool[numberOfProps];
458  props->InitTraversal();
459  i = 0;
460  while (i < numberOfProps)
461  {
462  vtkProp *p = props->GetNextProp();
463  propVisibilities[i] = p->GetVisibility() == 1;
464  if (p != volume)
465  {
466  p->SetVisibility(false);
467  }
468  ++i;
469  }
470 
471  vtkCamera *savedCamera = ren->GetActiveCamera();
472  savedCamera->Modified();
473  vtkCamera *canonicalViewCamera = vtkCamera::New();
474 
475  // Code from vtkFixedPointVolumeRayCastMapper:
476  double *center = volume->GetCenter();
477  double bounds[6];
478  volume->GetBounds(bounds);
479  double d =
480  sqrt((bounds[1] - bounds[0]) * (bounds[1] - bounds[0]) + (bounds[3] - bounds[2]) * (bounds[3] - bounds[2]) +
481  (bounds[5] - bounds[4]) * (bounds[5] - bounds[4]));
482 
483  // For now use x distance - need to change this
484  d = bounds[1] - bounds[0];
485 
486  // Set up the camera in parallel
487  canonicalViewCamera->SetFocalPoint(center);
488  canonicalViewCamera->ParallelProjectionOn();
489  canonicalViewCamera->SetPosition(
490  center[0] - d * viewDirection[0], center[1] - d * viewDirection[1], center[2] - d * viewDirection[2]);
491  canonicalViewCamera->SetViewUp(viewUp);
492  canonicalViewCamera->SetParallelScale(d / 2);
493 
494  ren->SetActiveCamera(canonicalViewCamera);
495  ren->GetRenderWindow()->Render();
496 
497  ren->SetActiveCamera(savedCamera);
498  canonicalViewCamera->Delete();
499 
500  // Shrink to image to the desired size
501  vtkImageResample *resample = vtkImageResample::New();
502  resample->SetInputData(bigImage);
503  resample->SetAxisMagnificationFactor(0, scale[0]);
504  resample->SetAxisMagnificationFactor(1, scale[1]);
505  resample->SetAxisMagnificationFactor(2, 1);
506  resample->UpdateWholeExtent();
507 
508  // Copy the pixels over
509  image->DeepCopy(resample->GetOutput());
510 
511  bigImage->Delete();
512  resample->Delete();
513 
514  // Restore the visibility flags of the props
515  props->InitTraversal();
516  i = 0;
517  while (i < numberOfProps)
518  {
519  vtkProp *p = props->GetNextProp();
520  p->SetVisibility(propVisibilities[i]);
521  ++i;
522  }
523 
524  delete[] propVisibilities;
525 
526  // Restore the visibility flags of the renderers
527  renderers->InitTraversal();
528  i = 0;
529  while (i < numberOfRenderers)
530  {
531  vtkRenderer *r = renderers->GetNextItem();
532  r->SetDraw(rendererVisibilities[i]);
533  ++i;
534  }
535 
536  delete[] rendererVisibilities;
537 
538  ren->GetRenderWindow()->SetSwapBuffers(oldSwap);
539  this->CanonicalViewImageData = nullptr;
540  this->GeneratingCanonicalView = 0;
541 }
542 
543 // ----------------------------------------------------------------------------
544 // Print method for vtkMitkGPUVolumeRayCastMapper
545 void vtkMitkGPUVolumeRayCastMapper::PrintSelf(ostream &os, vtkIndent indent)
546 {
547  this->Superclass::PrintSelf(os, indent);
548 
549  os << indent << "AutoAdjustSampleDistances: " << this->AutoAdjustSampleDistances << endl;
550  os << indent << "MinimumImageSampleDistance: " << this->MinimumImageSampleDistance << endl;
551  os << indent << "MaximumImageSampleDistance: " << this->MaximumImageSampleDistance << endl;
552  os << indent << "ImageSampleDistance: " << this->ImageSampleDistance << endl;
553  os << indent << "SampleDistance: " << this->SampleDistance << endl;
554  os << indent << "FinalColorWindow: " << this->FinalColorWindow << endl;
555  os << indent << "FinalColorLevel: " << this->FinalColorLevel << endl;
556  os << indent << "MaskInput: " << this->MaskInput << endl;
557  os << indent << "MaskBlendFactor: " << this->MaskBlendFactor << endl;
558  os << indent << "MaxMemoryInBytes: " << this->MaxMemoryInBytes << endl;
559  os << indent << "MaxMemoryFraction: " << this->MaxMemoryFraction << endl;
560  os << indent << "ReportProgress: " << this->ReportProgress << endl;
561 }
562 
563 // ----------------------------------------------------------------------------
564 // Description:
565 // Compute the cropping planes clipped by the bounds of the volume.
566 // The result is put into this->ClippedCroppingRegionPlanes.
567 // NOTE: IT WILL BE MOVED UP TO vtkVolumeMapper after bullet proof usage
568 // in this mapper. Other subclasses will use the ClippedCroppingRegionsPlanes
569 // members instead of CroppingRegionPlanes.
570 // \pre volume_exists: this->GetInput()!=0
571 // \pre valid_cropping: this->Cropping &&
572 // this->CroppingRegionPlanes[0]<this->CroppingRegionPlanes[1] &&
573 // this->CroppingRegionPlanes[2]<this->CroppingRegionPlanes[3] &&
574 // this->CroppingRegionPlanes[4]<this->CroppingRegionPlanes[5])
576 {
577  assert("pre: volume_exists" && this->GetInput() != nullptr);
578  assert("pre: valid_cropping" && this->Cropping && this->CroppingRegionPlanes[0] < this->CroppingRegionPlanes[1] &&
579  this->CroppingRegionPlanes[2] < this->CroppingRegionPlanes[3] &&
580  this->CroppingRegionPlanes[4] < this->CroppingRegionPlanes[5]);
581 
582  // vtkVolumeMapper::Render() will have something like:
583  // if(this->Cropping && (this->CroppingRegionPlanes[0]>=this->CroppingRegionPlanes[1] ||
584  // this->CroppingRegionPlanes[2]>=this->CroppingRegionPlanes[3] ||
585  // this->CroppingRegionPlanes[4]>=this->CroppingRegionPlanes[5]))
586  // {
587  // // silentely stop because the cropping is not valid.
588  // return;
589  // }
590 
591  double volBounds[6];
592  this->GetInput()->GetBounds(volBounds);
593 
594  int i = 0;
595  while (i < 6)
596  {
597  // max of the mins
598  if (this->CroppingRegionPlanes[i] < volBounds[i])
599  {
600  this->ClippedCroppingRegionPlanes[i] = volBounds[i];
601  }
602  else
603  {
604  this->ClippedCroppingRegionPlanes[i] = this->CroppingRegionPlanes[i];
605  }
606  ++i;
607  // min of the maxs
608  if (this->CroppingRegionPlanes[i] > volBounds[i])
609  {
610  this->ClippedCroppingRegionPlanes[i] = volBounds[i];
611  }
612 
613  else
614  {
615  this->ClippedCroppingRegionPlanes[i] = this->CroppingRegionPlanes[i];
616  }
617  ++i;
618  }
619 }
virtual void GPURender(vtkRenderer *, vtkVolume *)
void CanonicalViewRender(vtkRenderer *, vtkVolume *)
static void info(const char *fmt,...)
Definition: svm.cpp:86
void PrintSelf(ostream &os, vtkIndent indent) override
vtkCxxSetObjectMacro(vtkMitkGPUVolumeRayCastMapper, MaskInput, vtkImageData)
static void clone(T *&dst, S *src, int n)
Definition: svm.cpp:59
void Render(vtkRenderer *, vtkVolume *) override
mitk::Image::Pointer image
void CreateCanonicalView(vtkRenderer *ren, vtkVolume *volume, vtkImageData *image, int blend_mode, double viewDirection[3], double viewUp[3])
void SetTransformedInput(vtkImageData *)
void SetMaskInput(vtkImageData *mask)
int ValidateRender(vtkRenderer *, vtkVolume *)