def calculateLRE(case): success, intraopLandmarks = slicer.util.loadMarkupsFiducialList( case['intraopLandmarks'], returnNode=True) success, preopTransformedLandmarks = slicer.util.loadMarkupsFiducialList( case['preopTransformedLandmarks'], returnNode=True) numLandmarks = intraopLandmarks.GetNumberOfFiducials() caseData = [] caseTRE = 0 for i in range(numLandmarks): label = preopTransformedLandmarks.GetNthFiducialLabel(i) label = "-" + label.split("-")[-1] fiducialIndex = getFiducialIndexByLabel(intraopLandmarks, label) intraopPos = ModuleLogicMixin.getTargetPosition( intraopLandmarks, fiducialIndex) preopTransformedPos = ModuleLogicMixin.getTargetPosition( preopTransformedLandmarks, i) landmarkTRE = ModuleLogicMixin.get3DEuclideanDistance( intraopPos, preopTransformedPos) caseTRE = caseTRE + landmarkTRE caseData.append([ " ", intraopLandmarks.GetNthFiducialLabel(fiducialIndex), intraopPos[0], intraopPos[1], intraopPos[2], preopTransformedLandmarks.GetNthFiducialLabel(i), preopTransformedPos[0], preopTransformedPos[1], preopTransformedPos[2], "", landmarkTRE ]) caseTRE = caseTRE / (numLandmarks * 1.0) caseData.append(["", "", "", "", "", "", "", "", "", "", "", caseTRE]) return caseData
def _generateJSON(self, seriesUIDs): data = self._getGeneralMetaInformation() data['imageLibrary'] = [] params = {"metaDataFileName": os.path.join(self.tempDir, "meta.json")} acqTypes = self._getAcquisitionTypes() data["compositeContext"], params[ "compositeContextDataDir"] = self._populateCompositeContext( seriesUIDs) seriesDirs = set( os.path.dirname(os.path.abspath(self.db.filesForSeries(series)[0])) for series in seriesUIDs) params["imageLibraryDataDir"] = os.path.commonprefix(list(seriesDirs)) for series in seriesUIDs: try: data['imageLibrary'].append( self._createImageLibraryEntry(series, acqTypes, params, len(seriesDirs) > 1)) except ValueError as exc: print(exc) if not data['imageLibrary']: raise ValueError( "No eligible series has been found for PIRADS reading!") if not os.path.exists(self.tempDir): ModuleLogicMixin.createDirectory(self.tempDir) with open(params['metaDataFileName'], 'w') as outfile: json.dump(data, outfile, indent=2) return params
def generateJSON4DcmSR(self, dcmSegmentationFile, sourceVolumeNode): measurements = [] sourceImageSeriesUID = ModuleLogicMixin.getDICOMValue(sourceVolumeNode, "0020,000E") logging.debug("SourceImageSeriesUID: {}".format(sourceImageSeriesUID)) segmentationSOPInstanceUID = ModuleLogicMixin.getDICOMValue(dcmSegmentationFile, "0008,0018") logging.debug("SegmentationSOPInstanceUID: {}".format(segmentationSOPInstanceUID)) for segmentID in self.statistics["SegmentIDs"]: if not self.isSegmentValid(segmentID): continue data = dict() data["TrackingIdentifier"] = self.statistics[segmentID, "Segment"] data["ReferencedSegment"] = len(measurements)+1 data["SourceSeriesForImageSegmentation"] = sourceImageSeriesUID data["segmentationSOPInstanceUID"] = segmentationSOPInstanceUID segment = self.segmentationNode.GetSegmentation().GetSegment(segmentID) terminologyEntry = DICOMSegmentationExporter.getDeserializedTerminologyEntry(segment) data["Finding"] = self.createJSONFromTerminologyContext(terminologyEntry)["SegmentedPropertyTypeCodeSequence"] anatomicContext = self.createJSONFromAnatomicContext(terminologyEntry) if anatomicContext.has_key("AnatomicRegionSequence"): data["FindingSite"] = anatomicContext["AnatomicRegionSequence"] data["measurementItems"] = self.createMeasurementItemsForLabelValue(segmentID) measurements.append(data) return measurements
def getPatientInformation(self): if not self.patientInfo: masterVolume = ModuleLogicMixin.getReferencedVolumeFromSegmentationNode(self.segmentationNode) self.patientInfo = self.patientInfoTemplate.format(ModuleLogicMixin.getDICOMValue(masterVolume, DICOMTAGS.PATIENT_NAME), ModuleLogicMixin.getDICOMValue(masterVolume, DICOMTAGS.PATIENT_ID), ModuleLogicMixin.getDICOMValue(masterVolume, DICOMTAGS.PATIENT_BIRTH_DATE)) return self.patientInfo
def getPatientInformation(self): if not self.patientInfo: masterVolume = ModuleLogicMixin.getReferencedVolumeFromSegmentationNode(self.segmentationNode) self.patientInfo = self.patientInfoTemplate.format(ModuleLogicMixin.getDICOMValue(masterVolume, DICOMTAGS.PATIENT_NAME), ModuleLogicMixin.getDICOMValue(masterVolume, DICOMTAGS.PATIENT_ID), ModuleLogicMixin.getDICOMValue(masterVolume, DICOMTAGS.PATIENT_BIRTH_DATE)) return self.patientInfo
def onConfirmSegmentButtonClicked(self): if self.segmentationModified is True: volumesLogic = slicer.modules.volumes.logic() clonedLabelNode = volumesLogic.CloneVolume( slicer.mrmlScene, self.labelNode, self.labelNode.GetName() + "_modified") self.labelNode = clonedLabelNode slicer.modules.segmentations.logic( ).ExportAllSegmentsToLabelmapNode(self.segmentationNode, self.labelNode) ModuleLogicMixin.runBRAINSResample(inputVolume=self.labelNode, referenceVolume=self.volumeNode, outputVolume=self.labelNode) self.accept()
def getSeriesAttributes(self): attributes = dict() volumeNode = self.getReferencedVolumeFromSegmentationNode(self.segmentationNode) seriesNumber = ModuleLogicMixin.getDICOMValue(volumeNode, DICOMTAGS.SERIES_NUMBER) attributes["SeriesNumber"] = "100" if seriesNumber in [None,''] else str(int(seriesNumber)+100) attributes["InstanceNumber"] = "1" return attributes
def generateReport(self): def currentDateTime(): from datetime import datetime return datetime.now().strftime('%Y-%m-%d_%H%M%S') html = self.template.format(self.style, self.getData()) outputPath = os.path.join(slicer.app.temporaryPath, "QIICR", "QR") if not os.path.exists(outputPath): ModuleLogicMixin.createDirectory(outputPath) outputHTML = os.path.join(outputPath, currentDateTime() + "_testReport.html") print(outputHTML) f = open(outputHTML, 'w') f.write(html) f.close() webbrowser.open("file:///private" + outputHTML)
def applyTransformations(data): for d in data: success, transform = slicer.util.loadTransform(d['transform'], returnNode=True) success, preopLandmarks = slicer.util.loadMarkupsFiducialList( d['landmarks'], returnNode=True) ModuleLogicMixin.applyTransform(transform, preopLandmarks) print "saving to : %s" % os.path.dirname(d['landmarks']) ModuleLogicMixin.saveNodeData( preopLandmarks, os.path.dirname(d['landmarks']), FileExtension.FCSV, name="{}-PreopLandmarks-transformed".format(d['case']))
def generateReport(self): def currentDateTime(): from datetime import datetime return datetime.now().strftime('%Y-%m-%d_%H%M%S') html = self.template.format(self.style, self.getData()) outputPath = os.path.join(slicer.app.temporaryPath, "QIICR", "QR") if not os.path.exists(outputPath): ModuleLogicMixin.createDirectory(outputPath) outputHTML = os.path.join(outputPath, currentDateTime()+"_testReport.html") print outputHTML f = open(outputHTML, 'w') f.write(html) f.close() webbrowser.open("file:///private"+outputHTML)
def setupNeedleAndSegModelNode(self): self.clearOldNodesByName(self.NEEDLE_NAME) self.setupFiducialWidgetAndTableWidget() self.setupSegmentationWidget() if self.needleModelNode is None: self.needleModelNode = ModuleLogicMixin.createModelNode( self.NEEDLE_NAME) if (self.needleModelNode.GetScene() is None) or ( not self.needleModelNode.GetScene() == slicer.mrmlScene): slicer.mrmlScene.AddNode(self.needleModelNode) if self.needleModelNode.GetDisplayNode() is None: ModuleLogicMixin.createAndObserveDisplayNode( self.needleModelNode, displayNodeClass=slicer.vtkMRMLModelDisplayNode) self.needleModelNode.GetDisplayNode().SetColor(1.0, 0.0, 0.0) if self.affectedAreaModelNode is None: self.affectedAreaModelNode = ModuleLogicMixin.createModelNode( self.AFFECTEDAREA_NAME) if (self.affectedAreaModelNode.GetScene() is None) or ( not self.affectedAreaModelNode.GetScene() == slicer.mrmlScene): slicer.mrmlScene.AddNode(self.affectedAreaModelNode) if self.affectedAreaModelNode.GetDisplayNode() is None: ModuleLogicMixin.createAndObserveDisplayNode( self.affectedAreaModelNode, displayNodeClass=slicer.vtkMRMLModelDisplayNode) self.affectedAreaModelNode.GetDisplayNode().SetOpacity(0.5) self.affectedAreaModelNode.GetDisplayNode().SetColor(0.0, 1.0, 0.0) if self.data.segmentModelNode is None: # Create segmentation self.data.segmentModelNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(self.data.segmentModelNode) self.data.segmentModelNode.CreateDefaultDisplayNodes( ) # only needed for display self.data.segmentModelNode.CreateDefaultStorageNode() self.data.segmentModelNode.SetName("IntraOpSegmentation") if (self.data.segmentModelNode.GetScene() is None) or ( not self.data.segmentModelNode.GetScene() == slicer.mrmlScene): slicer.mrmlScene.AddNode(self.data.segmentModelNode) if self.data.segmentModelNode.GetDisplayNode() is None: ModuleLogicMixin.createAndObserveDisplayNode( self.data.segmentModelNode, displayNodeClass=slicer.vtkMRMLSegmentationDisplayNode) if self.segmentEditorNode is None: self.segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(self.segmentEditorNode) if (self.segmentEditorNode.GetScene() is None) or ( not self.segmentEditorNode.GetScene() == slicer.mrmlScene): slicer.mrmlScene.AddNode(self.segmentEditorNode) self.segmentationEditor.setMRMLScene(slicer.mrmlScene) self.segmentationEditor.setMRMLSegmentEditorNode( self.segmentEditorNode) self.segmentationEditorMaskOverWriteCombox.setCurrentIndex( self.segmentationEditorMaskOverWriteCombox.findText('None'))
def runRegistrations(data, destination): caseNumber = data["caseNumber"] success, intraopVolume = slicer.util.loadVolume(data["Intraop"]["volume"], returnNode=True) intraopVolume.SetName("{}: IntraopVolume".format(caseNumber)) for segmentationType in ["Manual", "Automatic"]: success, preopVolume = slicer.util.loadVolume(data["Preop"]["volume"], returnNode=True) preopVolume.SetName("{}: PreopVolume".format(caseNumber)) success, preopLabel = slicer.util.loadLabelVolume( data["Preop"]["labels"][segmentationType], returnNode=True) preopLabel.SetName("{}: PreopManual-label".format(caseNumber)) success, intraopLabel = slicer.util.loadLabelVolume( data["Intraop"]["labels"][segmentationType], returnNode=True) intraopLabel.SetName("{}: IntraopManual-label".format(caseNumber)) if data["Preop"]["used_endorectal_coil"] is True: preopVolume = applyBiasCorrection(preopVolume, preopLabel) result = runRegistration(intraopVolume, intraopLabel, preopVolume, preopLabel) if result: for regType, transform in result.transforms.asDict().iteritems(): ModuleLogicMixin.saveNodeData(transform, destination, FileExtension.H5, name="{}-TRANSFORM-{}-{}".format( caseNumber, regType, segmentationType)) for regType, volume in result.volumes.asDict().iteritems(): if not regType in ['rigid', 'affine', 'bSpline']: continue ModuleLogicMixin.saveNodeData(volume, destination, FileExtension.NRRD, name="{}-VOLUME-{}-{}".format( caseNumber, regType, segmentationType))
def load(self, loadable): uid = loadable.uids[0] self.tempDir = os.path.join(slicer.app.temporaryPath, self.TEMPLATE_ID, self.currentDateTime) if not os.path.exists(self.tempDir): ModuleLogicMixin.createDirectory(self.tempDir) outputFile = os.path.join(self.tempDir, "{}.json".format(uid)) srFileName = self.db.fileForInstance(uid) if srFileName is None: logging.debug( 'Failed to get the filename from the DICOM database for ', uid) return False param = { "inputDICOM": srFileName, "metaDataFileName": outputFile, } cliNode = slicer.cli.run(slicer.modules.qiicrxsr, None, param, wait_for_completion=True) if cliNode.GetStatusString() != 'Completed': logging.debug( 'qiicrxsr did not complete successfully, unable to load DICOM {}' .format(self.TEMPLATE_ID)) # self.cleanup() return False with open(outputFile) as metaFile: data = json.load(metaFile) for imageLibraryEntry in data['imageLibrary']: files = [ self.db.fileForInstance(e) for e in imageLibraryEntry['instanceUIDs'] ] self.loadSeries(files) return True
def generateReport(self): def currentDateTime(): from datetime import datetime return datetime.now().strftime('%Y-%m-%d_%H%M%S') html = self.template.format(self.style, self.getData()) outputPath = os.path.join(slicer.app.temporaryPath, "QIICR", "QR") if not os.path.exists(outputPath): ModuleLogicMixin.createDirectory(outputPath) outputHTML = os.path.join(outputPath, currentDateTime()+"_testReport.html") print(outputHTML) f = open(outputHTML, 'w') f.write(html) f.close() # Open the html report in the default web browser import qt qt.QDesktopServices.openUrl(qt.QUrl.fromLocalFile(outputHTML));
def getSeriesAttributes(self): attributes = dict() volumeNode = self.getReferencedVolumeFromSegmentationNode( self.segmentationNode) seriesNumber = ModuleLogicMixin.getDICOMValue(volumeNode, DICOMTAGS.SERIES_NUMBER) attributes["SeriesNumber"] = "100" if seriesNumber in [ None, '' ] else str(int(seriesNumber) + 100) attributes["InstanceNumber"] = "1" return attributes
def caseRootDir(self, path): try: exists = os.path.exists(path) except TypeError: exists = False self.setSetting('CasesRootLocation', path if exists else None) self.casesRootDirectoryButton.text = ModuleLogicMixin.truncatePath( path) if exists else "Choose output directory" self.casesRootDirectoryButton.toolTip = path self.openCaseButton.enabled = exists self.createNewCaseButton.enabled = exists
def createSegmentations(data, outputDir): caseNumber = data["caseNumber"] for imageType in ["Preop", "Intraop"]: automaticLabelPath = data[imageType]["labels"]["Automatic"] if not os.path.exists(automaticLabelPath): logic = AutomaticSegmentationLogic() endorectalCoilUsed = "BWH_WITHOUT_ERC" if data[imageType][ "used_endorectal_coil"] is False else "BWH_WITH_ERC" success, volume = slicer.util.loadVolume(data[imageType]["volume"], returnNode=True) automaticLabel = logic.run(volume, domain=endorectalCoilUsed) labelName = "{}-{}Automatic-label".format(caseNumber, imageType) ModuleLogicMixin.saveNodeData(automaticLabel, outputDir, FileExtension.NRRD, name=labelName) else: print "Not running {} segmentation for case {} because label already exists".format( imageType, caseNumber)
def jumpToSegmentAndCreateScreenShot(segmentationNode, segment, widgets, center=False, crosshair=False): imageData = vtkSegmentationCore.vtkOrientedImageData() segmentID = segmentationNode.GetSegmentation().GetSegmentIdBySegment(segment) segmentationsLogic = slicer.modules.segmentations.logic() segmentationsLogic.GetSegmentBinaryLabelmapRepresentation(segmentationNode, segmentID, imageData) extent = imageData.GetExtent() if extent[1] != -1 and extent[3] != -1 and extent[5] != -1: tempLabel = slicer.vtkMRMLLabelMapVolumeNode() slicer.mrmlScene.AddNode(tempLabel) tempLabel.SetName(segment.GetName() + "CentroidHelper") segmentationsLogic.CreateLabelmapVolumeFromOrientedImageData(imageData, tempLabel) CustomSegmentEditorLogic.applyThreshold(tempLabel, 1) centroid = ModuleLogicMixin.getCentroidForLabel(tempLabel, 1) slicer.mrmlScene.RemoveNode(tempLabel) annotationNodes = [] crosshairButton = None if crosshair: crosshairButton = CrosshairButton() crosshairButton.setSliceIntersectionEnabled(True) crosshairButton.checked = True for widget in widgets: sliceLogic = widget.sliceLogic() sliceNode = sliceLogic.GetSliceNode() if not center: sliceNode.JumpSliceByOffsetting(centroid[0], centroid[1], centroid[2]) else: markupsLogic = slicer.modules.markups.logic() markupsLogic.JumpSlicesToLocation(centroid[0], centroid[1], centroid[2], True) dNodeProperties = ScreenShotHelper.saveSegmentDisplayProperties(segmentationNode, segment) segmentationNode.GetDisplayNode().SetAllSegmentsVisibility(False) ScreenShotHelper.setDisplayNodeProperties(segmentationNode, segment, properties={'fill': True, 'outline': True, 'visible': True}) if crosshairButton: crosshairButton.crosshairNode.SetCrosshairRAS(centroid) annotationNode = ScreenShotHelper.takeScreenShot("{}_Screenshot_{}_{}".format(segment.GetName(), sliceNode.GetName(), sliceNode.GetOrientation()), "", widget) segmentationNode.GetDisplayNode().SetAllSegmentsVisibility(True) ScreenShotHelper.setDisplayNodeProperties(segmentationNode, segment, dNodeProperties) annotationNodes.append(annotationNode) if crosshairButton: crosshairButton.checked = False return annotationNodes[0] if len(annotationNodes) == 1 else annotationNodes
def generateJSON4DcmSR(self, dcmSegmentationFile, sourceVolumeNode): measurements = [] sourceImageSeriesUID = ModuleLogicMixin.getDICOMValue( sourceVolumeNode, "0020,000E") logging.debug("SourceImageSeriesUID: {}".format(sourceImageSeriesUID)) segmentationSOPInstanceUID = ModuleLogicMixin.getDICOMValue( dcmSegmentationFile, "0008,0018") logging.debug("SegmentationSOPInstanceUID: {}".format( segmentationSOPInstanceUID)) for segmentID in self.statistics["SegmentIDs"]: if not self.isSegmentValid(segmentID): continue data = dict() data["TrackingIdentifier"] = self.statistics[segmentID, "Segment"] data["ReferencedSegment"] = len(measurements) + 1 data["SourceSeriesForImageSegmentation"] = sourceImageSeriesUID data["segmentationSOPInstanceUID"] = segmentationSOPInstanceUID segment = self.segmentationNode.GetSegmentation().GetSegment( segmentID) terminologyEntry = DICOMSegmentationExporter.getDeserializedTerminologyEntry( segment) data["Finding"] = self.createJSONFromTerminologyContext( terminologyEntry)["SegmentedPropertyTypeCodeSequence"] anatomicContext = self.createJSONFromAnatomicContext( terminologyEntry) if "AnatomicRegionSequence" in anatomicContext: data["FindingSite"] = anatomicContext["AnatomicRegionSequence"] data[ "measurementItems"] = self.createMeasurementItemsForLabelValue( segmentID) measurements.append(data) return measurements
def refresh(): self.segmentEditorWidget.editor.masterVolumeNodeSelectorVisible = \ self.measurementReportSelector.currentNode() and \ not ModuleLogicMixin.getReferencedVolumeFromSegmentationNode(self.segmentEditorWidget.segmentationNode) masterVolume = self.segmentEditorWidget.masterVolumeNode self.importSegmentationCollapsibleButton.enabled = masterVolume is not None if not self.importSegmentationCollapsibleButton.collapsed: self.importSegmentationCollapsibleButton.collapsed = masterVolume is None self.importLabelMapCollapsibleButton.enabled = masterVolume is not None if not self.importLabelMapCollapsibleButton.collapsed: self.importLabelMapCollapsibleButton.collapsed = masterVolume is None if not self.tableNode: self.enableReportButtons(False) self.updateMeasurementsTable(triggered=True)
def refresh(): self.segmentEditorWidget.editor.masterVolumeNodeSelectorVisible = \ self.measurementReportSelector.currentNode() and \ not ModuleLogicMixin.getReferencedVolumeFromSegmentationNode(self.segmentEditorWidget.segmentationNode) masterVolume = self.segmentEditorWidget.masterVolumeNode self.importSegmentationCollapsibleButton.enabled = masterVolume is not None if not self.importSegmentationCollapsibleButton.collapsed: self.importSegmentationCollapsibleButton.collapsed = masterVolume is None self.importLabelMapCollapsibleButton.enabled = masterVolume is not None if not self.importLabelMapCollapsibleButton.collapsed: self.importLabelMapCollapsibleButton.collapsed = masterVolume is None if not self.tableNode: self.enableReportButtons(False) self.updateMeasurementsTable(triggered=True)
def getSegmentCentroid(segmentationNode, segment): imageData = vtkSegmentationCore.vtkOrientedImageData() segmentID = segmentationNode.GetSegmentation().GetSegmentIdBySegment(segment) segmentationsLogic = slicer.modules.segmentations.logic() segmentationsLogic.GetSegmentBinaryLabelmapRepresentation(segmentationNode, segmentID, imageData) extent = imageData.GetExtent() if extent[1] != -1 and extent[3] != -1 and extent[5] != -1: tempLabel = slicer.vtkMRMLLabelMapVolumeNode() slicer.mrmlScene.AddNode(tempLabel) tempLabel.SetName(segment.GetName() + "CentroidHelper") segmentationsLogic.CreateLabelmapVolumeFromOrientedImageData(imageData, tempLabel) CustomSegmentEditorLogic.applyThreshold(tempLabel, 1) centroid = ModuleLogicMixin.getCentroidForLabel(tempLabel, 1) slicer.mrmlScene.RemoveNode(tempLabel) return centroid return None
def getSegmentCentroid(segmentationNode, segment): imageData = vtkSegmentationCore.vtkOrientedImageData() segmentID = segmentationNode.GetSegmentation().GetSegmentIdBySegment(segment) segmentationsLogic = slicer.modules.segmentations.logic() segmentationsLogic.GetSegmentBinaryLabelmapRepresentation(segmentationNode, segmentID, imageData) extent = imageData.GetExtent() if extent[1] != -1 and extent[3] != -1 and extent[5] != -1: tempLabel = slicer.vtkMRMLLabelMapVolumeNode() slicer.mrmlScene.AddNode(tempLabel) tempLabel.SetName(segment.GetName() + "CentroidHelper") segmentationsLogic.CreateLabelmapVolumeFromOrientedImageData(imageData, tempLabel) CustomSegmentEditorLogic.applyThreshold(tempLabel, 1) centroid = ModuleLogicMixin.getCentroidForLabel(tempLabel, 1) slicer.mrmlScene.RemoveNode(tempLabel) return centroid return None
def updateInformationFromWatchBoxAttribute(self, attribute): if attribute.tags and self.sourceFile: values = [] for tag in attribute.tags: currentValue = ModuleLogicMixin.getDICOMValue(self.sourceFile, tag, "") if tag in self.DATE_TAGS_TO_FORMAT: currentValue = self._formatDate(currentValue) elif tag == DICOMTAGS.PATIENT_NAME: currentValue = self._formatPatientName(currentValue) elif tag == self.CURRENTDIRTAG: path = os.path.normpath(self.sourceFile) folderList = path.split(os.sep) if len(folderList)>=4: currentValue = folderList[-4] values.append(currentValue) return self._getTagValueFromTagValues(values) return ""
def _processData(self, caller=None, event=None): self._seriesTypeLabel.text = "{}: {}".format( ModuleLogicMixin.getDICOMValue(self._seriesType.getVolume(), DICOMTAGS.SERIES_NUMBER), self._seriesType.getName())
def main(argv): try: parser = argparse.ArgumentParser( description="Slicetracker Transform Applicator") parser.add_argument( "-ld", "--landmark-root-directory", dest="landmarkRootDir", metavar="PATH", default="-", required=True, help= "Root directory that lists all cases holding information for landmarks" ) parser.add_argument( "-st", "--segmentation-type", dest="segmentationType", metavar="NAME", default="-", choices=['Manual', 'Automatic'], required=True, help="Expected transform name will be " "{casenumber}-TRANSFORM-{transformType}-{segmentationType}.h5") parser.add_argument( "-tt", "--transform-type", dest="transformType", metavar="NAME", default="-", choices=['rigid', 'affine', 'bSpline'], required=True, help= "%(choices). expected transform name: {casenumber}-TRANSFORM-{transformType}-{segmentationType}.h5" ) parser.add_argument( "-ft", "--fiducial-type", dest="fiducialType", metavar="NAME", default="-", choices=['Targets', 'Landmarks'], required=True, help='list servers, storage, or both (default: %(default)s)') args = parser.parse_args(argv) segmentationType = args.segmentationType transformType = args.transformType fiducialType = args.fiducialType for root, dirs, _ in os.walk(args.landmarkRootDir): for case in dirs: landmarks = os.path.join( root, case, "{}-Preop{}.fcsv".format(case, fiducialType)) transform = os.path.join( root, case, "{}-TRANSFORM-{}-{}.h5".format(case, transformType, segmentationType)) # check if exists and if is identity volume = os.path.join( root, case, "{}-VOLUME-{}-{}.nrrd".format(case, transformType, segmentationType)) if not os.path.exists(volume): logging.info( "Case {}: No valid {} transform found.Falling back to affine" .format(case, transformType)) # volume = os.path.join(root, case, "{}-VOLUME-affine-{}.nrrd".format(case, segmentationType)) transform = os.path.join( root, case, "{}-TRANSFORM-affine-{}.h5".format( case, segmentationType)) if all(os.path.exists(f) for f in [landmarks, transform]): success, landmarksNode = slicer.util.loadMarkupsFiducialList( landmarks, returnNode=True) success, transformNode = slicer.util.loadTransform( transform, returnNode=True) ModuleLogicMixin.applyTransform(transformNode, landmarksNode) fileName = "{}-Preop{}-transformed-{}-{}".format( case, fiducialType, transformType, segmentationType) print "saving to : {}/{}{}".format( os.path.dirname(landmarks), fileName, FileExtension.FCSV) ModuleLogicMixin.saveNodeData(landmarksNode, os.path.dirname(landmarks), FileExtension.FCSV, name=fileName) else: logging.warn( "Did not find landmarks/transforms for case %s" % case) except Exception, e: print e
def findTransformFromDataDirectory(directory): coverProstateFiles = [ item for item in os.listdir(directory) if re.search('.?-T2-COVER-PROSTATE-.?', item) ] if len(coverProstateFiles): seriesNumber = coverProstateFiles[0].split("-")[0] coverProstateFiles = [ i for i in os.listdir(directory) if i.startswith("%s-" % seriesNumber) ] # filter unapproved case first holding -approved suffix = "" targets = {} transforms = {} approvedTargets = None regTypes = ['rigid', 'affine', 'bSpline'] for f in coverProstateFiles: if f.endswith("-approved.fcsv"): success, approvedTargets = slicer.util.loadMarkupsFiducialList( os.path.join(directory, f), returnNode=True) # elif any(regType in f for regType in regTypes): # if "TARGETS" in f: # targets[] # elif "TRANSFORM" in f: elif f.endswith("-affine.fcsv"): targets["affine"] = os.path.join(directory, f) elif f.endswith("-bSpline.fcsv"): targets["bSpline"] = os.path.join(directory, f) elif f.endswith("-rigid.fcsv"): targets["rigid"] = os.path.join(directory, f) elif f.endswith("-affine.h5"): transforms["affine"] = os.path.join(directory, f) elif f.endswith("-bSpline.h5"): transforms["bSpline"] = os.path.join(directory, f) elif f.endswith("-rigid.h5"): transforms["rigid"] = os.path.join(directory, f) minDistance = None smallestDistanceType = None for regType, filepath in targets.iteritems(): print filepath success, tempNode = slicer.util.loadMarkupsFiducialList( filepath, returnNode=True) distance = ModuleLogicMixin.get3DDistance( ModuleLogicMixin.getTargetPosition(tempNode, 0), ModuleLogicMixin.getTargetPosition(approvedTargets, 0)) if not minDistance or distance < minDistance: minDistance = distance smallestDistanceType = regType if smallestDistanceType: print "Smallest distance to approved targets could be computed for type %s" % smallestDistanceType return transforms[smallestDistanceType] raise ValueError( "Approved Cover Prostate transform could not be computed from parsing case directory!" )
def onSegmentationSelected(self, node): if not node: return masterVolume = ModuleLogicMixin.getReferencedVolumeFromSegmentationNode(node) if masterVolume: self.initializeWatchBox(masterVolume)
def jumpToSegmentAndCreateScreenShot(segmentationNode, segment, widgets, center=False, crosshair=False): imageData = vtkSegmentationCore.vtkOrientedImageData() segmentID = segmentationNode.GetSegmentation().GetSegmentIdBySegment( segment) segmentationsLogic = slicer.modules.segmentations.logic() segmentationsLogic.GetSegmentBinaryLabelmapRepresentation( segmentationNode, segmentID, imageData) extent = imageData.GetExtent() if extent[1] != -1 and extent[3] != -1 and extent[5] != -1: tempLabel = slicer.vtkMRMLLabelMapVolumeNode() slicer.mrmlScene.AddNode(tempLabel) tempLabel.SetName(segment.GetName() + "CentroidHelper") segmentationsLogic.CreateLabelmapVolumeFromOrientedImageData( imageData, tempLabel) CustomSegmentEditorLogic.applyThreshold(tempLabel, 1) centroid = ModuleLogicMixin.getCentroidForLabel(tempLabel, 1) slicer.mrmlScene.RemoveNode(tempLabel) annotationNodes = [] crosshairButton = None if crosshair: crosshairButton = CrosshairButton() crosshairButton.setSliceIntersectionEnabled(True) crosshairButton.checked = True for widget in widgets: sliceLogic = widget.sliceLogic() sliceNode = sliceLogic.GetSliceNode() if not center: sliceNode.JumpSliceByOffsetting(centroid[0], centroid[1], centroid[2]) else: markupsLogic = slicer.modules.markups.logic() markupsLogic.JumpSlicesToLocation(centroid[0], centroid[1], centroid[2], True) dNodeProperties = ScreenShotHelper.saveSegmentDisplayProperties( segmentationNode, segment) segmentationNode.GetDisplayNode().SetAllSegmentsVisibility( False) ScreenShotHelper.setDisplayNodeProperties(segmentationNode, segment, properties={ 'fill': True, 'outline': True, 'visible': True }) if crosshairButton: crosshairButton.crosshairNode.SetCrosshairRAS(centroid) annotationNode = ScreenShotHelper.takeScreenShot( "{}_Screenshot_{}_{}".format(segment.GetName(), sliceNode.GetName(), sliceNode.GetOrientation()), "", widget) segmentationNode.GetDisplayNode().SetAllSegmentsVisibility( True) ScreenShotHelper.setDisplayNodeProperties( segmentationNode, segment, dNodeProperties) annotationNodes.append(annotationNode) if crosshairButton: crosshairButton.checked = False return annotationNodes[0] if len( annotationNodes) == 1 else annotationNodes
def updateAffectiveZone(self, caller=None, event=None): targetingNode = self.targetingPlugin.targetTablePlugin.currentTargets if self.targetingPlugin.fiducialsWidget.visible: targetingNode = self.targetingPlugin.fiducialsWidget.currentNode if self.needleModelNode and self.affectedAreaModelNode and self.approvedCoverTemplate and targetingNode.GetNumberOfFiducials( ): needleModelAppend = vtk.vtkAppendPolyData() affectedBallAreaAppend = vtk.vtkAppendPolyData() zFrameTransformMatrix = self.data.zFrameRegistrationResult.transform.GetMatrixTransformToParent( ) # The offset and ellipsoid parameters are taken from the following source code # http://viewvc.slicer.org/viewvc.cgi/NAMICSandBox/trunk/IGTLoadableModules/ProstateNav/TransPerinealProstateCryoTemplate/vtkMRMLTransPerinealProstateCryoTemplateNode.cxx?revision=8043&view=markup offsetFromTip = 5.0 #unit mm coneHeight = 5.0 for targetIndex in range(targetingNode.GetNumberOfFiducials()): if self.displayForTargets.get( targetingNode.GetNthMarkupID( targetIndex)) == qt.Qt.Checked: affectedBallAreaRadius = self.GetIceBallRadius( self.needleTypeForTargets.get( targetingNode.GetNthMarkupID( targetIndex))) # unit mm targetPosition = [0.0, 0.0, 0.0] targetingNode.GetNthFiducialPosition( targetIndex, targetPosition) (start, end, indexX, indexY, depth, inRange) = self.needlePathCaculator.computeNearestPath( targetPosition) needleDirection = (numpy.array(end) - numpy.array(start)) / numpy.linalg.norm( numpy.array(end) - numpy.array(start)) cone = vtk.vtkConeSource() cone.SetRadius(1.5) cone.SetResolution(6) cone.SetHeight(coneHeight) cone.CappingOff() cone.Update() transform = vtk.vtkTransform() transform.RotateY(-90) transform.RotateX(30) transform.Translate(-coneHeight / 2, 0.0, 0.0) tFilter0 = vtk.vtkTransformPolyDataFilter() tFilter0.SetInputData(cone.GetOutput()) tFilter0.SetTransform(transform) tFilter0.Update() translatePart = start + depth * needleDirection for index, posElement in enumerate(translatePart): zFrameTransformMatrix.SetElement(index, 3, posElement) transform.SetMatrix(zFrameTransformMatrix) tFilter1 = vtk.vtkTransformPolyDataFilter() tFilter1.SetTransform(transform) tFilter1.SetInputData(tFilter0.GetOutput()) tFilter1.Update() needleModelAppend.AddInputData(tFilter1.GetOutput()) needleModelAppend.Update() pathTubeFilter = ModuleLogicMixin.createVTKTubeFilter( start, start + (depth - coneHeight) * needleDirection, radius=1.5, numSides=6) needleModelAppend.AddInputData(pathTubeFilter.GetOutput()) needleModelAppend.Update() #End of needle model #-------------- #-------------- #Begin of affectedBallArea affectedBallArea = vtk.vtkParametricEllipsoid() affectedBallArea.SetXRadius( float(affectedBallAreaRadius[0])) affectedBallArea.SetYRadius( float(affectedBallAreaRadius[1])) affectedBallArea.SetZRadius( float(affectedBallAreaRadius[2])) affectedBallAreaSource = vtk.vtkParametricFunctionSource() affectedBallAreaSource.SetParametricFunction( affectedBallArea) affectedBallAreaSource.SetScalarModeToV() affectedBallAreaSource.Update() translatePart = start + (depth + offsetFromTip - float( affectedBallAreaRadius[2])) * needleDirection for index, posElement in enumerate(translatePart): zFrameTransformMatrix.SetElement(index, 3, posElement) transform.SetMatrix(zFrameTransformMatrix) tFilter2 = vtk.vtkTransformPolyDataFilter() tFilter2.SetTransform(transform) tFilter2.SetInputData(affectedBallAreaSource.GetOutput()) tFilter2.Update() affectedBallAreaAppend.AddInputData(tFilter2.GetOutput()) affectedBallAreaAppend.Update() self.needleModelNode.SetAndObservePolyData( needleModelAppend.GetOutput()) self.affectedAreaModelNode.SetAndObservePolyData( affectedBallAreaAppend.GetOutput()) ModuleLogicMixin.setNodeVisibility(self.needleModelNode, True) ModuleLogicMixin.setNodeVisibility(self.affectedAreaModelNode, True) ModuleLogicMixin.setNodeSliceIntersectionVisibility( self.needleModelNode, True) ModuleLogicMixin.setNodeSliceIntersectionVisibility( self.affectedAreaModelNode, True) pass
else: print "Data was not found for case %s" % case return data def calculateLRE(case, landmark, transformed): success, landmarksNode = slicer.util.loadMarkupsFiducialList( landmark, returnNode=True) success, transformedNode = slicer.util.loadMarkupsFiducialList( transformed, returnNode=True) caseData = [] for i in range(landmarksNode.GetNumberOfFiducials()): landmarkData = [case] landmarkPos = ModuleLogicMixin.getTargetPosition(landmarksNode, i) transformedPos = ModuleLogicMixin.getTargetPosition(transformedNode, i) landmarkTRE = ModuleLogicMixin.get3DEuclideanDistance( landmarkPos, transformedPos) landmarkData.append(landmarksNode.GetNthFiducialLabel(i)) landmarkData.append(str(landmarkPos)) landmarkData.append(transformedNode.GetNthFiducialLabel(i)) landmarkData.append(str(transformedPos)) landmarkData.append(landmarkTRE) caseData.append(landmarkData) return caseData
def copyData(data, outputDir): logic = DeepInfer.DeepInferLogic() parameters = DeepInfer.ModelParameters() segmenter_json_file = os.path.join(DeepInfer.JSON_LOCAL_DIR, "ProstateNeedleFinder.json") with open(segmenter_json_file, "r") as fp: j = json.load(fp, object_pairs_hook=OrderedDict) iodict = parameters.create_iodict(j) dockerName, modelName, dataPath = parameters.create_model_info(j) csvData = [[ 'Case', 'SeriesNumber', 'TargetName', 'Pos', 'NeedleDistance', 'ErrorVector', 'Comment' ]] for case, caseData in data.iteritems(): if not caseData: continue outputCaseDir = os.path.join(outputDir, case) if not os.path.exists(outputCaseDir): ModuleLogicMixin.createDirectory(outputCaseDir) print "processing data of case %s" % case for data in caseData: seriesNumber = data["seriesNumber"] inputs = dict() temp = os.path.join(outputCaseDir, "{}-label.nrrd".format(seriesNumber)) if not os.path.exists(temp): copy(os.path.join(data["path"], data["label"]), temp) # success, inputs['InputProstateMask'] = slicer.util.loadLabelVolume(temp, returnNode=True) temp = os.path.join(outputCaseDir, "{}-volume.nrrd".format(seriesNumber)) if not os.path.exists(temp): copy(os.path.join(data["path"], data["volume"]), temp) # success, inputs['InputVolume'] = slicer.util.loadVolume(temp, returnNode=True) temp = os.path.join(outputCaseDir, "{}-targets.fcsv".format(seriesNumber)) if not os.path.exists(temp): copy(os.path.join(data["path"], data["targets"]), temp) success, targetNode = slicer.util.loadMarkupsFiducialList( temp, returnNode=True) temp = os.path.join(outputCaseDir, "{}-needle-label.nrrd".format(seriesNumber)) if not os.path.exists(temp): outputs = dict() outputs['OutputLabel'] = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLLabelMapVolumeNode") outputs[ 'OutputFiducialList'] = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLMarkupsFiducialNode") params = dict() params['InferenceType'] = 'Ensemble' logic.executeDocker(dockerName, modelName, dataPath, iodict, inputs, params) logic.updateOutput(iodict, outputs) ModuleLogicMixin.saveNodeData( outputs['OutputLabel'], outputCaseDir, FileExtension.NRRD, name="{}-needle-label".format(seriesNumber)) ModuleLogicMixin.saveNodeData( outputs['OutputFiducialList'], outputCaseDir, FileExtension.FCSV, name="{}-needle-tip".format(seriesNumber)) temp = os.path.join( outputCaseDir, "{}-needle-centerline.fcsv".format(seriesNumber)) if not os.path.exists(temp): centerLine = CenterLinePoints( os.path.join(outputCaseDir, "{}-needle-label.nrrd".format(seriesNumber))) points_ijk = centerLine.get_needle_points_ijk() points_ras = centerLine.convert_points_ijk_to_ras(points_ijk) centerLineNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLMarkupsFiducialNode") for point in points_ras: centerLineNode.AddFiducialFromArray(point) centerLineNode.SetLocked(True) ModuleLogicMixin.saveNodeData( centerLineNode, outputCaseDir, FileExtension.FCSV, name="{}-needle-centerline".format(seriesNumber)) success, centerLineNode = slicer.util.loadMarkupsFiducialList( temp, returnNode=True) if not centerLineNode.GetNumberOfFiducials(): csvData.append([ case, seriesNumber, "", "", "", "", "No centerline was found" ]) else: cmLogic = CurveMaker.CurveMakerLogic() cmLogic.DestinationNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelNode") cmLogic.SourceNode = centerLineNode cmLogic.updateCurve() cmLogic.CurvePoly = vtk.vtkPolyData() cmLogic.enableAutomaticUpdate(1) for idx in range(targetNode.GetNumberOfFiducials()): targetName = targetNode.GetNthFiducialLabel(idx) if targetName.lower() in ["right", "left"]: continue pos = ModuleLogicMixin.getTargetPosition(targetNode, idx) (distance, minErrorVec) = cmLogic.distanceToPoint(pos, True) # print "{}: {} ({})".format(targetName, distance, minErrorVec) csvData.append([ case, seriesNumber, targetName, pos, distance, minErrorVec, "" ]) def cleanup(): slicer.mrmlScene.RemoveNode(cmLogic.DestinationNode) cleanup() return csvData
def getData(self): annotationLogic = slicer.modules.annotations.logic() qrLogic = CustomSegmentEditorLogic data = "" def find_2nd(string, substring): return string.find(substring, string.find(substring) + 1) widget = self.redWidget for w in [self.redWidget, self.greenWidget]: ScreenShotHelper.addRuler(w) self.setFOV2Largest2DRegion(widget) self.greenWidget.sliceLogic().FitSliceToAll() fov = self.greenSliceNode.GetFieldOfView() masterVolume = ModuleLogicMixin.getReferencedVolumeFromSegmentationNode(self.segmentationNode) xNumSlices = masterVolume.GetImageData().GetDimensions() [0] xSpacing = masterVolume.GetSpacing()[0] size = xNumSlices * xSpacing self.greenSliceNode.SetFieldOfView(size, fov[1] * size/fov[0], fov[2]) tableHelper = vtkMRMLTableNodeHTMLHelper(self.statistics) for idx, segment in enumerate(qrLogic.getAllSegments(self.segmentationNode)): redAnnotationNode = self.jumpToSegmentAndCreateScreenShot(self.segmentationNode, segment, [widget], center=True) redSS = annotationLogic.GetHTMLRepresentation(redAnnotationNode, 0) redSS = redSS[find_2nd(redSS, "<img src="):redSS.find(">", find_2nd(redSS, "<img src=")) + 1] redSS = redSS.replace("width='400'", "width=100%") greenAnnotationNode = self.jumpToSegmentAndCreateScreenShot(self.segmentationNode, segment, [self.greenWidget], center=False, crosshair=True) greenSS = annotationLogic.GetHTMLRepresentation(greenAnnotationNode, 0) greenSS = greenSS[find_2nd(greenSS, "<img src="):greenSS.find(">", find_2nd(greenSS, "<img src=")) + 1] greenSS = greenSS.replace("width='400'", "width=100%") data += ''' <div class="print-friendly"> <h2>{0}</h2> <table border=1 width='100%' cellPadding=3 cellSpacing=0> <thead> <tr> <th><b>Terminology</b></th> <th><b>Patient Info</b></th> </tr> </thead> <tr> <td valign='top' width='50%'>{1}</td> <td valign='top' width='50%'>{2}</td> </tr> </table> <br> <table border=1 width='100%' cellPadding=3 cellSpacing=0> <thead border=1> <tr> <th colspan="2"><b>Screenshots</b></th> </tr> <tr> <th><b>Axial</b></th> <th><b>Coronal</b></th> </tr> </thead> <tr> <td>{3}</td> <td>{4}</td> </tr> </table> <br> <table border=1 width='100%' cellPadding=3 cellSpacing=0> <thead border=1> <tr> <th><b>Measurements</b></th> </tr> </thead> <tr> <td valign='top' width='100%'>{5}</td> </tr> </table> </div> '''.format(tableHelper.getNthSegmentName(idx), self.getTerminologyInformation(segment), self.getPatientInformation(), redSS, greenSS, tableHelper.getHeaderAndNthRow(idx)) for w in [self.redWidget, self.greenWidget]: ScreenShotHelper.hideRuler(w) # ModuleWidgetMixin.setFOV(sliceLogic, savedFOV) return data
def onSegmentationSelected(self, node): if not node: return masterVolume = ModuleLogicMixin.getReferencedVolumeFromSegmentationNode(node) if masterVolume: self.initializeWatchBox(masterVolume)
def getData(self): annotationLogic = slicer.modules.annotations.logic() qrLogic = CustomSegmentEditorLogic data = "" def find_2nd(string, substring): return string.find(substring, string.find(substring) + 1) widget = self.redWidget for w in [self.redWidget, self.greenWidget]: ScreenShotHelper.addRuler(w) self.setFOV2Largest2DRegion(widget) self.greenWidget.sliceLogic().FitSliceToAll() fov = self.greenSliceNode.GetFieldOfView() masterVolume = ModuleLogicMixin.getReferencedVolumeFromSegmentationNode(self.segmentationNode) xNumSlices = masterVolume.GetImageData().GetDimensions() [0] xSpacing = masterVolume.GetSpacing()[0] size = xNumSlices * xSpacing self.greenSliceNode.SetFieldOfView(size, fov[1] * size/fov[0], fov[2]) tableHelper = vtkMRMLTableNodeHTMLHelper(self.statistics) for idx, segment in enumerate(qrLogic.getAllSegments(self.segmentationNode)): redAnnotationNode = self.jumpToSegmentAndCreateScreenShot(self.segmentationNode, segment, [widget], center=True) redSS = annotationLogic.GetHTMLRepresentation(redAnnotationNode, 0) redSS = redSS[find_2nd(redSS, "<img src="):redSS.find(">", find_2nd(redSS, "<img src=")) + 1] redSS = redSS.replace("width='400'", "width=100%") greenAnnotationNode = self.jumpToSegmentAndCreateScreenShot(self.segmentationNode, segment, [self.greenWidget], center=False, crosshair=True) greenSS = annotationLogic.GetHTMLRepresentation(greenAnnotationNode, 0) greenSS = greenSS[find_2nd(greenSS, "<img src="):greenSS.find(">", find_2nd(greenSS, "<img src=")) + 1] greenSS = greenSS.replace("width='400'", "width=100%") data += ''' <div class="print-friendly"> <h2>{0}</h2> <table border=1 width='100%' cellPadding=3 cellSpacing=0> <thead> <tr> <th><b>Terminology</b></th> <th><b>Patient Info</b></th> </tr> </thead> <tr> <td valign='top' width='50%'>{1}</td> <td valign='top' width='50%'>{2}</td> </tr> </table> <br> <table border=1 width='100%' cellPadding=3 cellSpacing=0> <thead border=1> <tr> <th colspan="2"><b>Screenshots</b></th> </tr> <tr> <th><b>Axial</b></th> <th><b>Coronal</b></th> </tr> </thead> <tr> <td>{3}</td> <td>{4}</td> </tr> </table> <br> <table border=1 width='100%' cellPadding=3 cellSpacing=0> <thead border=1> <tr> <th><b>Measurements</b></th> </tr> </thead> <tr> <td valign='top' width='100%'>{5}</td> </tr> </table> </div> '''.format(tableHelper.getNthSegmentName(idx), self.getTerminologyInformation(segment), self.getPatientInformation(), redSS, greenSS, tableHelper.getHeaderAndNthRow(idx)) for w in [self.redWidget, self.greenWidget]: ScreenShotHelper.hideRuler(w) # ModuleWidgetMixin.setFOV(sliceLogic, savedFOV) return data