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
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.