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