Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkExtractDirectedPlaneImageFilterNew.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 #include "itkImageRegionIterator.h"
19 #include "mitkImageCast.h"
20 #include "mitkImageTimeSelector.h"
21 
22 #include <mitkImageAccessByItk.h>
23 
25  : m_CurrentWorldPlaneGeometry(nullptr), m_ActualInputTimestep(0)
26 {
27  MITK_WARN << "Class ExtractDirectedPlaneImageFilterNew is deprecated! Use ExtractSliceFilter instead.";
28 }
29 
31 {
32 }
33 
35 {
37 
38  if (!inputImage)
39  {
40  MITK_ERROR << "mitk::ExtractDirectedPlaneImageFilterNew: No input available. Please set the input!" << std::endl;
41  itkExceptionMacro("mitk::ExtractDirectedPlaneImageFilterNew: No input available. Please set the input!");
42  return;
43  }
44 
45  m_ImageGeometry = inputImage->GetGeometry();
46 
47  // If no timestep is set, the lowest given will be selected
48  // const mitk::TimeGeometry* inputTimeGeometry = this->GetInput()->GetTimeGeometry();
49 
50  if (inputImage->GetDimension() > 4 || inputImage->GetDimension() < 2)
51  {
52  MITK_ERROR << "mitk::ExtractDirectedPlaneImageFilterNew:GenerateData works only with 3D and 3D+t images, sorry."
53  << std::endl;
54  itkExceptionMacro("mitk::ExtractDirectedPlaneImageFilterNew works only with 3D and 3D+t images, sorry.");
55  return;
56  }
57  else if (inputImage->GetDimension() == 4)
58  {
60  timeselector->SetInput(inputImage);
61  timeselector->SetTimeNr(m_ActualInputTimestep);
62  timeselector->UpdateLargestPossibleRegion();
63  inputImage = timeselector->GetOutput();
64  }
65  else if (inputImage->GetDimension() == 2)
66  {
68  resultImage = const_cast<mitk::Image *>(inputImage.GetPointer());
69  ImageToImageFilter::SetNthOutput(0, resultImage);
70  return;
71  }
72 
73  if (!m_CurrentWorldPlaneGeometry)
74  {
75  MITK_ERROR << "mitk::ExtractDirectedPlaneImageFilterNew::GenerateData has no CurrentWorldPlaneGeometry set"
76  << std::endl;
77  return;
78  }
79 
80  AccessFixedDimensionByItk(inputImage, ItkSliceExtraction, 3);
81 } // Generate Data
82 
84 {
85  Superclass::GenerateOutputInformation();
86 }
87 
88 /*
89 * The desired slice is extracted by filling the image`s corresponding pixel values in an empty 2 dimensional itk::Image
90 * Therefor the itk image`s extent in pixel (in each direction) is doubled and its spacing (also in each direction) is
91 * divided by two
92 * (similar to the shannon theorem).
93 */
94 template <typename TPixel, unsigned int VImageDimension>
95 void mitk::ExtractDirectedPlaneImageFilterNew::ItkSliceExtraction(const itk::Image<TPixel, VImageDimension> *inputImage)
96 {
97  typedef itk::Image<TPixel, VImageDimension> InputImageType;
98  typedef itk::Image<TPixel, VImageDimension - 1> SliceImageType;
99 
100  typedef itk::ImageRegionConstIterator<SliceImageType> SliceIterator;
101 
102  // Creating an itk::Image that represents the sampled slice
103  typename SliceImageType::Pointer resultSlice = SliceImageType::New();
104 
105  typename SliceImageType::IndexType start;
106 
107  start[0] = 0;
108  start[1] = 0;
109 
110  Point3D origin = m_CurrentWorldPlaneGeometry->GetOrigin();
111  Vector3D right = m_CurrentWorldPlaneGeometry->GetAxisVector(0);
112  Vector3D bottom = m_CurrentWorldPlaneGeometry->GetAxisVector(1);
113 
114  // Calculation the sample-spacing, i.e the half of the smallest spacing existing in the original image
115  Vector3D newPixelSpacing = m_ImageGeometry->GetSpacing();
116  float minSpacing = newPixelSpacing[0];
117  for (unsigned int i = 1; i < newPixelSpacing.Size(); i++)
118  {
119  if (newPixelSpacing[i] < minSpacing)
120  {
121  minSpacing = newPixelSpacing[i];
122  }
123  }
124 
125  newPixelSpacing[0] = 0.5 * minSpacing;
126  newPixelSpacing[1] = 0.5 * minSpacing;
127  newPixelSpacing[2] = 0.5 * minSpacing;
128 
129  float pixelSpacing[2];
130  pixelSpacing[0] = newPixelSpacing[0];
131  pixelSpacing[1] = newPixelSpacing[1];
132 
133  // Calculating the size of the sampled slice
134  typename SliceImageType::SizeType size;
135  Vector2D extentInMM;
136  extentInMM[0] = m_CurrentWorldPlaneGeometry->GetExtentInMM(0);
137  extentInMM[1] = m_CurrentWorldPlaneGeometry->GetExtentInMM(1);
138 
139  // The maximum extent is the lenght of the diagonal of the considered plane
140  double maxExtent = sqrt(extentInMM[0] * extentInMM[0] + extentInMM[1] * extentInMM[1]);
141  unsigned int xTranlation = (maxExtent - extentInMM[0]);
142  unsigned int yTranlation = (maxExtent - extentInMM[1]);
143  size[0] = (maxExtent + xTranlation) / newPixelSpacing[0];
144  size[1] = (maxExtent + yTranlation) / newPixelSpacing[1];
145 
146  // Creating an ImageRegion Object
147  typename SliceImageType::RegionType region;
148 
149  region.SetSize(size);
150  region.SetIndex(start);
151 
152  // Defining the image`s extent and origin by passing the region to it and allocating memory for it
153  resultSlice->SetRegions(region);
154  resultSlice->SetSpacing(pixelSpacing);
155  resultSlice->Allocate();
156 
157  /*
158  * Here we create an new geometry so that the transformations are calculated correctly (our resulting slice has a
159  * different bounding box and spacing)
160  * The original current worldgeometry must be cloned because we have to keep the directions of the axis vector which
161  * represents the rotation
162  */
163  right.Normalize();
164  bottom.Normalize();
165  // Here we translate the origin to adapt the new geometry to the previous calculated extent
166  origin[0] -= xTranlation * right[0] + yTranlation * bottom[0];
167  origin[1] -= xTranlation * right[1] + yTranlation * bottom[1];
168  origin[2] -= xTranlation * right[2] + yTranlation * bottom[2];
169 
170  // Putting it together for the new geometry
171  mitk::BaseGeometry::Pointer newSliceGeometryTest =
172  dynamic_cast<BaseGeometry *>(m_CurrentWorldPlaneGeometry->Clone().GetPointer());
173  newSliceGeometryTest->ChangeImageGeometryConsideringOriginOffset(true);
174 
175  // Workaround because of BUG (#6505)
176  newSliceGeometryTest->GetIndexToWorldTransform()->SetMatrix(
177  m_CurrentWorldPlaneGeometry->GetIndexToWorldTransform()->GetMatrix());
178  // Workaround end
179 
180  newSliceGeometryTest->SetOrigin(origin);
181  ScalarType bounds[6] = {0, static_cast<ScalarType>(size[0]), 0, static_cast<ScalarType>(size[1]), 0, 1};
182  newSliceGeometryTest->SetBounds(bounds);
183  newSliceGeometryTest->SetSpacing(newPixelSpacing);
184  newSliceGeometryTest->Modified();
185 
186  // Workaround because of BUG (#6505)
187  itk::MatrixOffsetTransformBase<mitk::ScalarType, 3, 3>::MatrixType tempTransform =
188  newSliceGeometryTest->GetIndexToWorldTransform()->GetMatrix();
189  // Workaround end
190 
191  /*
192  * Now we iterate over the recently created slice.
193  * For each slice - pixel we check whether there is an according
194  * pixel in the input - image which can be set in the slice.
195  * In this way a slice is sampled out of the input - image regrading to the given PlaneGeometry
196  */
197  Point3D currentSliceIndexPointIn2D;
198  Point3D currentImageWorldPointIn3D;
199  typename InputImageType::IndexType inputIndex;
200 
201  SliceIterator sliceIterator(resultSlice, resultSlice->GetLargestPossibleRegion());
202  sliceIterator.GoToBegin();
203 
204  while (!sliceIterator.IsAtEnd())
205  {
206  /*
207  * Here we add 0.5 to to assure that the indices are correctly transformed.
208  * (Because of the 0.5er Bug)
209  */
210  currentSliceIndexPointIn2D[0] = sliceIterator.GetIndex()[0] + 0.5;
211  currentSliceIndexPointIn2D[1] = sliceIterator.GetIndex()[1] + 0.5;
212  currentSliceIndexPointIn2D[2] = 0;
213 
214  newSliceGeometryTest->IndexToWorld(currentSliceIndexPointIn2D, currentImageWorldPointIn3D);
215 
216  m_ImageGeometry->WorldToIndex(currentImageWorldPointIn3D, inputIndex);
217 
218  if (m_ImageGeometry->IsIndexInside(inputIndex))
219  {
220  resultSlice->SetPixel(sliceIterator.GetIndex(), inputImage->GetPixel(inputIndex));
221  }
222  else
223  {
224  resultSlice->SetPixel(sliceIterator.GetIndex(), 0);
225  }
226 
227  ++sliceIterator;
228  }
229 
231  GrabItkImageMemory(resultSlice, resultImage, nullptr, false);
232  resultImage->SetClonedGeometry(newSliceGeometryTest);
233  // Workaround because of BUG (#6505)
234  resultImage->GetGeometry()->GetIndexToWorldTransform()->SetMatrix(tempTransform);
235  // Workaround end
236 }
237 
239 // right.Normalize();
240 // bottom.Normalize();
241 // Point3D currentImagePointIn3D = origin /*+ bottom*newPixelSpacing*/;
242 // unsigned int columns ( 0 );
245 /****TEST***/
246 
247 // SliceImageType::IndexType index = sliceIterator.GetIndex();
248 
249 // if ( columns == (extentInPixel[0]) )
250 //{
251 // If we are at the end of a row, then we have to go to the beginning of the next row
252 // currentImagePointIn3D = origin;
253 // currentImagePointIn3D += newPixelSpacing[1]*bottom*index[1];
254 // columns = 0;
255 // m_ImageGeometry->WorldToIndex(currentImagePointIn3D, inputIndex);
256 //}
257 // else
258 //{
260 // if ( columns != 0 )
261 //{
262 // currentImagePointIn3D += newPixelSpacing[0]*right;
263 //}
264 // m_ImageGeometry->WorldToIndex(currentImagePointIn3D, inputIndex);
265 //}
266 
267 // if ( m_ImageGeometry->IsIndexInside( inputIndex ))
268 //{
269 // resultSlice->SetPixel( sliceIterator.GetIndex(), inputImage->GetPixel(inputIndex) );
270 //}
271 // else if (currentImagePointIn3D == origin)
272 //{
273 // Point3D temp;
274 // temp[0] = bottom[0]*newPixelSpacing[0]*0.5;
275 // temp[1] = bottom[1]*newPixelSpacing[1]*0.5;
276 // temp[2] = bottom[2]*newPixelSpacing[2]*0.5;
277 // origin[0] += temp[0];
278 // origin[1] += temp[1];
279 // origin[2] += temp[2];
280 // currentImagePointIn3D = origin;
281 // m_ImageGeometry->WorldToIndex(currentImagePointIn3D, inputIndex);
282 // if ( m_ImageGeometry->IsIndexInside( inputIndex ))
283 //{
284 // resultSlice->SetPixel( sliceIterator.GetIndex(), inputImage->GetPixel(inputIndex) );
285 //}
286 //}
287 
288 /****TEST ENDE****/
virtual void GenerateData() override
A version of GenerateData() specific for image processing filters.
itk::SmartPointer< Self > Pointer
#define AccessFixedDimensionByItk(mitkImage, itkImageTypeFunction, dimension)
Access a mitk-image with known dimension by an itk-image.
#define MITK_ERROR
Definition: mitkLogMacros.h:24
double ScalarType
itk::SmartPointer< Self > Pointer
Definition: mitkImage.h:88
Image::Pointer GrabItkImageMemory(itk::SmartPointer< ItkOutputImageType > &itkimage, mitk::Image *mitkImage=nullptr, const BaseGeometry *geometry=nullptr, bool update=true)
Grabs the memory of an itk::Image (with a specific type) and puts it into an mitk::Image.The memory is managed by the mitk::Image after calling this function. The itk::Image remains valid until the mitk::Image decides to free the memory.
class ITK_EXPORT Image
Vector< ScalarType, 2 > Vector2D
Definition: mitkVector.h:133
#define MITK_WARN
Definition: mitkLogMacros.h:23
itk::Image< double, 3 > InputImageType
Image class for storing images.
Definition: mitkImage.h:76
Point< ScalarType, 3 > Point3D
Definition: mitkPoint.h:99
InputImageType * GetInput(void)
OutputType * GetOutput()
Get the output data of this image source object.
static Pointer New()
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.