Slicer 4.2
Slicer is a multi-platform, free and open source software package for visualization and medical image computing
EditOptions.py
Go to the documentation of this file.
00001 import slicer
00002 from __main__ import tcl
00003 from __main__ import qt
00004 from __main__ import ctk
00005 from __main__ import getNodes
00006 import EditUtil
00007 
00008 #########################################################
00009 #
00010 # 
00011 comment = """
00012 In this file:
00013 
00014   Helpers - small widget-like helper classes
00015   EditOptions - effect superclass
00016   LabelerOptions - superclass for labeler effects
00017   *Options - per-effect interfaces
00018 
00019   Each effect interface is created when the corresponding
00020   editor effect is active on the slice views.  The main
00021   (only) responsibility of these GUIs is to set parameters
00022   on the mrml node that influence the behavior of the 
00023   editor effects.
00024 
00025 """
00026 #
00027 #########################################################
00028 
00029 #########################################################
00030 # Helpers
00031 #########################################################
00032 
00033 class HelpButton(object):
00034   """ 
00035   Puts a button on the interface that pops up a message
00036   dialog for help when pressed
00037   """
00038   def __init__(self, parent, helpString = ""):
00039     self.helpString = helpString
00040     self.message = qt.QMessageBox()
00041     self.message.setWindowTitle("Editor Help")
00042     self.button = qt.QPushButton("?", parent)
00043     self.button.setMaximumWidth(15)
00044     self.button.setToolTip("Bring up a help window")
00045     parent.layout().addWidget(self.button)
00046     self.button.connect('clicked()', self.showHelp)
00047 
00048   def showHelp(self):
00049     self.message.setText(self.helpString)
00050     self.message.open()
00051 
00052 #########################################################
00053 # Options
00054 #########################################################
00055 class EditOptions(object):
00056   """ This EditOptions is a parent class for all the GUI options
00057   for editor effects.  These are small custom interfaces
00058   that it in the toolOptionsFrame of the Editor interface.
00059   TODO: no support yet for scope options
00060   """
00061 
00062   def __init__(self, parent=0):
00063     self.updatingGUI = False
00064     self.observerTags = []
00065     self.widgets = []
00066     self.parameterNode = None
00067     self.parameterNodeTag = None
00068     self.editUtil = EditUtil.EditUtil()
00069     if parent == 0:
00070       self.parent = slicer.qMRMLWidget()
00071       self.parent.setLayout(qt.QVBoxLayout())
00072       self.parent.setMRMLScene(slicer.mrmlScene)
00073       self.create()
00074       self.parent.show()
00075     else:
00076       self.parent = parent
00077       self.create()
00078 
00079     # 1) find the parameter node in the scene and observe it
00080     # 2) set the defaults (will only set them if they are not
00081     # already set)
00082     # 3) update the GUI to match the defaults
00083     self.updateParameterNode( self.parameterNode, "ModifiedEvent" )
00084     self.setMRMLDefaults()
00085     self.updateGUIFromMRML( self.parameterNode, "ModifiedEvent" )
00086 
00087     # TODO: change this to look for specfic events (added, removed...)
00088     # but this requires being able to access events by number from wrapped code
00089     tag = slicer.mrmlScene.AddObserver("ModifiedEvent", self.updateParameterNode)
00090     self.observerTags.append( (slicer.mrmlScene, tag) )
00091 
00092   def __del__(self):
00093     self.destroy()
00094     if self.parameterNode:
00095       self.parameterNode.RemoveObserver(self.parameterNodeTag)
00096     for tagpair in self.observerTags:
00097       tagpair[0].RemoveObserver(tagpair[1])
00098 
00099   def create(self):
00100     self.frame = qt.QFrame(self.parent)
00101     self.frame.setLayout(qt.QVBoxLayout())
00102     self.parent.layout().addWidget(self.frame)
00103     self.widgets.append(self.frame)
00104 
00105   def destroy(self):
00106     for w in self.widgets:
00107       self.parent.layout().removeWidget(w)
00108       w.deleteLater()
00109       w.setParent(None)
00110     self.widgets = []
00111 
00112   #
00113   # update the GUI for the given label
00114   # - to be overriden by the subclass
00115   #
00116   def updateMRMLFromGUI(self):
00117     pass
00118 
00119   #
00120   # update the GUI from MRML
00121   # - to be overriden by the subclass
00122   #
00123   def updateGUIFromMRML(self,caller,event):
00124     pass
00125 
00126   #
00127   # set the default option values
00128   # - to be overriden by the subclass
00129   #
00130   def setMRMLDefaults(self):
00131     pass
00132 
00133   def getBackgroundScalarRange(self):
00134     success = False
00135     lo = -1
00136     hi = -1
00137     backgroundVolume = self.editUtil.getBackgroundVolume()
00138     if backgroundVolume:
00139       backgroundImage = backgroundVolume.GetImageData()
00140       if backgroundImage:
00141         lo, hi = backgroundImage.GetScalarRange()
00142         success = True
00143     return success, lo, hi    
00144 
00145   def setRangeWidgetToBackgroundRange(self, rangeWidget):
00146     if not rangeWidget:
00147       return
00148     success, lo, hi = self.getBackgroundScalarRange()
00149     if success:
00150       rangeWidget.minimum, rangeWidget.maximum = lo, hi
00151     
00152   def getPaintLabel(self):
00153     """ returns int index of the current paint label 
00154         - look for self's parameter node first, but if
00155           this is not set, query the scene for the first
00156           valid one (this can happen during startup
00157           when self has not yet observed the node)
00158     """
00159     pNode = self.parameterNode
00160     if not pNode:
00161       nodeID = tcl('[EditorGetParameterNode] GetID')
00162       pNode = slicer.mrmlScene.GetNodeByID(nodeID)
00163     if pNode:
00164       return int(pNode.GetParameter('label'))
00165     return 0
00166 
00167   def getPaintColor(self):
00168     """ returns rgba tuple for the current paint color """
00169     labelVolume = self.editUtil.getLabelVolume()
00170     if labelVolume:
00171       volumeDisplayNode = labelVolume.GetDisplayNode()
00172       if volumeDisplayNode != '':
00173         colorNode = volumeDisplayNode.GetColorNode()
00174         lut = colorNode.GetLookupTable()
00175         index = self.getPaintLabel()
00176         return lut.GetTableValue(index)
00177     return (0,0,0,0)
00178 
00179   def getPaintName(self):
00180     """ returns the string name of the currently selected index """
00181     labelVolume = self.editUtil.getLabelVolume()
00182     if labelVolume:
00183       volumeDisplayNode = labelVolume.GetDisplayNode()
00184       if volumeDisplayNode != '':
00185         colorNode = volumeDisplayNode.GetColorNode()
00186         index = self.getPaintLabel()
00187         return colorNode.GetColorName(index)
00188     return ""
00189 
00190   def statusText(self,text):
00191     # TODO: update on an application level status line
00192     print( text )
00193 
00194 #### Labeler
00195 class LabelerOptions(EditOptions):
00196   """ Labeler classes are the ones that implement
00197   draw and paint like functionality - common options
00198   include the threshold paint functionality
00199 
00200   TODO: there is no dialog when the scalar type of the labelmap 
00201   is changed to unsigned short
00202   """
00203 
00204   def __init__(self, parent=0):
00205     super(LabelerOptions,self).__init__(parent)
00206 
00207   def __del__(self):
00208     super(LabelerOptions,self).__del__()
00209 
00210   def create(self):
00211     super(LabelerOptions,self).create()
00212     self.paintOver = qt.QCheckBox("Paint Over", self.frame)
00213     self.paintOver.setToolTip("Allow effect to overwrite non-zero labels.")
00214     self.frame.layout().addWidget(self.paintOver)
00215     self.widgets.append(self.paintOver)
00216 
00217     self.thresholdPaint = qt.QCheckBox("Threshold Paint", self.frame)
00218     self.thresholdPaint.setToolTip("Enable/Disable threshold mode for labeling.")
00219     self.frame.layout().addWidget(self.thresholdPaint)
00220     self.widgets.append(self.thresholdPaint)
00221 
00222     self.thresholdLabel = qt.QLabel("Threshold", self.frame)
00223     self.thresholdLabel.setToolTip("In threshold mode, the label will only be set if the background value is within this range.")
00224     self.frame.layout().addWidget(self.thresholdLabel)
00225     self.widgets.append(self.thresholdLabel)
00226     self.threshold = ctk.ctkRangeWidget(self.frame)
00227     self.threshold.spinBoxAlignment = 0xff # put enties on top
00228     self.setRangeWidgetToBackgroundRange(self.threshold)
00229     self.frame.layout().addWidget(self.threshold)
00230     self.widgets.append(self.threshold)
00231 
00232     self.paintOver.connect( "clicked()", self.updateMRMLFromGUI )
00233     self.thresholdPaint.connect( "clicked()", self.updateMRMLFromGUI )
00234     self.threshold.connect( "valuesChanged(double,double)", self.onThresholdValuesChange )
00235 
00236   def destroy(self):
00237     super(LabelerOptions,self).destroy()
00238 
00239   def setMRMLDefaults(self):
00240     super(LabelerOptions,self).setMRMLDefaults()
00241     disableState = self.parameterNode.GetDisableModifiedEvent()
00242     self.parameterNode.SetDisableModifiedEvent(1)
00243     defaults = (
00244       ("paintOver", "1"),
00245       ("paintThreshold", "0"),
00246       ("paintThresholdMin", "0"),
00247       ("paintThresholdMax", "1000"),
00248     )
00249     for d in defaults:
00250       param = "Labeler,"+d[0]
00251       pvalue = self.parameterNode.GetParameter(param)
00252       if pvalue == '':
00253         self.parameterNode.SetParameter(param, d[1])
00254     self.parameterNode.SetDisableModifiedEvent(disableState)
00255 
00256   def updateGUIFromMRML(self,caller,event):
00257     params = ("paintOver", "paintThreshold", "paintThresholdMin", "paintThresholdMax")
00258     for p in params:
00259       if self.parameterNode.GetParameter("Labeler,"+p) == '':
00260         # don't update if the parameter node has not got all values yet
00261         return
00262     self.updatingGUI = True
00263     super(LabelerOptions,self).updateGUIFromMRML(caller,event)
00264     self.paintOver.setChecked( int(self.parameterNode.GetParameter("Labeler,paintOver")) )
00265     self.thresholdPaint.setChecked( int(self.parameterNode.GetParameter("Labeler,paintThreshold")) )
00266     self.threshold.setMinimumValue( float(self.parameterNode.GetParameter("Labeler,paintThresholdMin")) )
00267     self.threshold.setMaximumValue( float(self.parameterNode.GetParameter("Labeler,paintThresholdMax")) )
00268     self.thresholdLabel.setHidden( not self.thresholdPaint.checked )
00269     self.threshold.setHidden( not self.thresholdPaint.checked )
00270     self.threshold.setEnabled( self.thresholdPaint.checked )
00271     self.updatingGUI = False
00272 
00273   def onThresholdValuesChange(self,min,max):
00274     self.updateMRMLFromGUI()
00275 
00276   def updateMRMLFromGUI(self):
00277     if self.updatingGUI:
00278       return
00279     disableState = self.parameterNode.GetDisableModifiedEvent()
00280     self.parameterNode.SetDisableModifiedEvent(1)
00281     super(LabelerOptions,self).updateMRMLFromGUI()
00282     if self.paintOver.checked:
00283       self.parameterNode.SetParameter( "Labeler,paintOver", "1" )
00284     else:
00285       self.parameterNode.SetParameter( "Labeler,paintOver", "0" )
00286     if self.thresholdPaint.checked:
00287       self.parameterNode.SetParameter( "Labeler,paintThreshold", "1" )
00288     else:
00289       self.parameterNode.SetParameter( "Labeler,paintThreshold", "0" )
00290     self.parameterNode.SetParameter( "Labeler,paintThresholdMin", str(self.threshold.minimumValue) )
00291     self.parameterNode.SetParameter( "Labeler,paintThresholdMax", str(self.threshold.maximumValue) )
00292     self.parameterNode.SetDisableModifiedEvent(disableState)
00293     if not disableState:
00294       self.parameterNode.InvokePendingModifiedEvent()
00295 
00296 
00297 #### Paint
00298 class PaintOptions(LabelerOptions):
00299   """ Paint-specfic gui
00300   """
00301 
00302   def __init__(self, parent=0):
00303     super(PaintOptions,self).__init__(parent)
00304 
00305   def __del__(self):
00306     super(PaintOptions,self).__del__()
00307 
00308   def create(self):
00309     super(PaintOptions,self).create()
00310 
00311     self.radiusFrame = qt.QFrame(self.frame)
00312     self.radiusFrame.setLayout(qt.QHBoxLayout())
00313     self.frame.layout().addWidget(self.radiusFrame)
00314     self.widgets.append(self.radiusFrame)
00315     self.radiusLabel = qt.QLabel("Radius:", self.radiusFrame)
00316     self.radiusLabel.setToolTip("Set the radius of the paint brush in millimeters")
00317     self.radiusFrame.layout().addWidget(self.radiusLabel)
00318     self.widgets.append(self.radiusLabel)
00319     self.radiusSpinBox = qt.QDoubleSpinBox(self.radiusFrame)
00320     self.radiusSpinBox.setToolTip("Set the radius of the paint brush in millimeters")
00321     self.radiusSpinBox.minimum = 0.01
00322     self.radiusSpinBox.maximum = 100
00323     self.radiusSpinBox.suffix = "mm"
00324     self.radiusFrame.layout().addWidget(self.radiusSpinBox)
00325     self.widgets.append(self.radiusSpinBox)
00326 
00327     self.radius = ctk.ctkDoubleSlider(self.frame)
00328     self.radius.minimum = 0.01
00329     self.radius.maximum = 100
00330     self.radius.orientation = 1
00331     self.radius.singleStep = 0.01
00332     self.frame.layout().addWidget(self.radius)
00333     self.widgets.append(self.radius)
00334 
00335     self.smudge = qt.QCheckBox("Smudge", self.frame)
00336     self.smudge.setToolTip("Set the label number automatically by sampling the pixel location where the brush stroke starts.")
00337     self.frame.layout().addWidget(self.smudge)
00338     self.widgets.append(self.smudge)
00339 
00340     HelpButton(self.frame, "Use this tool to paint with a round brush of the selected radius")
00341 
00342     self.smudge.connect('clicked()', self.updateMRMLFromGUI)
00343     self.radius.connect('valueChanged(double)', self.onRadiusValueChanged)
00344     self.radiusSpinBox.connect('valueChanged(double)', self.onRadiusSpinBoxChanged)
00345 
00346     # Add vertical spacer
00347     self.frame.layout().addStretch(1)
00348 
00349   def destroy(self):
00350     super(PaintOptions,self).destroy()
00351 
00352   # note: this method needs to be implemented exactly as-is
00353   # in each leaf subclass so that "self" in the observer
00354   # is of the correct type 
00355   def updateParameterNode(self, caller, event):
00356     nodeID = tcl('[EditorGetParameterNode] GetID')
00357     node = slicer.mrmlScene.GetNodeByID(nodeID)
00358     if node != self.parameterNode:
00359       if self.parameterNode:
00360         node.RemoveObserver(self.parameterNodeTag)
00361       self.parameterNode = node
00362       self.parameterNodeTag = node.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
00363 
00364   def setMRMLDefaults(self):
00365     super(PaintOptions,self).setMRMLDefaults()
00366     disableState = self.parameterNode.GetDisableModifiedEvent()
00367     self.parameterNode.SetDisableModifiedEvent(1)
00368     defaults = (
00369       ("radius", "5"),
00370       ("smudge", "0"),
00371     )
00372     for d in defaults:
00373       param = "Paint,"+d[0]
00374       pvalue = self.parameterNode.GetParameter(param)
00375       if pvalue == '':
00376         self.parameterNode.SetParameter(param, d[1])
00377     self.parameterNode.SetDisableModifiedEvent(disableState)
00378 
00379   def updateGUIFromMRML(self,caller,event):
00380     if self.updatingGUI:
00381       return
00382     params = ("radius", "smudge")
00383     for p in params:
00384       if self.parameterNode.GetParameter("Paint,"+p) == '':
00385         # don't update if the parameter node has not got all values yet
00386         return
00387     self.updatingGUI = True
00388     super(PaintOptions,self).updateGUIFromMRML(caller,event)
00389     self.smudge.setChecked( int(self.parameterNode.GetParameter("Paint,smudge")) )
00390     self.radius.setValue( float(self.parameterNode.GetParameter("Paint,radius")) )
00391     self.radiusSpinBox.setValue( float(self.parameterNode.GetParameter("Paint,radius")) )
00392     self.updatingGUI = False
00393 
00394   def onRadiusValueChanged(self,value):
00395     if self.updatingGUI:
00396       return
00397     self.updatingGUI = True
00398     self.radiusSpinBox.setValue(self.radius.value)
00399     self.updatingGUI = False
00400     self.updateMRMLFromGUI()
00401 
00402   def onRadiusSpinBoxChanged(self,value):
00403     if self.updatingGUI:
00404       return
00405     self.updatingGUI = True
00406     self.radius.setValue(self.radiusSpinBox.value)
00407     self.updatingGUI = False
00408     self.updateMRMLFromGUI()
00409 
00410   def updateMRMLFromGUI(self):
00411     if self.updatingGUI:
00412       return
00413     disableState = self.parameterNode.GetDisableModifiedEvent()
00414     self.parameterNode.SetDisableModifiedEvent(1)
00415     super(PaintOptions,self).updateMRMLFromGUI()
00416     if self.smudge.checked:
00417       self.parameterNode.SetParameter( "Paint,smudge", "1" )
00418     else:
00419       self.parameterNode.SetParameter( "Paint,smudge", "0" )
00420     self.parameterNode.SetParameter( "Paint,radius", str(self.radius.value) )
00421     self.parameterNode.SetDisableModifiedEvent(disableState)
00422     if not disableState:
00423       self.parameterNode.InvokePendingModifiedEvent()
00424 
00425 #### Draw
00426 class DrawOptions(LabelerOptions):
00427   """ Draw-specfic gui
00428   """
00429 
00430   def __init__(self, parent=0):
00431     super(DrawOptions,self).__init__(parent)
00432 
00433   def __del__(self):
00434     super(DrawOptions,self).__del__()
00435 
00436   def create(self):
00437     super(DrawOptions,self).create()
00438     self.apply = qt.QPushButton("Apply", self.frame)
00439     self.apply.setToolTip("Apply current outline.\nUse the 'a' or 'Enter' hotkey to apply in slice window")
00440     self.frame.layout().addWidget(self.apply)
00441     self.widgets.append(self.apply)
00442 
00443     HelpButton(self.frame, "Use this tool to draw an outline.\n\nLeft Click: add point.\nLeft Drag: add multiple points.\nx: delete last point.\na: apply outline.")
00444 
00445     self.apply.connect('clicked()', self.onApply)
00446 
00447     # Add vertical spacer
00448     self.frame.layout().addStretch(1)
00449 
00450   def destroy(self):
00451     super(DrawOptions,self).destroy()
00452 
00453   # note: this method needs to be implemented exactly as-is
00454   # in each leaf subclass so that "self" in the observer
00455   # is of the correct type 
00456   def updateParameterNode(self, caller, event):
00457     nodeID = tcl('[EditorGetParameterNode] GetID')
00458     node = slicer.mrmlScene.GetNodeByID(nodeID)
00459     if node != self.parameterNode:
00460       if self.parameterNode:
00461         node.RemoveObserver(self.parameterNodeTag)
00462       self.parameterNode = node
00463       self.parameterNodeTag = node.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
00464 
00465   def setMRMLDefaults(self):
00466     super(DrawOptions,self).setMRMLDefaults()
00467 
00468   def updateGUIFromMRML(self,caller,event):
00469     self.updatingGUI = True
00470     super(DrawOptions,self).updateGUIFromMRML(caller,event)
00471     self.updatingGUI = False
00472 
00473   def onApply(self):
00474     tcl('::DrawEffect::ApplyAll')
00475 
00476   def updateMRMLFromGUI(self):
00477     if self.updatingGUI:
00478       return
00479     disableState = self.parameterNode.GetDisableModifiedEvent()
00480     self.parameterNode.SetDisableModifiedEvent(1)
00481     super(DrawOptions,self).updateMRMLFromGUI()
00482     self.parameterNode.SetDisableModifiedEvent(disableState)
00483     if not disableState:
00484       self.parameterNode.InvokePendingModifiedEvent()
00485 
00486 
00487 #### Level Tracing
00488 class LevelTracingOptions(LabelerOptions):
00489   """ LevelTracing-specfic gui
00490   """
00491 
00492   def __init__(self, parent=0):
00493     super(LevelTracingOptions,self).__init__(parent)
00494 
00495   def __del__(self):
00496     super(LevelTracingOptions,self).__del__()
00497 
00498   def create(self):
00499     super(LevelTracingOptions,self).create()
00500 
00501     HelpButton(self.frame, "Use this tool to track around similar intensity levels.\n\nAs you move the mouse, the current background voxel is used to find a closed path that follows the same intensity value back to the starting point within the current slice.  Pressing the left mouse button fills the the path according to the current labeling rules.")
00502 
00503     # Add vertical spacer
00504     self.frame.layout().addStretch(1)
00505 
00506   def destroy(self):
00507     super(LevelTracingOptions,self).destroy()
00508 
00509   # note: this method needs to be implemented exactly as-is
00510   # in each leaf subclass so that "self" in the observer
00511   # is of the correct type 
00512   def updateParameterNode(self, caller, event):
00513     nodeID = tcl('[EditorGetParameterNode] GetID')
00514     node = slicer.mrmlScene.GetNodeByID(nodeID)
00515     if node != self.parameterNode:
00516       if self.parameterNode:
00517         node.RemoveObserver(self.parameterNodeTag)
00518       self.parameterNode = node
00519       self.parameterNodeTag = node.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
00520 
00521   def setMRMLDefaults(self):
00522     super(LevelTracingOptions,self).setMRMLDefaults()
00523 
00524   def updateGUIFromMRML(self,caller,event):
00525     self.updatingGUI = True
00526     super(LevelTracingOptions,self).updateGUIFromMRML(caller,event)
00527     self.updatingGUI = False
00528 
00529   def updateMRMLFromGUI(self):
00530     if self.updatingGUI:
00531       return
00532     disableState = self.parameterNode.GetDisableModifiedEvent()
00533     self.parameterNode.SetDisableModifiedEvent(1)
00534     super(LevelTracingOptions,self).updateMRMLFromGUI()
00535     self.parameterNode.SetDisableModifiedEvent(disableState)
00536     if not disableState:
00537       self.parameterNode.InvokePendingModifiedEvent()
00538 
00539 
00540 class ImplicitRectangleOptions(LabelerOptions):
00541   """ ImplicitRectangle-specfic gui
00542   """
00543 
00544   def __init__(self, parent=0):
00545     super(ImplicitRectangleOptions,self).__init__(parent)
00546 
00547   def __del__(self):
00548     super(ImplicitRectangleOptions,self).__del__()
00549 
00550   def create(self):
00551     super(ImplicitRectangleOptions,self).create()
00552 
00553     HelpButton(self.frame, "Click and drag the left mouse button to define a rectangle that will be filled according to the current labeling rules.")
00554 
00555     # Add vertical spacer
00556     self.frame.layout().addStretch(1)
00557 
00558   def destroy(self):
00559     super(ImplicitRectangleOptions,self).destroy()
00560 
00561   # note: this method needs to be implemented exactly as-is
00562   # in each leaf subclass so that "self" in the observer
00563   # is of the correct type 
00564   def updateParameterNode(self, caller, event):
00565     nodeID = tcl('[EditorGetParameterNode] GetID')
00566     node = slicer.mrmlScene.GetNodeByID(nodeID)
00567     if node != self.parameterNode:
00568       if self.parameterNode:
00569         node.RemoveObserver(self.parameterNodeTag)
00570       self.parameterNode = node
00571       self.parameterNodeTag = node.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
00572 
00573   def setMRMLDefaults(self):
00574     super(ImplicitRectangleOptions,self).setMRMLDefaults()
00575 
00576   def updateGUIFromMRML(self,caller,event):
00577     self.updatingGUI = True
00578     super(ImplicitRectangleOptions,self).updateGUIFromMRML(caller,event)
00579     self.updatingGUI = False
00580 
00581   def updateMRMLFromGUI(self):
00582     if self.updatingGUI:
00583       return
00584     disableState = self.parameterNode.GetDisableModifiedEvent()
00585     self.parameterNode.SetDisableModifiedEvent(1)
00586     super(ImplicitRectangleOptions,self).updateMRMLFromGUI()
00587     self.parameterNode.SetDisableModifiedEvent(disableState)
00588     if not disableState:
00589       self.parameterNode.InvokePendingModifiedEvent()
00590 
00591 
00592 #### IdentifyIslands
00593 class IdentifyIslandsOptions(EditOptions):
00594   """ IdentifyIslands-specfic gui
00595   """
00596 
00597   def __init__(self, parent=0):
00598     super(IdentifyIslandsOptions,self).__init__(parent)
00599 
00600   def __del__(self):
00601     super(IdentifyIslandsOptions,self).__del__()
00602 
00603   def create(self):
00604     super(IdentifyIslandsOptions,self).create()
00605     self.minSizeLabel = qt.QLabel("Minimum Size", self.frame)
00606     self.minSizeLabel.setToolTip("Any islands smaller than this number of voxels will be ignored (label value will be 0).")
00607     self.frame.layout().addWidget(self.minSizeLabel)
00608     self.widgets.append(self.minSizeLabel)
00609     self.minSize = qt.QSpinBox(self.frame)
00610     self.frame.layout().addWidget(self.minSize)
00611     self.widgets.append(self.minSize)
00612 
00613     self.fullyConnected = qt.QCheckBox("Fully Connected", self.frame)
00614     self.fullyConnected.setToolTip("When on, do not treat diagonally adjacent voxels as neighbors.")
00615     self.frame.layout().addWidget(self.fullyConnected)
00616     self.widgets.append(self.fullyConnected)
00617 
00618     self.apply = qt.QPushButton("Apply", self.frame)
00619     self.apply.setToolTip("Run the selected operation.")
00620     self.frame.layout().addWidget(self.apply)
00621     self.widgets.append(self.apply)
00622 
00623     HelpButton(self.frame, "Use this tool to create a unique label value for each connected region in the current label map.  Connected regions are defined as groups of pixels which touch each other but are surrounded by zero valued voxels.  If FullyConnected is selected, then only voxels that share a face are counted as connected; if unselected, then voxels that touch at an edge or a corner are considered connected.\n\n Note: be aware that all non-zero label values labels values are considered equal by this filter and that the result will renumber the resulting islands in order of size.")
00624 
00625     self.fullyConnected.connect('clicked()', self.updateMRMLFromGUI)
00626     self.minSize.connect('valueChanged()', self.onMinSizeValueChanged)
00627     self.apply.connect('clicked()', self.onApply)
00628 
00629     # Add vertical spacer
00630     self.frame.layout().addStretch(1)
00631 
00632   def destroy(self):
00633     super(IdentifyIslandsOptions,self).destroy()
00634 
00635   # note: this method needs to be implemented exactly as-is
00636   # in each leaf subclass so that "self" in the observer
00637   # is of the correct type 
00638   def updateParameterNode(self, caller, event):
00639     nodeID = tcl('[EditorGetParameterNode] GetID')
00640     node = slicer.mrmlScene.GetNodeByID(nodeID)
00641     if node != self.parameterNode:
00642       if self.parameterNode:
00643         node.RemoveObserver(self.parameterNodeTag)
00644       self.parameterNode = node
00645       self.parameterNodeTag = node.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
00646 
00647   def setMRMLDefaults(self):
00648     super(IdentifyIslandsOptions,self).setMRMLDefaults()
00649     disableState = self.parameterNode.GetDisableModifiedEvent()
00650     self.parameterNode.SetDisableModifiedEvent(1)
00651     defaults = (
00652       ("minSize", "5"),
00653       ("fullyConnected", "0"),
00654     )
00655     for d in defaults:
00656       param = "IdentifyIslands,"+d[0]
00657       pvalue = self.parameterNode.GetParameter(param)
00658       if pvalue == '':
00659         self.parameterNode.SetParameter(param, d[1])
00660     self.parameterNode.SetDisableModifiedEvent(disableState)
00661 
00662   def updateGUIFromMRML(self,caller,event):
00663     params = ("minSize", "fullyConnected")
00664     for p in params:
00665       if self.parameterNode.GetParameter("IdentifyIslands,"+p) == '':
00666         # don't update if the parameter node has not got all values yet
00667         return
00668     self.updatingGUI = True
00669     super(IdentifyIslandsOptions,self).updateGUIFromMRML(caller,event)
00670     self.fullyConnected.setChecked( int(self.parameterNode.GetParameter("IdentifyIslands,fullyConnected")) )
00671     self.minSize.setValue( float(self.parameterNode.GetParameter("IdentifyIslands,minSize")) )
00672     self.updatingGUI = False
00673 
00674   def onApply(self):
00675     tcl('set effect [lindex [itcl::find objects -class IdentifyIslandsEffect] 0]; if { $effect != "" } { $effect apply }')
00676 
00677   def onMinSizeValueChanged(self,value):
00678     self.updateMRMLFromGUI()
00679 
00680   def updateMRMLFromGUI(self):
00681     if self.updatingGUI:
00682       return
00683     disableState = self.parameterNode.GetDisableModifiedEvent()
00684     self.parameterNode.SetDisableModifiedEvent(1)
00685     super(IdentifyIslandsOptions,self).updateMRMLFromGUI()
00686     if self.fullyConnected.checked:
00687       self.parameterNode.SetParameter( "IdentifyIslands,fullyConnected", "1" )
00688     else:
00689       self.parameterNode.SetParameter( "IdentifyIslands,fullyConnected", "0" )
00690     self.parameterNode.SetParameter( "IdentifyIslands,minSize", str(self.minSize.value) )
00691     self.parameterNode.SetDisableModifiedEvent(disableState)
00692     if not disableState:
00693       self.parameterNode.InvokePendingModifiedEvent()
00694 
00695 
00696 #### ChangeIsland
00697 class ChangeIslandOptions(EditOptions):
00698   """ ChangeIsland-specfic gui
00699   """
00700 
00701   def __init__(self, parent=0):
00702     super(ChangeIslandOptions,self).__init__(parent)
00703 
00704   def __del__(self):
00705     super(ChangeIslandOptions,self).__del__()
00706 
00707   def create(self):
00708     super(ChangeIslandOptions,self).create()
00709 
00710     HelpButton(self.frame, "Use this tool change the label for a selected region to the current label value.  Every voxel connected to the point you click will change.")
00711 
00712     # Add vertical spacer
00713     self.frame.layout().addStretch(1)
00714 
00715   def destroy(self):
00716     super(ChangeIslandOptions,self).destroy()
00717 
00718   # note: this method needs to be implemented exactly as-is
00719   # in each leaf subclass so that "self" in the observer
00720   # is of the correct type 
00721   def updateParameterNode(self, caller, event):
00722     nodeID = tcl('[EditorGetParameterNode] GetID')
00723     node = slicer.mrmlScene.GetNodeByID(nodeID)
00724     if node != self.parameterNode:
00725       if self.parameterNode:
00726         node.RemoveObserver(self.parameterNodeTag)
00727       self.parameterNode = node
00728       self.parameterNodeTag = node.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
00729 
00730   def setMRMLDefaults(self):
00731     super(ChangeIslandOptions,self).setMRMLDefaults()
00732 
00733   def updateGUIFromMRML(self,caller,event):
00734     self.updatingGUI = True
00735     super(ChangeIslandOptions,self).updateGUIFromMRML(caller,event)
00736     self.updatingGUI = False
00737 
00738   def updateMRMLFromGUI(self):
00739     if self.updatingGUI:
00740       return
00741     disableState = self.parameterNode.GetDisableModifiedEvent()
00742     self.parameterNode.SetDisableModifiedEvent(1)
00743     super(ChangeIslandOptions,self).updateMRMLFromGUI()
00744     if not disableState:
00745       self.parameterNode.InvokePendingModifiedEvent()
00746 
00747 
00748 #### RemoveIslands
00749 class RemoveIslandsOptions(EditOptions):
00750   """ RemoveIslands-specfic gui
00751   """
00752 
00753   def __init__(self, parent=0):
00754     super(RemoveIslandsOptions,self).__init__(parent)
00755 
00756   def __del__(self):
00757     super(RemoveIslandsOptions,self).__del__()
00758 
00759   def create(self):
00760     super(RemoveIslandsOptions,self).create()
00761 
00762     self.fullyConnected = qt.QCheckBox("Fully Connected", self.frame)
00763     self.fullyConnected.setToolTip("When on, do not treat diagonally adjacent voxels as neighbors.")
00764     self.frame.layout().addWidget(self.fullyConnected)
00765     self.widgets.append(self.fullyConnected)
00766 
00767     self.apply = qt.QPushButton("Apply", self.frame)
00768     self.apply.setToolTip("Run the selected operation.")
00769     self.frame.layout().addWidget(self.apply)
00770     self.widgets.append(self.apply)
00771 
00772     HelpButton(self.frame, "Use this tool to remove isolated islands of background (0) within a segmented region (current label color).  Note that only completely isolated islands of background are removed.  You may need to manually cut the connections between interior regions and the background using one of the paint or draw tools.")
00773 
00774     self.fullyConnected.connect('clicked()', self.updateMRMLFromGUI)
00775     self.apply.connect('clicked()', self.onApply)
00776 
00777     # Add vertical spacer
00778     self.frame.layout().addStretch(1)
00779 
00780   def destroy(self):
00781     super(RemoveIslandsOptions,self).destroy()
00782 
00783   # note: this method needs to be implemented exactly as-is
00784   # in each leaf subclass so that "self" in the observer
00785   # is of the correct type 
00786   def updateParameterNode(self, caller, event):
00787     nodeID = tcl('[EditorGetParameterNode] GetID')
00788     node = slicer.mrmlScene.GetNodeByID(nodeID)
00789     if node != self.parameterNode:
00790       if self.parameterNode:
00791         node.RemoveObserver(self.parameterNodeTag)
00792       self.parameterNode = node
00793       self.parameterNodeTag = node.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
00794 
00795   def setMRMLDefaults(self):
00796     super(RemoveIslandsOptions,self).setMRMLDefaults()
00797     disableState = self.parameterNode.GetDisableModifiedEvent()
00798     self.parameterNode.SetDisableModifiedEvent(1)
00799     defaults = (
00800       ("fullyConnected", "0"),
00801     )
00802     for d in defaults:
00803       param = "RemoveIslands,"+d[0]
00804       pvalue = self.parameterNode.GetParameter(param)
00805       if pvalue == '':
00806         self.parameterNode.SetParameter(param, d[1])
00807     self.parameterNode.SetDisableModifiedEvent(disableState)
00808 
00809   def updateGUIFromMRML(self,caller,event):
00810     params = ("minSize", "fullyConnected")
00811     for p in params:
00812       if self.parameterNode.GetParameter("RemoveIslands,"+p) == '':
00813         # don't update if the parameter node has not got all values yet
00814         return
00815     self.updatingGUI = True
00816     super(RemoveIslandsOptions,self).updateGUIFromMRML(caller,event)
00817     self.fullyConnected.setChecked( int(self.parameterNode.GetParameter("RemoveIslands,fullyConnected")) )
00818     self.updatingGUI = False
00819 
00820   def onApply(self):
00821     tcl('set effect [lindex [itcl::find objects -class RemoveIslandsEffect] 0]; if { $effect != "" } { $effect apply }')
00822 
00823   def onMinSizeValueChanged(self,value):
00824     self.updateMRMLFromGUI()
00825 
00826   def updateMRMLFromGUI(self):
00827     if self.updatingGUI:
00828       return
00829     disableState = self.parameterNode.GetDisableModifiedEvent()
00830     self.parameterNode.SetDisableModifiedEvent(1)
00831     super(RemoveIslandsOptions,self).updateMRMLFromGUI()
00832     if self.fullyConnected.checked:
00833       self.parameterNode.SetParameter( "RemoveIslands,fullyConnected", "1" )
00834     else:
00835       self.parameterNode.SetParameter( "RemoveIslands,fullyConnected", "0" )
00836     self.parameterNode.SetDisableModifiedEvent(disableState)
00837     if not disableState:
00838       self.parameterNode.InvokePendingModifiedEvent()
00839 
00840 #### SaveIsland
00841 class SaveIslandOptions(EditOptions):
00842   """ SaveIsland-specfic gui
00843   """
00844 
00845   def __init__(self, parent=0):
00846     super(SaveIslandOptions,self).__init__(parent)
00847 
00848   def __del__(self):
00849     super(SaveIslandOptions,self).__del__()
00850 
00851   def create(self):
00852     super(SaveIslandOptions,self).create()
00853 
00854     HelpButton(self.frame, "Click on an island you want to keep.  All voxels not connected to the island are set to zero.")
00855 
00856     # Add vertical spacer
00857     self.frame.layout().addStretch(1)
00858 
00859   def destroy(self):
00860     super(SaveIslandOptions,self).destroy()
00861 
00862   # note: this method needs to be implemented exactly as-is
00863   # in each leaf subclass so that "self" in the observer
00864   # is of the correct type 
00865   def updateParameterNode(self, caller, event):
00866     nodeID = tcl('[EditorGetParameterNode] GetID')
00867     node = slicer.mrmlScene.GetNodeByID(nodeID)
00868     if node != self.parameterNode:
00869       if self.parameterNode:
00870         node.RemoveObserver(self.parameterNodeTag)
00871       self.parameterNode = node
00872       self.parameterNodeTag = node.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
00873 
00874   def setMRMLDefaults(self):
00875     super(SaveIslandOptions,self).setMRMLDefaults()
00876 
00877   def updateGUIFromMRML(self,caller,event):
00878     self.updatingGUI = True
00879     super(SaveIslandOptions,self).updateGUIFromMRML(caller,event)
00880     self.updatingGUI = False
00881 
00882   def updateMRMLFromGUI(self):
00883     if self.updatingGUI:
00884       return
00885     disableState = self.parameterNode.GetDisableModifiedEvent()
00886     self.parameterNode.SetDisableModifiedEvent(1)
00887     super(SaveIslandOptions,self).updateMRMLFromGUI()
00888     if not disableState:
00889       self.parameterNode.InvokePendingModifiedEvent()
00890 
00891 
00892 #### Threshold
00893 class ThresholdOptions(EditOptions):
00894   """ Threshold-specfic gui
00895   """
00896 
00897   def __init__(self, parent=0):
00898     super(ThresholdOptions,self).__init__(parent)
00899 
00900   def __del__(self):
00901     super(ThresholdOptions,self).__del__()
00902 
00903   def create(self):
00904     super(ThresholdOptions,self).create()
00905     self.thresholdLabel = qt.QLabel("Threshold", self.frame)
00906     self.thresholdLabel.setToolTip("Set the range of the background values that should be labeled.")
00907     self.frame.layout().addWidget(self.thresholdLabel)
00908     self.widgets.append(self.thresholdLabel)
00909     self.threshold = ctk.ctkRangeWidget(self.frame)
00910     self.threshold.spinBoxAlignment = 0xff # put enties on top
00911     # set min/max based on current range
00912     success, lo, hi = self.getBackgroundScalarRange()
00913     if success:
00914       self.threshold.minimum, self.threshold.maximum = lo, hi
00915     self.frame.layout().addWidget(self.threshold)
00916     self.widgets.append(self.threshold)
00917 
00918     self.useForPainting = qt.QPushButton("Use For Paint", self.frame)
00919     self.useForPainting.setToolTip("Transfer the current threshold settings to be used for labeling operations such as Paint and Draw.")
00920     self.frame.layout().addWidget(self.useForPainting)
00921     self.widgets.append(self.useForPainting)
00922 
00923     self.apply = qt.QPushButton("Apply", self.frame)
00924     self.apply.setToolTip("Apply current threshold settings to the label map.")
00925     self.frame.layout().addWidget(self.apply)
00926     self.widgets.append(self.apply)
00927 
00928     self.timer = qt.QTimer()
00929     self.previewState = 0
00930     self.previewStep = 1
00931     self.previewSteps = 5
00932     self.timer.start(200)
00933 
00934     self.timer.connect('timeout()', self.preview)
00935     self.useForPainting.connect('clicked()', self.onUseForPainting)
00936     self.threshold.connect('valuesChanged(double,double)', self.onThresholdValuesChanged)
00937     self.apply.connect('clicked()', self.onApply)
00938 
00939     HelpButton(self.frame, "Set labels based on threshold range.  Note: this replaces the current label map values.")
00940 
00941     # Add vertical spacer
00942     self.frame.layout().addStretch(1)
00943 
00944   def destroy(self):
00945     self.timer.stop()
00946     tcl('foreach te [itcl::find objects -class ThresholdEffect] { $te preview "0 0 0 0" }')
00947     super(ThresholdOptions,self).destroy()
00948 
00949   # note: this method needs to be implemented exactly as-is
00950   # in each leaf subclass so that "self" in the observer
00951   # is of the correct type 
00952   def updateParameterNode(self, caller, event):
00953     nodeID = tcl('[EditorGetParameterNode] GetID')
00954     node = slicer.mrmlScene.GetNodeByID(nodeID)
00955     if node != self.parameterNode:
00956       if self.parameterNode:
00957         node.RemoveObserver(self.parameterNodeTag)
00958       self.parameterNode = node
00959       self.parameterNodeTag = node.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
00960 
00961   def setMRMLDefaults(self):
00962     super(ThresholdOptions,self).setMRMLDefaults()
00963     disableState = self.parameterNode.GetDisableModifiedEvent()
00964     self.parameterNode.SetDisableModifiedEvent(1)
00965     defaults = (
00966       ("min", "0"),
00967       ("max", "100"),
00968     )
00969     for d in defaults:
00970       param = "Threshold,"+d[0]
00971       pvalue = self.parameterNode.GetParameter(param)
00972       if pvalue == '':
00973         self.parameterNode.SetParameter(param, d[1])
00974     # override default min/max settings based on current background
00975     success, lo, hi = self.getBackgroundScalarRange()
00976     if success:
00977       self.parameterNode.SetParameter("Threshold,min", str(lo + 0.25 * (hi-lo)))
00978       self.parameterNode.SetParameter("Threshold,max", str(hi))
00979     self.parameterNode.SetDisableModifiedEvent(disableState)
00980 
00981   def onThresholdValuesChanged(self,min,max):
00982     self.updateMRMLFromGUI()
00983 
00984   def onUseForPainting(self):
00985     disableState = self.parameterNode.GetDisableModifiedEvent()
00986     self.parameterNode.SetDisableModifiedEvent(1)
00987     self.parameterNode.SetParameter( "Labeler,paintThreshold", "1" )
00988     self.parameterNode.SetParameter( "Labeler,paintThresholdMin", str(self.threshold.minimumValue) )
00989     self.parameterNode.SetParameter( "Labeler,paintThresholdMax", str(self.threshold.maximumValue) )
00990     self.parameterNode.SetDisableModifiedEvent(disableState)
00991     self.parameterNode.InvokePendingModifiedEvent()
00992 
00993   def updateGUIFromMRML(self,caller,event):
00994     params = ("min", "max")
00995     for p in params:
00996       if self.parameterNode.GetParameter("Threshold,"+p) == '':
00997         # don't update if the parameter node has not got all values yet
00998         return
00999     self.updatingGUI = True
01000     super(ThresholdOptions,self).updateGUIFromMRML(caller,event)
01001     min = self.parameterNode.GetParameter("Threshold,min")
01002     max = self.parameterNode.GetParameter("Threshold,max")
01003     self.threshold.setMinimumValue( int(float(min)) )
01004     self.threshold.setMaximumValue( int(float(max)) )
01005     tcl('foreach te [itcl::find objects -class ThresholdEffect] { $te configure -range "%s %s" }' % (min, max))
01006     self.updatingGUI = False
01007 
01008   def onApply(self):
01009     min = self.parameterNode.GetParameter("Threshold,min")
01010     max = self.parameterNode.GetParameter("Threshold,max")
01011     tcl('set effect [lindex [itcl::find objects -class ThresholdEffect] 0]; if { $effect != "" } { $effect configure -range "%s %s"; $effect apply }' % (min, max))
01012 
01013   def onMinSizeValueChanged(self,value):
01014     self.updateMRMLFromGUI()
01015 
01016   def updateMRMLFromGUI(self):
01017     if self.updatingGUI:
01018       return
01019     disableState = self.parameterNode.GetDisableModifiedEvent()
01020     self.parameterNode.SetDisableModifiedEvent(1)
01021     super(ThresholdOptions,self).updateMRMLFromGUI()
01022     self.parameterNode.SetParameter( "Threshold,min", str(self.threshold.minimumValue) )
01023     self.parameterNode.SetParameter( "Threshold,max", str(self.threshold.maximumValue) )
01024     self.parameterNode.SetDisableModifiedEvent(disableState)
01025     if not disableState:
01026       self.parameterNode.InvokePendingModifiedEvent()
01027 
01028   def preview(self):
01029     opacity = 0.5 + self.previewState / (2. * self.previewSteps)
01030     min = self.parameterNode.GetParameter("Threshold,min")
01031     max = self.parameterNode.GetParameter("Threshold,max")
01032     tcl('foreach te [itcl::find objects -class ThresholdEffect] { $te configure -range "%s %s" }' % (min, max))
01033     tcl('foreach te [itcl::find objects -class ThresholdEffect] { $te preview "%g %g %g %g" }' % (self.getPaintColor()[:3] + (opacity,)))
01034     self.previewState += self.previewStep
01035     if self.previewState >= self.previewSteps:
01036       self.previewStep = -1
01037     if self.previewState <= 0:
01038       self.previewStep = 1
01039 
01040 #### Morphology - intermediate class for erode and dilate
01041 class MorphologyOptions(EditOptions):
01042   """ Morphology-specfic gui
01043   TODO: it would be nice to have other kernels and closure operations
01044   TODO: it would be nice to support multiple iterations
01045   """
01046 
01047   def __init__(self, parent=0):
01048     super(MorphologyOptions,self).__init__(parent)
01049 
01050   def __del__(self):
01051     super(MorphologyOptions,self).__del__()
01052 
01053   def create(self):
01054     super(MorphologyOptions,self).create()
01055     # TODO: provide an entry for label to replace with (defaults to zero)
01056     self.eightNeighbors = qt.QRadioButton("Eight Neighbors", self.frame)
01057     self.eightNeighbors.setToolTip("Treat diagonally adjacent voxels as neighbors.")
01058     self.frame.layout().addWidget(self.eightNeighbors)
01059     self.widgets.append(self.eightNeighbors)
01060     self.fourNeighbors = qt.QRadioButton("Four Neighbors", self.frame)
01061     self.fourNeighbors.setToolTip("Do not treat diagonally adjacent voxels as neighbors.")
01062     self.frame.layout().addWidget(self.fourNeighbors)
01063     self.widgets.append(self.fourNeighbors)
01064 
01065     self.eightNeighbors.connect('clicked()', self.updateMRMLFromGUI)
01066     self.fourNeighbors.connect('clicked()', self.updateMRMLFromGUI)
01067 
01068   def destroy(self):
01069     super(MorphologyOptions,self).destroy()
01070 
01071   def setMRMLDefaults(self):
01072     super(MorphologyOptions,self).setMRMLDefaults()
01073     disableState = self.parameterNode.GetDisableModifiedEvent()
01074     self.parameterNode.SetDisableModifiedEvent(1)
01075     defaults = (
01076       ("iterations", "1"),
01077       ("neighborMode", "4"),
01078       ("fill", "0"),
01079     )
01080     for d in defaults:
01081       param = "Morphology,"+d[0]
01082       pvalue = self.parameterNode.GetParameter(param)
01083       if pvalue == '':
01084         self.parameterNode.SetParameter(param, d[1])
01085     self.parameterNode.SetDisableModifiedEvent(disableState)
01086 
01087   def updateGUIFromMRML(self,caller,event):
01088     params = ("neighborMode", "iterations", "fill")
01089     for p in params:
01090       if self.parameterNode.GetParameter("Morphology,"+p) == '':
01091         # don't update if the parameter node has not got all values yet
01092         return
01093     self.updatingGUI = True
01094     super(MorphologyOptions,self).updateGUIFromMRML(caller,event)
01095     eightMode = (self.parameterNode.GetParameter("Morphology,neighborMode") == "8")
01096     self.eightNeighbors.setChecked(eightMode)
01097     self.fourNeighbors.setChecked(not eightMode)
01098     self.updatingGUI = False
01099 
01100   def updateMRMLFromGUI(self):
01101     if self.updatingGUI:
01102       return
01103     disableState = self.parameterNode.GetDisableModifiedEvent()
01104     self.parameterNode.SetDisableModifiedEvent(1)
01105     super(MorphologyOptions,self).updateMRMLFromGUI()
01106     if self.eightNeighbors.checked:
01107       self.parameterNode.SetParameter( "Morphology,neighborMode", "8" )
01108     else:
01109       self.parameterNode.SetParameter( "Morphology,neighborMode", "4" )
01110     self.parameterNode.SetDisableModifiedEvent(disableState)
01111     if not disableState:
01112       self.parameterNode.InvokePendingModifiedEvent()
01113 
01114 
01115 #### ErodeLabel
01116 class ErodeLabelOptions(MorphologyOptions):
01117   """ ErodeLabel-specfic gui
01118   """
01119 
01120   def __init__(self, parent=0):
01121     super(ErodeLabelOptions,self).__init__(parent)
01122 
01123   def __del__(self):
01124     super(ErodeLabelOptions,self).__del__()
01125 
01126   def create(self):
01127     super(ErodeLabelOptions,self).create()
01128     self.apply = qt.QPushButton("Apply", self.frame)
01129     self.apply.setToolTip("Erode current label")
01130     self.frame.layout().addWidget(self.apply)
01131     self.widgets.append(self.apply)
01132 
01133     HelpButton(self.frame, "Use this tool to remove pixels from the boundary of the current label.")
01134 
01135     self.apply.connect('clicked()', self.onApply)
01136 
01137     # Add vertical spacer
01138     self.frame.layout().addStretch(1)
01139 
01140   def destroy(self):
01141     super(ErodeLabelOptions,self).destroy()
01142 
01143   # note: this method needs to be implemented exactly as-is
01144   # in each leaf subclass so that "self" in the observer
01145   # is of the correct type 
01146   def updateParameterNode(self, caller, event):
01147     nodeID = tcl('[EditorGetParameterNode] GetID')
01148     node = slicer.mrmlScene.GetNodeByID(nodeID)
01149     if node != self.parameterNode:
01150       if self.parameterNode:
01151         node.RemoveObserver(self.parameterNodeTag)
01152       self.parameterNode = node
01153       self.parameterNodeTag = node.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
01154 
01155 
01156   def setMRMLDefaults(self):
01157     super(ErodeLabelOptions,self).setMRMLDefaults()
01158 
01159   def onApply(self):
01160     tcl('set effect [lindex [itcl::find objects -class ErodeLabelEffect] 0]; if { $effect != "" } { $effect apply }')
01161 
01162   def updateGUIFromMRML(self,caller,event):
01163     self.updatingGUI = True
01164     super(ErodeLabelOptions,self).updateGUIFromMRML(caller,event)
01165     self.updatingGUI = False
01166 
01167   def updateMRMLFromGUI(self):
01168     if self.updatingGUI:
01169       return
01170     disableState = self.parameterNode.GetDisableModifiedEvent()
01171     self.parameterNode.SetDisableModifiedEvent(1)
01172     super(ErodeLabelOptions,self).updateMRMLFromGUI()
01173     self.parameterNode.SetDisableModifiedEvent(disableState)
01174     if not disableState:
01175       self.parameterNode.InvokePendingModifiedEvent()
01176 
01177 #### DilateLabel
01178 class DilateLabelOptions(MorphologyOptions):
01179   """ DilateLabel-specfic gui
01180   """
01181 
01182   def __init__(self, parent=0):
01183     super(DilateLabelOptions,self).__init__(parent)
01184 
01185   def __del__(self):
01186     super(DilateLabelOptions,self).__del__()
01187 
01188   def create(self):
01189     super(DilateLabelOptions,self).create()
01190     self.apply = qt.QPushButton("Apply", self.frame)
01191     self.apply.setToolTip("Dilate current label")
01192     self.frame.layout().addWidget(self.apply)
01193     self.widgets.append(self.apply)
01194 
01195     HelpButton(self.frame, "Use this tool to add pixels to the boundary of the current label.")
01196 
01197     self.apply.connect('clicked()', self.onApply)
01198 
01199     # Add vertical spacer
01200     self.frame.layout().addStretch(1)
01201 
01202   def destroy(self):
01203     super(DilateLabelOptions,self).destroy()
01204 
01205   # note: this method needs to be implemented exactly as-is
01206   # in each leaf subclass so that "self" in the observer
01207   # is of the correct type 
01208   def updateParameterNode(self, caller, event):
01209     nodeID = tcl('[EditorGetParameterNode] GetID')
01210     node = slicer.mrmlScene.GetNodeByID(nodeID)
01211     if node != self.parameterNode:
01212       if self.parameterNode:
01213         node.RemoveObserver(self.parameterNodeTag)
01214       self.parameterNode = node
01215       self.parameterNodeTag = node.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
01216 
01217   def setMRMLDefaults(self):
01218     super(DilateLabelOptions,self).setMRMLDefaults()
01219 
01220   def onApply(self):
01221     tcl('set effect [lindex [itcl::find objects -class DilateLabelEffect] 0]; if { $effect != "" } { $effect apply }')
01222 
01223   def updateGUIFromMRML(self,caller,event):
01224     self.updatingGUI = True
01225     super(DilateLabelOptions,self).updateGUIFromMRML(caller,event)
01226     self.updatingGUI = False
01227 
01228   def updateMRMLFromGUI(self):
01229     if self.updatingGUI:
01230       return
01231     disableState = self.parameterNode.GetDisableModifiedEvent()
01232     self.parameterNode.SetDisableModifiedEvent(1)
01233     super(DilateLabelOptions,self).updateMRMLFromGUI()
01234     self.parameterNode.SetDisableModifiedEvent(disableState)
01235     if not disableState:
01236       self.parameterNode.InvokePendingModifiedEvent()
01237 
01238 #### ChangeLabel
01239 class ChangeLabelOptions(EditOptions):
01240   """ ChangeLabel-specfic gui
01241   """
01242 
01243   def __init__(self, parent=0):
01244     super(ChangeLabelOptions,self).__init__(parent)
01245 
01246   def __del__(self):
01247     super(ChangeLabelOptions,self).__del__()
01248 
01249   def create(self):
01250     super(ChangeLabelOptions,self).create()
01251 
01252     self.inputColor = EditColor.EditColor(self.frame,'ChangeLabel,inputColor')
01253     self.inputColor.label.setText("Input Color:")
01254     self.inputColor.colorSpin.setValue(0)
01255     self.inputColor.colorSpin.setToolTip("Set the color to replace.")
01256 
01257     self.outputColor = EditColor.EditColor(self.frame,'ChangeLabel,outputColor')
01258     self.outputColor.label.setText("Input Color:")
01259     self.outputColor.colorSpin.setValue(1)
01260     self.outputColor.colorSpin.setToolTip("Set the new label value")
01261 
01262     self.apply = qt.QPushButton("Apply", self.frame)
01263     self.apply.setToolTip("Apply current threshold settings to the label map.")
01264     self.frame.layout().addWidget(self.apply)
01265     self.widgets.append(self.apply)
01266 
01267     HelpButton(self.frame, "Replace all instances of input color with output color in current label map")
01268 
01269     self.inputColor.colorSpin.connect('valueChanged()', self.onColorChanged)
01270     self.outputColor.colorSpin.connect('valueChanged()', self.onColorChanged)
01271     self.apply.connect('clicked()', self.onApply)
01272 
01273     # Add vertical spacer
01274     self.frame.layout().addStretch(1)
01275 
01276   def destroy(self):
01277     super(ChangeLabelOptions,self).destroy()
01278 
01279   # note: this method needs to be implemented exactly as-is
01280   # in each leaf subclass so that "self" in the observer
01281   # is of the correct type 
01282   def updateParameterNode(self, caller, event):
01283     nodeID = tcl('[EditorGetParameterNode] GetID')
01284     node = slicer.mrmlScene.GetNodeByID(nodeID)
01285     if node != self.parameterNode:
01286       if self.parameterNode:
01287         node.RemoveObserver(self.parameterNodeTag)
01288       self.parameterNode = node
01289       self.parameterNodeTag = node.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
01290 
01291   def setMRMLDefaults(self):
01292     super(ChangeLabelOptions,self).setMRMLDefaults()
01293     disableState = self.parameterNode.GetDisableModifiedEvent()
01294     self.parameterNode.SetDisableModifiedEvent(1)
01295     defaults = (
01296       ("inputColor", "0"),
01297       ("outputColor", "1"),
01298     )
01299     for d in defaults:
01300       param = "ChangeLabel,"+d[0]
01301       pvalue = self.parameterNode.GetParameter(param)
01302       if pvalue == '':
01303         self.parameterNode.SetParameter(param, d[1])
01304     self.parameterNode.SetDisableModifiedEvent(disableState)
01305 
01306   def onColorChanged(self,value):
01307     self.updateMRMLFromGUI()
01308 
01309   def updateGUIFromMRML(self,caller,event):
01310     params = ("inputColor", "outputColor")
01311     for p in params:
01312       if self.parameterNode.GetParameter("ChangeLabel,"+p) == '':
01313         # don't update if the parameter node has not got all values yet
01314         return
01315     self.updatingGUI = True
01316     super(ChangeLabelOptions,self).updateGUIFromMRML(caller,event)
01317     self.inputColor.colorSpin.setValue( int(self.parameterNode.GetParameter("ChangeLabel,inputColor")) )
01318     self.outputColor.colorSpin.setValue( int(self.parameterNode.GetParameter("ChangeLabel,outputColor")) )
01319     self.updatingGUI = False
01320 
01321   def onApply(self):
01322     inputColor = int(self.parameterNode.GetParameter("ChangeLabel,inputColor"))
01323     outputColor = int(self.parameterNode.GetParameter("ChangeLabel,outputColor"))
01324     tcl('set effect [lindex [itcl::find objects -class ChangeLabelEffect] 0]; if { $effect != "" } { $effect apply }')
01325 
01326   def updateMRMLFromGUI(self):
01327     if self.updatingGUI:
01328       return
01329     disableState = self.parameterNode.GetDisableModifiedEvent()
01330     self.parameterNode.SetDisableModifiedEvent(1)
01331     super(ChangeLabelOptions,self).updateMRMLFromGUI()
01332     self.parameterNode.SetParameter( "ChangeLabel,inputColor", str(self.inputColor.colorSpin.value) )
01333     self.parameterNode.SetParameter( "ChangeLabel,outputColor", str(self.outputColor.colorSpin.value) )
01334     self.parameterNode.SetDisableModifiedEvent(disableState)
01335     if not disableState:
01336       self.parameterNode.InvokePendingModifiedEvent()
01337 
01338 #### MakeModel
01339 class MakeModelOptions(EditOptions):
01340   """ MakeModel-specfic gui
01341   """
01342 
01343   def __init__(self, parent=0):
01344     self.CLINode = None
01345     super(MakeModelOptions,self).__init__(parent)
01346 
01347   def __del__(self):
01348     super(MakeModelOptions,self).__del__()
01349 
01350   def create(self):
01351     super(MakeModelOptions,self).create()
01352 
01353     self.goToModelMaker = qt.QPushButton("Go To Model Maker", self.frame)
01354     self.goToModelMaker.setToolTip( "The Model Maker interface contains a whole range of options for building sets of models and controlling the parameters." )
01355     self.frame.layout().addWidget(self.goToModelMaker)
01356     self.widgets.append(self.goToModelMaker)
01357 
01358     self.smooth = qt.QCheckBox("Smooth Model", self.frame)
01359     self.smooth.checked = True
01360     self.smooth.setToolTip("When smoothed, the model will look better, but some details of the label map will not be visible on the model.  When not smoothed you will see individual voxel boundaries in the model.  Smoothing here corresponds to Decimation of 0.25 and Smooting iterations of 10.")
01361     self.frame.layout().addWidget(self.smooth)
01362     self.widgets.append(self.smooth)
01363 
01364     #
01365     # model name
01366     #
01367     self.nameFrame = qt.QFrame(self.frame)
01368     self.nameFrame.setLayout(qt.QHBoxLayout())
01369     self.frame.layout().addWidget(self.nameFrame)
01370     self.widgets.append(self.nameFrame)
01371 
01372     self.modelNameLabel = qt.QLabel("Model Name: ", self.nameFrame)
01373     self.modelNameLabel.setToolTip( "Select the name for the newly created model." )
01374     self.nameFrame.layout().addWidget(self.modelNameLabel)
01375     self.widgets.append(self.modelNameLabel)
01376 
01377     self.modelName = qt.QLineEdit(self.nameFrame)
01378     self.modelName.setText( self.getUniqueModelName( self.getPaintName() ) )
01379     self.nameFrame.layout().addWidget(self.modelName)
01380     self.widgets.append(self.modelName)
01381 
01382     self.apply = qt.QPushButton("Apply", self.frame)
01383     self.apply.setToolTip("Build a model for the current label value of the label map being edited in the Red slice window.  Model will be created in the background." )
01384     self.frame.layout().addWidget(self.apply)
01385     self.widgets.append(self.apply)
01386 
01387     HelpButton(self.frame, "Use this tool build a model.  A subset of model building options is provided here.  Go to the Model Maker module to expose a range of parameters.  Use Merge and Build button in the Advanced... tab to quickly make a model of all defined structures in the merge label map.")
01388 
01389     # Add vertical spacer
01390     self.frame.layout().addStretch(1)
01391 
01392     self.apply.connect('clicked()', self.onApply)
01393     self.goToModelMaker.connect('clicked()', self.onGoToModelMaker)
01394 
01395   def onGoToModelMaker(self):
01396     m = slicer.util.mainWindow()
01397     m.moduleSelector().selectModuleByTitle('Model Maker')
01398 
01399   def onApply(self):
01400     #
01401     # create a model using the command line module
01402     # based on the current editor parameters
01403     #
01404 
01405     volumeNode = self.editUtil.getLabelVolume()
01406     if not volumeNode:
01407       return
01408 
01409     #
01410     # set up the model maker node
01411     #
01412 
01413     parameters = {}
01414     parameters['Name'] = self.modelName.text
01415     parameters["InputVolume"] = volumeNode.GetID()
01416     parameters['FilterType'] = "Sinc"
01417 
01418     # build only the currently selected model.
01419     parameters['Labels'] = self.getPaintLabel()
01420     parameters["StartLabel"] = -1
01421     parameters["EndLabel"] = -1
01422     
01423     parameters['GenerateAll'] = False
01424     parameters["JointSmoothing"] = False
01425     parameters["SplitNormals"] = True
01426     parameters["PointNormals"] = True
01427     parameters["SkipUnNamed"] = True
01428 
01429     if self.smooth.checked:
01430       parameters["Decimate"] = 0.25
01431       parameters["Smooth"] = 10
01432     else:
01433       parameters["Decimate"] = 0
01434       parameters["Smooth"] = 0
01435 
01436     #
01437     # output 
01438     # - make a new hierarchy node if needed
01439     #
01440     numNodes = slicer.mrmlScene.GetNumberOfNodesByClass( "vtkMRMLModelHierarchyNode" )
01441     outHierarchy = None
01442     for n in xrange(numNodes):
01443       node = slicer.mrmlScene.GetNthNodeByClass( n, "vtkMRMLModelHierarchyNode" )
01444       if node.GetName() == "Editor Models":
01445         outHierarchy = node
01446         break
01447 
01448     if not outHierarchy:
01449       outHierarchy = slicer.vtkMRMLModelHierarchyNode()
01450       outHierarchy.SetScene( slicer.mrmlScene )
01451       outHierarchy.SetName( "Editor Models" )
01452       slicer.mrmlScene.AddNode( outHierarchy )
01453 
01454     parameters["ModelSceneFile"] = outHierarchy
01455 
01456     modelMaker = slicer.modules.modelmaker
01457 
01458     # 
01459     # run the task (in the background)
01460     # - use the GUI to provide progress feedback
01461     # - use the GUI's Logic to invoke the task
01462     # - model will show up when the processing is finished
01463     #
01464     self.CLINode = slicer.cli.run(modelMaker, self.CLINode, parameters)
01465 
01466     self.statusText( "Model Making Started..." )
01467 
01468   def getUniqueModelName(self, baseName):
01469       names = getNodes().keys()
01470       name = baseName
01471       index = 0
01472       while names.__contains__(name):
01473         index += 1
01474         name = "%s %d" % (baseName, index)
01475       return name
01476 
01477   def destroy(self):
01478     super(MakeModelOptions,self).destroy()
01479 
01480   # note: this method needs to be implemented exactly as-is
01481   # in each leaf subclass so that "self" in the observer
01482   # is of the correct type 
01483   def updateParameterNode(self, caller, event):
01484     nodeID = tcl('[EditorGetParameterNode] GetID')
01485     node = slicer.mrmlScene.GetNodeByID(nodeID)
01486     if node != self.parameterNode:
01487       if self.parameterNode:
01488         node.RemoveObserver(self.parameterNodeTag)
01489       self.parameterNode = node
01490       self.parameterNodeTag = node.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
01491 
01492   def setMRMLDefaults(self):
01493     super(MakeModelOptions,self).setMRMLDefaults()
01494 
01495   def updateGUIFromMRML(self,caller,event):
01496     self.updatingGUI = True
01497     super(MakeModelOptions,self).updateGUIFromMRML(caller,event)
01498     self.updatingGUI = False
01499 
01500   def updateMRMLFromGUI(self):
01501     if self.updatingGUI:
01502       return
01503     disableState = self.parameterNode.GetDisableModifiedEvent()
01504     self.parameterNode.SetDisableModifiedEvent(1)
01505     super(MakeModelOptions,self).updateMRMLFromGUI()
01506     if not disableState:
01507       self.parameterNode.InvokePendingModifiedEvent()
01508 
01509 #### GrowCutSegment
01510 class GrowCutSegmentOptions(EditOptions):
01511   """ GrowCutSegment-specfic gui
01512   """
01513 
01514   def __init__(self, parent=0):
01515     super(GrowCutSegmentOptions,self).__init__(parent)
01516 
01517   def __del__(self):
01518     super(GrowCutSegmentOptions,self).__del__()
01519 
01520   def create(self):
01521     super(GrowCutSegmentOptions,self).create()
01522     self.applyFrame = qt.QFrame(self.frame)
01523     self.applyFrame.setLayout(qt.QHBoxLayout())
01524     self.frame.layout().addWidget(self.applyFrame)
01525     self.widgets.append(self.applyFrame)
01526     
01527     self.radiusFrame = qt.QFrame(self.frame)
01528     self.radiusFrame.setLayout(qt.QHBoxLayout())
01529     self.frame.layout().addWidget(self.radiusFrame)
01530     self.widgets.append(self.radiusFrame)
01531     self.radiusLabel = qt.QLabel("Radius:", self.radiusFrame)
01532     self.radiusLabel.setToolTip("Set the radius of the paint brush in millimeters")
01533     self.radiusFrame.layout().addWidget(self.radiusLabel)
01534     self.widgets.append(self.radiusLabel)
01535     self.radiusSpinBox = qt.QDoubleSpinBox(self.radiusFrame)
01536     self.radiusSpinBox.setToolTip("Set the radius of the paint brush in millimeters")
01537     self.radiusSpinBox.minimum = 0.01
01538     self.radiusSpinBox.maximum = 100
01539     self.radiusSpinBox.suffix = "mm"
01540     self.radiusFrame.layout().addWidget(self.radiusSpinBox)
01541     self.widgets.append(self.radiusSpinBox)
01542     
01543     self.radius = ctk.ctkDoubleSlider(self.frame)
01544     self.radius.minimum = 0.01
01545     self.radius.maximum = 100
01546     self.radius.orientation = 1
01547     self.radius.singleStep = 0.01
01548     self.frame.layout().addWidget(self.radius)
01549     self.widgets.append(self.radius)
01550 
01551     self.smudge = qt.QCheckBox("Smudge", self.frame)
01552     self.smudge.setToolTip("Set the label number automatically by sampling the pixel location where the brush stroke starts.")
01553     self.frame.layout().addWidget(self.smudge)
01554     self.widgets.append(self.smudge)
01555 
01556     self.smudge.connect('clicked()', self.updateMRMLFromGUI)
01557     self.radius.connect('valueChanged(double)', self.onRadiusValueChanged)
01558     self.radiusSpinBox.connect('valueChanged(double)', self.onRadiusSpinBoxChanged)
01559 
01560     self.radius1 = qt.QPushButton("1", self.frame)
01561     self.radius1.setToolTip("Set radius to 1")
01562     self.radius1.setGeometry(80,79,20,20)
01563     #self.frame.layout().addWidget(self.radius1)
01564     self.widgets.append(self.radius1)
01565 
01566     self.radius2 = qt.QPushButton("2", self.frame)
01567     self.radius2.setToolTip("Set radius to 2")
01568     self.radius2.setGeometry(102,79,20,20)
01569     #self.frame.layout().addWidget(self.radius2)
01570     self.widgets.append(self.radius2)
01571 
01572     self.radius3 = qt.QPushButton("3", self.frame)
01573     self.radius3.setToolTip("Set radius to 3")
01574     self.radius3.setGeometry(122,79,20,20)
01575     #self.frame.layout().addWidget(self.radius3)
01576     self.widgets.append(self.radius3)
01577 
01578     self.radius4 = qt.QPushButton("4", self.frame)
01579     self.radius4.setToolTip("Set radius to 4")
01580     self.radius4.setGeometry(142,79,20,20)
01581    # self.frame.layout().addWidget(self.radius4)
01582     self.widgets.append(self.radius4)
01583 
01584     self.radius5 = qt.QPushButton("5", self.frame)
01585     self.radius5.setToolTip("Set radius to 5")
01586     self.radius5.setGeometry(162,79,20,20)
01587    # self.frame.layout().addWidget(self.radius5)
01588     self.widgets.append(self.radius5)
01589 
01590     self.apply = qt.QPushButton("Apply", self.frame)
01591     self.apply.setToolTip("Apply to run segmentation.\nUse the 'a' or 'Enter' hotkey to apply in slice window")
01592     self.frame.layout().addWidget(self.apply)
01593     self.widgets.append(self.apply)
01594 
01595     HelpButton(self.frame, "Use this tool to apply grow cut segmentation.\n\n Select different label colors and paint on foreground and background or as many different classes as you want. \n But to run segmentation correctly, you need to supply a minimum or two class labels.")
01596 
01597     self.radius1.connect('clicked()', self.onRadius1)
01598     self.radius2.connect('clicked()', self.onRadius2)
01599     self.radius3.connect('clicked()', self.onRadius3)
01600     self.radius4.connect('clicked()', self.onRadius4)
01601     self.radius5.connect('clicked()', self.onRadius5)
01602 
01603     self.apply.connect('clicked()', self.onApply)
01604 
01605     # Add vertical spacer
01606     self.frame.layout().addStretch(1)
01607 
01608   def onRadius1(self):
01609     tcl('set effect [lindex [itcl::find objects -class GrowCutSegmentEffect] 0]; if { $effect != "" } { $effect updateRadius1 }')
01610 
01611   def onRadius2(self):
01612     tcl('set effect [lindex [itcl::find objects -class GrowCutSegmentEffect] 0]; if { $effect != "" } { $effect updateRadius2 }')
01613 
01614   def onRadius3(self):
01615     tcl('set effect [lindex [itcl::find objects -class GrowCutSegmentEffect] 0]; if { $effect != "" } { $effect updateRadius3 }')
01616 
01617   def onRadius4(self):
01618     tcl('set effect [lindex [itcl::find objects -class GrowCutSegmentEffect] 0]; if { $effect != "" } { $effect updateRadius4 }')
01619 
01620   def onRadius5(self):
01621     tcl('set effect [lindex [itcl::find objects -class GrowCutSegmentEffect] 0]; if { $effect != "" } { $effect updateRadius5 }')
01622 
01623 
01624   def onApply(self):
01625     tcl('set effect [lindex [itcl::find objects -class GrowCutSegmentEffect] 0]; if { $effect != "" } { $effect apply }')
01626     #tcl('::GrowCutSegmentEffect::apply')
01627     
01628   def destroy(self):
01629     super(GrowCutSegmentOptions,self).destroy()
01630 
01631   # note: this method needs to be implemented exactly as-is
01632   # in each leaf subclass so that "self" in the observer
01633   # is of the correct type 
01634   def updateParameterNode(self, caller, event):
01635     nodeID = tcl('[EditorGetParameterNode] GetID')
01636     node = slicer.mrmlScene.GetNodeByID(nodeID)
01637     if node != self.parameterNode:
01638       if self.parameterNode:
01639         node.RemoveObserver(self.parameterNodeTag)
01640       self.parameterNode = node
01641       self.parameterNodeTag = node.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
01642 
01643   def setMRMLDefaults(self):
01644     super(GrowCutSegmentOptions,self).setMRMLDefaults()
01645     disableState = self.parameterNode.GetDisableModifiedEvent()
01646     self.parameterNode.SetDisableModifiedEvent(1)
01647     paintdefaults = (
01648       ("radius", "3"),
01649       ("smudge", "0")
01650     )
01651     growcutdefaults = (
01652       ("contrastNoiseRatio", "0.8"),
01653       ("priorStrength", "0.0003"),
01654       ("segmented", "2")
01655     )
01656     for d in paintdefaults:
01657       param = "Paint,"+d[0]
01658       pvalue = self.parameterNode.GetParameter(param)
01659       print pvalue
01660       if pvalue == '':
01661         self.parameterNode.SetParameter(param, d[1])
01662     for d in growcutdefaults:
01663        param = "GrowCutSegment,"+d[0]
01664        pvalue = self.parameterNode.GetParameter(param)
01665        if pvalue == '':
01666           self.parameterNode.SetParameter(param, d[1])
01667           
01668     self.parameterNode.SetDisableModifiedEvent(disableState)
01669 
01670   def updateGUIFromMRML(self,caller,event):
01671     if self.updatingGUI:
01672       return
01673     paintparams = ("radius", "smudge")
01674     for p in paintparams:
01675       if self.parameterNode.GetParameter("Paint,"+p) == '':
01676         # don't update if the parameter node has not got all values yet
01677         return
01678  
01679     self.updatingGUI = True
01680     super(GrowCutSegmentOptions,self).updateGUIFromMRML(caller,event)
01681     self.smudge.setChecked( int(self.parameterNode.GetParameter("Paint,smudge")) )
01682     self.radius.setValue( float(self.parameterNode.GetParameter("Paint,radius")) )
01683     self.radiusSpinBox.setValue( float(self.parameterNode.GetParameter("Paint,radius")) )
01684     self.updatingGUI = False
01685 
01686   def onRadiusValueChanged(self,value):
01687     if self.updatingGUI:
01688       return
01689     self.updatingGUI = True
01690     self.radiusSpinBox.setValue(self.radius.value)
01691     self.updatingGUI = False
01692     self.updateMRMLFromGUI()
01693 
01694   def onRadiusSpinBoxChanged(self,value):
01695     if self.updatingGUI:
01696       return
01697     self.updatingGUI = True
01698     self.radius.setValue(self.radiusSpinBox.value)
01699     self.updatingGUI = False
01700     self.updateMRMLFromGUI()
01701 
01702   def updateMRMLFromGUI(self):
01703     if self.updatingGUI:
01704       return
01705     disableState = self.parameterNode.GetDisableModifiedEvent()
01706     self.parameterNode.SetDisableModifiedEvent(1)
01707     super(GrowCutSegmentOptions,self).updateMRMLFromGUI()
01708     if self.smudge.checked:
01709       self.parameterNode.SetParameter( "Paint,smudge", "1" )
01710     else:
01711       self.parameterNode.SetParameter( "Paint,smudge", "0" )
01712     self.parameterNode.SetParameter( "Paint,radius", str(self.radius.value) )
01713     self.parameterNode.SetDisableModifiedEvent(disableState)
01714     if not disableState:
01715       self.parameterNode.InvokePendingModifiedEvent()
01716 
01717 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines