|
Slicer 4.2
Slicer is a multi-platform, free and open source software package for visualization and medical image computing
|
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
1.7.4