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