Slicer  5.0
Slicer is a multi-platform, free and open source software package for visualization and medical image computing
SegmentEditorGrowFromSeedsEffect.py
Go to the documentation of this file.
1 import logging
2 import os
3 import time
4 
5 import qt
6 import vtk
7 
8 import slicer
9 
10 from SegmentEditorEffects import *
11 
12 
14  """ AutoCompleteEffect is an effect that can create a full segmentation
15  from a partial segmentation (not all slices are segmented or only
16  part of the target structures are painted).
17  """
18 
19  def __init__(self, scriptedEffect):
20  AbstractScriptedSegmentEditorAutoCompleteEffect.__init__(self, scriptedEffect)
21  scriptedEffect.name = 'Grow from seeds'
23  self.clippedMasterImageDataRequired = True # master volume intensities are used by this effect
24  self.clippedMaskImageDataRequired = True # masking is used
25  self.growCutFilter = None
26 
27  def clone(self):
28  import qSlicerSegmentationsEditorEffectsPythonQt as effects
29  clonedEffect = effects.qSlicerSegmentEditorScriptedEffect(None)
30  clonedEffect.setPythonSource(__file__.replace('\\', '/'))
31  return clonedEffect
32 
33  def icon(self):
34  iconPath = os.path.join(os.path.dirname(__file__), 'Resources/Icons/GrowFromSeeds.png')
35  if os.path.exists(iconPath):
36  return qt.QIcon(iconPath)
37  return qt.QIcon()
38 
39  def helpText(self):
40  return """<html>Growing segments to create complete segmentation<br>.
41 Location, size, and shape of initial segments and content of master volume are taken into account.
42 Final segment boundaries will be placed where master volume brightness changes abruptly. Instructions:<p>
43 <ul style="margin: 0">
44 <li>Use Paint or other offects to draw seeds in each region that should belong to a separate segment.
45 Paint each seed with a different segment. Minimum two segments are required.</li>
46 <li>Click <dfn>Initialize</dfn> to compute preview of full segmentation.</li>
47 <li>Browse through image slices. If previewed segmentation result is not correct then switch to
48 Paint or other effects and add more seeds in the misclassified region. Full segmentation will be
49 updated automatically within a few seconds</li>
50 <li>Click <dfn>Apply</dfn> to update segmentation with the previewed result.</li>
51 </ul><p>
52 If segments overlap, segment higher in the segments table will have priority.
53 The effect uses <a href="http://interactivemedical.org/imic2014/CameraReadyPapers/Paper%204/IMIC_ID4_FastGrowCut.pdf">fast grow-cut method</a>.
54 <p></html>"""
55 
56  def reset(self):
57  self.growCutFilter = None
58  AbstractScriptedSegmentEditorAutoCompleteEffect.reset(self)
59  self.updateGUIFromMRML()
60 
61  def setupOptionsFrame(self):
62  AbstractScriptedSegmentEditorAutoCompleteEffect.setupOptionsFrame(self)
63 
64  # Object scale slider
65  self.seedLocalityFactorSlider = slicer.qMRMLSliderWidget()
66  self.seedLocalityFactorSlider.setMRMLScene(slicer.mrmlScene)
67  self.seedLocalityFactorSlider.minimum = 0
68  self.seedLocalityFactorSlider.maximum = 10
69  self.seedLocalityFactorSlider.value = 0.0
70  self.seedLocalityFactorSlider.decimals = 1
71  self.seedLocalityFactorSlider.singleStep = 0.1
72  self.seedLocalityFactorSlider.pageStep = 1.0
73  self.seedLocalityFactorSlider.setToolTip('Increasing this value makes the effect of seeds more localized,'
74  ' thereby reducing leaks, but requires seed regions to be more evenly distributed in the image.'
75  ' The value is specified as an additional "intensity level difference" per "unit distance."')
76  self.scriptedEffect.addLabeledOptionsWidget("Seed locality:", self.seedLocalityFactorSlider)
77  self.seedLocalityFactorSlider.connect('valueChanged(double)', self.updateAlgorithmParameterFromGUI)
78 
79  def setMRMLDefaults(self):
80  AbstractScriptedSegmentEditorAutoCompleteEffect.setMRMLDefaults(self)
81  self.scriptedEffect.setParameterDefault("SeedLocalityFactor", 0.0)
82 
83  def updateGUIFromMRML(self):
84  AbstractScriptedSegmentEditorAutoCompleteEffect.updateGUIFromMRML(self)
85  if self.scriptedEffect.parameterDefined("SeedLocalityFactor"):
86  seedLocalityFactor = self.scriptedEffect.doubleParameter("SeedLocalityFactor")
87  else:
88  seedLocalityFactor = 0.0
89  wasBlocked = self.seedLocalityFactorSlider.blockSignals(True)
90  self.seedLocalityFactorSlider.value = abs(seedLocalityFactor)
91  self.seedLocalityFactorSlider.blockSignals(wasBlocked)
92 
93  def updateMRMLFromGUI(self):
94  AbstractScriptedSegmentEditorAutoCompleteEffect.updateMRMLFromGUI(self)
95  self.scriptedEffect.setParameter("SeedLocalityFactor", self.seedLocalityFactorSlider.value)
96 
98  self.updateMRMLFromGUI()
99 
100  # Trigger preview update
101  if self.getPreviewNode():
102  self.delayedAutoUpdateTimer.start()
103 
104  def computePreviewLabelmap(self, mergedImage, outputLabelmap):
105  import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic
106 
107  if not self.growCutFilter:
108  self.growCutFilter = vtkSlicerSegmentationsModuleLogic.vtkImageGrowCutSegment()
109  self.growCutFilter.SetIntensityVolume(self.clippedMasterImageData)
110  self.growCutFilter.SetMaskVolume(self.clippedMaskImageData)
111  maskExtent = self.clippedMaskImageData.GetExtent() if self.clippedMaskImageData else None
112  if maskExtent is not None and maskExtent[0] <= maskExtent[1] and maskExtent[2] <= maskExtent[3] and maskExtent[4] <= maskExtent[5]:
113  # Mask is used.
114  # Grow the extent more, as background segment does not surround region of interest.
115  self.extentGrowthRatio = 0.50
116  else:
117  # No masking is used.
118  # Background segment is expected to surround region of interest, so narrower margin is enough.
119  self.extentGrowthRatio = 0.20
120 
121  if self.scriptedEffect.parameterDefined("SeedLocalityFactor"):
122  seedLocalityFactor = self.scriptedEffect.doubleParameter("SeedLocalityFactor")
123  else:
124  seedLocalityFactor = 0.0
125  self.growCutFilter.SetDistancePenalty(seedLocalityFactor)
126  self.growCutFilter.SetSeedLabelVolume(mergedImage)
127  startTime = time.time()
128  self.growCutFilter.Update()
129  logging.info('Grow-cut operation on volume of {}x{}x{} voxels was completed in {:3.1f} seconds.'.format(
130  self.clippedMasterImageData.GetDimensions()[0],
131  self.clippedMasterImageData.GetDimensions()[1],
132  self.clippedMasterImageData.GetDimensions()[2],
133  time.time() - startTime))
134 
135  outputLabelmap.DeepCopy(self.growCutFilter.GetOutput())
136  imageToWorld = vtk.vtkMatrix4x4()
137  mergedImage.GetImageToWorldMatrix(imageToWorld)
138  outputLabelmap.SetImageToWorldMatrix(imageToWorld)