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