Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkBinaryThresholdULTool.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 "mitkToolManager.h"
20 
21 #include "mitkColorProperty.h"
23 #include "mitkProperties.h"
24 
25 #include "mitkDataStorage.h"
26 #include "mitkRenderingManager.h"
28 
29 #include "mitkImageAccessByItk.h"
30 #include "mitkImageCast.h"
32 #include "mitkImageTimeSelector.h"
33 #include "mitkLabelSetImage.h"
35 #include "mitkPadImageFilter.h"
36 #include <itkBinaryThresholdImageFilter.h>
37 #include <itkImageRegionIterator.h>
38 
39 // us
40 #include "usGetModuleContext.h"
41 #include "usModule.h"
42 #include "usModuleContext.h"
43 #include "usModuleResource.h"
44 
45 namespace mitk
46 {
48 }
49 
51  : m_SensibleMinimumThresholdValue(-100),
52  m_SensibleMaximumThresholdValue(+100),
53  m_CurrentLowerThresholdValue(1),
54  m_CurrentUpperThresholdValue(1)
55 {
57  m_ThresholdFeedbackNode->SetProperty("color", ColorProperty::New(0.0, 1.0, 0.0));
58  m_ThresholdFeedbackNode->SetProperty("name", StringProperty::New("Thresholding feedback"));
59  m_ThresholdFeedbackNode->SetProperty("opacity", FloatProperty::New(0.3));
60  m_ThresholdFeedbackNode->SetProperty("binary", BoolProperty::New(true));
61  m_ThresholdFeedbackNode->SetProperty("helper object", BoolProperty::New(true));
62 }
63 
65 {
66 }
67 
69 {
70  return NULL;
71 }
72 
74 {
76  us::ModuleResource resource = module->GetResource("TwoThresholds_48x48.png");
77  return resource;
78 }
79 
81 {
82  return "UL Threshold";
83 }
84 
86 {
87  Superclass::Activated();
88 
89  m_ToolManager->RoiDataChanged +=
91 
92  m_OriginalImageNode = m_ToolManager->GetReferenceData(0);
93  m_NodeForThresholding = m_OriginalImageNode;
94 
95  if (m_NodeForThresholding.IsNotNull())
96  {
97  SetupPreviewNode();
98  }
99  else
100  {
101  m_ToolManager->ActivateTool(-1);
102  }
103 }
104 
106 {
107  m_ToolManager->RoiDataChanged -=
109  m_NodeForThresholding = NULL;
110  m_OriginalImageNode = NULL;
111  try
112  {
113  if (DataStorage *storage = m_ToolManager->GetDataStorage())
114  {
115  storage->Remove(m_ThresholdFeedbackNode);
117  }
118  }
119  catch (...)
120  {
121  // don't care
122  }
123  m_ThresholdFeedbackNode->SetData(NULL);
124 
125  Superclass::Deactivated();
126 }
127 
128 void mitk::BinaryThresholdULTool::SetThresholdValues(double lower, double upper)
129 {
130  if (m_ThresholdFeedbackNode.IsNotNull())
131  {
132  m_CurrentLowerThresholdValue = lower;
133  m_CurrentUpperThresholdValue = upper;
134  UpdatePreview();
135  }
136 }
137 
139 {
140  CreateNewSegmentationFromThreshold(m_NodeForThresholding);
141 
143  m_ToolManager->ActivateTool(-1);
144 }
145 
147 {
148  m_ToolManager->ActivateTool(-1);
149 }
150 
152 {
153  itk::RGBPixel<float> pixel;
154  pixel[0] = 0.0f;
155  pixel[1] = 1.0f;
156  pixel[2] = 0.0f;
157 
158  if (m_NodeForThresholding.IsNotNull())
159  {
160  Image::Pointer image = dynamic_cast<Image *>(m_NodeForThresholding->GetData());
161  Image::Pointer originalImage = dynamic_cast<Image *>(m_OriginalImageNode->GetData());
162 
163  if (image.IsNotNull())
164  {
165  mitk::LabelSetImage::Pointer workingImage =
166  dynamic_cast<mitk::LabelSetImage *>(m_ToolManager->GetWorkingData(0)->GetData());
167 
168  if (workingImage.IsNotNull())
169  {
170  m_ThresholdFeedbackNode->SetData(workingImage->Clone());
171  m_IsOldBinary = false;
172 
173  // Let's paint the feedback node green...
174  mitk::LabelSetImage::Pointer previewImage =
175  dynamic_cast<mitk::LabelSetImage *>(m_ThresholdFeedbackNode->GetData());
176 
177  if (previewImage.IsNull())
178  {
179  MITK_ERROR << "Cannot create helper objects.";
180  return;
181  }
182 
183  previewImage->GetActiveLabel()->SetColor(pixel);
184  previewImage->GetActiveLabelSet()->UpdateLookupTable(previewImage->GetActiveLabel()->GetValue());
185  }
186  else
187  {
188  mitk::Image::Pointer workingImageBin = dynamic_cast<mitk::Image *>(m_ToolManager->GetWorkingData(0)->GetData());
189  if (workingImageBin)
190  {
191  m_ThresholdFeedbackNode->SetData(workingImageBin->Clone());
192  m_IsOldBinary = true;
193  }
194  else
195  m_ThresholdFeedbackNode->SetData(mitk::Image::New());
196  }
197 
198  m_ThresholdFeedbackNode->SetColor(pixel);
199  m_ThresholdFeedbackNode->SetOpacity(0.5);
200 
201  int layer(50);
202  m_NodeForThresholding->GetIntProperty("layer", layer);
203  m_ThresholdFeedbackNode->SetIntProperty("layer", layer + 1);
204 
205  if (DataStorage *ds = m_ToolManager->GetDataStorage())
206  {
207  if (!ds->Exists(m_ThresholdFeedbackNode))
208  ds->Add(m_ThresholdFeedbackNode, m_OriginalImageNode);
209  }
210 
211  if (image.GetPointer() == originalImage.GetPointer())
212  {
213  Image::StatisticsHolderPointer statistics = originalImage->GetStatistics();
214  m_SensibleMinimumThresholdValue = static_cast<double>(statistics->GetScalarValueMin());
215  m_SensibleMaximumThresholdValue = static_cast<double>(statistics->GetScalarValueMax());
216  }
217 
218  double range = m_SensibleMaximumThresholdValue - m_SensibleMinimumThresholdValue;
219  m_CurrentLowerThresholdValue = m_SensibleMinimumThresholdValue + range / 3.0;
220  m_CurrentUpperThresholdValue = m_SensibleMinimumThresholdValue + 2 * range / 3.0;
221 
222  bool isFloatImage = false;
223  if ((originalImage->GetPixelType().GetPixelType() == itk::ImageIOBase::SCALAR) &&
224  (originalImage->GetPixelType().GetComponentType() == itk::ImageIOBase::FLOAT ||
225  originalImage->GetPixelType().GetComponentType() == itk::ImageIOBase::DOUBLE))
226  {
227  isFloatImage = true;
228  }
229 
230  IntervalBordersChanged.Send(m_SensibleMinimumThresholdValue, m_SensibleMaximumThresholdValue, isFloatImage);
231  ThresholdingValuesChanged.Send(m_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue);
232  }
233  }
234 }
235 
236 template <typename TPixel, unsigned int VImageDimension>
237 static void ITKSetVolume(itk::Image<TPixel, VImageDimension> *originalImage,
238  mitk::Image *segmentation,
239  unsigned int timeStep)
240 {
241  segmentation->SetVolume((void *)originalImage->GetPixelContainer()->GetBufferPointer(), timeStep);
242 }
243 
245 {
246  if (node)
247  {
248  Image::Pointer feedBackImage = dynamic_cast<Image *>(m_ThresholdFeedbackNode->GetData());
249  if (feedBackImage.IsNotNull())
250  {
251  // create a new image of the same dimensions and smallest possible pixel type
252  DataNode::Pointer emptySegmentation = GetTargetSegmentationNode();
253 
254  if (emptySegmentation)
255  {
256  // actually perform a thresholding and ask for an organ type
257  for (unsigned int timeStep = 0; timeStep < feedBackImage->GetTimeSteps(); ++timeStep)
258  {
259  try
260  {
262  timeSelector->SetInput(feedBackImage);
263  timeSelector->SetTimeNr(timeStep);
264  timeSelector->UpdateLargestPossibleRegion();
265  Image::Pointer feedBackImage3D = timeSelector->GetOutput();
266 
267  if (feedBackImage3D->GetDimension() == 2)
268  {
270  feedBackImage3D, ITKSetVolume, 2, dynamic_cast<Image *>(emptySegmentation->GetData()), timeStep);
271  }
272  else
273  {
275  feedBackImage3D, ITKSetVolume, 3, dynamic_cast<Image *>(emptySegmentation->GetData()), timeStep);
276  }
277  }
278  catch (...)
279  {
280  Tool::ErrorMessage("Error accessing single time steps of the original image. Cannot create segmentation.");
281  }
282  }
283 
284  // since we are maybe working on a smaller image, pad it to the size of the original image
285  if (m_OriginalImageNode.GetPointer() != m_NodeForThresholding.GetPointer())
286  {
288 
289  padFilter->SetInput(0, dynamic_cast<mitk::Image *>(emptySegmentation->GetData()));
290  padFilter->SetInput(1, dynamic_cast<mitk::Image *>(m_OriginalImageNode->GetData()));
291  padFilter->SetBinaryFilter(true);
292  padFilter->SetUpperThreshold(1);
293  padFilter->SetLowerThreshold(1);
294  padFilter->Update();
295 
296  emptySegmentation->SetData(padFilter->GetOutput());
297  }
298 
299  m_ToolManager->SetWorkingData(emptySegmentation);
300  m_ToolManager->GetWorkingData(0)->Modified();
301  }
302  }
303  }
304 }
305 
307 {
308  mitk::DataNode::Pointer node = m_ToolManager->GetRoiData(0);
309 
310  if (node.IsNotNull())
311  {
313  mitk::Image::Pointer image = dynamic_cast<mitk::Image *>(m_NodeForThresholding->GetData());
314 
315  if (image.IsNull())
316  return;
317 
318  roiFilter->SetInput(image);
319  roiFilter->SetRegionOfInterest(node->GetData());
320  roiFilter->Update();
321 
323  tmpNode->SetData(roiFilter->GetOutput());
324 
325  m_SensibleMinimumThresholdValue = static_cast<double>(roiFilter->GetMinValue());
326  m_SensibleMaximumThresholdValue = static_cast<double>(roiFilter->GetMaxValue());
327 
328  m_NodeForThresholding = tmpNode;
329  }
330  else
331  m_NodeForThresholding = m_OriginalImageNode;
332 
333  this->SetupPreviewNode();
334  this->UpdatePreview();
335 }
336 
337 template <typename TPixel, unsigned int VImageDimension>
338 static void ITKThresholding(itk::Image<TPixel, VImageDimension> *originalImage,
339  mitk::Image *segmentation,
340  double lower,
341  double upper,
342  unsigned int timeStep)
343 {
344  typedef itk::Image<TPixel, VImageDimension> ImageType;
345  typedef itk::Image<mitk::Tool::DefaultSegmentationDataType, VImageDimension> SegmentationType;
346  typedef itk::BinaryThresholdImageFilter<ImageType, SegmentationType> ThresholdFilterType;
347 
349  filter->SetInput(originalImage);
350  filter->SetLowerThreshold(lower);
351  filter->SetUpperThreshold(upper);
352  filter->SetInsideValue(1);
353  filter->SetOutsideValue(0);
354  filter->Update();
355 
356  segmentation->SetVolume((void *)(filter->GetOutput()->GetPixelContainer()->GetBufferPointer()), timeStep);
357 }
358 
359 template <typename TPixel, unsigned int VImageDimension>
360 static void ITKThresholdingOldBinary(itk::Image<TPixel, VImageDimension> *originalImage,
361  mitk::Image *segmentation,
362  double lower,
363  double upper,
364  unsigned int timeStep)
365 {
366  typedef itk::Image<TPixel, VImageDimension> ImageType;
367  typedef itk::Image<unsigned char, VImageDimension> SegmentationType;
368  typedef itk::BinaryThresholdImageFilter<ImageType, SegmentationType> ThresholdFilterType;
369 
371  filter->SetInput(originalImage);
372  filter->SetLowerThreshold(lower);
373  filter->SetUpperThreshold(upper);
374  filter->SetInsideValue(1);
375  filter->SetOutsideValue(0);
376  filter->Update();
377 
378  segmentation->SetVolume((void *)(filter->GetOutput()->GetPixelContainer()->GetBufferPointer()), timeStep);
379 }
380 
382 {
383  mitk::Image::Pointer thresholdImage = dynamic_cast<mitk::Image *>(m_NodeForThresholding->GetData());
384  mitk::Image::Pointer previewImage = dynamic_cast<mitk::Image *>(m_ThresholdFeedbackNode->GetData());
385  if (thresholdImage && previewImage)
386  {
387  for (unsigned int timeStep = 0; timeStep < thresholdImage->GetTimeSteps(); ++timeStep)
388  {
390  timeSelector->SetInput(thresholdImage);
391  timeSelector->SetTimeNr(timeStep);
392  timeSelector->UpdateLargestPossibleRegion();
393  Image::Pointer feedBackImage3D = timeSelector->GetOutput();
394 
395  if (m_IsOldBinary)
396  {
397  AccessByItk_n(feedBackImage3D,
399  (previewImage, m_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue, timeStep));
400  }
401  else
402  {
403  AccessByItk_n(feedBackImage3D,
405  (previewImage, m_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue, timeStep));
406  }
407  }
409  }
410 }
Data management class that handles 'was created by' relations.
itk::SmartPointer< Self > Pointer
void CreateNewSegmentationFromThreshold(DataNode *node)
virtual void Deactivated() override
Called when the tool gets deactivated.
virtual void SetThresholdValues(double lower, double upper)
#define MITK_ERROR
Definition: mitkLogMacros.h:24
virtual const char * GetName() const override
Returns the name of this tool. Make it short!
virtual void Activated() override
Called when the tool gets activated.
static Pointer New()
#define MITKSEGMENTATION_EXPORT
DataCollection - Class to facilitate loading/accessing structured data.
#define MITK_TOOL_MACRO(EXPORT_SPEC, CLASS_NAME, DESCRIPTION)
Message1< std::string > ErrorMessage
To send error messages (to be shown by some GUI)
Definition: mitkTool.h:105
#define AccessByItk_n(mitkImage, itkImageTypeFunction, va_tuple)
Access a MITK image by an ITK image with one or more parameters.
virtual const char ** GetXPM() const override
Returns an icon in the XPM format.
virtual bool SetVolume(const void *data, int t=0, int n=0)
Set data as volume at time t in channel n. It is in the responsibility of the caller to ensure that t...
Definition: mitkImage.cpp:673
virtual ScalarType GetScalarValueMin(int t=0, unsigned int component=0)
Get the minimum for scalar images. Recomputation performed only when necessary.
static Pointer New()
map::core::discrete::Elements< 3 >::InternalImageType ImageType
static Pointer New()
#define AccessFixedDimensionByItk_2(mitkImage, itkImageTypeFunction, dimension, arg1, arg2)
static RenderingManager * GetInstance()
Module * GetModule() const
virtual ScalarType GetScalarValueMax(int t=0, unsigned int component=0)
Get the maximum for scalar images. Recomputation performed only when necessary.
Image class for storing images.
Definition: mitkImage.h:76
static Pointer New()
static Pointer New()
Class holding the statistics informations about a single mitk::Image.
static Pointer New()
LabelSetImage class for handling labels and layers in a segmentation session.
static void ITKThresholding(itk::Image< TPixel, VImageDimension > *originalImage, mitk::Image *segmentation, double lower, double upper, unsigned int timeStep)
us::ModuleResource GetIconResource() const override
Returns the tool button icon of the tool wrapped by a usModuleResource.
static void ITKThresholdingOldBinary(itk::Image< TPixel, VImageDimension > *originalImage, mitk::Image *segmentation, double lower, double upper, unsigned int timeStep)
ModuleResource GetResource(const std::string &path) const
Definition: usModule.cpp:267
static void ITKSetVolume(itk::Image< TPixel, VImageDimension > *originalImage, mitk::Image *segmentation, unsigned int timeStep)
static ModuleContext * GetModuleContext()
Returns the module context of the calling module.
static Pointer New()
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
Class for nodes of the DataTree.
Definition: mitkDataNode.h:66
static Pointer New()
Calculates the segmented volumes for binary images.
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.