def runWatershed(self, masterImageData, seedLabelmap, outputLabelmap): masterVolumeNode = slicer.vtkMRMLScalarVolumeNode() slicer.mrmlScene.AddNode(masterVolumeNode) slicer.vtkSlicerSegmentationsModuleLogic.CopyOrientedImageDataToVolumeNode(masterImageData, masterVolumeNode) seedLabelmapNode = slicer.vtkMRMLLabelMapVolumeNode() slicer.mrmlScene.AddNode(seedLabelmapNode) slicer.vtkSlicerSegmentationsModuleLogic.CopyOrientedImageDataToVolumeNode(seedLabelmap, seedLabelmapNode) # Read input data from Slicer into SimpleITK labelImage = sitk.ReadImage(sitkUtils.GetSlicerITKReadWriteAddress(seedLabelmapNode.GetName())) backgroundImage = sitk.ReadImage(sitkUtils.GetSlicerITKReadWriteAddress(masterVolumeNode.GetName())) # Run watershed filter featureImage = sitk.GradientMagnitudeRecursiveGaussian(backgroundImage, float(self.scriptedEffect.doubleParameter(FEATURE_SIZE_MM_PARAMETER_NAME))) del backgroundImage f = sitk.MorphologicalWatershedFromMarkersImageFilter() f.SetMarkWatershedLine(False) f.SetFullyConnected(False) labelImage = f.Execute(featureImage, labelImage) del featureImage # Pixel type of watershed output is the same as the input. Convert it to int16 now. if labelImage.GetPixelID() != sitk.sitkInt16: labelImage = sitk.Cast(labelImage, sitk.sitkInt16) # Write result from SimpleITK to Slicer. This currently performs a deep copy of the bulk data. sitk.WriteImage(labelImage, sitkUtils.GetSlicerITKReadWriteAddress(seedLabelmapNode.GetName())) # Update segmentation from labelmap node and remove temporary nodes outputLabelmap.ShallowCopy(seedLabelmapNode.GetImageData()) outputLabelmap.SetExtent(masterImageData.GetExtent()) slicer.mrmlScene.RemoveNode(masterVolumeNode) slicer.mrmlScene.RemoveNode(seedLabelmapNode)
def apply(self): if not self.editUtil.getBackgroundImage() or not self.editUtil.getLabelImage(): return node = self.editUtil.getParameterNode() self.undoRedo.saveState() # # get the label and background images # sliceLogic = self.sliceWidget.sliceLogic() labelLogic = sliceLogic.GetLabelLayer() labelNode = labelLogic.GetVolumeNode() labelNodeName = labelNode.GetName() backgroundLogic = sliceLogic.GetBackgroundLayer() backgroundNode = backgroundLogic.GetVolumeNode() backgroundNodeName = backgroundNode.GetName() backgroundImage = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress( backgroundNodeName ) ) filter = sitk.DoubleThresholdImageFilter() filter.SetThreshold1( self.outer_min ) filter.SetThreshold2( self.min ) filter.SetThreshold3( self.max ) filter.SetThreshold4( self.outer_max ) filter.FullyConnectedOn() filter.SetInsideValue( self.editUtil.getLabel() ) filter.SetOutsideValue( 0 ) # todo # cast to output scalar type sitk.WriteImage( filter.Execute(backgroundImage), sitkUtils.GetSlicerITKReadWriteAddress( labelNodeName ) )
def getBoundingBox(self, fixedLabelNodeID, movingLabelNodeID): ls = sitk.LabelStatisticsImageFilter() fixedLabelNode = slicer.mrmlScene.GetNodeByID(fixedLabelNodeID) movingLabelNode = slicer.mrmlScene.GetNodeByID(movingLabelNodeID) fixedLabelAddress = sitkUtils.GetSlicerITKReadWriteAddress( fixedLabelNode.GetName()) movingLabelAddress = sitkUtils.GetSlicerITKReadWriteAddress( movingLabelNode.GetName()) fixedLabelImage = sitk.ReadImage(fixedLabelAddress) movingLabelImage = sitk.ReadImage(movingLabelAddress) cast = sitk.CastImageFilter() cast.SetOutputPixelType(2) unionLabelImage = (cast.Execute(fixedLabelImage) + cast.Execute(movingLabelImage)) > 0 unionLabelImage = cast.Execute(unionLabelImage) ls.Execute(unionLabelImage, unionLabelImage) bb = ls.GetBoundingBox(1) print(str(bb)) size = unionLabelImage.GetSize() bbMin = (max(0, bb[0] - 30), max(0, bb[2] - 30), max(0, bb[4] - 5)) bbMax = (size[0] - min(size[0], bb[1] + 30), size[1] - min(size[1], bb[3] + 30), size[2] - (min(size[2], bb[5] + 5))) return (bbMin, bbMax)
def computePreviewLabelmap(self, mergedImage, outputLabelmap): import vtkSegmentationCorePython as vtkSegmentationCore import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic # This can be a long operation - indicate it to the user qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor) masterVolumeNode = slicer.vtkMRMLScalarVolumeNode() slicer.mrmlScene.AddNode(masterVolumeNode) slicer.vtkSlicerSegmentationsModuleLogic.CopyOrientedImageDataToVolumeNode( self.clippedMasterImageData, masterVolumeNode) mergedLabelmapNode = slicer.vtkMRMLLabelMapVolumeNode() slicer.mrmlScene.AddNode(mergedLabelmapNode) slicer.vtkSlicerSegmentationsModuleLogic.CopyOrientedImageDataToVolumeNode( mergedImage, mergedLabelmapNode) outputRasToIjk = vtk.vtkMatrix4x4() mergedImage.GetImageToWorldMatrix(outputRasToIjk) outputExtent = mergedImage.GetExtent() # Run segmentation algorithm import SimpleITK as sitk import sitkUtils # Read input data from Slicer into SimpleITK labelImage = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress( mergedLabelmapNode.GetName())) backgroundImage = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(masterVolumeNode.GetName())) # Run watershed filter featureImage = sitk.GradientMagnitudeRecursiveGaussian( backgroundImage, float(self.scriptedEffect.doubleParameter("ObjectScaleMm"))) del backgroundImage f = sitk.MorphologicalWatershedFromMarkersImageFilter() f.SetMarkWatershedLine(False) f.SetFullyConnected(False) labelImage = f.Execute(featureImage, labelImage) del featureImage # Pixel type of watershed output is the same as the input. Convert it to int16 now. if labelImage.GetPixelID() != sitk.sitkInt16: labelImage = sitk.Cast(labelImage, sitk.sitkInt16) # Write result from SimpleITK to Slicer. This currently performs a deep copy of the bulk data. sitk.WriteImage( labelImage, sitkUtils.GetSlicerITKReadWriteAddress( mergedLabelmapNode.GetName())) # Update segmentation from labelmap node and remove temporary nodes outputLabelmap.ShallowCopy(mergedLabelmapNode.GetImageData()) outputLabelmap.SetImageToWorldMatrix(outputRasToIjk) outputLabelmap.SetExtent(outputExtent) slicer.mrmlScene.RemoveNode(masterVolumeNode) slicer.mrmlScene.RemoveNode(mergedLabelmapNode) qt.QApplication.restoreOverrideCursor()
def onApply(self): # Get list of visible segment IDs, as the effect ignores hidden segments. segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode() visibleSegmentIds = vtk.vtkStringArray() segmentationNode.GetDisplayNode().GetVisibleSegmentIDs(visibleSegmentIds) if visibleSegmentIds.GetNumberOfValues() == 0: logging.info("Smoothing operation skipped: there are no visible segments") return # This can be a long operation - indicate it to the user qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor) # Allow users revert to this state by clicking Undo self.scriptedEffect.saveStateForUndo() # Export master image data to temporary new volume node. # Note: Although the original master volume node is already in the scene, we do not use it here, # because the master volume may have been resampled to match segmentation geometry. import vtkSegmentationCorePython as vtkSegmentationCore masterVolumeNode = slicer.vtkMRMLScalarVolumeNode() slicer.mrmlScene.AddNode(masterVolumeNode) masterVolumeNode.SetAndObserveTransformNodeID(segmentationNode.GetTransformNodeID()) slicer.vtkSlicerSegmentationsModuleLogic.CopyOrientedImageDataToVolumeNode(self.scriptedEffect.masterVolumeImageData(), masterVolumeNode) # Generate merged labelmap of all visible segments, as the filter expects a single labelmap with all the labels. mergedLabelmapNode = slicer.vtkMRMLLabelMapVolumeNode() slicer.mrmlScene.AddNode(mergedLabelmapNode) slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentsToLabelmapNode(segmentationNode, visibleSegmentIds, mergedLabelmapNode, masterVolumeNode) # Run segmentation algorithm import SimpleITK as sitk import sitkUtils # Read input data from Slicer into SimpleITK labelImage = sitk.ReadImage(sitkUtils.GetSlicerITKReadWriteAddress(mergedLabelmapNode.GetName())) backgroundImage = sitk.ReadImage(sitkUtils.GetSlicerITKReadWriteAddress(masterVolumeNode.GetName())) # Run watershed filter featureImage = sitk.GradientMagnitudeRecursiveGaussian(backgroundImage, float(self.scriptedEffect.doubleParameter("ObjectScaleMm"))) del backgroundImage f = sitk.MorphologicalWatershedFromMarkersImageFilter() f.SetMarkWatershedLine(False) f.SetFullyConnected(False) labelImage = f.Execute(featureImage, labelImage) del featureImage # Pixel type of watershed output is the same as the input. Convert it to int16 now. if labelImage.GetPixelID() != sitk.sitkInt16: labelImage = sitk.Cast(labelImage, sitk.sitkInt16) # Write result from SimpleITK to Slicer. This currently performs a deep copy of the bulk data. sitk.WriteImage(labelImage, sitkUtils.GetSlicerITKReadWriteAddress(mergedLabelmapNode.GetName())) mergedLabelmapNode.GetImageData().Modified() mergedLabelmapNode.Modified() # Update segmentation from labelmap node and remove temporary nodes slicer.vtkSlicerSegmentationsModuleLogic.ImportLabelmapToSegmentationNode(mergedLabelmapNode, segmentationNode, visibleSegmentIds) slicer.mrmlScene.RemoveNode(masterVolumeNode) slicer.mrmlScene.RemoveNode(mergedLabelmapNode) qt.QApplication.restoreOverrideCursor()
def prepareLabelsFromSegmentation(self, segmentationNode, grayscaleImage, labelsDict): import vtkSegmentationCorePython as vtkSegmentationCore segLogic = slicer.modules.segmentations.logic() segmentation = segmentationNode.GetSegmentation() binaryRepresentationDef = vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName() if not segmentation.ContainsRepresentation(binaryRepresentationDef): segmentation.CreateRepresentation(binaryRepresentationDef) segmentLabelmapNode = slicer.vtkMRMLLabelMapVolumeNode() slicer.mrmlScene.AddNode(segmentLabelmapNode) for segmentID in range(segmentation.GetNumberOfSegments()): segment = segmentation.GetNthSegment(segmentID) segmentLabelmap = segment.GetRepresentation( vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName()) if not segLogic.CreateLabelmapVolumeFromOrientedImageData(segmentLabelmap, segmentLabelmapNode): self.logger.error("Failed to convert label map") return labelsDict labelmapImage = sitk.ReadImage(sitkUtils.GetSlicerITKReadWriteAddress(segmentLabelmapNode.GetName())) labelmapImage = self.resampleITKLabel(labelmapImage, grayscaleImage) labelsDict[segmentationNode.GetName()+"_segment_"+segment.GetName()] = labelmapImage displayNode = segmentLabelmapNode.GetDisplayNode() if displayNode: slicer.mrmlScene.RemoveNode(displayNode) slicer.mrmlScene.RemoveNode(segmentLabelmapNode) return labelsDict
def onFiducialNode(self, name, mrmlWidget, isPoint): if not mrmlWidget.visible: return annotationFiducialNode = mrmlWidget.currentNode() # point in physical space coord = [0, 0, 0] if annotationFiducialNode.GetClassName( ) == "vtkMRMLMarkupsFiducialNode": # slicer4 Markups node if annotationFiducialNode.GetNumberOfFiducials() < 1: return annotationFiducialNode.GetNthFiducialPosition(0, coord) else: annotationFiducialNode.GetFiducialCoordinates(coord) # HACK transform from RAS to LPS coord = [-coord[0], -coord[1], coord[2]] # FIXME: we should not need to copy the image if not isPoint and len(self.inputs) and self.inputs[0]: imgNodeName = self.inputs[0].GetName() img = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(imgNodeName)) coord = img.TransformPhysicalPointToIndex(coord) exec('self.filter.Set{0}(coord)'.format(name))
def run(self, filter, outputMRMLNode, outputLabelMap, *inputs): """ Run the actual algorithm """ if self.thread.is_alive(): import sys sys.stderr.write("FilterLogic is already executing!") return inputImages = [] for i in inputs: if i is None: break imgNodeName = i.GetName() img = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(imgNodeName)) inputImages.append(img) self.output = None # check self.outputNodeName = outputMRMLNode.GetName() self.outputLabelMap = outputLabelMap self.abort = False self.thread = threading.Thread(target=lambda f=filter, i=inputImages: self.thread_doit(f, *inputImages)) self.main_queue_start() self.thread.start()
def calculateFeatures(self, imageNode, labelNode, segmentationNode, extractor): """ Calculate the feature on the image node for each ROI contained in the labelNode and/or the segmentation node, using an instantiated RadiomicsFeatureExtractor (with customization already configured). """ # Prepare the input volume self.logger.debug('Read the input image node') grayscaleImage = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(imageNode.GetName())) # Prepare the input label map self.logger.debug('Read and prepare the input ROI(s)') labelsDict = {} if labelNode: labelsDict = self.prepareLabelsFromLabelmap( labelNode, grayscaleImage, labelsDict) if segmentationNode: labelsDict = self.prepareLabelsFromSegmentation( segmentationNode, grayscaleImage, labelsDict) # Calculate the features featuresDict = {} for l in labelsDict.keys(): self.logger.debug("Calculating features for " + l) try: self.logger.debug('Starting feature calculation') featuresDict[l] = extractor.execute(grayscaleImage, labelsDict[l]) self.logger.debug('Features calculated') except: self.logger.error('calculateFeatures() failed') traceback.print_exc() return featuresDict
def run(self, imageNode, labelNode, segmentationNode, featureClasses, **kwargs): """ Run the actual algorithm """ self.logger.info('Processing started') grayscaleImage = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(imageNode.GetName())) #sitkUtils.PushToSlicer(label, labelNode.GetName(), overwrite=True, compositeView=2) labelsDict = {} if labelNode: labelsDict = self.prepareLabelsFromLabelmap( labelNode, grayscaleImage, labelsDict) if segmentationNode: labelsDict = self.prepareLabelsFromSegmentation( segmentationNode, grayscaleImage, labelsDict) #self.featureValues = extractor.execute(grayscaleImage, labelImage, image, **kwargs) featuresDict = {} for l in labelsDict.keys(): self.logger.debug("Calculating features for " + l) featuresDict[l] = self.calculateFeatures(grayscaleImage, labelsDict[l], featureClasses, **kwargs) return featuresDict
def _getLabelGeneratorFromLabelMap(self, labelNode, imageNode): combinedLabelImage = sitk.ReadImage(sitkUtils.GetSlicerITKReadWriteAddress(labelNode.GetName())) combinedLabelArray = sitk.GetArrayFromImage(combinedLabelImage) labels = numpy.unique(combinedLabelArray) for l in labels: if l == 0: continue yield '%s_label_%d' % (labelNode.GetName(), l), labelNode, int(l), imageNode
def onInputSelect(self, mrmlNode, n): self.inputs[n] = mrmlNode if n == 0 and self.inputs[0]: # if the input zero is a label assume the output is too, test widgets self.onOutputLabelMapChanged(mrmlNode.GetLabelMap()) imgNodeName = self.inputs[0].GetName() img = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(imgNodeName))
def doit(self): import SimpleITK as sitk import sitkUtils labelLogic = self.sliceLogic.GetLabelLayer() labelNode = labelLogic.GetVolumeNode() labelNodeName = labelNode.GetName() labelImage = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(labelNodeName)) backgroundLogic = self.sliceLogic.GetBackgroundLayer() backgroundNode = backgroundLogic.GetVolumeNode() backgroundNodeName = backgroundNode.GetName() backgroundImage = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(backgroundNodeName)) # store a backup copy of the label map for undo # (this happens in it's own thread, so it is cheap) if self.undoRedo: self.undoRedo.saveState() featureImage = sitk.GradientMagnitudeRecursiveGaussian( backgroundImage, float(self.sigma)) del backgroundImage f = sitk.MorphologicalWatershedFromMarkersImageFilter() f.SetMarkWatershedLine(False) f.SetFullyConnected(False) labelImage = f.Execute(featureImage, labelImage) del featureImage # The output of the watershed is the same as the input. # But Slicer expects labelMaps to be Int16, so convert to that # type to improve compatibility, just in case if needed. if labelImage.GetPixelID() != sitk.sitkInt16: labelImage = sitk.Cast(labelImage, sitk.sitkInt16) # This currently performs a deep copy of the bulk data. sitk.WriteImage(labelImage, sitkUtils.GetSlicerITKReadWriteAddress(labelNodeName)) labelNode.GetImageData().Modified() labelNode.Modified()
def getDice(reference, moving): moving = runBRAINSResample(moving, reference) referenceAddress = sitkUtils.GetSlicerITKReadWriteAddress( reference.GetName()) image_reference = sitk.ReadImage(referenceAddress) movingAddress = sitkUtils.GetSlicerITKReadWriteAddress(moving.GetName()) image_input = sitk.ReadImage(movingAddress) # make sure both labels have the same value threshold = sitk.BinaryThresholdImageFilter() threshold.SetUpperThreshold(100) threshold.SetLowerThreshold(1) threshold.SetInsideValue(1) image_reference = threshold.Execute(image_reference) image_input = threshold.Execute(image_input) measureFilter = sitk.LabelOverlapMeasuresImageFilter() if measureFilter.Execute(image_reference, image_input): print 'filter executed' value = measureFilter.GetDiceCoefficient() return value
def prepareLabelsFromLabelmap(self, labelmapNode, grayscaleImage, labelsDict): combinedLabelImage = sitk.ReadImage(sitkUtils.GetSlicerITKReadWriteAddress(labelmapNode.GetName())) resampledLabelImage = self.resampleITKLabel(combinedLabelImage, grayscaleImage) ls = sitk.LabelStatisticsImageFilter() ls.Execute(resampledLabelImage,resampledLabelImage) th = sitk.BinaryThresholdImageFilter() th.SetInsideValue(1) th.SetOutsideValue(0) for l in ls.GetLabels()[1:]: th.SetUpperThreshold(l) th.SetLowerThreshold(l) labelsDict[labelmapNode.GetName()+"_label_"+str(l)] = th.Execute(combinedLabelImage) return labelsDict
def onFiducialListNode(self, name, mrmlNode): annotationHierarchyNode = mrmlNode # list of points in physical space coords = [] if annotationHierarchyNode.GetClassName( ) == "vtkMRMLMarkupsFiducialNode": # slicer4 Markups node for i in range(annotationHierarchyNode.GetNumberOfFiducials()): coord = [0, 0, 0] annotationHierarchyNode.GetNthFiducialPosition(i, coord) coords.append(coord) else: # slicer4 style hierarchy nodes # get the first in the list for listIndex in range( annotationHierarchyNode.GetNumberOfChildrenNodes()): if annotationHierarchyNode.GetNthChildNode(listIndex) is None: continue annotation = annotationHierarchyNode.GetNthChildNode( listIndex).GetAssociatedNode() if annotation is None: continue coord = [0, 0, 0] annotation.GetFiducialCoordinates(coord) coords.append(coord) if self.inputs[0]: imgNodeName = self.inputs[0].GetName() img = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(imgNodeName)) # HACK transform from RAS to LPS coords = [[-pt[0], -pt[1], pt[2]] for pt in coords] idx_coords = [ img.TransformPhysicalPointToIndex(pt) for pt in coords ] exec('self.filter.Set{0}(idx_coords)'.format(name))
def updateOutput(self, img): nodeWriteAddress = sitkUtils.GetSlicerITKReadWriteAddress( self.outputNodeName) sitk.WriteImage(img, nodeWriteAddress) node = slicer.util.getNode(self.outputNodeName) applicationLogic = slicer.app.applicationLogic() selectionNode = applicationLogic.GetSelectionNode() if self.outputLabelMap: selectionNode.SetReferenceActiveLabelVolumeID(node.GetID()) else: selectionNode.SetReferenceActiveVolumeID(node.GetID()) applicationLogic.PropagateVolumeSelection(0) applicationLogic.FitSliceToAll()
def getCentroidForLabel(labelNode, value): if not labelNode: return None labelAddress = sitkUtils.GetSlicerITKReadWriteAddress( labelNode.GetName()) labelImage = sitk.ReadImage(labelAddress) ls = sitk.LabelStatisticsImageFilter() ls.Execute(labelImage, labelImage) bb = ls.GetBoundingBox(value) centroid = None # sagittal, coronal, axial if len(bb) > 0: centerIJK = [((bb[0] + bb[1]) / 2), ((bb[2] + bb[3]) / 2), ((bb[4] + bb[5]) / 2)] logging.debug('BB is: ' + str(bb)) logging.debug('i_center = ' + str(centerIJK[0])) logging.debug('j_center = ' + str(centerIJK[1])) logging.debug('k_center = ' + str(centerIJK[2])) IJKtoRAS = vtk.vtkMatrix4x4() labelNode.GetIJKToRASMatrix(IJKtoRAS) IJKtoRASDir = vtk.vtkMatrix4x4() labelNode.GetIJKToRASDirectionMatrix(IJKtoRASDir) RAScoord = IJKtoRAS.MultiplyPoint( (centerIJK[0], centerIJK[1], centerIJK[2], 1)) order = labelNode.ComputeScanOrderFromIJKToRAS(IJKtoRAS) if order == 'IS': RASDir = IJKtoRASDir.MultiplyPoint( (RAScoord[0], RAScoord[1], RAScoord[2], 1)) centroid = [-RASDir[0], -RASDir[1], RASDir[2]] elif order == 'AP': RASDir = IJKtoRASDir.MultiplyPoint( (RAScoord[0], RAScoord[1], RAScoord[2], 1)) centroid = [-RASDir[0], -RASDir[2], -RASDir[1]] elif order == 'LR': RASDir = IJKtoRASDir.MultiplyPoint( (RAScoord[2], RAScoord[1], RAScoord[0], 1)) centroid = [RASDir[0], -RASDir[2], -RASDir[1]] return centroid
def __init__(self, grayscaleNode, labelNode, fileName=None): #import numpy self.keys = [ "Label", "Count", "Volume mm^3", "Volume cc", "Min", "Max", "Mean", "StdDev" ] cubicMMPerVoxel = reduce(lambda x, y: x * y, labelNode.GetSpacing()) ccPerCubicMM = 0.001 # TODO: progress and status updates # this->InvokeEvent(vtkLabelStatisticsLogic::StartLabelStats, (void*)"start label stats") self.labelStats = {} self.labelStats['Labels'] = [] labelNodeName = labelNode.GetName() labelImage = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(labelNodeName)) grayscaleNodeName = grayscaleNode.GetName() grayscaleImage = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(grayscaleNodeName)) sitkStats = sitk.LabelStatisticsImageFilter() sitkStats.Execute(grayscaleImage, labelImage) for l in sitkStats.GetLabels(): # add an entry to the LabelStats list self.labelStats["Labels"].append(l) self.labelStats[l, "Label"] = l self.labelStats[l, "Count"] = sitkStats.GetCount(l) self.labelStats[ l, "Volume mm^3"] = self.labelStats[l, "Count"] * cubicMMPerVoxel self.labelStats[ l, "Volume cc"] = self.labelStats[l, "Volume mm^3"] * ccPerCubicMM self.labelStats[l, "Min"] = sitkStats.GetMinimum(l) self.labelStats[l, "Max"] = sitkStats.GetMaximum(l) self.labelStats[l, "Mean"] = sitkStats.GetMean(l) self.labelStats[l, "StdDev"] = sitkStats.GetSigma(l) self.labelStats[l, "Sum"] = sitkStats.GetSum(l) del sitkStats sitkShapeStats = sitk.LabelShapeStatisticsImageFilter() sitkShapeStats.ComputeFeretDiameterOff() sitkShapeStats.ComputePerimeterOn() sitkShapeStats.Execute(labelImage) # use a set to accumulate attributes to make sure they are unuque shapeAttributes = [ # 'Number Of Pixels', # 'Physical Size', # 'Centroid', # 'Bounding Box', 'Number Of Pixels On Border', 'Perimeter On Border', 'Perimeter On Border Ratio', # 'Principal Moments', 'Principal Axes', 'Elongation', 'Perimeter', 'Roundness', 'Equivalent Spherical Radius', 'Equivalent Spherical Perimeter', # 'Equivalent Ellipsoid Diameter', 'Flatness', 'Feret Diameter' ] if not sitkShapeStats.GetComputeFeretDiameter(): shapeAttributes.remove('Feret Diameter') if not sitkShapeStats.GetComputePerimeter(): shapeAttributes.remove('Perimeter') # We don't have a good way to show shapeAttributes.remove('Principal Axes') self.keys += shapeAttributes for l in sitkShapeStats.GetLabels(): # add attributes form the Shape label object for name in shapeAttributes: attr = getattr(sitkShapeStats, "Get" + name.replace(' ', ''))(l) self.labelStats[l, name] = attr for l in sitkShapeStats.GetLabels(): attr = getattr(sitkShapeStats, "Get" + "PrincipalMoments")(l) for i in range(1, 4): self.labelStats[l, "Principal Moments " + str(i)] = attr[i - 1] self.keys += ["Principal Moments " + str(i) for i in range(1, 4)]
def createModels(self): self.deleteModels() self.labelScores = [] self.selectedLableList = [] if self.calcinationType == 0 and self.volumeNode and self.roiNode: #print 'in Heart Create Models' slicer.vtkSlicerCropVolumeLogic().CropVoxelBased(self.roiNode, self.volumeNode, self.croppedNode) croppedImage = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(self.croppedNode.GetName())) thresholdImage = sitk.BinaryThreshold(croppedImage,self.ThresholdMin, self.ThresholdMax, 1, 0) connectedCompImage =sitk.ConnectedComponent(thresholdImage, True) relabelImage =sitk.RelabelComponent(connectedCompImage) labelStatFilter =sitk.LabelStatisticsImageFilter() labelStatFilter.Execute(croppedImage, relabelImage) if relabelImage.GetPixelID() != sitk.sitkInt16: relabelImage = sitk.Cast( relabelImage, sitk.sitkInt16 ) sitk.WriteImage( relabelImage, sitkUtils.GetSlicerITKReadWriteAddress(self.labelsNode.GetName())) nLabels = labelStatFilter.GetNumberOfLabels() #print "Number of labels = ", nLabels self.totalScore = 0 count = 0 for n in range(0,nLabels): max = labelStatFilter.GetMaximum(n); size = labelStatFilter.GetCount(n) score = self.computeScore(max) if size*self.voxelVolume > self.MaximumLesionSize: continue if size*self.voxelVolume < self.MinimumLesionSize: nLabels = n+1 break #print "label = ", n, " max = ", max, " score = ", score, " voxels = ", size self.labelScores.append(score) self.selectedLableList.append(0) self.marchingCubes.SetInputData(self.labelsNode.GetImageData()) self.marchingCubes.SetValue(0, n) self.marchingCubes.Update() self.transformPolyData.SetInputData(self.marchingCubes.GetOutput()) mat = vtk.vtkMatrix4x4() self.labelsNode.GetIJKToRASMatrix(mat) trans = vtk.vtkTransform() trans.SetMatrix(mat) self.transformPolyData.SetTransform(trans) self.transformPolyData.Update() poly = vtk.vtkPolyData() poly.DeepCopy(self.transformPolyData.GetOutput()) modelNode = slicer.vtkMRMLModelNode() slicer.mrmlScene.AddNode(modelNode) dnode = slicer.vtkMRMLModelDisplayNode() slicer.mrmlScene.AddNode(dnode) modelNode.AddAndObserveDisplayNodeID(dnode.GetID()) modelNode.SetAndObservePolyData(poly) ct=slicer.mrmlScene.GetNodeByID('vtkMRMLColorTableNodeLabels') rgb = [0,0,0] ct.GetLookupTable().GetColor(count+1,rgb) dnode.SetColor(rgb) self.addLabel(count, rgb, score) self.modelNodes.append(modelNode) self.selectedLables[poly] = n count = count+1 #a = slicer.util.array(tn.GetID()) #sa = sitk.GetImageFromArray(a) self.scoreField.setText(self.totalScore) else: print "not implemented"
def preProcessLabel(self, labelNodeID, bbMin, bbMax): print('Label node ID: ' + labelNodeID) labelNode = slicer.util.getNode(labelNodeID) labelNodeAddress = sitkUtils.GetSlicerITKReadWriteAddress( labelNode.GetName()) print('Label node address: ' + str(labelNodeAddress)) labelImage = sitk.ReadImage(labelNodeAddress) print('Read image: ' + str(labelImage)) crop = sitk.CropImageFilter() crop.SetLowerBoundaryCropSize(bbMin) crop.SetUpperBoundaryCropSize(bbMax) croppedImage = crop.Execute(labelImage) print('Cropped image done: ' + str(croppedImage)) croppedLabelName = labelNode.GetName() + '-Cropped' sitkUtils.PushToSlicer(croppedImage, croppedLabelName, overwrite=True) print('Cropped volume pushed') croppedLabel = slicer.util.getNode(croppedLabelName) print('Smoothed image done') smoothLabelName = labelNode.GetName() + '-Smoothed' smoothLabel = self.createVolumeNode(smoothLabelName) # smooth the labels smoothingParameters = { 'inputImageName': croppedLabel.GetID(), 'outputImageName': smoothLabel.GetID() } print(str(smoothingParameters)) cliNode = slicer.cli.run(slicer.modules.segmentationsmoothing, None, smoothingParameters, wait_for_completion=True) # crop the bounding box ''' TODO: * output volume node probably not needed here * intermediate nodes should probably be hidden ''' dt = sitk.SignedMaurerDistanceMapImageFilter() dt.SetSquaredDistance(False) distanceMapName = labelNode.GetName() + '-DistanceMap' print('Reading smoothed image: ' + smoothLabel.GetID()) smoothLabelAddress = sitkUtils.GetSlicerITKReadWriteAddress( smoothLabel.GetName()) smoothLabelImage = sitk.ReadImage(smoothLabelAddress) print(smoothLabelAddress) distanceImage = dt.Execute(smoothLabelImage) sitkUtils.PushToSlicer(distanceImage, distanceMapName, overwrite=True) return slicer.util.getNode(distanceMapName)
def getStartEndWithConnectedComponents(self, volume, center): address = sitkUtils.GetSlicerITKReadWriteAddress(volume.GetName()) image = sitk.ReadImage(address) start = self.getStartSliceUsingConnectedComponents(center, image) end = self.getEndSliceUsingConnectedComponents(center, image) return start, end
def createModels(self): # Reset previous model and labels self.deleteModels() for sr in self.summary_reports: self.labelScores[sr] = [] self.selectedLabelList = [] if self.calcificationType == 0 and self.volumeNode and self.roiNode: slicer.vtkSlicerCropVolumeLogic().CropVoxelBased( self.roiNode, self.volumeNode, self.croppedNode) croppedImage = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress( self.croppedNode.GetName())) thresholdImage = sitk.BinaryThreshold(croppedImage, self.ThresholdMin, self.ThresholdMax, 1, 0) connectedCompImage = sitk.ConnectedComponent(thresholdImage, True) relabelImage = sitk.RelabelComponent(connectedCompImage) labelStatFilter = sitk.LabelStatisticsImageFilter() labelStatFilter.Execute(croppedImage, relabelImage) if relabelImage.GetPixelID() != sitk.sitkInt16: relabelImage = sitk.Cast(relabelImage, sitk.sitkInt16) sitk.WriteImage( relabelImage, sitkUtils.GetSlicerITKReadWriteAddress( self.labelsNode.GetName())) prod_spacing = np.prod(croppedImage.GetSpacing()) nLabels = labelStatFilter.GetNumberOfLabels() self.totalScore = 0 count = 0 for n in range(0, nLabels): max = labelStatFilter.GetMaximum(n) mean = labelStatFilter.GetMean(n) size = labelStatFilter.GetCount(n) volume = size * self.voxelVolume # current label is discarted if volume not meet the maximum allowed threshold if volume > self.MaximumLesionSize: continue # As ordered, we stop here if the volume of the current label is less than threshold if volume < self.MinimumLesionSize: nLabels = n + 1 break score2d, volume, mass_score = self.agatston_computation( n, relabelImage, croppedImage, prod_spacing) # Agatston 3d: # ----------- density_score = self.computeDensityScore(max) score3d = size * (self.sx * self.sy) * density_score mass_score = mean * volume # self.labelScores["Agatston Score"].append(score) self.labelScores["Agatston Score 3D"].append(score3d) self.labelScores["Agatston Score 2D"].append(score2d) self.labelScores["Mass Score"].append(mass_score) self.labelScores["Volume"].append(volume) self.selectedLabelList.append(0) # generate the contour marchingCubes = vtk.vtkDiscreteMarchingCubes() marchingCubes.SetInputData(self.labelsNode.GetImageData()) marchingCubes.SetValue(0, count + 1) marchingCubes.Update() transformPolyData = vtk.vtkTransformPolyDataFilter() transformPolyData.SetInputData(marchingCubes.GetOutput()) mat = vtk.vtkMatrix4x4() self.labelsNode.GetIJKToRASMatrix(mat) trans = vtk.vtkTransform() trans.SetMatrix(mat) transformPolyData.SetTransform(trans) transformPolyData.Update() poly = vtk.vtkPolyData() poly.DeepCopy(transformPolyData.GetOutput()) modelNode = slicer.vtkMRMLModelNode() slicer.mrmlScene.AddNode(modelNode) dnode = slicer.vtkMRMLModelDisplayNode() slicer.mrmlScene.AddNode(dnode) modelNode.AddAndObserveDisplayNodeID(dnode.GetID()) modelNode.SetAndObservePolyData(poly) ct = slicer.mrmlScene.GetNodeByID( 'vtkMRMLColorTableNodeLabels') rgb = [0, 0, 0] ct.GetLookupTable().GetColor(count + 1, rgb) dnode.SetColor(rgb) # Enable Slice intersection dnode.SetSliceDisplayMode(0) dnode.SetSliceIntersectionVisibility(1) # self.addLabel(count, rgb, [score, mass_score, volume, mean, max]) self.addLabel( count, rgb, [score2d, score3d, mass_score, volume, mean, max]) count = count + 1 self.modelNodes.append(modelNode) self.selectedLabels[poly] = n for sr in self.summary_reports: self.scoreField[sr].setText(self.totalScores[sr])
def createModels(self): self.deleteModels() for sr in self.summary_reports: self.labelScores[sr]=[] self.selectedLabelList = [] if self.calcificationType == 0 and self.volumeNode and self.roiNode: #print 'in Heart Create Models' slicer.vtkSlicerCropVolumeLogic().CropVoxelBased(self.roiNode, self.volumeNode, self.croppedNode) croppedImage = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(self.croppedNode.GetName())) thresholdImage = sitk.BinaryThreshold(croppedImage,self.ThresholdMin, self.ThresholdMax, 1, 0) connectedCompImage =sitk.ConnectedComponent(thresholdImage, True) relabelImage =sitk.RelabelComponent(connectedCompImage) labelStatFilter =sitk.LabelStatisticsImageFilter() labelStatFilter.Execute(croppedImage, relabelImage) if relabelImage.GetPixelID() != sitk.sitkInt16: relabelImage = sitk.Cast( relabelImage, sitk.sitkInt16 ) sitk.WriteImage( relabelImage, sitkUtils.GetSlicerITKReadWriteAddress(self.labelsNode.GetName())) nLabels = labelStatFilter.GetNumberOfLabels() #print "Number of labels = ", nLabels self.totalScore = 0 count = 0 #Computation of the score follows this paper: #C. H McCollough, Radiology, 243(2), 2007 for n in range(0,nLabels): max = labelStatFilter.GetMaximum(n) mean = labelStatFilter.GetMean(n) size = labelStatFilter.GetCount(n) volume = size*self.voxelVolume if volume > self.MaximumLesionSize: continue if volume < self.MinimumLesionSize: nLabels = n+1 break density_score = self.computeDensityScore(max) #Agatston score is \sum_i area_i * density_score_i #For now we assume that all the plaques have the same density score score = size*(self.sx*self.sy)*density_score mass_score = mean*volume #print "label = ", n, " max = ", max, " score = ", score, " voxels = ", size self.labelScores["Agatston Score"].append(score) self.labelScores["Mass Score"].append(mass_score) self.labelScores["Volume"].append(volume) self.selectedLabelList.append(0) self.marchingCubes.SetInputData(self.labelsNode.GetImageData()) self.marchingCubes.SetValue(0, n) self.marchingCubes.Update() self.transformPolyData.SetInputData(self.marchingCubes.GetOutput()) mat = vtk.vtkMatrix4x4() self.labelsNode.GetIJKToRASMatrix(mat) trans = vtk.vtkTransform() trans.SetMatrix(mat) self.transformPolyData.SetTransform(trans) self.transformPolyData.Update() poly = vtk.vtkPolyData() poly.DeepCopy(self.transformPolyData.GetOutput()) modelNode = slicer.vtkMRMLModelNode() slicer.mrmlScene.AddNode(modelNode) dnode = slicer.vtkMRMLModelDisplayNode() slicer.mrmlScene.AddNode(dnode) modelNode.AddAndObserveDisplayNodeID(dnode.GetID()) modelNode.SetAndObservePolyData(poly) ct=slicer.mrmlScene.GetNodeByID('vtkMRMLColorTableNodeLabels') rgb = [0,0,0] ct.GetLookupTable().GetColor(count+1,rgb) dnode.SetColor(rgb) #Enable Slice intersection dnode.SetSliceDisplayMode(0) dnode.SetSliceIntersectionVisibility(1) self.addLabel(count, rgb, [score,mass_score,volume,mean,max]) count = count+1 self.modelNodes.append(modelNode) self.selectedLabels[poly] = n #a = slicer.util.array(tn.GetID()) #sa = sitk.GetImageFromArray(a) for sr in self.summary_reports: self.scoreField[sr].setText(self.totalScores[sr]) else: print ("not implemented")
def doit(self): labelLogic = self.sliceLogic.GetLabelLayer() labelNode = labelLogic.GetVolumeNode() labelNodeName = labelNode.GetName() labelImage = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(labelNodeName)) bgLogic = self.sliceLogic.GetBackgroundLayer() bgNode = bgLogic.GetVolumeNode() bgNodeName = bgNode.GetName() bgImage = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(bgNodeName)) # store a backup copy of the label map for undo # (this happens in it's own thread, so it is cheap) if self.undoRedo: self.undoRedo.saveState() labelID = self.editUtil.getLabel() l = sitk.BinaryThreshold(labelImage, labelID, labelID, 1, 0) filled = sitk.BinaryFillhole(l) d = sitk.SignedMaurerDistanceMap(filled, insideIsPositive=False, squaredDistance=False, useImageSpacing=True) del filled d = sitk.Threshold(d, -1e23, 0, 0) feature = d if (self.splitSize != 0.0): # the splitSize is divided by 2 to convert from a diameter size of a radius size level = self.splitSize * 0.5 d = sitk.HMinima(feature, height=level, fullyConnected=False) markers = sitk.RegionalMinima(d, backgroundValue=0, foregroundValue=1, fullyConnected=False, flatIsMinima=True) del d markers = sitk.ConnectedComponent(markers, fullyConnected=False) ws = sitk.MorphologicalWatershedFromMarkers(feature, markers, markWatershedLine=False) del feature del markers ws = sitk.Mask(sitk.Cast(ws, labelImage.GetPixelIDValue()), l) del l sitk.WriteImage(ws, sitkUtils.GetSlicerITKReadWriteAddress(labelNodeName)) labelNode.GetImageData().Modified() labelNode.Modified()
def refineLandmark(self, state): """Refine the specified landmark""" # Refine landmark, or if none, do nothing # Crop images around the fiducial # Affine registration of the cropped images # Transform the fiducial using the transformation # # No need to take into account the current transformation because landmarks are in World RAS timing = False if self.VerboseMode == "Verbose": timing = True if state.fixed == None or state.moving == None or state.fixedFiducials == None or state.movingFiducials == None or state.currentLandmarkName == None: print "Cannot refine landmarks. Images or landmarks not selected." return print("Refining landmark " + state.currentLandmarkName) + " using " + self.name start = time.time() if timing: loadStart = start volumes = (state.fixed, state.moving) (fixedVolume, movingVolume) = volumes fixedImage = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(fixedVolume.GetName())) movingImage = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(movingVolume.GetName())) if timing: print 'Time for loading was ' + str(time.time() - loadStart) + ' seconds' landmarks = state.logic.landmarksForVolumes(volumes) (fixedFiducial, movingFiducial) = landmarks[state.currentLandmarkName] (fixedList, fixedIndex) = fixedFiducial (movingList, movingIndex) = movingFiducial fixedPoint = [ 0, ] * 3 movingPoint = [ 0, ] * 3 fixedList.GetNthFiducialPosition(fixedIndex, fixedPoint) movingList.GetNthFiducialPosition(movingIndex, movingPoint) # HACK transform from RAS to LPS fixedPoint = [-fixedPoint[0], -fixedPoint[1], fixedPoint[2]] movingPoint = [-movingPoint[0], -movingPoint[1], movingPoint[2]] # NOTE: SimpleITK index always starts at 0 # define an roi for the fixed if timing: roiStart = time.time() fixedRadius = 30 fixedROISize = [ 0, ] * 3 fixedROIIndex = [ 0, ] * 3 fixedROIIndex = list( fixedImage.TransformPhysicalPointToIndex(fixedPoint)) for i in range(3): if fixedROIIndex[i] < 0 or fixedROIIndex[i] > fixedImage.GetSize( )[i] - 1: import sys sys.stderr.write( "Fixed landmark {0} in not with in fixed image!\n".format( landmarkName)) return radius = min(fixedRadius, fixedROIIndex[i], fixedImage.GetSize()[i] - fixedROIIndex[i] - 1) fixedROISize[i] = radius * 2 + 1 fixedROIIndex[i] -= radius if self.VerboseMode == "Full Verbose": print "Fixed ROI: ", fixedROIIndex, fixedROISize if timing: roiEnd = time.time() # crop the fixed if timing: cropStart = time.time() croppedFixedImage = sitk.RegionOfInterest(fixedImage, fixedROISize, fixedROIIndex) croppedFixedImage = sitk.Cast(croppedFixedImage, sitk.sitkFloat32) if timing: cropEnd = time.time() # define an roi for the moving if timing: roi2Start = time.time() if self.LocalSimpleITKMode == "Small": movingRadius = 45 else: movingRadius = 60 movingROISize = [ 0, ] * 3 movingROIIndex = [ 0, ] * 3 movingROIIndex = list( movingImage.TransformPhysicalPointToIndex(movingPoint)) for i in range(3): if movingROIIndex[i] < 0 or movingROIIndex[ i] > movingImage.GetSize()[i] - 1: import sys sys.stderr.write( "Moving landmark {0} in not with in moving image!\n". format(landmarkName)) return radius = min(movingRadius, movingROIIndex[i], movingImage.GetSize()[i] - movingROIIndex[i] - 1) movingROISize[i] = radius * 2 + 1 movingROIIndex[i] -= radius if self.VerboseMode == "Full Verbose": print "Moving ROI: ", movingROIIndex, movingROISize if timing: roi2End = time.time() if timing: crop2Start = time.time() croppedMovingImage = sitk.RegionOfInterest(movingImage, movingROISize, movingROIIndex) croppedMovingImage = sitk.Cast(croppedMovingImage, sitk.sitkFloat32) if timing: crop2End = time.time() if timing: print 'Time to set up fixed ROI was ' + str(roiEnd - roiStart) + ' seconds' if timing: print 'Time to set up moving ROI was ' + str( roi2End - roi2Start) + ' seconds' if timing: print 'Time to crop fixed volume ' + str(cropEnd - cropStart) + ' seconds' if timing: print 'Time to crop moving volume ' + str(crop2End - crop2Start) + ' seconds' # initialize the registration if timing: initTransformStart = time.time() tx = sitk.CenteredTransformInitializer( croppedFixedImage, croppedMovingImage, sitk.VersorRigid3DTransform(), sitk.CenteredTransformInitializerFilter.GEOMETRY) if timing: initTransformEnd = time.time() if timing: print 'Time to initialize transformation was ' + str( initTransformEnd - initTransformStart) + ' seconds' # define the registration R = sitk.ImageRegistrationMethod() R.SetMetricAsMattesMutualInformation(numberOfHistogramBins=50) R.SetMetricSamplingPercentage(0.2) R.SetMetricSamplingStrategy(sitk.ImageRegistrationMethod.RANDOM) R.SetOptimizerAsRegularStepGradientDescent(learningRate=1, minStep=0.1, relaxationFactor=0.5, numberOfIterations=250) R.SetOptimizerScalesFromJacobian( ) # Use this for versor based transforms R.SetShrinkFactorsPerLevel([1]) R.SetSmoothingSigmasPerLevel([1]) R.SetInitialTransform(tx) R.SetInterpolator(sitk.sitkLinear) #R.SetNumberOfThreads(1) # setup an observer def command_iteration(method): print("{0:3} = {1:10.5f} : {2}".format( method.GetOptimizerIteration(), method.GetMetricValue(), method.GetOptimizerPosition())) if self.VerboseMode == "Full Verbose": R.AddCommand(sitk.sitkIterationEvent, lambda: command_iteration(R)) # run the registration if timing: regStart = time.time() outTx = R.Execute(croppedFixedImage, croppedMovingImage) if self.VerboseMode == "Full Verbose": print("-------") print(outTx) print("Optimizer stop condition: {0}".format( R.GetOptimizerStopConditionDescription())) print(" Iteration: {0}".format(R.GetOptimizerIteration())) print(" Metric value: {0}".format(R.GetMetricValue())) if timing: regEnd = time.time() if timing: print 'Time for local registration was ' + str( regEnd - regStart) + ' seconds' # apply the local transform to the landmark #print transform if timing: resultStart = time.time() #outTx.SetInverse() updatedPoint = outTx.TransformPoint(fixedPoint) # HACK transform from LPS to RAS updatedPoint = [-updatedPoint[0], -updatedPoint[1], updatedPoint[2]] movingList.SetNthFiducialPosition(movingIndex, updatedPoint[0], updatedPoint[1], updatedPoint[2]) if timing: resultEnd = time.time() if timing: print 'Time for transforming landmark was ' + str( resultEnd - resultStart) + ' seconds' end = time.time() print 'Refined landmark ' + state.currentLandmarkName + ' in ' + str( end - start) + ' seconds'
def run(self, dockerPath, dockerVolumePath, inputVolume): """ Run the actual algorithm """ qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor) if not self.isValidInputOutputData(inputVolume): slicer.util.errorDisplay( 'Input volume is the same as output vessel model. Choose a different output vessel model.' ) return False slicer.app.processEvents() fileList = os.listdir(dockerVolumePath) for fileName in fileList: os.remove(os.path.join(dockerVolumePath, fileName)) oriVolumeDim = inputVolume.GetImageData().GetDimensions() inputVolumeSpacing = inputVolume.GetSpacing() spacing = (inputVolumeSpacing[0] * oriVolumeDim[0] / self.DOCKERVOLUMEDIMENSION[0], \ inputVolumeSpacing[1] * oriVolumeDim[1] / self.DOCKERVOLUMEDIMENSION[1], \ inputVolumeSpacing[2] * oriVolumeDim[2] / self.DOCKERVOLUMEDIMENSION[2]) self.resampledVolume = self.ResampleVolume(inputVolume, spacing, self.resampledVolume) img = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress( self.resampledVolume.GetName())) fileName = "quarterVolume.nii.gz" sitk.WriteImage(img, str(os.path.join(dockerVolumePath, fileName))) #----------------------------------- logging.info('Processing started') cmd = list() cmd.append(dockerPath) cmd.extend(('run', '-t', '-v')) cmd.append(str(dockerVolumePath) + ':' + "/workspace/data/Case1") cmd.append( 'li3igtlab/brain-vessel-seg@sha256:2095141606837f364a857ec90a19efe49f8879918881a24a4cf0e72c74a2c2d2' ) cmd.extend(('python3', '/workspace/NiftyNet/net_run.py', 'inference')) cmd.extend(('-a', 'brainVesselSegApp.brainVesselSegApp', '-c', '/workspace/data/vesselSeg.ini')) p = subprocess.Popen(cmd, stdout=subprocess.PIPE) print cmd progress = 0 while True: progress += 0.15 slicer.app.processEvents() line = p.stdout.readline() if not line: print "no line" break print(line) slicer.app.processEvents() successful, probabilityMap = slicer.util.loadVolume(os.path.join( dockerVolumePath, "Case1__niftynet_out.nii.gz"), returnNode=True) if successful and probabilityMap: inputVolumeSpacing = probabilityMap.GetSpacing() spacing = (inputVolumeSpacing[0] * self.DOCKERVOLUMEDIMENSION[0] / oriVolumeDim[0] , \ inputVolumeSpacing[1] * self.DOCKERVOLUMEDIMENSION[1] / oriVolumeDim[1] , \ inputVolumeSpacing[2] * self.DOCKERVOLUMEDIMENSION[2] / oriVolumeDim[2] ) probabilityMap_resampled = self.ResampleVolume( probabilityMap, spacing, resampledVolume=None) probabilityMap_resampled.SetName("ProbabilityMap_Resampled") slicer.mrmlScene.AddNode(probabilityMap_resampled) inputVolume.SetAttribute(self.REL_PROBABLITYMAP, probabilityMap_resampled.GetID()) logging.info('Processing completed') qt.QApplication.restoreOverrideCursor() return True
def run(self, leftVol, rightVol, enableScreenshots=0): """ Run the actual algorithm """ logging.info('Processing started') nodeName = "BlankVolume" imageSize = [390, 466, 318] voxelType = vtk.VTK_UNSIGNED_CHAR imageOrigin = [98, 98, -72] imageSpacing = [0.5, 0.5, 0.5] imageDirections = [[-1, 0, 0], [0, -1, 0], [0, 0, 1]] fillVoxelValue = 255 # Create an empty image volume, filled with fillVoxelValue imageData = vtk.vtkImageData() imageData.SetDimensions(imageSize) imageData.AllocateScalars(voxelType, 1) thresholder = vtk.vtkImageThreshold() thresholder.SetInputData(imageData) thresholder.SetInValue(fillVoxelValue) thresholder.SetOutValue(fillVoxelValue) thresholder.Update() # Create volume node blankVolumeNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLScalarVolumeNode", nodeName) blankVolumeNode.SetOrigin(imageOrigin) blankVolumeNode.SetSpacing(imageSpacing) blankVolumeNode.SetIJKToRASDirections(imageDirections) blankVolumeNode.SetAndObserveImageData(thresholder.GetOutput()) blankVolumeNode.CreateDefaultDisplayNodes() blankVolumeNode.CreateDefaultStorageNode() logging.info('Created empty volume Blank Volume') # left right front back bottom top leftData = leftVol.GetPolyData().GetPoints().GetBounds() rightData = rightVol.GetPolyData().GetPoints().GetBounds() leftBound = leftData[0] rightBound = rightData[1] topBound = max(leftData[5], rightData[5]) frontBound = min(leftData[2], rightData[2]) backBound = max(leftData[3], rightData[3]) midline = (leftBound + rightBound) / 2 halfway = -(backBound + frontBound) / 1.7 print(leftBound, rightBound) print("Midline:", midline) print(frontBound, backBound) print("Halfway:", halfway) print("Top:", topBound) # handleNode.SetAndObservePolyData(handle.GetOutput()) # handleNode.CreateDefaultDisplayNodes() def makeHandle(): fn = vtk.vtkParametricTorus() fn.SetRingRadius((rightBound - leftBound) / 5) fn.SetCrossSectionRadius((rightBound - leftBound) / 15) #vtk.FlipNormalsOn() source = vtk.vtkParametricFunctionSource() source.SetParametricFunction(fn) source.Update() trans = vtk.vtkTransform() trans.RotateX(90) trans.Translate(midline, topBound + 5, halfway) # vtk generate normals # communicate with SLACK rotate = vtk.vtkTransformPolyDataFilter() rotate.SetTransform(trans) rotate.SetInputConnection(source.GetOutputPort()) rotate.Update() return rotate.GetOutput() handleVol = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLModelNode', "handle") handle = makeHandle() handleVol.SetAndObservePolyData(handle) handleVol.CreateDefaultDisplayNodes() handleVol.CreateDefaultStorageNode() leftBLM = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLLabelMapVolumeNode', "leftBLM") # leftBLM.CreateDefaultDisplayNodes() # leftBLM.CreateDefaultStorageNode() rightBLM = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLLabelMapVolumeNode', "rightBLM") # rightBLM.CreateDefaultDisplayNodes() # rightBLM.CreateDefaultStorageNode() handleBLM = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLLabelMapVolumeNode', "handleBLM") # handleBLM.CreateDefaultDisplayNodes() # handleBLM.CreateDefaultStorageNode() leftParams = { 'sampleDistance': 0.1, 'InputVolume': blankVolumeNode.GetID(), 'surface': leftVol.GetID(), 'OutputVolume': leftBLM.GetID() } process = slicer.cli.run(slicer.modules.modeltolabelmap, None, leftParams, wait_for_completion=True) rightParams = { 'sampleDistance': 0.1, 'InputVolume': blankVolumeNode.GetID(), 'surface': rightVol.GetID(), 'OutputVolume': rightBLM.GetID() } process = slicer.cli.run(slicer.modules.modeltolabelmap, None, rightParams, wait_for_completion=True) # we have leftBLM, rightBLM, and handleBLM; all are binary label maps brainBLM = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLLabelMapVolumeNode', "brainBLM") # brainBLM.CreateDefaultDisplayNodes() # brainBLM.CreateDefaultStorageNode() path = slicer.util.tempDirectory("saves") leftPath = path + "/left.nrrd" rightPath = path + "/right.nrrd" slicer.util.saveNode(leftBLM, leftPath) slicer.util.saveNode(rightBLM, rightPath) left = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(leftBLM.GetName())) right = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(rightBLM.GetName())) orFilter = sitk.OrImageFilter() brain = orFilter.Execute(right, left) dilateFilter = sitk.BinaryDilateImageFilter() rad = round((rightBound - leftBound) / 30) dilateFilter.SetKernelRadius(rad) dilateFilter.SetBackgroundValue(0) dilateFilter.SetForegroundValue(255) print(dilateFilter.GetKernelType(), dilateFilter.GetKernelRadius()) brain_dilated = dilateFilter.Execute(brain) holesFilter = sitk.BinaryFillholeImageFilter() brain_dilated_fixed = holesFilter.Execute(brain_dilated, True, 255) #output = orFilter.Execute(intermediate, handle) sitkUtils.PushToSlicer(brain_dilated_fixed, "combined sides", compositeView=0, overwrite=False) slicer.mrmlScene.RemoveNode(leftBLM) slicer.mrmlScene.RemoveNode(rightBLM) slicer.mrmlScene.RemoveNode(handleBLM) slicer.mrmlScene.RemoveNode(brainBLM) slicer.mrmlScene.RemoveNode(blankVolumeNode) # Capture screenshot if enableScreenshots: self.takeScreenshot('MySlicerExtensionTest-Start', 'MyScreenshot', -1) logging.info('Processing completed') return True
def run(self, leftVol, rightVol, enableScreenshots=0): """ Run the actual algorithm """ logging.info('Processing started') nodeName = "BlankVolume" imageSize = [390, 466, 318] voxelType = vtk.VTK_UNSIGNED_CHAR imageOrigin = [98, 98, -72] imageSpacing = [0.5, 0.5, 0.5] imageDirections = [[-1, 0, 0], [0, -1, 0], [0, 0, 1]] fillVoxelValue = 255 # Create an empty image volume, filled with fillVoxelValue imageData = vtk.vtkImageData() imageData.SetDimensions(imageSize) imageData.AllocateScalars(voxelType, 1) thresholder = vtk.vtkImageThreshold() thresholder.SetInputData(imageData) thresholder.SetInValue(fillVoxelValue) thresholder.SetOutValue(fillVoxelValue) thresholder.Update() # Create volume node blankVolumeNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLScalarVolumeNode", nodeName) blankVolumeNode.SetOrigin(imageOrigin) blankVolumeNode.SetSpacing(imageSpacing) blankVolumeNode.SetIJKToRASDirections(imageDirections) blankVolumeNode.SetAndObserveImageData(thresholder.GetOutput()) blankVolumeNode.CreateDefaultDisplayNodes() blankVolumeNode.CreateDefaultStorageNode() logging.info('Created empty volume Blank Volume') # left right front back bottom top leftData = leftVol.GetPolyData().GetPoints().GetBounds() rightData = rightVol.GetPolyData().GetPoints().GetBounds() leftBound = leftData[0] rightBound = rightData[1] topBound = max(leftData[5], rightData[5]) frontBound = min(leftData[2], rightData[2]) backBound = max(leftData[3], rightData[3]) midline = (leftBound + rightBound) / 2 halfway = -(backBound + frontBound) / 1.7 print(leftBound, rightBound) # medial could be constant zero but why not account for lateral brain asymmetry print("Medial:", midline) print("Coronal:", halfway) print("Top Bound:", topBound) # function for creating solid taurus and positioning using coronal/medial/top bound measurements def makeHandle(): fn = vtk.vtkParametricTorus() # scale radius by a factor of the brain width fn.SetRingRadius((rightBound - leftBound) / 5) fn.SetCrossSectionRadius((rightBound - leftBound) / 15) source = vtk.vtkParametricFunctionSource() source.SetParametricFunction(fn) source.Update() trans = vtk.vtkTransform() trans.RotateX(90) # add a bit extra to top bound so it sticks out trans.Translate(midline, topBound + 5, halfway) rotate = vtk.vtkTransformPolyDataFilter() rotate.SetTransform(trans) rotate.SetInputConnection(source.GetOutputPort()) rotate.Update() return rotate.GetOutput() handleVol = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLModelNode', "handle") handle = makeHandle() handleVol.SetAndObservePolyData(handle) handleVol.CreateDefaultDisplayNodes() handleVol.CreateDefaultStorageNode() # add nodes to scene leftBLM = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLLabelMapVolumeNode', "leftBLM") rightBLM = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLLabelMapVolumeNode', "rightBLM") handleBLM = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLLabelMapVolumeNode', "handleBLM") # manually create parameters for the left and right maps for ModelToLabelMap module leftParams = { 'sampleDistance': 0.1, 'InputVolume': blankVolumeNode.GetID(), 'surface': leftVol.GetID(), 'OutputVolume': leftBLM.GetID() } process = slicer.cli.run(slicer.modules.modeltolabelmap, None, leftParams, wait_for_completion=True) rightParams = { 'sampleDistance': 0.1, 'InputVolume': blankVolumeNode.GetID(), 'surface': rightVol.GetID(), 'OutputVolume': rightBLM.GetID() } process = slicer.cli.run(slicer.modules.modeltolabelmap, None, rightParams, wait_for_completion=True) # we have leftBLM, rightBLM, and handleBLM; all are binary label maps brainBLM = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLLabelMapVolumeNode', "brainBLM") path = slicer.util.tempDirectory("saves") leftPath = path + "/left.nrrd" rightPath = path + "/right.nrrd" slicer.util.saveNode(leftBLM, leftPath) slicer.util.saveNode(rightBLM, rightPath) # move to simple itk in order to Or function the binary label maps # look into doing this manually by looping thru voxels and bitwise oring them maybe? left = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(leftBLM.GetName())) right = sitk.ReadImage( sitkUtils.GetSlicerITKReadWriteAddress(rightBLM.GetName())) orFilter = sitk.OrImageFilter() brain = orFilter.Execute(right, left) # dilate the image to increase structural integrity of the 3D printed Model and make it more aesthetic dilateFilter = sitk.BinaryDilateImageFilter() rad = round((rightBound - leftBound) / 30) dilateFilter.SetKernelRadius(rad) dilateFilter.SetBackgroundValue(0) dilateFilter.SetForegroundValue(255) print(dilateFilter.GetKernelType(), dilateFilter.GetKernelRadius()) brain_dilated = dilateFilter.Execute(brain) holesFilter = sitk.BinaryFillholeImageFilter() brain_dilated_fixed = holesFilter.Execute(brain_dilated, True, 255) # push SimpleITK back to Slicer and clean up the extra nodes sitkUtils.PushToSlicer(brain_dilated_fixed, "combined sides", compositeView=0, overwrite=False) slicer.mrmlScene.RemoveNode(leftBLM) slicer.mrmlScene.RemoveNode(rightBLM) slicer.mrmlScene.RemoveNode(handleBLM) slicer.mrmlScene.RemoveNode(brainBLM) slicer.mrmlScene.RemoveNode(blankVolumeNode) # TODO: convert to a different type so that it's ready to go with 3D printing, makes it easier when running on a batch of .nrrd files # Capture screenshot if enableScreenshots: self.takeScreenshot('MySlicerExtensionTest-Start', 'MyScreenshot', -1) logging.info('Processing completed') return True