Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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