def onReload(self): EditUtil.EditUtil().setCurrentEffect("DefaultTool") import Isobrush # TODO: this causes a flash of the new widget, but not a big deal since it's only devel mode w = Isobrush.IsobrushWidget() w.onReload() del (w.parent) EditUtil.EditUtil().setCurrentEffect("Isobrush")
def updateParam(self, p, v): r = self.structuresView.currentIndex().row() if (r > -1): ei = slicer.modules.SlicerPathologyWidget.editorWidget.helper.structures.item( r, 3).text() else: ei = EditUtil.EditUtil().getParameterNode().GetParameter( 'SlicerPathology,tilename') + '-label' if ei not in params: params[ei] = cparams.copy() if (r < 0): params[ei][ 'label'] = slicer.modules.SlicerPathologyWidget.editorWidget.helper.editUtil.getLabelName( ) else: params[ei][ 'label'] = slicer.modules.SlicerPathologyWidget.editorWidget.helper.structures.item( r, 2).text() params[ei][p] = v cparams[p] = v jstr = json.dumps(params, sort_keys=True, indent=4, separators=(',', ': ')) self.parameterNode.SetParameter("QuickTCGAEffect,erich", jstr)
def updateParameterNode(self, caller, event): node = EditUtil.EditUtil().getParameterNode() if node != self.parameterNode: if self.parameterNode: node.RemoveObserver(self.parameterNodeTag) self.parameterNode = node self.parameterNodeTag = node.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
def updateSliders(self): r = self.structuresView.currentIndex().row() if (r > -1): ei = slicer.modules.SlicerPathologyWidget.editorWidget.helper.structures.item( r, 3).text() else: ei = EditUtil.EditUtil().getParameterNode().GetParameter( 'SlicerPathology,tilename') + '-label' if ei not in params: params[ei] = cparams.copy() if (r < 0): params[ei][ 'label'] = slicer.modules.SlicerPathologyWidget.editorWidget.helper.editUtil.getLabelName( ) else: params[ei][ 'label'] = slicer.modules.SlicerPathologyWidget.editorWidget.helper.structures.item( r, 2).text() jstr = json.dumps(params, sort_keys=True, indent=4, separators=(',', ': ')) self.parameterNode.SetParameter("QuickTCGAEffect,erich", jstr) self.frameOtsuSlider.value = params[ei]["otsuRatio"] self.frameCurvatureWeightSlider.value = params[ei]["curvatureWeight"] self.frameSizeThldSlider.value = params[ei]["sizeThld"] self.frameSizeUpperThldSlider.value = params[ei]["sizeUpperThld"] self.frameMPPSlider.value = params[ei]["mpp"]
def setDefaultParams(self): """Configure here all the required params for any LabelEffect (Paint, Draw, ect.)""" self.editUtil = EditUtil.EditUtil() self.parameterNode = self.editUtil.getParameterNode() self.parameterNode.SetParameter("LabelEffect,paintOver", "1") # Enable paintOver self.parameterNode.SetParameter("LabelEffect,paintThreshold", "0") # Enable Threshold checkbox
def step(self, iterations=1): if self.pendingEvent: if self.pendingEvent.command_execution_status == 0: # TODO: is there an attribute for CL_COMPLETE? # TODO: also catch error codes here # # put data back in node # self.steeredArray[:] = self.labelNext_dev.get() self.steeredNode.GetImageData().Modified() self.steeredNode.Modified() else: return # # get the parameters from MRML # # TODO: handl any real growcut parameters node = EditUtil.EditUtil().getParameterNode() # # initialize candidates if needed # if not self.candidatesInitialized: self.clProgram.clearShort( self.clQueue, self.shape, None, self.candidatesNext_dev.data).wait() print("self.candidatesNext_dev mean ", self.candidatesNext_dev.get().mean()) self.clProgram.initialCandidates( self.clQueue, self.shape, None, self.labelArray_dev.data, self.candidates_dev.data).wait() print("self.labelArray_dev mean ", self.labelArray_dev.get().mean()) print("self.candidates_dev mean ", self.candidates_dev.get().mean()) self.candidatesInitialized = True # # run iterations # - save the pending event from the last call so that we can # know when the execution is finished (so the main event loop # is not blocked on this execution) # for iteration in xrange(iterations): self.clProgram.growCut(self.clQueue, self.work_size, None, self.backgroundArray_dev.data, self.labelArray_dev.data, self.theta_dev.data, self.thetaNext_dev.data, self.labelNext_dev.data, self.candidates_dev.data, self.candidatesNext_dev.data, self.backgroundArrayMax, global_offset=self.work_offset) self.clProgram.copyShort(self.clQueue, self.work_size, None, self.labelNext_dev.data, self.labelArray_dev.data, global_offset=self.work_offset) self.clProgram.copyShort(self.clQueue, self.work_size, None, self.candidatesNext_dev.data, self.candidates_dev.data, global_offset=self.work_offset) self.clProgram.clearShort(self.clQueue, self.work_size, None, self.candidatesNext_dev.data, global_offset=self.work_offset) self.pendingEvent = self.clProgram.copyFloat(self.clQueue, self.work_size, None, self.thetaNext_dev.data, self.theta_dev.data, global_offset=self.work_offset)
def __init__(self,options,preferredDeviceType='GPU'): self.preferredDeviceType = preferredDeviceType self.editUtil = EditUtil.EditUtil() self.sliceWidget = options.tools[0].sliceWidget if hasattr(slicer.modules, 'editorBot'): slicer.modules.editorBot.active = False del(slicer.modules.editorBot) slicer.modules.editorBot = self self.interval = 100 self.active = False self.start()
def apply(self, xy, mode=0, forced_path=None, forced_point=None): # # get the parameters from MRML # # For sanity purposes, tool can always "paint" over existing labels. If we find some foreseeable reason why we might # not want this in all cases, we can re-add to the GUI. # # get the label and background volume nodes # labelLogic = self.sliceLogic.GetLabelLayer() labelNode = labelLogic.GetVolumeNode() backgroundLogic = self.sliceLogic.GetBackgroundLayer() backgroundNode = backgroundLogic.GetVolumeNode() ##### self.errorMessageFrame.textCursor().insertHtml('Error Detected!') ##### self.errorMessageFrame.setStyleSheet("QTextEdit {color:red}") # # get the ijk location of the clicked point # by projecting through patient space back into index # space of the volume. Result is sub-pixel, so round it # (note: bg and lb will be the same for volumes created # by the editor, but can be different if the use selected # different bg nodes, but that is not handled here). # xyToIJK = labelLogic.GetXYToIJKTransform() ijkFloat = xyToIJK.TransformDoublePoint(xy + (0, )) ijk = [] for element in ijkFloat: try: intElement = int(round(element)) except ValueError: intElement = 0 ijk.append(intElement) ijk.reverse() ijk = tuple(ijk) ### IJK ACTIVE HERE # # Get the numpy array for the bg and label # node = EditUtil.EditUtil().getParameterNode() offset = float(node.GetParameter("TraceAndSelect,offsetvalue")) if offset != 0 and mode == 0: self.progress = qt.QProgressDialog() self.progress.setLabelText("Processing Slices...") self.progress.setCancelButtonText("Abort Fill") self.progress.setMinimum(0) self.progress.setMaximum(abs(offset)) self.progress.setAutoClose(1) self.progress.open() return self.fill(ijk, [], mode, forced_path, forced_point)
def __init__(self, options): self.editUtil = EditUtil.EditUtil() #self.sliceWidget = options.tools[0].sliceWidget self.sliceWidget = slicer.app.layoutManager().sliceWidget('Red') if hasattr(slicer.modules, 'TCGAEditorBot'): slicer.modules.TCGAEditorBot.active = False del (slicer.modules.TCGAEditorBot) slicer.modules.TCGAEditorBot = self self.redSliceWidget = options.redSliceWidget self.greenSliceWidget = options.greenSliceWidget self.yellowSliceWidget = options.yellowSliceWidget self.start()
def onloadCTButtonClicked(self): # widge to load file w = qt.QWidget() w.resize(320, 240) w.setWindowTitle("Select CT Image") image_path = qt.QFileDialog.getOpenFileName(w, 'Open File', '/') path = str('/'.join(image_path.split('/')[0:-1])) + '/' print(path) print(image_path) if image_path is not None: self.image_loaded = True print(image_path) filetype = ".nrrd" self.filetype = filetype lm = slicer.app.layoutManager() lm.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutFourUpView) view = lm.threeDWidget(0).threeDView() viewNode = view.mrmlViewNode() viewNode.SetBackgroundColor((0, 0, 0)) viewNode.SetBackgroundColor2((0, 0, 0)) viewNode.SetAxisLabelsVisible(0) viewNode.SetBoxVisible(0) # load image (master volume) load, image = slicer.util.loadVolume(image_path, returnNode=True) volumesLogic = slicer.modules.volumes.logic() label_name = image.GetName() + "-rough-label" label = volumesLogic.CreateLabelVolume(slicer.mrmlScene, image, label_name) label_path = str(path + label_name + filetype) print(label_path) self.view = view self.path = path self.image_path = image_path self.label_path = label_path self.image_name = image.GetName() self.label_name = label_name self.labelpostfix1 = '_tumor_label' self.labelpostfix2 = '_lung_label' selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceActiveLabelVolumeID(label.GetID()) EditUtil.EditUtil().propagateVolumeSelection() # switch to Edit module slicer.util.selectModule('Editor') slicer.modules.EditorWidget.toolsBox.selectEffect('PaintEffect')
def __init__(self, sliceLogic): print("Preparing Growcut interaction") self.attributes = ('MouseTool') self.displayName = 'FastGrowCut Effect' #disconnect all shortcuts that may exist, to allow Fast GrowCut's to work, reconnect once bot is turned off slicer.modules.EditorWidget.removeShortcutKeys() self.sliceLogic = sliceLogic self.editUtil = EditUtil.EditUtil() #initialize Fast GrowCut self.init_fGrowCut() self.fastCrowCutCreated = False
def __init__(self, sliceLogic): print("Preparing CleverSeg interaction") self.attributes = ('MouseTool') self.displayName = 'CleverSeg Effect' # disconnect all shortcuts that may exist, to allow CleverSeg's to work, reconnect once bot is turned off slicer.modules.EditorWidget.removeShortcutKeys() self.sliceLogic = sliceLogic self.editUtil = EditUtil.EditUtil() # initialize CleverSeg self.init_fCleverSeg() self.CleverSegCreated = False
def onloadMRIFLAIRButtonClicked(self): # widge to load file w = qt.QWidget() w.resize(320, 240) w.setWindowTitle("Select MRI FLAIR Image") self.FLAIR_image_path = qt.QFileDialog.getOpenFileName( w, 'Open File', '/') self.FLAIR_path = str('/'.join( self.FLAIR_image_path.split('/')[0:-1])) + '/' lm = slicer.app.layoutManager() lm.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutFourUpView) view = lm.threeDWidget(0).threeDView() viewNode = view.mrmlViewNode() viewNode.SetBackgroundColor((0, 0, 0)) viewNode.SetBackgroundColor2((0, 0, 0)) viewNode.SetAxisLabelsVisible(0) viewNode.SetBoxVisible(0) self.view = view load, image = slicer.util.loadVolume(self.FLAIR_image_path, returnNode=True) # adding a automated seed point volumesLogic = slicer.modules.volumes.logic() label_name = image.GetName() + "-rough-label" label = volumesLogic.CreateLabelVolume(slicer.mrmlScene, image, label_name) # label_path = str(path+label_name+filetype) # print(label_path) # # self.view = view # self.path = path # self.image_path = image_path # self.label_path = label_path # self.image_name = image.GetName() self.label_name = label_name # self.labelpostfix1 = '_tumor_confidenceconnected' # self.labelpostfix2 = '_lung_confidenceconnected' selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceActiveLabelVolumeID(label.GetID()) EditUtil.EditUtil().propagateVolumeSelection() # switch to Edit module slicer.util.selectModule('Editor') slicer.modules.EditorWidget.toolsBox.selectEffect('PaintEffect')
def run_qtcga_segmentation_1(self): """ Original recipe :return: """ if self.bEditTCGA: self.currentMessage = "Quick TCGA: running nucleus segmentation ..." slicer.util.showStatusMessage(self.currentMessage) seedArray = slicer.util.array(self.labelNode.GetName()) self.qTCGASeedArray[:] = seedArray[:] node = EditUtil.EditUtil().getParameterNode() # get the parameters from MRML otsuRatio = float(node.GetParameter("ShortCut,otsuRatio")) print(otsuRatio) curvatureWeight = float(node.GetParameter("ShortCut,curvatureWeight")) / 10 print(curvatureWeight) sizeThld = float(node.GetParameter("ShortCut,sizeThld")) print(sizeThld) sizeUpperThld = float(node.GetParameter("ShortCut,sizeUpperThld")) print(sizeUpperThld) mpp = float(node.GetParameter("ShortCut,mpp")) / 100 print(mpp) self.qTCGAMod.SetotsuRatio(otsuRatio) self.qTCGAMod.SetcurvatureWeight(curvatureWeight) self.qTCGAMod.SetsizeThld(sizeThld) self.qTCGAMod.SetsizeUpperThld(sizeUpperThld) self.qTCGAMod.Setmpp(mpp) self.qTCGAMod.SetSourceVol(self.foregroundNode.GetImageData()) self.qTCGAMod.SetSeedVol(self.labelNode.GetImageData()) self.qTCGASegArray[:] = seedArray[:] self.labelNode.GetImageData().Modified() self.labelNode.Modified() self.bEditTCGA = False self.currentMessage = "Quick TCGA done: nuclei segmentation is done; press 'F' to enable ROI selection for refinement" slicer.util.showStatusMessage(self.currentMessage) else: self.currentMessage = "Quick TCGA: go to seed labels first by pressing 'E'" slicer.util.showStatusMessage(self.currentMessage)
def setErrorMessage(self, errorText, errorColor=0): """Call this to seet the message in the error box. Parameters: errorText: string to be displayed in the box errorColor: int 1 or 0 (DEFAULT IS 0) that sets the color of the text as either green (1) or red (0) Returns: none""" if (errorColor == 1): errorColor = "QTextEdit {color:Green}" elif (errorColor == 0): errorColor = "QTextEdit {color:red}" else: # Why did you do this? Read the function? I'm going to make the text white to punish you errorColor = "QTextEdit {color:white}" node = EditUtil.EditUtil().getParameterNode() node.SetParameter("TraceAndSelect,errorMessage", str(errorText)) node.SetParameter("TraceAndSelect,errorMessageColor", str(errorColor)) return
def runQTCGA_NucleiSegYi(self): self.currentMessage = "Quick TCGA: running nucleus segmentation ..." slicer.util.showStatusMessage(self.currentMessage) seedArray = slicer.util.array(self.labelNode.GetName()) self.qTCGASeedArray[:] = seedArray[:] node = EditUtil.EditUtil().getParameterNode( ) # get the parameters from MRML otsuRatio = float(node.GetParameter("QuickTCGAEffect,otsuRatio")) curvatureWeight = float( node.GetParameter("QuickTCGAEffect,curvatureWeight")) / 10 sizeThld = float(node.GetParameter("QuickTCGAEffect,sizeThld")) sizeUpperThld = float( node.GetParameter("QuickTCGAEffect,sizeUpperThld")) mpp = float(node.GetParameter("QuickTCGAEffect,mpp")) / 100 self.qTCGAMod.SetotsuRatio(otsuRatio) self.qTCGAMod.SetcurvatureWeight(curvatureWeight) self.qTCGAMod.SetsizeThld(sizeThld) self.qTCGAMod.SetsizeUpperThld(sizeUpperThld) self.qTCGAMod.Setmpp(mpp) AA = self.foregroundNode.GetImageData() a1 = 0 b1 = 0 ddd = AA.GetDimensions() a2 = ddd[0] - 1 b2 = ddd[1] - 1 LL = self.labelNode.GetImageData() BB = self.GetTile(AA, a1, b1, a2, b2) LL = self.GetTile(LL, a1, b1, a2, b2) self.qTCGAMod.SetSourceVol(BB) self.qTCGAMod.SetSeedVol(LL) self.qTCGAMod.Run_NucleiSegYi() self.qTCGASegArray[:] = seedArray[:] self.MergeImages(LL, self.labelNode.GetImageData(), a1, b1) self.foregroundNode.GetImageData().Modified() self.foregroundNode.Modified() self.labelNode.GetImageData().Modified() self.labelNode.Modified() self.currentMessage = "Quick TCGA done: nuclei segmetnation is done; press 'F' to enable ROI selection for refinement" slicer.util.showStatusMessage(self.currentMessage)
def __init__(self, sliceLogic): print("Preparing Quick TCGA Interaction") self.attributes = 'MouseTool' self.displayName = 'ShortCut Effect' # disconnect all shortcuts that may exist, to allow ShortCut's to work, reconnect once bot is turned off if hasattr(slicer.modules, 'EditorWidget'): slicer.modules.EditorWidget.removeShortcutKeys() self.sliceLogic = sliceLogic self.editUtil = EditUtil.EditUtil() self.swRed = slicer.app.layoutManager().sliceWidget('Red').sliceLogic() self.sw = slicer.app.layoutManager().sliceWidget('Red') self.interactor = self.sw.sliceView().interactor() # initialize to red slice interactor # self.computeCurrSliceSmarter() # initialize the current slice to something meaningful self.mouse_obs_growcut, self.swLUT_growcut = bind_view_observers(self.updateShortCutROI) # initialize Fast GrowCut self.init_ShortCut() self.ShortCutCreated = False
def onSaveButtonClicked(self): bundle = EditUtil.EditUtil().getParameterNode().GetParameter( 'QuickTCGAEffect,erich') tran = json.loads(bundle) layers = [] for key in tran: nn = tran[key] nn["file"] = key + '.tif' layers.append(tran[key]) j = {} j['layers'] = layers j['username'] = self.setupUserName.text j['sourcetile'] = self.tilename j['generator'] = "3DSlicer-4.5.0 with SlicerPathology v1.0a" j['timestamp'] = datetime.datetime.now().strftime("%Y%m%d%H%M%S") labelNodes = slicer.util.getNodes('vtkMRMLLabelMapVolumeNode*') savedMessage = 'Segmentations for the following series were saved:\n\n' for label in labelNodes.values(): labelName = label.GetName() labelFileName = os.path.join(self.dataDirButton.directory, labelName + '.tif') print "labelFileName : " + labelFileName sNode = slicer.vtkMRMLVolumeArchetypeStorageNode() sNode.SetFileName(labelFileName) sNode.SetWriteFileFormat('tif') sNode.SetURI(None) success = sNode.WriteData(label) if success: print "successful writing " + labelFileName else: print "failed writing " + labelFileName jstr = json.dumps(j, sort_keys=True, indent=4, separators=(',', ': ')) f = open( os.path.join(self.dataDirButton.directory, self.tilename + '.json'), 'w') f.write(jstr) f.close()
def fill(self, ijk, optional_seeds=[], mode=0, forced_path=None, forced_point=None): print("Mode: %d" % mode) paintOver = 1 mean = (0, 0) count = 0 node = EditUtil.EditUtil().getParameterNode() # Max number of pixels to fill in (does not include path) print("@@@MaxPixels:%s" % node.GetParameter("TraceAndSelect,maxPixels")) maxPixels = float(node.GetParameter("TraceAndSelect,maxPixels")) # Minimum intensity value to be detected print("@@@Theshold Min:%s" % node.GetParameter("TraceAndSelect,paintThresholdMin")) thresholdMin = float( node.GetParameter("TraceAndSelect,paintThresholdMin")) # Maximum intensity value to be detected print("@@@Theshold Max:%s" % node.GetParameter("TraceAndSelect,paintThresholdMax")) thresholdMax = float( node.GetParameter("TraceAndSelect,paintThresholdMax")) labelLogic = self.sliceLogic.GetLabelLayer() labelNode = labelLogic.GetVolumeNode() backgroundLogic = self.sliceLogic.GetBackgroundLayer() backgroundNode = backgroundLogic.GetVolumeNode() import vtk.util.numpy_support, numpy backgroundImage = backgroundNode.GetImageData() labelImage = labelNode.GetImageData() shape = list(backgroundImage.GetDimensions()) shape.reverse() backgroundArray = vtk.util.numpy_support.vtk_to_numpy( backgroundImage.GetPointData().GetScalars()).reshape(shape) labelArray = vtk.util.numpy_support.vtk_to_numpy( labelImage.GetPointData().GetScalars()).reshape(shape) ijk_reconstruction_indexes = [] # THIS SHOULD ALWAYS BE TRUE # VOLUME MODE IS DISABLED BECAUSE I HAVE NO CLUE WHAT IT IS original_ijk = list(ijk) if self.fillMode == 'Plane': # select the plane corresponding to current slice orientation # for the input volume ijkPlane = self.sliceIJKPlane() i, j, k = ijk if ijkPlane == 'JK': backgroundDrawArray = backgroundArray[:, :, k] labelDrawArray = labelArray[:, :, k] ijk = (i, j) ijk_reconstruction_indexes = (0, 1) if ijkPlane == 'IK': backgroundDrawArray = backgroundArray[:, j, :] labelDrawArray = labelArray[:, j, :] ijk = (i, k) ijk_reconstruction_indexes = (0, 2) if ijkPlane == 'IJ': backgroundDrawArray = backgroundArray[i, :, :] labelDrawArray = labelArray[i, :, :] ijk = (j, k) ijk_reconstruction_indexes = (1, 2) else: print( "HOW DID YOU DO THAT??? WHAT DID YOU DO TO ACTIVATE VOLUME MODE???" ) self.setErrorMessage("Error: volume mode not supported.") return # Log info about where the user clicked for debugging purposes value = backgroundDrawArray[ijk] print("@@@location=", ijk) print("@@@value=", value) # Get the current label that the user wishes to assign using the tool label = EditUtil.EditUtil().getLabel() # Use lo and hi for threshold checks # Easiest way to do things is check if a pixel is outside the threshold, ie. lo = thresholdMin hi = thresholdMax best_path = [] fill_point = ijk if mode == 0 and forced_path is not None and forced_point is not None: best_path = forced_path fill_point = forced_point else: # Build path best_path, visited, dead_ends = gimme_a_path( ijk, 200, hi, lo, backgroundDrawArray, optional_seeds) print("@@@Dead ends:", dead_ends) attempts = 0 max_attempts = 2 while dead_ends > 150 or dead_ends < 0 and attempts < max_attempts: attempts += 1 lo -= 25 print("Lowering min tolerance to:", lo) node.SetParameter("LabelEffect,paintThresholdMin", str(lo)) best_path, visited, dead_ends = gimme_a_path( ijk, 200, hi, lo, backgroundDrawArray, optional_seeds) print("@@@Dead ends:", dead_ends) if dead_ends < 0: print("@@@No path found? Weird.") self.setErrorMessage( "Error: could not find any suitable path.") return # Save state before doing anything self.undoRedo.saveState() for pixel in visited: labelDrawArray[pixel] = label EditUtil.EditUtil().markVolumeNodeAsModified(labelNode) if mode == 1: # Outline only mode print("Outline made, returning.") self.setErrorMessage( "Preview complete. No errrors detected.\nLeft click to confirm.\nRight click to try a new outline.\nUndo to remove.", 1) return (best_path, ijk) # # Fill path # # Fill the path using a recursive search toVisit = [ fill_point, ] extrema = get_extrema(best_path) # Create a map that contains the location of the pixels # that have been already visited (added or considered to be added). # This is required if paintOver is enabled because then we reconsider # all pixels (not just the ones that have not labelled yet). if paintOver: labelDrawVisitedArray = numpy.zeros(labelDrawArray.shape, dtype='bool') pixelsSet = 0 print("@@@FILLING PATH") while toVisit != []: location = toVisit.pop(0) try: l = fetch_val(labelDrawArray, location) b = fetch_val(backgroundDrawArray, location) except IndexError: continue if (not paintOver and l != 0): # label filled already and not painting over, leave it alone continue try: if (paintOver and l == label): temp1 = mean[0] + location[0] temp2 = mean[1] + location[1] mean = (temp1, temp2) count += 1 # label is the current one, but maybe it was filled with another high/low value, # so we have to visit it once (and only once) in this session, too if labelDrawVisitedArray[location]: # visited already, so don't try to fill it again continue else: # we'll visit this pixel now, so mark it as visited labelDrawVisitedArray[location] = True except ValueError: print("@@@VALUE ERROR!", l) print("@@@Location: ", location) print("@@@fill_point:", fill_point) print("@@@toVisit:", toVisit) continue if location in best_path: continue if not (extrema[0] < location[0] < extrema[1] and extrema[2] < location[1] < extrema[3]): # Went out of bounds for path print("@@@WENT OUT OF BOUNDS FOR PATH!") self.setErrorMessage("Error: Went out of bounds for path.") self.undoRedo.undo() return labelDrawArray[location] = label if l != label: # only count those pixels that were changed (to allow step-by-step growing by multiple mouse clicks) pixelsSet += 1 if pixelsSet > maxPixels: toVisit = [] else: # add the 4 neighbors to the stack toVisit.append((location[0] - 1, location[1])) toVisit.append((location[0] + 1, location[1])) toVisit.append((location[0], location[1] - 1)) toVisit.append((location[0], location[1] + 1)) # signal to slicer that the label needs to be updated ## CHANGE OFFSET print("@@@Offset:|%s|" % node.GetParameter("TraceAndSelect,offsetvalue")) self.offset = float(node.GetParameter("TraceAndSelect,offsetvalue")) print("OFFSET SIGN: %s" % math.copysign(1, self.offset)) if self.offset != 0: slices_seen = self.progress.maximum - abs(self.offset) if self.progress.wasCanceled: self.offset = 0 layoutManager = slicer.app.layoutManager() widget = layoutManager.sliceWidget('Red') rednode = widget.sliceLogic().GetSliceNode() rednode.SetSliceOffset(rednode.GetSliceOffset() + math.copysign(1, self.offset)) node.SetParameter("TraceAndSelect,offsetvalue", str(0)) self.setErrorMessage( "Fill abandoned after {} slice(s)".format( int(slices_seen)), 1) return self.progress.setValue(slices_seen) layoutManager = slicer.app.layoutManager() widget = layoutManager.sliceWidget('Red') rednode = widget.sliceLogic().GetSliceNode() rednode.SetSliceOffset(rednode.GetSliceOffset() + math.copysign(1, self.offset)) node.SetParameter("TraceAndSelect,offsetvalue", str(self.offset - math.copysign(1, self.offset))) print(self.offset) ### Calc centoid mean stuff here recs_mean = (mean[0] / count, mean[1] / count) rec_mean = get_optional_seeds(best_path, recs_mean)[0] print("MEAN:", rec_mean, recs_mean) rec_ijk = list(original_ijk) for i in range(0, 3): rec_ijk[i] = int(rec_ijk[i] + int(math.copysign(1, self.offset))) rec_ijk[ijk_reconstruction_indexes[0]] = rec_mean[0] rec_ijk[ijk_reconstruction_indexes[1]] = rec_mean[1] print("RECURSIVE IJK:", rec_ijk) print("#########RECURSE#########") return self.fill(rec_ijk, optional_seeds=get_optional_seeds( best_path, recs_mean)) ### print("@@@FILL DONE") EditUtil.EditUtil().markVolumeNodeAsModified(labelNode) self.setErrorMessage("Fill complete. No errors detected.", 1) return
def apply(self,xy): # # get the parameters from MRML # node = EditUtil.EditUtil().getParameterNode() tolerance = float(node.GetParameter("WandEffect,tolerance")) maxPixels = float(node.GetParameter("WandEffect,maxPixels")) paintOver = int(node.GetParameter("LabelEffect,paintOver")) # # get the label and background volume nodes # labelLogic = self.sliceLogic.GetLabelLayer() labelNode = labelLogic.GetVolumeNode() backgroundLogic = self.sliceLogic.GetBackgroundLayer() backgroundNode = backgroundLogic.GetVolumeNode() # # get the ijk location of the clicked point # by projecting through patient space back into index # space of the volume. Result is sub-pixel, so round it # (note: bg and lb will be the same for volumes created # by the editor, but can be different if the use selected # different bg nodes, but that is not handled here). # xyToIJK = labelLogic.GetXYToIJKTransform().GetMatrix() ijkFloat = xyToIJK.MultiplyPoint(xy+(0,1))[:3] ijk = [] for element in ijkFloat: try: intElement = int(round(element)) except ValueError: intElement = 0 ijk.append(intElement) ijk.reverse() ijk = tuple(ijk) # # Get the numpy array for the bg and label # import vtk.util.numpy_support backgroundImage = backgroundNode.GetImageData() labelImage = labelNode.GetImageData() shape = list(backgroundImage.GetDimensions()) shape.reverse() backgroundArray = vtk.util.numpy_support.vtk_to_numpy(backgroundImage.GetPointData().GetScalars()).reshape(shape) labelArray = vtk.util.numpy_support.vtk_to_numpy(labelImage.GetPointData().GetScalars()).reshape(shape) if self.fillMode == 'Plane': # select the plane corresponding to current slice orientation # for the input volume ijkPlane = self.sliceIJKPlane() i,j,k = ijk if ijkPlane == 'JK': backgroundDrawArray = backgroundArray[:,:,k] labelDrawArray = labelArray[:,:,k] ijk = (i, j) if ijkPlane == 'IK': backgroundDrawArray = backgroundArray[:,j,:] labelDrawArray = labelArray[:,j,:] ijk = (i, k) if ijkPlane == 'IJ': backgroundDrawArray = backgroundArray[i,:,:] labelDrawArray = labelArray[i,:,:] ijk = (j, k) elif self.fillMode == 'Volume': backgroundDrawArray = backgroundArray labelDrawArray = labelArray # # do a recursive search for pixels to change # self.undoRedo.saveState() value = backgroundDrawArray[ijk] label = EditUtil.EditUtil().getLabel() lo = value - tolerance hi = value + tolerance pixelsSet = 0 toVisit = [ijk,] visited = [] while toVisit != []: location = toVisit.pop(0) try: l = labelDrawArray[location] b = backgroundDrawArray[location] except IndexError: continue if (not paintOver and l != 0): # label filled already and not painting over, leave it alone continue if (paintOver and l == label): # label is the current one, but maybe it was filled with another high/low value, # so we have to visit it once (and only once) in this session, too visitedCurrentLocation = True try: visited.index(location) except ValueError: # not found, so not visited yet visitedCurrentLocation = False if visitedCurrentLocation: continue else: visited.append(location) if b < lo or b > hi: continue labelDrawArray[location] = label if l != label: # only count those pixels that were changed (to allow step-by-step growing by multiple mouse clicks) pixelsSet += 1 if pixelsSet > maxPixels: toVisit = [] else: if self.fillMode == 'Plane': # add the 4 neighbors to the stack toVisit.append((location[0] - 1, location[1] )) toVisit.append((location[0] + 1, location[1] )) toVisit.append((location[0] , location[1] - 1 )) toVisit.append((location[0] , location[1] + 1 )) elif self.fillMode == 'Volume': # add the 6 neighbors to the stack toVisit.append((location[0] - 1, location[1] , location[2] )) toVisit.append((location[0] + 1, location[1] , location[2] )) toVisit.append((location[0] , location[1] - 1, location[2] )) toVisit.append((location[0] , location[1] + 1, location[2] )) toVisit.append((location[0] , location[1] , location[2] - 1)) toVisit.append((location[0] , location[1] , location[2] + 1)) # signal to slicer that the label needs to be updated labelImage.Modified() labelNode.Modified()
def init_QuickTCGA(self): self.emergencyStopFunc = None self.dialogBox = qt.QMessageBox( ) #will display messages to draw users attention if he does anything wrong self.dialogBox.setWindowTitle("QuickTCGA Error") self.dialogBox.setWindowModality( qt.Qt.NonModal ) #will allow user to continue interacting with Slicer # TODO: check this claim- might be causing leaks # set the image, label nodes (this will not change although the user can # alter what is bgrnd/frgrnd in editor) # Confused about how info propagates UIarray to UIVol, not the other way, NEEDS AUTO TESTS self.labelNode = self.editUtil.getLabelVolume( ) #labelLogic.GetVolumeNode() self.backgroundNode = self.editUtil.getBackgroundVolume( ) #backgroundLogic.GetVolumeNode() self.foregroundNode = self.swRed.GetForegroundLayer().GetVolumeNode() #perform safety check on right images/labels being selected, #set up images #if red slice doesnt have a label or image, go no further if type(self.backgroundNode) == type(None) or type( self.labelNode) == type(None): self.dialogBox.setText( "Either Image (must be Background Image) or Label not set in slice views." ) self.dialogBox.show() if self.emergencyStopFunc: self.emergencyStopFunc() return volumesLogic = slicer.modules.volumes.logic() self.labelName = self.labelNode.GetName( ) # record name of label so user, cant trick us self.imgBgrdName = self.backgroundNode.GetName() self.imgFgrdName = self.foregroundNode.GetName() if self.sliceViewMatchEditor( self.sliceLogic ) == False: # do nothing, exit function if user has played with images if self.emergencyStopFunc: self.emergencyStopFunc() return # QuickTCGA shortcuts ##resetQTCGAKey = qt.QKeySequence(qt.Qt.Key_R) # reset initialization flag ##runQTCGAClusterKey = qt.QKeySequence(qt.Qt.Key_S) # run fast growcut runNucleiSegKey = qt.QKeySequence(qt.Qt.Key_Y) ##editTCGAKey = qt.QKeySequence(qt.Qt.Key_E) # edit seed labels ##runQTCGATemplateKey = qt.QKeySequence(qt.Qt.Key_T) ##runQTCGARefineCurvatureKey = qt.QKeySequence(qt.Qt.Key_U) ##runQTCGAShortCutKey = qt.QKeySequence(qt.Qt.Key_C) ##runQTCGAShortEditCutKey = qt.QKeySequence(qt.Qt.Key_F) print " key to run QuickTCGA segmentation is Y" self.qtkeyconnections = [] self.qtkeydefsQTCGA = [[runNucleiSegKey, self.runQTCGA_NucleiSegYi]] for keydef in self.qtkeydefsQTCGA: s = qt.QShortcut(keydef[0], slicer.util.mainWindow() ) # connect this qt event to mainWindow focus s.connect('activated()', keydef[1]) self.qtkeyconnections.append(s) self.qTCGALabMod_tag = self.sliceLogic.AddObserver( "ModifiedEvent", self.QTCGAChangeLabelInput ) # put test listener on the whole window # Quick TCGA parameters self.bEditTCGA = True self.bEditShortCut = False self.currentMessage = "" seedArray = slicer.util.array(self.labelName) self.qTCGASeedArray = seedArray.copy() self.qTCGASegArray = seedArray.copy() self.qTCGASeedArray[:] = 0 self.qTCGASegArray[:] = 0 self.SCutROIRad = 50 self.volSize = self.labelNode.GetImageData().GetDimensions() self.qSCutROIArray = seedArray.copy( ) #np.zeros([self.volSize[0],self.volSize[1],1]) self.qSCutROIArray[:] = 0 roiVTK = vtk.vtkImageData() roiVTK.DeepCopy(self.labelNode.GetImageData()) self.roiVTK = roiVTK import vtkSlicerQuickTCGAModuleLogicPython node = EditUtil.EditUtil().getParameterNode( ) # get the parameters from MRML otsuRatio = float(node.GetParameter("QuickTCGAEffect,otsuRatio")) curvatureWeight = float( node.GetParameter("QuickTCGAEffect,curvatureWeight")) / 10 sizeThld = float(node.GetParameter("QuickTCGAEffect,sizeThld")) sizeUpperThld = float( node.GetParameter("QuickTCGAEffect,sizeUpperThld")) mpp = float(node.GetParameter("QuickTCGAEffect,mpp")) / 100 cparams["otsuRatio"] = otsuRatio cparams["curvatureWeight"] = curvatureWeight cparams["sizeThld"] = sizeThld cparams["sizeUpperThld"] = sizeUpperThld cparams["mpp"] = mpp qTCGAMod = vtkSlicerQuickTCGAModuleLogicPython.vtkQuickTCGA() qTCGAMod.SetSourceVol(self.foregroundNode.GetImageData()) qTCGAMod.SetotsuRatio(otsuRatio) qTCGAMod.SetcurvatureWeight(curvatureWeight) qTCGAMod.SetsizeThld(sizeThld) qTCGAMod.SetsizeUpperThld(sizeUpperThld) qTCGAMod.Setmpp(mpp) qTCGAMod.Initialization() self.qTCGAMod = qTCGAMod self.QuickTCGACreated = True #tracks if completed the initializtion (so can do stop correctly) of KSlice
def apply(self,xy): # TODO: save the undo state - not yet available for extensions # EditorStoreCheckPoint $_layers(label,node) # # get the parameters from MRML # node = EditUtil.EditUtil().getParameterNode() tolerance = float(node.GetParameter("GooCut,tolerance")) maxPixels = float(node.GetParameter("GooCut,maxPixels")) # # get the label and background volume nodes # labelLogic = self.sliceLogic.GetLabelLayer() labelNode = labelLogic.GetVolumeNode() labelNode.SetModifiedSinceRead(1) backgroundLogic = self.sliceLogic.GetBackgroundLayer() backgroundNode = backgroundLogic.GetVolumeNode() # # get the ijk location of the clicked point # by projecting through patient space back into index # space of the volume. Result is sub-pixel, so round it # (note: bg and lb will be the same for volumes created # by the editor, but can be different if the use selected # different bg nodes, but that is not handled here). # xyToIJK = labelLogic.GetXYToIJKTransform().GetMatrix() ijkFloat = xyToIJK.MultiplyPoint(xy+(0,1))[:3] ijk = [] for element in ijkFloat: try: intElement = int(element) except ValueError: intElement = 0 ijk.append(intElement) ijk.reverse() ijk = tuple(ijk) # # Get the numpy array for the bg and label # import vtk.util.numpy_support backgroundImage = backgroundNode.GetImageData() labelImage = labelNode.GetImageData() shape = list(backgroundImage.GetDimensions()) shape.reverse() backgroundArray = vtk.util.numpy_support.vtk_to_numpy(backgroundImage.GetPointData().GetScalars()).reshape(shape) labelArray = vtk.util.numpy_support.vtk_to_numpy(labelImage.GetPointData().GetScalars()).reshape(shape) # # do a region growing # try: value = backgroundArray[ijk] except IndexError: # outside of volume return label = EditUtil.EditUtil().getLabel() lo = value - tolerance hi = value + tolerance pixelsSet = 0 toVisit = [ijk,] while toVisit != []: location = toVisit.pop() try: l = labelArray[location] b = backgroundArray[location] except IndexError: continue if l != 0 or b < lo or b > hi: continue labelArray[location] = label pixelsSet += 1 if pixelsSet > maxPixels: toVisit = [] else: # add the 6 neighbors to the stack toVisit.append((location[0] - 1, location[1] , location[2] )) toVisit.append((location[0] + 1, location[1] , location[2] )) toVisit.append((location[0] , location[1] - 1, location[2] )) toVisit.append((location[0] , location[1] + 1, location[2] )) toVisit.append((location[0] , location[1] , location[2] - 1)) toVisit.append((location[0] , location[1] , location[2] + 1)) labelImage.Modified() labelNode.Modified()
def processEvent(self, caller=None, event=None): """ handle events from the render window interactor """ node = EditUtil.EditUtil().getParameterNode() preview = int(node.GetParameter("TraceAndSelect,preview")) # Clear any saved outlines if preview has been just disabled if not preview: if self.prevPath != []: self.prevPath = [] self.prevFillPoint = None self.undoRedo.undo() # let the superclass deal with the event if it wants to super(TraceAndSelectTool, self).processEvent(caller, event) # LEFT CLICK if event == "LeftButtonPressEvent": xy = self.interactor.GetEventPosition() sliceLogic = self.sliceWidget.sliceLogic() logic = TraceAndSelectLogic(sliceLogic) logic.undoRedo = self.undoRedo if self.prevPath != []: logic.apply(xy, forced_path=self.prevPath, forced_point=self.prevFillPoint) self.prevPath = [] self.prevFillPoint = None else: logic.apply(xy) print("Got a %s at %s in %s" % (event, str(xy), self.sliceWidget.sliceLogic().GetSliceNode().GetName())) self.abortEvent(event) # RIGHT CLICK elif event == "RightButtonPressEvent" and preview: xy = self.interactor.GetEventPosition() sliceLogic = self.sliceWidget.sliceLogic() logic = TraceAndSelectLogic(sliceLogic) logic.undoRedo = self.undoRedo # Erase stored path and remove from view if self.prevPath != []: self.prevPath = [] self.prevFillPoint = None logic.undoRedo.undo() # Store prevPath and prevFillPoint self.prevPath, self.prevFillPoint = logic.apply(xy, 1) print("Got a %s at %s in %s" % (event, str(xy), self.sliceWidget.sliceLogic().GetSliceNode().GetName())) self.abortEvent(event) # SLICE VIEW HAS CHANGED elif event == "ModifiedEvent": # Offset was changed on one of the viewing panels # Erase stored path and remove from view if self.prevPath != []: self.prevPath = [] self.prevFillPoint = None self.undoRedo.undo() sliceLogic = self.sliceWidget.sliceLogic() logic = TraceAndSelectLogic(sliceLogic) logic.setErrorMessage("Previewed path was discarded.", 1) else: pass # events from the slice node if caller and caller.IsA('vtkMRMLSliceNode'): # here you can respond to pan/zoom or other changes # to the view pass