def setupMeasurementsArea(self): self.measurementsGroupBox = qt.QGroupBox("Measurements") self.measurementsGroupBox.setLayout(qt.QGridLayout()) self.tableView = slicer.qMRMLTableView() self.tableView.setMinimumHeight(150) self.tableView.setMaximumHeight(150) self.tableView.setSelectionBehavior(qt.QTableView.SelectRows) if ModuleWidgetMixin.isQtVersionOlder(): self.tableView.horizontalHeader().setResizeMode(qt.QHeaderView.Stretch) else: self.tableView.horizontalHeader().setSectionResizeMode(qt.QHeaderView.Stretch) self.fourUpTableView = None self.segmentStatisticsConfigButton = self.createButton("Segment Statistics Parameters") self.calculateMeasurementsButton = self.createButton("Calculate Measurements", enabled=False) self.calculateAutomaticallyCheckbox = qt.QCheckBox("Auto Update") self.calculateAutomaticallyCheckbox.checked = True self.measurementsGroupBox.layout().addWidget(self.tableView, 0, 0, 1, 2) self.measurementsGroupBox.layout().addWidget(self.segmentStatisticsConfigButton, 1, 0, 1, 2) self.measurementsGroupBox.layout().addWidget(self.calculateMeasurementsButton, 2, 0) self.measurementsGroupBox.layout().addWidget(self.calculateAutomaticallyCheckbox, 2, 1) self.mainModuleWidgetLayout.addWidget(self.measurementsGroupBox)
def setFOV2Largest2DRegion(self, widget, largestLabel=None, factor=1.5): if not largestLabel: largestLabel = self.findLargest2DRegion(self.segmentationNode) slicer.mrmlScene.AddNode(largestLabel) sliceLogic = widget.sliceLogic() sliceNode = sliceLogic.GetSliceNode() compositeNode = widget.mrmlSliceCompositeNode() savedVolumeID = compositeNode.GetBackgroundVolumeID() savedFOV = sliceNode.GetFieldOfView() compositeNode.SetBackgroundVolumeID(largestLabel.GetID()) sliceLogic.FitSliceToAll() compositeNode.SetBackgroundVolumeID(savedVolumeID) FOV = sliceNode.GetFieldOfView() ModuleWidgetMixin.setFOV(sliceLogic, [FOV[0] * factor, FOV[1] * factor, FOV[2]]) slicer.mrmlScene.RemoveNode(largestLabel) return largestLabel
def getData(self): data = "" prostateMap = ProstateSectorMapDialog() prostateMap.displayCheckboxBorder(visible=False) for finding in self._assessmentCategory.getFindings(): prostateMap.resetButtons() prostateMap.setSelectedSectors(finding.getSectors()) prostateMap.setButtonsVisible(checkedOnly=True) data += ''' <div class="print-friendly"> <h2>{0}</h2> <table border=1 width='100%' cellPadding=3 cellSpacing=0> {1} </table> <br> </div> '''.format( finding.getName(), "".join([ self.sectorMapScreenShot.format( ModuleWidgetMixin.pixelmapAsRaw(pixmap)) for pixmap in prostateMap.getScreenShots() ])) return data
def viewerPerVolume(cls, volumeNodes, layout, background, opacity=1.0): """ Load each volume in the scene into its own slice viewer and link them all together. If background is specified, put it in the background of all viewers and make the other volumes be the foreground. If label is specified, make it active as the label layer of all viewers. Return a map of slice nodes indexed by the view name (given or generated). Opacity applies only when background is selected. """ if not volumeNodes: raise ValueError("VolumeNodes are supposed to be non empty") layoutManager = slicer.app.layoutManager() layoutManager.setLayout(layout) sliceWidgets = list(ModuleWidgetMixin.getAllVisibleWidgets()) slicer.app.processEvents() for index, volume in enumerate(volumeNodes): sliceWidget = sliceWidgets[index] volumeNodeID = volume.GetID() compositeNode = sliceWidget.mrmlSliceCompositeNode() compositeNode.SetBackgroundVolumeID(background.GetID()) compositeNode.SetForegroundVolumeID(volumeNodeID) compositeNode.SetForegroundOpacity(opacity) sliceNode = sliceWidget.mrmlSliceNode() orientation = cls.getOrientation(volume) if orientation: sliceNode.SetOrientation(orientation) sliceNode.RotateToVolumePlane(volume) sliceWidget.fitSliceToBackground()
def addSideBySideSliceAnnotations(self): self.removeSliceAnnotations() kwargs = {"yPos":55 if ModuleWidgetMixin.isQtVersionOlder() else 80, "size":30} self.sliceAnnotations.append(SliceAnnotation(self.redWidget, constants.LEFT_VIEWER_SLICE_ANNOTATION_TEXT, **kwargs)) self.sliceAnnotations.append(SliceAnnotation(self.yellowWidget, constants.RIGHT_VIEWER_SLICE_ANNOTATION_TEXT, **kwargs)) self.addNewImageAnnotation(self.yellowWidget, constants.RIGHT_VIEWER_SLICE_NEEDLE_IMAGE_ANNOTATION_TEXT) self.addOldImageAnnotation(self.yellowWidget, constants.RIGHT_VIEWER_SLICE_TRANSFORMED_ANNOTATION_TEXT) self.addRegistrationResultStatusAnnotation(self.yellowWidget)
def setTargetTableSizeConstraints(self): method = getattr(self.targetTable.horizontalHeader(), "setResizeMode" if ModuleWidgetMixin.isQtVersionOlder() else "setSectionResizeMode") method(qt.QHeaderView.Stretch) method(0, qt.QHeaderView.Stretch) method(1, qt.QHeaderView.ResizeToContents) method(2, qt.QHeaderView.ResizeToContents)
def addFourUpSliceAnnotations(self): self.removeSliceAnnotations() if not (self.currentResult.skipped or (self.session.seriesTypeManager.isCoverProstate(self.currentResult.name) and not self.session.data.usePreopData)): self.sliceAnnotations.append(SliceAnnotation(self.redWidget, constants.RIGHT_VIEWER_SLICE_ANNOTATION_TEXT, yPos=50 if ModuleWidgetMixin.isQtVersionOlder() else 75, size=20)) self.addNewImageAnnotation(self.redWidget, constants.RIGHT_VIEWER_SLICE_NEEDLE_IMAGE_ANNOTATION_TEXT, size=15) self.addOldImageAnnotation(self.redWidget, constants.RIGHT_VIEWER_SLICE_TRANSFORMED_ANNOTATION_TEXT, size=15) self.addRegistrationResultStatusAnnotation(self.redWidget)
def _fitIntoViewport(self, size): tempSize = self.textProperty.GetFontSize() self.textProperty.SetFontSize(size) self.textActor.SetTextProperty(self.textProperty) if self._getFontWidth() > (self.sliceView.width if ModuleWidgetMixin.isQtVersionOlder() else \ self.sliceView.width * self.sliceView.devicePixelRatio()): self.textProperty.SetFontSize(tempSize) self.textActor.SetTextProperty(self.textProperty) return False return True
def onInvokeRegistration(self, initial=True, retryMode=False, segmentationData=None): self.progress = ModuleWidgetMixin.createProgressDialog(maximum=4, value=1, windowFlags=qt.Qt.CustomizeWindowHint | qt.Qt.WindowTitleHint) self.progress.setCancelButton(None) if initial: self.applyInitialRegistration(retryMode, segmentationData, progressCallback=self.updateProgressBar) else: self.applyRegistration(progressCallback=self.updateProgressBar) self.progress.close() self.progress = None logging.debug('Re-Registration is done')
def setupViewSettingsArea(self): self.fourUpSliceLayoutButton = FourUpLayoutButton() self.fourUpSliceTableViewLayoutButton = FourUpTableViewLayoutButton() self.crosshairButton = CrosshairButton() self.crosshairButton.setSliceIntersectionEnabled(True) hbox = ModuleWidgetMixin.createHLayout([ self.fourUpSliceLayoutButton, self.fourUpSliceTableViewLayoutButton, self.crosshairButton ]) self.layout.addWidget(hbox)
def targetList(self, targetList): self._targetList = targetList if self.currentGuidanceComputation and self.observer: self.self.currentGuidanceComputation.RemoveObserver(self.observer) self.currentGuidanceComputation = self.getOrCreateNewGuidanceComputation(targetList) if self.currentGuidanceComputation: self.observer = self.currentGuidanceComputation.addEventObserver(vtk.vtkCommand.ModifiedEvent, self.updateHoleAndDepth) if ModuleWidgetMixin.isQtVersionOlder(): self.reset() else: self.beginResetModel() self.endResetModel()
def _applyVerticalAlign(self): sliceViewHeight = self.sliceView.height if ModuleWidgetMixin.isQtVersionOlder() else \ self.sliceView.height * self.sliceView.devicePixelRatio() centerY = int((sliceViewHeight - self._getFontHeight()) / 2) if self.yPos: yPos = self.yPos if 0 < self.yPos < centerY else centerY else: if self.verticalAlign == self.ALIGN_TOP: yPos = sliceViewHeight - self._getFontHeight() elif self.verticalAlign == self.ALIGN_CENTER: yPos = centerY elif self.verticalAlign == self.ALIGN_BOTTOM: yPos = 0 return int(yPos)
def _applyHorizontalAlign(self): sliceViewWidth = self.sliceView.width if ModuleWidgetMixin.isQtVersionOlder() else \ self.sliceView.width * self.sliceView.devicePixelRatio() centerX = int((sliceViewWidth - self._getFontWidth()) / 2) if self.xPos: xPos = self.xPos if 0 < self.xPos < centerX else centerX else: if self.horizontalAlign == self.ALIGN_LEFT: xPos = 0 elif self.horizontalAlign == self.ALIGN_CENTER: xPos = centerX elif self.horizontalAlign == self.ALIGN_RIGHT: xPos = sliceViewWidth - self._getFontWidth() return int(xPos)
def _onAnnotationButtonClicked(self, button, checked): currentItem = self._annotationListWidget.currentItem() if not currentItem: return itemWidget = self._annotationListWidget.itemWidget(currentItem) seriesType = itemWidget.getSeriesType() if checked: for b in self._annotationButtonGroup.buttons(): if b.checked and b is not button: b.checked = False for w in ModuleWidgetMixin.getAllVisibleWidgets(): enabled = w.mrmlSliceCompositeNode().GetForegroundVolumeID() is not None and seriesType.getVolume() is \ slicer.mrmlScene.GetNodeByID(w.mrmlSliceCompositeNode().GetForegroundVolumeID()) w.enabled = enabled w.setStyleSheet("#frame{{border: 5px ridge {};}}".format( "green" if enabled else "black")) self._onAnnotationToolSelected(seriesType, button.property("MRML_NODE_CLASS")) else: for w in ModuleWidgetMixin.getAllVisibleWidgets(): w.enabled = True w.setStyleSheet("") self._onAnnotationToolDeselected( seriesType, button.property("MRML_NODE_CLASS"))
def _onLoadButtonClicked(self): self._dataSelectionDialog = DataSelectionDialog() self._loadedVolumeNodes = OrderedDict() nodeAddedObserver = slicer.mrmlScene.AddObserver(slicer.mrmlScene.NodeAddedEvent, self._onVolumeNodeAdded) nodeRemovedObserver = slicer.mrmlScene.AddObserver(slicer.mrmlScene.NodeRemovedEvent, self._onVolumeNodeRemoved) try: if self._dataSelectionDialog.exec_(): self._hangingProtocol = HangingProtocolFactory.getHangingProtocol(self.loadedVolumeNodes.values()) if not self._hangingProtocol: raise RuntimeError("No eligible hanging protocol found.") background = list(self._loadedVolumeNodes.values())[0] self.logic.viewerPerVolume(volumeNodes=self._loadedVolumeNodes.values(), layout=self._hangingProtocol.LAYOUT, background=background) ModuleWidgetMixin.linkAllSliceWidgets(1) for sliceWidget in ModuleWidgetMixin.getAllVisibleWidgets(): sliceWidget.mrmlSliceNode().RotateToVolumePlane(background) self._checkForMultiVolumes() except Exception as exc: logging.error(exc) finally: slicer.mrmlScene.RemoveObserver(nodeAddedObserver) slicer.mrmlScene.RemoveObserver(nodeRemovedObserver) self.updateGUIFromData()
def addNewImageAnnotation(self, widget, text, size=20): self.newImageAnnotation = SliceAnnotation(widget, text, yPos=35 if ModuleWidgetMixin.isQtVersionOlder() else 45, opacity=0.0, color=(0, 0.5, 0), size=size) self.sliceAnnotations.append(self.newImageAnnotation)
def updateProgressBar(self, **kwargs): ModuleWidgetMixin.updateProgressBar(self, progress=self.progress, **kwargs)
class SliceTrackerConstants(object): MODULE_NAME = "SliceTracker" PREOP_SAMPLE_DATA_URL = 'https://github.com/SlicerProstate/SliceTracker/releases/download/test-data/Preop-deid.zip' INTRAOP_SAMPLE_DATA_URL = 'https://github.com/SlicerProstate/SliceTracker/releases/download/test-data/Intraop-deid.zip' JSON_FILENAME = "results.json" MISSING_PREOP_ANNOTATION_TEXT = "No preop data available" LEFT_VIEWER_SLICE_ANNOTATION_TEXT = 'BIOPSY PLAN' RIGHT_VIEWER_SLICE_ANNOTATION_TEXT = 'TRACKED TARGETS' RIGHT_VIEWER_SLICE_TRANSFORMED_ANNOTATION_TEXT = 'OLD' RIGHT_VIEWER_SLICE_NEEDLE_IMAGE_ANNOTATION_TEXT = 'NEW' APPROVED_RESULT_TEXT_ANNOTATION = "approved" REJECTED_RESULT_TEXT_ANNOTATION = "rejected" SKIPPED_RESULT_TEXT_ANNOTATION = "skipped" LAYOUT_RED_SLICE_ONLY = slicer.vtkMRMLLayoutNode.SlicerLayoutOneUpRedSliceView LAYOUT_FOUR_UP = slicer.vtkMRMLLayoutNode.SlicerLayoutFourUpView LAYOUT_FOUR_UP_QUANTITATIVE = slicer.vtkMRMLLayoutNode.SlicerLayoutFourUpPlotView LAYOUT_SIDE_BY_SIDE = slicer.vtkMRMLLayoutNode.SlicerLayoutSideBySideView ALLOWED_LAYOUTS = [LAYOUT_SIDE_BY_SIDE, LAYOUT_FOUR_UP, LAYOUT_RED_SLICE_ONLY, LAYOUT_FOUR_UP_QUANTITATIVE] PLANNING_IMAGE = "PLANNING IMAGE" COVER_PROSTATE = "COVER PROSTATE" COVER_TEMPLATE = "COVER TEMPLATE" GUIDANCE_IMAGE = "GUIDANCE" VIBE_IMAGE = "VIBE" OTHER_IMAGE = "OTHER" TRACKABLE_IMAGE_TYPES = [COVER_PROSTATE, COVER_TEMPLATE, GUIDANCE_IMAGE] ZFrame_INSTRUCTION_STEPS = {1: "Scroll and click into ZFrame center to set ROI center", 2: "Click outside of upper right ZFrame corner to set ROI border"} IntraopSeriesSelectorToolTip = """ <html> <head> <style type="text/css"> </style> </head> <body style="font-family:'Lucida Grande',sans-serif; font-size: 12pt; font-weight: 400; font-style: normal;border: 1px solid black;margin-top:0px;"> <table cellspacing=5> <tbody> <tr> <td> <img src="%s"> </td> <td style="vertical-align: middle"> <strong>tracked</strong>(registration result available) </td> </tr> <tr> <td> <img src="%s"> </td> <td style="vertical-align: middle"> <strong>untracked</strong>(no registration result available) </td> </tr> <tr> <td> <img src="%s"> </td> <td style="vertical-align: middle"> <strong>skipped</strong>(no registration result available) </td> </tr> <tr> <td style="vertical-align: middle"> <img src="%s"> </td> <td> <strong>rejected</strong>(non satisfactory/approved registration result available) </td> </tr> </tbody> </table> </body> </html> """ % (helper.createAndGetRawColoredPixelMap("green"), helper.createAndGetRawColoredPixelMap("yellow"), helper.createAndGetRawColoredPixelMap("red"), helper.createAndGetRawColoredPixelMap("grey"))
def setupPreopLoadedTargets(self): targets = self.data.initialTargets ModuleWidgetMixin.setFiducialNodeVisibility(targets, show=True) self.applyDefaultTargetDisplayNode(targets) self.markupsLogic.JumpSlicesToNthPointInMarkup(targets.GetID(), 0)
def addOldImageAnnotation(self, widget, text, size=20): self.oldImageAnnotation = SliceAnnotation(widget, text, yPos=35 if ModuleWidgetMixin.isQtVersionOlder() else 45, size=size) self.sliceAnnotations.append(self.oldImageAnnotation)