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