Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
vtkMitkThickSlicesFilter.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 
14 
15 #include "vtkDataArray.h"
16 #include "vtkImageData.h"
17 #include "vtkInformation.h"
18 #include "vtkInformationVector.h"
19 #include "vtkObjectFactory.h"
20 #include "vtkPointData.h"
21 #include "vtkStreamingDemandDrivenPipeline.h"
22 
23 #include <cmath>
24 #include <sstream>
25 
27 
28 //----------------------------------------------------------------------------
29 // Construct an instance of vtkMitkThickSlicesFilter filter.
31 {
32  this->HandleBoundaries = 1;
33  this->Dimensionality = 2;
34 
35  this->m_CurrentMode = MIP;
36 
37  // by default process active point scalars
38  this->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS);
39 }
40 
41 //----------------------------------------------------------------------------
42 void vtkMitkThickSlicesFilter::PrintSelf(ostream &os, vtkIndent indent)
43 {
44  this->Superclass::PrintSelf(os, indent);
45  os << indent << "HandleBoundaries: " << this->HandleBoundaries << "\n";
46  os << indent << "Dimensionality: " << this->Dimensionality << "\n";
47 }
48 
49 //----------------------------------------------------------------------------
51  vtkInformationVector **inputVector,
52  vtkInformationVector *outputVector)
53 {
54  // Get input and output pipeline information.
55  vtkInformation *outInfo = outputVector->GetInformationObject(0);
56  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
57 
58  // Get the input whole extent.
59  int extent[6];
60  inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent);
61 
62  // Reduce 3D to 2D output
63  extent[4] = extent[5] = 0;
64 
65  // Store the new whole extent for the output.
66  outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent, 6);
67 
68  /*
69  // Set the number of point data componets to the number of
70  // components in the gradient vector.
71  vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_DOUBLE,
72  this->Dimensionality);
73  */
74  return 1;
75 }
76 
77 //----------------------------------------------------------------------------
78 // This method computes the input extent necessary to generate the output.
80  vtkInformationVector **inputVector,
81  vtkInformationVector *outputVector)
82 {
83  // Get input and output pipeline information.
84  vtkInformation *outInfo = outputVector->GetInformationObject(0);
85  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
86 
87  // Get the input whole extent.
88  int wholeExtent[6];
89  inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), wholeExtent);
90 
91  // Get the requested update extent from the output.
92  int inUExt[6];
93  outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), inUExt);
94 
95  /*inUExt[4] -= 5;
96  inUExt[5] += 5;
97 
98  if (inUExt[4] < wholeExtent[4]) */ inUExt[4] = wholeExtent[4];
99  /*if (inUExt[5] > wholeExtent[5]) */ inUExt[5] = wholeExtent[5];
100 
101  // Store the update extent needed from the intput.
102  inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), inUExt, 6);
103 
104  return 1;
105 }
106 
107 //----------------------------------------------------------------------------
108 // This execute method handles boundaries.
109 // it handles boundaries. Pixels are just replicated to get values
110 // out of extent.
111 template <class T>
113  vtkImageData *inData,
114  T *inPtr,
115  vtkImageData *outData,
116  T *outPtr,
117  int outExt[6],
118  int /*id*/)
119 {
120  int idxX, idxY;
121  int maxX, maxY;
122  vtkIdType inIncX, inIncY, inIncZ;
123  vtkIdType outIncX, outIncY, outIncZ;
124  // int axesNum;
125  int *inExt = inData->GetExtent();
126  int *wholeExtent;
127  vtkIdType *inIncs;
128  // int useYMin, useYMax, useXMin, useXMax;
129 
130  // find the region to loop over
131  maxX = outExt[1] - outExt[0];
132  maxY = outExt[3] - outExt[2];
133 
134  // maxZ = outExt[5] - outExt[4];
135 
136  // Get the dimensionality of the gradient.
137  // axesNum = self->GetDimensionality();
138 
139  // Get increments to march through data
140  inData->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ);
141  outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ);
142  /*
143 // The data spacing is important for computing the gradient.
144 // central differences (2 * ratio).
145 // Negative because below we have (min - max) for dx ...
146 inData->GetSpacing(r);
147 r[0] = -0.5 / r[0];
148 r[1] = -0.5 / r[1];
149 r[2] = -0.5 / r[2];
150  */
151  // get some other info we need
152  inIncs = inData->GetIncrements();
153  wholeExtent = inData->GetExtent();
154 
155  // Move the pointer to the correct starting position.
156  inPtr += (outExt[0] - inExt[0]) * inIncs[0] + (outExt[2] - inExt[2]) * inIncs[1] + (outExt[4] - inExt[4]) * inIncs[2];
157 
158  // Loop through ouput pixels
159 
160  int _minZ = /*-5 + outExt[4]; if( _minZ < wholeExtent[4]) _minZ=*/wholeExtent[4];
161  int _maxZ = /* 5 + outExt[4]; if( _maxZ > wholeExtent[5]) _maxZ=*/wholeExtent[5];
162 
163  if (_maxZ < _minZ)
164  return;
165 
166  double invNum = 1.0 / (_maxZ - _minZ + 1);
167 
168  switch (self->GetThickSliceMode())
169  {
170  default:
172  {
173  // MIP
174  for (idxY = 0; idxY <= maxY; idxY++)
175  {
176  // useYMin = ((idxY + outExt[2]) <= wholeExtent[2]) ? 0 : -inIncs[1];
177  // useYMax = ((idxY + outExt[2]) >= wholeExtent[3]) ? 0 : inIncs[1];
178  for (idxX = 0; idxX <= maxX; idxX++)
179  {
180  // useXMin = ((idxX + outExt[0]) <= wholeExtent[0]) ? 0 : -inIncs[0];
181  // useXMax = ((idxX + outExt[0]) >= wholeExtent[1]) ? 0 : inIncs[0];
182 
183  T mip = inPtr[_minZ * inIncs[2]];
184 
185  for (int z = _minZ + 1; z <= _maxZ; z++)
186  {
187  T value = inPtr[z * inIncs[2]];
188  if (value > mip)
189  mip = value;
190  }
191 
192  // do X axis
193  *outPtr = mip;
194  outPtr++;
195  inPtr++;
196  }
197  outPtr += outIncY;
198  inPtr += inIncY;
199  }
200  }
201  break;
202 
204  {
205  // MIP
206  for (idxY = 0; idxY <= maxY; idxY++)
207  {
208  // useYMin = ((idxY + outExt[2]) <= wholeExtent[2]) ? 0 : -inIncs[1];
209  // useYMax = ((idxY + outExt[2]) >= wholeExtent[3]) ? 0 : inIncs[1];
210  for (idxX = 0; idxX <= maxX; idxX++)
211  {
212  // useXMin = ((idxX + outExt[0]) <= wholeExtent[0]) ? 0 : -inIncs[0];
213  // useXMax = ((idxX + outExt[0]) >= wholeExtent[1]) ? 0 : inIncs[0];
214 
215  double sum = 0;
216 
217  for (int z = _minZ; z <= _maxZ; z++)
218  {
219  T value = inPtr[z * inIncs[2]];
220  sum += value;
221  }
222 
223  // do X axis
224  *outPtr = static_cast<T>(invNum * sum);
225  outPtr++;
226  inPtr++;
227  }
228  outPtr += outIncY;
229  inPtr += inIncY;
230  }
231  }
232  break;
233 
235  {
236  const int size = _maxZ - _minZ;
237  std::vector<double> weights(size);
238  double mean = 0.5 * double(_minZ + _maxZ);
239  double sigma_sq = double(size) / 6.0;
240  sigma_sq *= sigma_sq;
241  double sum = 0;
242  int i = 0;
243  for (int z = _minZ + 1; z <= _maxZ; z++)
244  {
245  double val = exp(-(((double)z - mean) / sigma_sq));
246  weights[i++] = val;
247  sum += val;
248  }
249  for (i = 0; i < size; i++)
250  {
251  weights[i] /= sum;
252  }
253 
254  for (idxY = 0; idxY <= maxY; idxY++)
255  {
256  // useYMin = ((idxY + outExt[2]) <= wholeExtent[2]) ? 0 : -inIncs[1];
257  // useYMax = ((idxY + outExt[2]) >= wholeExtent[3]) ? 0 : inIncs[1];
258  for (idxX = 0; idxX <= maxX; idxX++)
259  {
260  // useXMin = ((idxX + outExt[0]) <= wholeExtent[0]) ? 0 : -inIncs[0];
261  // useXMax = ((idxX + outExt[0]) >= wholeExtent[1]) ? 0 : inIncs[0];
262 
263  T mip = inPtr[_minZ * inIncs[2]];
264  i = 0;
265  double mymip = 0;
266  for (int z = _minZ + 1; z <= _maxZ; z++)
267  {
268  double value = inPtr[z * inIncs[2]];
269  mymip += value * weights[i++];
270  }
271  mip = static_cast<T>(mymip);
272  // do X axis
273  *outPtr = mip;
274  outPtr++;
275  inPtr++;
276  }
277  outPtr += outIncY;
278  inPtr += inIncY;
279  }
280  }
281  break;
282 
284  {
285  for (idxY = 0; idxY <= maxY; idxY++)
286  {
287  for (idxX = 0; idxX <= maxX; idxX++)
288  {
289  T mip = inPtr[_minZ * inIncs[2]];
290 
291  for (int z = _minZ + 1; z <= _maxZ; z++)
292  {
293  T value = inPtr[z * inIncs[2]];
294  if (value < mip)
295  mip = value;
296  }
297 
298  // do X axis
299  *outPtr = mip;
300  outPtr++;
301  inPtr++;
302  }
303  outPtr += outIncY;
304  inPtr += inIncY;
305  }
306  }
307  break;
308 
310  {
311  const int size = _maxZ - _minZ;
312 
313  // MEAN
314  for (idxY = 0; idxY <= maxY; idxY++)
315  {
316  for (idxX = 0; idxX <= maxX; idxX++)
317  {
318  long double sum = 0;
319  for (int z = _minZ; z <= _maxZ; z++)
320  {
321  T value = inPtr[z * inIncs[2]];
322  sum += value;
323  }
324 
325  T mip = static_cast<T>(sum / size);
326 
327  // do X axis
328  *outPtr = mip;
329  outPtr++;
330  inPtr++;
331  }
332  outPtr += outIncY;
333  inPtr += inIncY;
334  }
335  }
336  break;
337  }
338 }
339 
340 int vtkMitkThickSlicesFilter::RequestData(vtkInformation *request,
341  vtkInformationVector **inputVector,
342  vtkInformationVector *outputVector)
343 {
344  if (!this->Superclass::RequestData(request, inputVector, outputVector))
345  {
346  return 0;
347  }
348  vtkImageData *output = vtkImageData::GetData(outputVector);
349  vtkDataArray *outArray = output->GetPointData()->GetScalars();
350  std::ostringstream newname;
351  newname << (outArray->GetName() ? outArray->GetName() : "") << "Gradient";
352  outArray->SetName(newname.str().c_str());
353  // Why not pass the original array?
354  if (this->GetInputArrayToProcess(0, inputVector))
355  {
356  output->GetPointData()->AddArray(this->GetInputArrayToProcess(0, inputVector));
357  }
358  return 1;
359 }
360 
361 //----------------------------------------------------------------------------
362 // This method contains a switch statement that calls the correct
363 // templated function for the input data type. This method does handle
364 // boundary conditions.
366  vtkInformationVector **inputVector,
367  vtkInformationVector *,
368  vtkImageData ***inData,
369  vtkImageData **outData,
370  int outExt[6],
371  int threadId)
372 {
373  // Get the input and output data objects.
374  vtkImageData *input = inData[0][0];
375  vtkImageData *output = outData[0];
376 
377  // The ouptut scalar type must be double to store proper gradients.
378  /*
379  if(output->GetScalarType() != VTK_DOUBLE)
380  {
381  vtkErrorMacro("Execute: output ScalarType is "
382  << output->GetScalarType() << "but must be double.");
383  return;
384  }
385  */
386  vtkDataArray *inputArray = this->GetInputArrayToProcess(0, inputVector);
387  if (!inputArray)
388  {
389  vtkErrorMacro("No input array was found. Cannot execute");
390  return;
391  }
392 
393  // Gradient makes sense only with one input component. This is not
394  // a Jacobian filter.
395  if (inputArray->GetNumberOfComponents() != 1)
396  {
397  vtkErrorMacro("Execute: input has more than one component. "
398  "The input to gradient should be a single component image. "
399  "Think about it. If you insist on using a color image then "
400  "run it though RGBToHSV then ExtractComponents to get the V "
401  "components. That's probably what you want anyhow.");
402  return;
403  }
404 
405  void *inPtr = inputArray->GetVoidPointer(0);
406  void *outPtr = output->GetScalarPointerForExtent(outExt);
407 
408  switch (inputArray->GetDataType())
409  {
410  vtkTemplateMacro(vtkMitkThickSlicesFilterExecute(
411  this, input, static_cast<VTK_TT *>(inPtr), output, static_cast<VTK_TT *>(outPtr), outExt, threadId));
412  default:
413  vtkErrorMacro("Execute: Unknown ScalarType " << input->GetScalarType());
414  return;
415  }
416 }
vtkStandardNewMacro(vtkMitkThickSlicesFilter)
void vtkMitkThickSlicesFilterExecute(vtkMitkThickSlicesFilter *self, vtkImageData *inData, T *inPtr, vtkImageData *outData, T *outPtr, int outExt[6], int)
void ThreadedRequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *, vtkImageData ***inData, vtkImageData **outData, int outExt[6], int threadId) override
int RequestUpdateExtent(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override
int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override
void PrintSelf(ostream &os, vtkIndent indent) override
int RequestInformation(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override