def createMultiVolumeNumpyArray (self, node): # Generate Numpy Array from vtkMRMLMultiVolumeNode imageData = vtk.vtkImageData() imageData = node.GetImageData() numComponents = imageData.GetNumberOfScalarComponents() shapeData = list(imageData.GetDimensions() + (numComponents,)) return (vtk.util.numpy_support.vtk_to_numpy(imageData.GetPointData().GetScalars()).reshape(shapeData))
def onSelectOutput(self): merge=self.outputSelector.currentNode() master=self.masterSelector.currentNode() if master and merge: if not merge.GetImageData(): print("create Output Volume") imd=vtk.vtkImageData() mim=master.GetImageData() imd.SetDimensions(mim.GetDimensions()) imd.SetSpacing(mim.GetSpacing()) imd.SetOrigin(mim.GetOrigin()) # if mim.GetScalarTypeMin()>=0: #unsigned # mim.SetScalarType(mim.GetScalarType()-1) # imd.SetScalarType(mim.GetScalarType()) IJK=vtk.vtkMatrix4x4() master.GetIJKToRASMatrix(IJK) merge.SetIJKToRASMatrix(IJK) nd=slicer.vtkMRMLScalarVolumeDisplayNode() slicer.mrmlScene.AddNode(nd) merge.AddAndObserveDisplayNodeID(nd.GetID()) merge.SetAndObserveImageData(imd) warnings = self.checkForVolumeWarnings(master,merge) if warnings != "": self.errorDialog( "Warning: %s" % warnings ) self.outputSelector.setCurrentNode(None)
def createSampleLabelmapVolumeNode(self, volumeNode, name, label, colorNode=None): self.assertTrue( volumeNode != None ) self.assertTrue( volumeNode.IsA('vtkMRMLScalarVolumeNode') ) self.assertTrue( label > 0 ) sampleLabelmapNode = slicer.vtkMRMLLabelMapVolumeNode() sampleLabelmapNode.SetName(name) sampleLabelmapNode = slicer.mrmlScene.AddNode(sampleLabelmapNode) sampleLabelmapNode.Copy(volumeNode) imageData = vtk.vtkImageData() imageData.DeepCopy(volumeNode.GetImageData()) sampleLabelmapNode.SetAndObserveImageData(imageData) extent = imageData.GetExtent() for x in xrange(extent[0], extent[1]+1): for y in xrange(extent[2], extent[3]+1): for z in xrange(extent[4], extent[5]+1): if (x >= (extent[1]/4) and x <= (extent[1]/4) * 3) and (y >= (extent[3]/4) and y <= (extent[3]/4) * 3) and (z >= (extent[5]/4) and z <= (extent[5]/4) * 3): imageData.SetScalarComponentFromDouble(x,y,z,0,label) else: imageData.SetScalarComponentFromDouble(x,y,z,0,0) # Display labelmap labelmapVolumeDisplayNode = slicer.vtkMRMLLabelMapVolumeDisplayNode() slicer.mrmlScene.AddNode(labelmapVolumeDisplayNode) if colorNode == None: colorNode = slicer.util.getNode('GenericAnatomyColors') self.assertTrue( colorNode != None ) labelmapVolumeDisplayNode.SetAndObserveColorNodeID(colorNode.GetID()) labelmapVolumeDisplayNode.VisibilityOn() sampleLabelmapNodeName = slicer.mrmlScene.GenerateUniqueName(name) sampleLabelmapNode.SetName(sampleLabelmapNodeName) sampleLabelmapNode.SetAndObserveDisplayNodeID(labelmapVolumeDisplayNode.GetID()) return sampleLabelmapNode
def createNumpyArray (self, imageNode): # Generate Numpy Array from vtkMRMLScalarVolumeNode imageData = vtk.vtkImageData() imageData = imageNode.GetImageData() shapeData = list(imageData.GetDimensions()) shapeData.reverse() return (vtk.util.numpy_support.vtk_to_numpy(imageData.GetPointData().GetScalars()).reshape(shapeData))
def CreateNewVolume(self, trial_num, numSamp, labelType): imageSize=[64, 64, 64] imageSpacing=[1.0, 1.0, 1.0] voxelType=vtk.VTK_UNSIGNED_CHAR # Create an empty image volume imageData=vtk.vtkImageData() imageData.SetDimensions(imageSize) imageData.AllocateScalars(voxelType, 1) thresholder=vtk.vtkImageThreshold() thresholder.SetInputData(imageData) thresholder.SetInValue(0) thresholder.SetOutValue(0) # Create volume node volumeNode=slicer.vtkMRMLScalarVolumeNode() volumeNode.SetSpacing(imageSpacing) volumeNode.SetImageDataConnection(thresholder.GetOutputPort()) # Add volume to scene slicer.mrmlScene.AddNode(volumeNode) displayNode=slicer.vtkMRMLScalarVolumeDisplayNode() slicer.mrmlScene.AddNode(displayNode) colorNode = slicer.util.getNode('Grey') displayNode.SetAndObserveColorNodeID(colorNode.GetID()) volumeNode.SetAndObserveDisplayNodeID(displayNode.GetID()) volumeNode.CreateDefaultStorageNode() # name volume volume_name = str(labelType)+'_trial_'+str(trial_num)+'_nsamp_'+str(numSamp) volumeNode.SetName(volume_name) return volumeNode
def __init__(self, sliceWidget): super(ThresholdEffectTool,self).__init__(sliceWidget) # create a logic instance to do the non-gui work self.logic = ThresholdEffectLogic(self.sliceWidget.sliceLogic()) self.logic.undoRedo = self.undoRedo # interaction state variables self.min = 0 self.max = 0 # class instances self.lut = None self.thresh = None self.map = None # feedback actor self.cursorDummyImage = vtk.vtkImageData() self.cursorDummyImage.AllocateScalars() self.cursorMapper = vtk.vtkImageMapper() self.cursorMapper.SetInput( self.cursorDummyImage ) self.cursorActor = vtk.vtkActor2D() self.cursorActor.VisibilityOff() self.cursorActor.SetMapper( self.cursorMapper ) self.cursorMapper.SetColorWindow( 255 ) self.cursorMapper.SetColorLevel( 128 ) self.actors.append( self.cursorActor ) self.renderer.AddActor2D( self.cursorActor )
def addWebActor(self): self.webView = qt.QWebView() self.webView.setWindowFlags(0x800) self.webView.setStyleSheet('background:transparent;') w, h = self.sliceView.width,self.sliceView.height self.qImage = qt.QImage(w, h, qt.QImage.Format_ARGB32) self.vtkImage = vtk.vtkImageData() self.mapper = vtk.vtkImageMapper() self.mapper.SetColorLevel(128) self.mapper.SetColorWindow(255) self.mapper.SetInput(self.vtkImage) self.actor2D = vtk.vtkActor2D() self.actor2D.SetMapper(self.mapper) self.imageActor = vtk.vtkImageActor() #self.imageActor.SetPosition(0,-1000,0) self.renderWindow = self.sliceView.renderWindow() self.renderer = self.renderWindow.GetRenderers().GetItemAsObject(0) self.renderer.AddActor2D(self.actor2D) globals()['slicer'].ia = self.imageActor self.webView.connect('loadFinished(bool)', lambda worked : self.onLoadFinished(worked) ) #self.webView.page().connect('repaintRequested(QRect)', lambda rect : onLoadFinished(rect, self.webView, self.qImage) ) self.style = self.sliceView.interactor() events = ("ModifiedEvent", "MouseMoveEvent", "EnterEvent", "LeaveEvent",) for event in events: tag = self.style.AddObserver(event, self.processEvent) self.observerTags.append([self.style,tag])
def removeIslandsMorphology(self): """ Remove cruft from image by eroding away by iterations number of layers of surface pixels and then saving only islands that are bigger than the minimumSize. Then dilate back and save only the pixels that are in both the original and result image. Result is that small islands outside the foreground and small features on the foreground are removed. By calling the decrufter twice with fg and bg reversed, you can clean up small features in a label map while preserving the original boundary in other places. """ if not self.sliceLogic: self.sliceLogic = self.editUtil.getSliceLogic() parameterNode = self.editUtil.getParameterNode() self.minimumSize = int(parameterNode.GetParameter("IslandEffect,minimumSize")) self.fullyConnected = bool(parameterNode.GetParameter("IslandEffect,fullyConnected")) labelImage = vtk.vtkImageData() labelImage.DeepCopy(self.getScopedLabelInput()) label = self.editUtil.getLabel() slicer.modules.EditorWidget.toolsBox.undoRedo.saveState() self.removeIslandsMorphologyDecruft(labelImage, 0, label) self.getScopedLabelOutput().DeepCopy(labelImage) self.applyScopedLabel() slicer.app.processEvents(qt.QEventLoop.ExcludeUserInputEvents) self.removeIslandsMorphologyDecruft(labelImage, label, 0) self.getScopedLabelOutput().DeepCopy(labelImage) self.applyScopedLabel()
def renderLabelMap(self): # Initializes a vtkMRMLScalarVolumeNode for the SegmentCAD Output and copies ijkToRAS matrix and Image data from nodeLabel ijkToRASMatrix = vtk.vtkMatrix4x4() self.volumePre.GetIJKToRASMatrix(ijkToRASMatrix) self.SegmentCADLabelMap.SetIJKToRASMatrix(ijkToRASMatrix) SegmentCADLabelMapImageData = vtk.vtkImageData() SegmentCADLabelMapImageData.DeepCopy(self.volumePre.GetImageData()) SegmentCADLabelMapPointData = SegmentCADLabelMapImageData.GetPointData() # Numpy array is converted from signed int16 to signed vtkShortArray scalarArray = vtk.vtkShortArray() dims1D = SegmentCADLabelMapPointData.GetScalars().GetSize() self.nodeArraySegmentCADLabel = self.nodeArraySegmentCADLabel.reshape(dims1D, order='C') scalarArray = vtk.util.numpy_support.numpy_to_vtk(self.nodeArraySegmentCADLabel) # PointData() of SegmentCAD label output pointed to new vtkShortArray for scalar values SegmentCADLabelMapImageData.SetScalarTypeToShort() SegmentCADLabelMapPointData.SetScalars(scalarArray) SegmentCADLabelMapPointData.Update() SegmentCADLabelMapImageData.Update() self.SegmentCADLabelMap.SetAndObserveImageData(SegmentCADLabelMapImageData) # Corresponding display node and color table nodes created for SegmentCAD label Output self.SegmentCADLabelMapDisplay = slicer.vtkMRMLLabelMapVolumeDisplayNode() self.SegmentCADLabelMapDisplay.SetScene(slicer.mrmlScene) self.SegmentCADLabelMapDisplay.SetAndObserveColorNodeID('vtkMRMLColorTableNodeFileGenericColors.txt') self.SegmentCADLabelMapDisplay.SetInputImageData(SegmentCADLabelMapImageData) self.SegmentCADLabelMapDisplay.UpdateImageDataPipeline() slicer.mrmlScene.AddNode(self.SegmentCADLabelMapDisplay) self.SegmentCADLabelMap.SetAndObserveDisplayNodeID(self.SegmentCADLabelMapDisplay.GetID()) self.SegmentCADLabelMapDisplay.UpdateScene(slicer.mrmlScene)
def paintApply(self): if self.paintCoordinates != []: # TODO: # EditorStoreCheckPoint $_layers(label,node) pass for xy in self.paintCoordinates: self.paintBrush(xy[0], xy[1]) self.paintCoordinates = [] self.paintFeedback() # TODO: workaround for new pipeline in slicer4 # - editing image data of the calling modified on the node # does not pull the pipeline chain # - so we trick it by changing the image data first sliceLogic = self.sliceWidget.sliceLogic() labelLogic = sliceLogic.GetLabelLayer() labelNode = labelLogic.GetVolumeNode() labelNode.SetModifiedSinceRead(1) workaround = 1 if workaround: if not hasattr(self,"tempImageData"): self.tempImageData = vtk.vtkImageData() imageData = labelNode.GetImageData() labelNode.SetAndObserveImageData(self.tempImageData) labelNode.SetAndObserveImageData(imageData) else: labelNode.Modified()
def performFrangiVesselness( self, image, minimumDiameter, maximumDiameter, discretizationSteps, alpha, beta, gamma ): ''' ''' # import the vmtk libraries try: #from libvtkvmtkSegmentationPython import * import libvtkvmtkSegmentationPython as s except ImportError: print "FAILURE: Unable to import the SlicerVmtk libraries!" cast = vtk.vtkImageCast() cast.SetInput( image ) cast.SetOutputScalarTypeToFloat() cast.Update() image = cast.GetOutput() v = s.vtkvmtkVesselnessMeasureImageFilter() v.SetInput( image ) v.SetSigmaMin( minimumDiameter ) v.SetSigmaMax( maximumDiameter ) v.SetNumberOfSigmaSteps( discretizationSteps ) v.SetAlpha( alpha ) v.SetBeta( beta ) v.SetGamma( gamma ) v.Update() outImageData = vtk.vtkImageData() outImageData.DeepCopy( v.GetOutput() ) outImageData.Update() outImageData.GetPointData().GetScalars().Modified() return outImageData
def storeSceneView(self, name, description=""): """ NOTE: Taken from here: https://github.com/Slicer/Slicer/blob/master/Applications/SlicerApp/ Testing/Python/SlicerMRBTest.py#L273 Store a scene view into the current scene. TODO: this might move to slicer.util @param name: TheSceneViewName @return: vtkImageData """ viewport = slicer.app.layoutManager().viewport() qImage = qt.QPixmap().grabWidget(viewport).toImage() imageData = vtk.vtkImageData() slicer.qMRMLUtils().qImageToVtkImageData(qImage,imageData) sceneViewNode = slicer.vtkMRMLSceneViewNode() sceneViewNode.SetScreenShotType(4) sceneViewNode.SetScreenShot(imageData) return sceneViewNode.GetScreenShot()
def setupScene(self): logging.info("UltraSound.setupScene") # live ultrasound liveUltrasoundNodeName = self.guideletParent.parameterNode.GetParameter("LiveUltrasoundNodeName") self.liveUltrasoundNode_Reference = slicer.util.getNode(liveUltrasoundNodeName) if not self.liveUltrasoundNode_Reference: imageSpacing = [0.2, 0.2, 0.2] # Create an empty image volume imageData = vtk.vtkImageData() imageData.SetDimensions(self.DEFAULT_IMAGE_SIZE) imageData.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 1) thresholder = vtk.vtkImageThreshold() thresholder.SetInputData(imageData) thresholder.SetInValue(0) thresholder.SetOutValue(0) # Create volume node self.liveUltrasoundNode_Reference = slicer.vtkMRMLScalarVolumeNode() self.liveUltrasoundNode_Reference.SetName(liveUltrasoundNodeName) self.liveUltrasoundNode_Reference.SetSpacing(imageSpacing) self.liveUltrasoundNode_Reference.SetImageDataConnection(thresholder.GetOutputPort()) # Add volume to scene slicer.mrmlScene.AddNode(self.liveUltrasoundNode_Reference) displayNode = slicer.vtkMRMLScalarVolumeDisplayNode() slicer.mrmlScene.AddNode(displayNode) colorNode = slicer.util.getNode("Grey") displayNode.SetAndObserveColorNodeID(colorNode.GetID()) self.liveUltrasoundNode_Reference.SetAndObserveDisplayNodeID(displayNode.GetID()) # self.liveUltrasoundNode_Reference.CreateDefaultStorageNode() self.setupResliceDriver()
def CreateNewNode(self, colorName, color, dim, origin): # we add a pseudo-random number to the name of our empty volume to avoid the risk of having a volume called # exactly the same by the user which could be confusing. We could also have used slicer.app.sessionId() if colorName not in self.colorSliceVolumes.keys(): VolumeName = "EasyClip_EmptyVolume_" + str(slicer.app.applicationPid()) + "_" + colorName # Do NOT set the spacing and the origin of imageData (vtkImageData) # The spacing and the origin should only be set in the vtkMRMLScalarVolumeNode!!!!!! # We only create an image of 1 voxel (as we only use it to color the planes imageData = vtk.vtkImageData() imageData.SetDimensions(1, 1, 1) imageData.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 1) imageData.SetScalarComponentFromDouble(0, 0, 0, 0, color) if hasattr(slicer, 'vtkMRMLLabelMapVolumeNode'): sampleVolumeNode = slicer.vtkMRMLLabelMapVolumeNode() else: sampleVolumeNode = slicer.vtkMRMLScalarVolumeNode() sampleVolumeNode = slicer.mrmlScene.AddNode(sampleVolumeNode) sampleVolumeNode.SetName(VolumeName) labelmapVolumeDisplayNode = slicer.vtkMRMLLabelMapVolumeDisplayNode() slicer.mrmlScene.AddNode(labelmapVolumeDisplayNode) colorNode = slicer.util.getNode('GenericAnatomyColors') labelmapVolumeDisplayNode.SetAndObserveColorNodeID(colorNode.GetID()) sampleVolumeNode.SetAndObserveImageData(imageData) sampleVolumeNode.SetAndObserveDisplayNodeID(labelmapVolumeDisplayNode.GetID()) labelmapVolumeDisplayNode.VisibilityOff() self.colorSliceVolumes[colorName] = sampleVolumeNode.GetID() sampleVolumeNode = slicer.mrmlScene.GetNodeByID(self.colorSliceVolumes[colorName]) sampleVolumeNode.HideFromEditorsOn() sampleVolumeNode.SetOrigin(origin[0], origin[1], origin[2]) sampleVolumeNode.SetSpacing(dim[0], dim[1], dim[2]) if not hasattr(slicer, 'vtkMRMLLabelMapVolumeNode'): sampleVolumeNode.SetLabelMap(1) sampleVolumeNode.SetHideFromEditors(True) sampleVolumeNode.SetSaveWithScene(False) return sampleVolumeNode
def renderArray(self, labelNodeArray, labelNode, imageNode, shape=(512,512,88), spacing=(1,1,1), origin=(0,0,0)): ras2ijk = vtk.vtkMatrix4x4() ijk2ras = vtk.vtkMatrix4x4() imageNode.GetRASToIJKMatrix(ras2ijk) imageNode.GetIJKToRASMatrix(ijk2ras) labelNode.SetRASToIJKMatrix(ras2ijk) labelNode.SetIJKToRASMatrix(ijk2ras) labelNodeImageData = vtk.vtkImageData() labelNodeImageData.DeepCopy(imageNode.GetImageData()) #labelNodeImageData.AllocateScalars(4,1) #labelNodeImageData.SetDimensions(shape) labelNodePointData = labelNodeImageData.GetPointData() """ # Numpy array is converted from signed int16 to signed vtkShortArray scalarArray = vtk.vtkShortArray() dims1D = labelNodeArray.size #labelNodePointData.GetScalars().GetSize() flatArray = labelNodeArray.reshape(dims1D, order='C') scalarArray = vtk.util.numpy_support.numpy_to_vtk(flatArray) """ scalarArray = vtk.vtkShortArray() dims1D = labelNodePointData.GetScalars().GetSize() #labelNodePointData.GetScalars().GetSize() flatArray = labelNodeArray.reshape(dims1D, order='F') scalarArray = vtk.util.numpy_support.numpy_to_vtk(flatArray) # VTK Unsigned Char Array =3, short =4, uint = 7 labelNodePointData.SetScalars(scalarArray) labelNodeImageData.Modified() slicer.mrmlScene.AddNode(labelNode) labelNode.SetAndObserveImageData(labelNodeImageData) labelNode.SetSpacing(spacing) labelNode.SetOrigin(origin) return labelNode
def initializeNewLabel(newLabel, sourceVolume): displayNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLLabelMapVolumeDisplayNode()) threshold = vtk.vtkImageThreshold() threshold.ReplaceInOn() threshold.ReplaceOutOn() threshold.SetInValue(0) threshold.SetOutValue(0) threshold.SetOutputScalarTypeToUnsignedShort() threshold.SetInput(sourceVolume.GetImageData()) threshold.Update() labelImage = vtk.vtkImageData() labelImage.DeepCopy(threshold.GetOutput()) newLabel.SetAndObserveStorageNodeID(None) newLabel.SetLabelMap(1) newLabel.CopyOrientation(sourceVolume) ras2ijk = vtk.vtkMatrix4x4() sourceVolume.GetRASToIJKMatrix(ras2ijk) newLabel.SetRASToIJKMatrix(ras2ijk) newLabel.SetAttribute('ReportingReportNodeID', sourceVolume.GetAttribute('ReportingReportNodeID')) newLabel.SetAttribute('AssociatedNodeID', sourceVolume.GetID()) newLabel.SetAndObserveDisplayNodeID(displayNode.GetID()) newLabel.SetAndObserveImageData(labelImage)
def load(self,loadable): """Load the selection as a scalar volume, but rescale the values """ scalarVolumePlugin = slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']() vNode = scalarVolumePlugin.loadFilesWithArchetype(loadable.files, loadable.name) if vNode: intercept = float(slicer.dicomDatabase.fileValue(loadable.files[0], self.tags['ScaleIntercept'])) slope = float(slicer.dicomDatabase.fileValue(loadable.files[0], self.tags['ScaleSlope'])) privateIntercept = float(slicer.dicomDatabase.fileValue(loadable.files[0], self.tags['PrivateScaleIntercept'])) privateSlope = float(slicer.dicomDatabase.fileValue(loadable.files[0], self.tags['PrivateScaleSlope'])) print('Slope: '+str(slope)+' private: '+str(privateSlope)+' Intercept: '+str(intercept)+' private: '+str(privateIntercept)) # vtkImageShiftScale first shifts, then scales # First, revert the scaling applied on ITK-level read reverseShift = vtk.vtkImageShiftScale() reverseShift.SetShift(-1.*intercept) reverseShift.SetScale(1) reverseShift.SetInput(vNode.GetImageData()) reverseShift.SetOutputScalarTypeToFloat() reverseScale = vtk.vtkImageShiftScale() reverseScale.SetShift(0) reverseScale.SetScale(1./slope) reverseScale.SetInput(reverseShift.GetOutput()) reverseScale.SetOutputScalarTypeToFloat() # Second, apply scaling using the private tags information rescale = vtk.vtkImageShiftScale() rescale.SetShift(-1.*privateIntercept) rescale.SetScale(1./privateSlope) rescale.SetOutputScalarTypeToFloat() rescale.SetInput(reverseScale.GetOutput()) rescale.Update() imageData = vtk.vtkImageData() imageData.DeepCopy(rescale.GetOutput()) # Note: the assumption here is that intercept/slope are identical for all # slices in the series. According to Tom Chenevert, this is typically the # case: "The exception is when there are multiple image types in a series, # such as real, imaginary, magnitude and phase images all stored in the # series. But this is not common." vNode.SetAndObserveImageData(imageData) return vNode
def takeScreenshot(self,name,description,type=-1,screenshotScaleFactor=1): lm = slicer.app.layoutManager() # switch on the type to get the requested window widget = 0 if type == -1: # full window widget = slicer.util.mainWindow() elif type == slicer.qMRMLScreenShotDialog().FullLayout: # full layout widget = lm.viewport() elif type == slicer.qMRMLScreenShotDialog().ThreeD: # just the 3D window widget = lm.threeDWidget(0).threeDView() elif type == slicer.qMRMLScreenShotDialog().Red: # red slice window widget = lm.sliceWidget("Red") elif type == slicer.qMRMLScreenShotDialog().Yellow: # yellow slice window widget = lm.sliceWidget("Yellow") elif type == slicer.qMRMLScreenShotDialog().Green: # green slice window widget = lm.sliceWidget("Green") # grab and convert to vtk image data qpixMap = qt.QPixmap().grabWidget(widget) qimage = qpixMap.toImage() imageData = vtk.vtkImageData() slicer.qMRMLUtils().qImageToVtkImageData(qimage,imageData) annotationLogic = slicer.modules.annotations.logic() annotationLogic.CreateSnapShot(name, description, type, screenshotScaleFactor, imageData)
def setupScene(self): logging.info("UltraSound.setupScene") ''' ReferenceToRas transform is used in almost all IGT applications. Reference is the coordinate system of a tool fixed to the patient. Tools are tracked relative to Reference, to compensate for patient motion. ReferenceToRas makes sure that everything is displayed in an anatomical coordinate system, i.e. R, A, and S (Right, Anterior, and Superior) directions in Slicer are correct relative to any images or tracked tools displayed. ReferenceToRas is needed for initialization, so we need to set it up before calling Guidelet.setupScene(). ''' if self.referenceToRas is None or (self.referenceToRas and slicer.mrmlScene.GetNodeByID(self.referenceToRas.GetID()) is None): self.referenceToRas = slicer.mrmlScene.GetFirstNodeByName('ReferenceToRas') if self.referenceToRas is None: self.referenceToRas = slicer.vtkMRMLLinearTransformNode() self.referenceToRas.SetName("ReferenceToRas") m = self.guideletParent.logic.readTransformFromSettings('ReferenceToRas', self.guideletParent.configurationName) if m is None: m = self.guideletParent.logic.createMatrixFromString('1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1') self.referenceToRas.SetMatrixTransformToParent(m) slicer.mrmlScene.AddNode(self.referenceToRas) # live ultrasound liveUltrasoundNodeName = self.guideletParent.parameterNode.GetParameter('LiveUltrasoundNodeName') self.liveUltrasoundNode_Reference = slicer.mrmlScene.GetFirstNodeByName(liveUltrasoundNodeName) if not self.liveUltrasoundNode_Reference: imageSpacing=[0.2, 0.2, 0.2] # Create an empty image volume imageData=vtk.vtkImageData() imageData.SetDimensions(self.DEFAULT_IMAGE_SIZE) imageData.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 1) thresholder=vtk.vtkImageThreshold() thresholder.SetInputData(imageData) thresholder.SetInValue(0) thresholder.SetOutValue(0) # Create volume node self.liveUltrasoundNode_Reference=slicer.vtkMRMLScalarVolumeNode() self.liveUltrasoundNode_Reference.SetName(liveUltrasoundNodeName) self.liveUltrasoundNode_Reference.SetSpacing(imageSpacing) self.liveUltrasoundNode_Reference.SetImageDataConnection(thresholder.GetOutputPort()) # Add volume to scene slicer.mrmlScene.AddNode(self.liveUltrasoundNode_Reference) displayNode=slicer.vtkMRMLScalarVolumeDisplayNode() slicer.mrmlScene.AddNode(displayNode) colorNode = slicer.mrmlScene.GetFirstNodeByName('Grey') displayNode.SetAndObserveColorNodeID(colorNode.GetID()) self.liveUltrasoundNode_Reference.SetAndObserveDisplayNodeID(displayNode.GetID()) self.plusRemoteNode = slicer.mrmlScene.GetFirstNodeByClass('vtkMRMLPlusRemoteNode') if self.plusRemoteNode is None: self.plusRemoteNode = slicer.vtkMRMLPlusRemoteNode() self.plusRemoteNode.SetName("PlusRemoteNode") slicer.mrmlScene.AddNode(self.plusRemoteNode) self.plusRemoteNode.AddObserver(slicer.vtkMRMLPlusRemoteNode.RecordingStartedEvent, self.recordingCommandCompleted) self.plusRemoteNode.AddObserver(slicer.vtkMRMLPlusRemoteNode.RecordingCompletedEvent, self.recordingCommandCompleted) self.plusRemoteNode.SetAndObserveOpenIGTLinkConnectorNode(self.guideletParent.connectorNode) self.setupResliceDriver()
def buildGradientBasedFeatureImage( self, imageData ): ''' ''' # import the vmtk libraries try: #from libvtkvmtkSegmentationPython import * import libvtkvmtkSegmentationPython as s except ImportError: print "FAILURE: Unable to import the SlicerVmtk libraries!" derivativeSigma = 0.0 sigmoidRemapping = 1 cast = vtk.vtkImageCast() cast.SetInput( imageData ) cast.SetOutputScalarTypeToFloat() cast.Update() if ( derivativeSigma > 0.0 ): gradientMagnitude = s.vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter() gradientMagnitude.SetInput( cast.GetOutput() ) gradientMagnitude.SetSigma( derivativeSigma ) gradientMagnitude.SetNormalizeAcrossScale( 0 ) gradientMagnitude.Update() else: gradientMagnitude = s.vtkvmtkGradientMagnitudeImageFilter() gradientMagnitude.SetInput( cast.GetOutput() ) gradientMagnitude.Update() featureImage = None if sigmoidRemapping == 1: scalarRange = gradientMagnitude.GetOutput().GetPointData().GetScalars().GetRange() inputMinimum = scalarRange[0] inputMaximum = scalarRange[1] alpha = -( inputMaximum - inputMinimum ) / 6.0 beta = ( inputMaximum + inputMinimum ) / 2.0 sigmoid = s.vtkvmtkSigmoidImageFilter() sigmoid.SetInput( gradientMagnitude.GetOutput() ) sigmoid.SetAlpha( alpha ) sigmoid.SetBeta( beta ) sigmoid.SetOutputMinimum( 0.0 ) sigmoid.SetOutputMaximum( 1.0 ) sigmoid.Update() featureImage = sigmoid.GetOutput() else: boundedReciprocal = s.vtkvmtkBoundedReciprocalImageFilter() boundedReciprocal.SetInput( gradientMagnitude.GetOutput() ) boundedReciprocal.Update() featureImage = boundedReciprocal.GetOutput() outImageData = vtk.vtkImageData() outImageData.DeepCopy( featureImage ) outImageData.Update() return outImageData
def renderLabelMap(self): # Initializes a vtkMRMLScalarVolumeNode for the SegmentCAD Output and copies ijkToRAS matrix and Image data from nodeLabel ras2ijk = vtk.vtkMatrix4x4() ijk2ras = vtk.vtkMatrix4x4() self.nodePre.GetRASToIJKMatrix(ras2ijk) self.nodePre.GetIJKToRASMatrix(ijk2ras) self.SegmentCADLabelMap.SetRASToIJKMatrix(ras2ijk) self.SegmentCADLabelMap.SetIJKToRASMatrix(ijk2ras) SegmentCADLabelMapImageData = vtk.vtkImageData() SegmentCADLabelMapImageData.DeepCopy(self.nodePre.GetImageData()) SegmentCADLabelMapPointData = SegmentCADLabelMapImageData.GetPointData() # Numpy array is converted from signed int16 to signed vtkShortArray scalarArray = vtk.vtkShortArray() dims1D = SegmentCADLabelMapPointData.GetScalars().GetSize() self.nodeArraySegmentCADLabel = self.nodeArraySegmentCADLabel.reshape(dims1D, order='C') #use a flattening function scalarArray = vtk.util.numpy_support.numpy_to_vtk(self.nodeArraySegmentCADLabel) # PointData() of SegmentCAD label output pointed to new vtkShortArray for scalar values if vtk.VTK_MAJOR_VERSION <= 5: #SegmentCADLabelMapImageData.SetScalarTypeToShort() SegmentCADLabelMapPointData.SetScalars(scalarArray) SegmentCADLabelMapPointData.Update() else: #SegmentCADLabelMapImageData.SetScalarType(4) SegmentCADLabelMapPointData.SetScalars(scalarArray) SegmentCADLabelMapImageData.Modified() self.SegmentCADLabelMap.SetAndObserveImageData(SegmentCADLabelMapImageData) # Corresponding display node and color table nodes created for SegmentCAD label Output self.SegmentCADLabelMapDisplay = slicer.vtkMRMLLabelMapVolumeDisplayNode() self.SegmentCADLabelMapDisplay.SetScene(slicer.mrmlScene) self.SegmentCADLabelMapDisplay.SetAndObserveColorNodeID('vtkMRMLColorTableNodeFileGenericColors.txt') if vtk.VTK_MAJOR_VERSION <= 5: self.SegmentCADLabelMapDisplay.SetInputImageData(self.SegmentCADLabelMap.GetImageData()) else: self.SegmentCADLabelMapDisplay.SetInputImageDataConnection(self.SegmentCADLabelMap.GetImageDataConnection()) self.SegmentCADLabelMapDisplay.UpdateImageDataPipeline() slicer.mrmlScene.AddNode(self.SegmentCADLabelMapDisplay) self.SegmentCADLabelMap.SetAndObserveDisplayNodeID(self.SegmentCADLabelMapDisplay.GetID()) self.SegmentCADLabelMapDisplay.UpdateScene(slicer.mrmlScene) #red_logic = slicer.app.layoutManager().sliceWidget("Red").sliceLogic() #red_logic.GetSliceCompositeNode().SetLabelVolumeID(self.SegmentCADLabelMap.GetID()) #yellow_logic = slicer.app.layoutManager().sliceWidget("Yellow").sliceLogic() #yellow_logic.GetSliceCompositeNode().SetLabelVolumeID(self.SegmentCADLabelMap.GetID()) #green_logic = slicer.app.layoutManager().sliceWidget("Green").sliceLogic() #green_logic.GetSliceCompositeNode().SetLabelVolumeID(self.SegmentCADLabelMap.GetID()) appLogic = slicer.app.applicationLogic() selectionNode = appLogic.GetSelectionNode() #selectionNode.SetReferenceActiveVolumeID(self.nodePre.GetID()) selectionNode.SetReferenceActiveLabelVolumeID(self.SegmentCADLabelMap.GetID()) #selectionNode.SetReferenceSecondaryVolumeID(self.node1.GetID()) appLogic.PropagateVolumeSelection()
def fit(self,atlasName='DevelopmentalAtlas', range=[0,5]): """ Create a volume of the slope across the range of years. least squares notation from: http://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.lstsq.html """ ijkToRAS = vtk.vtkMatrix4x4() atlasVolume = slicer.util.getNode(atlasName) atlasVolume.GetIJKToRASMatrix(ijkToRAS) fitVolume = slicer.vtkMRMLScalarVolumeNode() fitVolume.SetIJKToRASMatrix(ijkToRAS) ageRange = str(range).replace('[','(').replace(']',')') fitName = 'Slope_'+ageRange+'_'+atlasName fitVolume.SetName(fitName) colorNode = slicer.vtkMRMLColorTableNode() colorNode.SetTypeToGrey() slicer.mrmlScene.AddNode(colorNode) fitDisplayNode = slicer.vtkMRMLScalarVolumeDisplayNode() fitDisplayNode.SetAutoWindowLevel(False) fitDisplayNode.SetWindow(10) fitDisplayNode.SetLevel(45) slicer.mrmlScene.AddNode(fitDisplayNode) fitDisplayNode.SetAndObserveColorNodeID(colorNode.GetID()) fitImage = vtk.vtkImageData() fitImage.ShallowCopy(atlasVolume.GetImageData()) fitImage.AllocateScalars(vtk.VTK_FLOAT, 1) fitVolume.SetAndObserveImageData(fitImage) slicer.mrmlScene.AddNode(fitVolume) fitVolume.SetAndObserveDisplayNodeID(fitDisplayNode.GetID()) fitArray = slicer.util.array(fitName) atlasArray = slicer.util.array(atlasName) # make a regression against a scale more or less like the multivolume plot timePoints = self.agesInYears[range[0]:range[1]] timePoints = map(lambda x : x * 1000., timePoints) A = numpy.vstack([timePoints, numpy.ones(len(timePoints))]).T slices, rows, columns, frames = atlasArray.shape for slice in xrange(slices): for row in xrange(rows): for column in xrange(columns): if atlasArray[slice, row, column, 0] == 0: fit = 0 else: series = atlasArray[slice, row, column][range[0]:range[1]] slope, intercept = numpy.linalg.lstsq(A, series)[0] fit = -1. * numpy.degrees(numpy.arctan(slope)) fitArray[slice, row, column] = fit return fitVolume
def maskVolume(self, volumeIn, roiNode, inPlace=False): # Clone input volume, unless inPlace inPlace = False # TODO: make this work nameout = volumeIn.GetName() if not "masked" in nameout: nameout += " masked" if inPlace: outData = vtk.vtkImageData() volumeIn.SetName(volumeIn.GetName() + " masked") else: volumeOut = slicer.modules.volumes.logic().CloneVolume(volumeIn, nameout) outData = volumeOut.GetImageData() # Get transform into image space IJKtoRAS = vtk.vtkMatrix4x4() volumeIn.GetIJKToRASMatrix(IJKtoRAS) # Get ROI to image transform ROItoImage = vtk.vtkMatrix4x4() ROItoImage.Identity() parentNode = roiNode.GetParentTransformNode() if parentNode is None and volumeIn.GetParentTransformNode(): volumeIn.GetParentTransformNode().GetMatrixTransformToWorld(ROItoImage) # don't invert here, this is already the proper direction. if parentNode is not None: parentNode.GetMatrixTransformToNode(volumeIn.GetParentTransformNode(), ROItoImage) ROItoImage.Invert() # Transformations tfm = vtk.vtkTransform() tfm.SetMatrix(IJKtoRAS) tfm.PostMultiply() tfm.Concatenate(ROItoImage) # Get planes and apply transform planes = vtk.vtkPlanes() roiNode.GetTransformedPlanes(planes) planes.SetTransform(tfm) # Blot out selected region tostencil = vtk.vtkImplicitFunctionToImageStencil() tostencil.SetInput(planes) imgstencil = vtk.vtkImageStencil() imgstencil.SetInput(volumeIn.GetImageData()) imgstencil.SetStencil(tostencil.GetOutput()) imgstencil.SetBackgroundValue(0) imgstencil.ReverseStencilOn() # Write the changes imgstencil.SetOutput(outData) imgstencil.Update()
def setupScene(self): layoutManager = slicer.app.layoutManager() # live ultrasound liveUltrasoundNodeName = self.guideletParent.parameterNode.GetParameter('LiveUltrasoundNodeName') self.liveUltrasoundNode_Reference = slicer.util.getNode(liveUltrasoundNodeName) if not self.liveUltrasoundNode_Reference: imageSize=[800, 600, 1] imageSpacing=[0.2, 0.2, 0.2] # Create an empty image volume imageData=vtk.vtkImageData() imageData.SetDimensions(imageSize) imageData.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 1) thresholder=vtk.vtkImageThreshold() thresholder.SetInputData(imageData) thresholder.SetInValue(0) thresholder.SetOutValue(0) # Create volume node self.liveUltrasoundNode_Reference=slicer.vtkMRMLScalarVolumeNode() self.liveUltrasoundNode_Reference.SetName(liveUltrasoundNodeName) self.liveUltrasoundNode_Reference.SetSpacing(imageSpacing) self.liveUltrasoundNode_Reference.SetImageDataConnection(thresholder.GetOutputPort()) # Add volume to scene slicer.mrmlScene.AddNode(self.liveUltrasoundNode_Reference) displayNode=slicer.vtkMRMLScalarVolumeDisplayNode() slicer.mrmlScene.AddNode(displayNode) colorNode = slicer.util.getNode('Grey') displayNode.SetAndObserveColorNodeID(colorNode.GetID()) self.liveUltrasoundNode_Reference.SetAndObserveDisplayNodeID(displayNode.GetID()) #self.liveUltrasoundNode_Reference.CreateDefaultStorageNode() # Show ultrasound in red view. redSlice = layoutManager.sliceWidget('Red') redSliceLogic = redSlice.sliceLogic() redSliceLogic.GetSliceCompositeNode().SetBackgroundVolumeID(self.liveUltrasoundNode_Reference.GetID()) # Set up volume reslice driver. resliceLogic = slicer.modules.volumereslicedriver.logic() if resliceLogic: redNode = slicer.util.getNode('vtkMRMLSliceNodeRed') # Typically the image is zoomed in, therefore it is faster if the original resolution is used # on the 3D slice (and also we can show the full image and not the shape and size of the 2D view) redNode.SetSliceResolutionMode(slicer.vtkMRMLSliceNode.SliceResolutionMatchVolumes) resliceLogic.SetDriverForSlice(self.liveUltrasoundNode_Reference.GetID(), redNode) resliceLogic.SetModeForSlice(6, redNode) # Transverse mode, default for PLUS ultrasound. resliceLogic.SetFlipForSlice(False, redNode) resliceLogic.SetRotationForSlice(180, redNode) redSliceLogic.FitSliceToAll() else: logging.warning('Logic not found for Volume Reslice Driver') self.liveUltrasoundNode_Reference.SetAndObserveTransformNodeID(self.guideletParent.ReferenceToRas.GetID())
def __init__(self,sliceLogic): self.sliceLogic = sliceLogic self.editUtil = EditUtil.EditUtil() # optionally set by users of the class self.undoRedo = None self.scope = 'All' # # instance variables used internally # - buffer for result of scoped editing self.scopedImageBuffer = vtk.vtkImageData() # - slice paint is used to extract/replace scoped regions self.scopedSlicePaint = slicer.vtkImageSlicePaint()
def detectEdgeInROI(self,edge,alternateEdge=None): qu=QCLib.QCUtil() VOIROI=qu.getVOIfromRectROI(self.ROI) eV=vtk.vtkExtractVOI() eV.SetInputData(self.input.GetImageData()) eV.SetVOI(VOIROI) eV.Update() imROI=eV.GetOutput() thr=[0,0] if self.algorithm==0: #find threshold for edge detection mL=makeROIGhostLogic() ghost=vtk.vtkImageData() ghnode=slicer.vtkMRMLScalarVolumeNode() ghnode.SetAndObserveImageData(ghost) mL.run(self.input,ghnode) rL=ROIStatisticsLogic() rL.run(self.input,ghnode) zROI=VOIROI[4] ghVals=[] stats=rL.stats.values() for n in range(rL.stats.__len__()): ghVals.append(stats[n][zROI]['mean']+stats[n][zROI]['sd']) thr=[max(ghVals),2*max(ghVals)] else: alternateEdge=None cast=vtk.vtkImageCast() cast.SetOutputScalarTypeToDouble() cast.SetInputData(imROI) cast.Update() em=slicer.vtkITKEdgeDetection() em.SetInputData(cast.GetOutput()) em.SetAlgorithmInt(self.algorithm) em.Setthreshold(thr) em.Setvariance(5) em.Update() edge.DeepCopy(em.GetOutput()) if alternateEdge: self.signedDistance(edge,alternateEdge)
def buildSimpleLabelMap( self, image, inValue, outValue ): threshold = vtk.vtkImageThreshold() threshold.SetInputData( image ) threshold.ThresholdByLower( 0 ) threshold.ReplaceInOn() threshold.ReplaceOutOn() threshold.SetOutValue( outValue ) threshold.SetInValue( inValue ) threshold.Update() outVolumeData = vtk.vtkImageData() outVolumeData.DeepCopy( threshold.GetOutput() ) return outVolumeData
def __init__(self, shaderComputation, textureUnit, node): self.shaderComputation = shaderComputation self.textureUnit = textureUnit self.node = node self.dummyImage = vtk.vtkImageData() self.dummyImage.SetDimensions(1,1,1) self.dummyImage.AllocateScalars(vtk.VTK_SHORT, 1) try: from vtkSlicerShadedActorModuleLogicPython import vtkOpenGLTextureImage except ImportError: import vtkAddon vtkOpenGLTextureImage=vtkAddon.vtkOpenGLTextureImage self.textureImage=vtkOpenGLTextureImage() self.textureImage.SetShaderComputation(self.shaderComputation) self.textureImage.SetImageData(self.dummyImage)
def performLaplaceOfGaussian( self, image ): ''' ''' gaussian = vtk.vtkImageGaussianSmooth() gaussian.SetInputData( image ) gaussian.Update() laplacian = vtk.vtkImageLaplacian() laplacian.SetInputData( gaussian.GetOutput() ) laplacian.Update() outImageData = vtk.vtkImageData() outImageData.DeepCopy( laplacian.GetOutput() ) return outImageData
def timeimage(self,cmd=''): """For debugging - return an image with the current time rendered as text down to the hundredth of a second""" # check arguments p = urlparse.urlparse(cmd) q = urlparse.parse_qs(p.query) try: color = "#" + q['color'][0].strip().lower() except KeyError: color = "#330" # # make a generally transparent image, # imageWidth = 128 imageHeight = 32 timeImage = qt.QImage(imageWidth, imageHeight, qt.QImage().Format_ARGB32) timeImage.fill(0) # a painter to use for various jobs painter = qt.QPainter() # draw a border around the pixmap painter.begin(timeImage) pen = qt.QPen() color = qt.QColor(color) color.setAlphaF(0.8) pen.setColor(color) pen.setWidth(5) pen.setStyle(3) # dotted line (Qt::DotLine) painter.setPen(pen) rect = qt.QRect(1, 1, imageWidth-2, imageHeight-2) painter.drawRect(rect) color = qt.QColor("#333") pen.setColor(color) painter.setPen(pen) position = qt.QPoint(10,20) text = str(time.time()) # text to draw painter.drawText(position, text) painter.end() # convert the image to vtk, then to png from there vtkTimeImage = vtk.vtkImageData() slicer.qMRMLUtils().qImageToVtkImageData(timeImage, vtkTimeImage) pngData = self.vtkImageDataToPNG(vtkTimeImage) return pngData
def renderLabelMap(self): # Initializes a vtkMRMLScalarVolumeNode for the SegmentCAD Output and copies ijkToRAS matrix and Image data from nodeLabel ras2ijk = vtk.vtkMatrix4x4() ijk2ras = vtk.vtkMatrix4x4() self.nodePre.GetRASToIJKMatrix(ras2ijk) self.nodePre.GetIJKToRASMatrix(ijk2ras) self.SegmentCADLabelMap.SetRASToIJKMatrix(ras2ijk) self.SegmentCADLabelMap.SetIJKToRASMatrix(ijk2ras) SegmentCADLabelMapImageData = vtk.vtkImageData() SegmentCADLabelMapImageData.DeepCopy(self.nodePre.GetImageData()) SegmentCADLabelMapPointData = SegmentCADLabelMapImageData.GetPointData( ) # Numpy array is converted from signed int16 to signed vtkShortArray scalarArray = vtk.vtkShortArray() dims1D = SegmentCADLabelMapPointData.GetScalars().GetSize() self.nodeArraySegmentCADLabel = self.nodeArraySegmentCADLabel.reshape( dims1D, order='C') #use a flattening function scalarArray = vtk.util.numpy_support.numpy_to_vtk( self.nodeArraySegmentCADLabel) # PointData() of SegmentCAD label output pointed to new vtkShortArray for scalar values if vtk.VTK_MAJOR_VERSION <= 5: #SegmentCADLabelMapImageData.SetScalarTypeToShort() SegmentCADLabelMapPointData.SetScalars(scalarArray) SegmentCADLabelMapPointData.Update() else: #SegmentCADLabelMapImageData.SetScalarType(4) SegmentCADLabelMapPointData.SetScalars(scalarArray) SegmentCADLabelMapImageData.Modified() self.SegmentCADLabelMap.SetAndObserveImageData( SegmentCADLabelMapImageData) # Corresponding display node and color table nodes created for SegmentCAD label Output self.SegmentCADLabelMapDisplay = slicer.vtkMRMLLabelMapVolumeDisplayNode( ) self.SegmentCADLabelMapDisplay.SetScene(slicer.mrmlScene) self.SegmentCADLabelMapDisplay.SetAndObserveColorNodeID( 'vtkMRMLColorTableNodeFileGenericColors.txt') if vtk.VTK_MAJOR_VERSION <= 5: self.SegmentCADLabelMapDisplay.SetInputImageData( self.SegmentCADLabelMap.GetImageData()) else: self.SegmentCADLabelMapDisplay.SetInputImageDataConnection( self.SegmentCADLabelMap.GetImageDataConnection()) self.SegmentCADLabelMapDisplay.UpdateImageDataPipeline() slicer.mrmlScene.AddNode(self.SegmentCADLabelMapDisplay) self.SegmentCADLabelMap.SetAndObserveDisplayNodeID( self.SegmentCADLabelMapDisplay.GetID()) self.SegmentCADLabelMapDisplay.UpdateScene(slicer.mrmlScene) #red_logic = slicer.app.layoutManager().sliceWidget("Red").sliceLogic() #red_logic.GetSliceCompositeNode().SetLabelVolumeID(self.SegmentCADLabelMap.GetID()) #yellow_logic = slicer.app.layoutManager().sliceWidget("Yellow").sliceLogic() #yellow_logic.GetSliceCompositeNode().SetLabelVolumeID(self.SegmentCADLabelMap.GetID()) #green_logic = slicer.app.layoutManager().sliceWidget("Green").sliceLogic() #green_logic.GetSliceCompositeNode().SetLabelVolumeID(self.SegmentCADLabelMap.GetID()) appLogic = slicer.app.applicationLogic() selectionNode = appLogic.GetSelectionNode() #selectionNode.SetReferenceActiveVolumeID(self.nodePre.GetID()) selectionNode.SetReferenceActiveLabelVolumeID( self.SegmentCADLabelMap.GetID()) #selectionNode.SetReferenceSecondaryVolumeID(self.node1.GetID()) appLogic.PropagateVolumeSelection()
def onComputeBox(self): numNodes = slicer.mrmlScene.GetNumberOfNodesByClass("vtkMRMLModelNode") bound = [MAXINT, -MAXINT, MAXINT, -MAXINT, MAXINT, -MAXINT] for i in range(3, numNodes): self.elements = slicer.mrmlScene.GetNthNodeByClass( i, "vtkMRMLModelNode") node = slicer.util.getNode(self.elements.GetName()) polydata = node.GetPolyData() tempbound = polydata.GetBounds() bound[0] = min(bound[0], tempbound[0]) bound[2] = min(bound[2], tempbound[2]) bound[4] = min(bound[4], tempbound[4]) bound[1] = max(bound[1], tempbound[1]) bound[3] = max(bound[3], tempbound[3]) bound[5] = max(bound[5], tempbound[5]) #--------------------------- Box around the model --------------------------# # print "bound", bound dimX = bound[1] - bound[0] dimY = bound[3] - bound[2] dimZ = bound[5] - bound[4] # print "dimension X :", dimX # print "dimension Y :", dimY # print "dimension Z :", dimZ dimX = dimX + 10 dimY = dimY + 10 dimZ = dimZ + 10 sampleVolumeNode = slicer.vtkMRMLScalarVolumeNode() sampleVolumeNode = slicer.mrmlScene.AddNode(sampleVolumeNode) imageData = vtk.vtkImageData() # Do NOT set the spacing and the origin of imageData (vtkImageData) # The spacing and the origin should only be set in the vtkMRMLScalarVolumeNode!!!!!! imageData.SetDimensions(int(dimX), int(dimY), int(dimZ)) imageData.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 1) extent = imageData.GetExtent() for x in xrange(extent[0], extent[1] + 1): for y in xrange(extent[2], extent[3] + 1): for z in xrange(extent[4], extent[5] + 1): imageData.SetScalarComponentFromDouble(x, y, z, 0, 0) sampleVolumeNode.SetSpacing(1, 1, 1) sampleVolumeNode.SetOrigin(bound[0], bound[2], bound[4]) sampleVolumeNode.SetName("Empty_volume") sampleVolumeNode.SetAndObserveImageData(imageData) sampleVolumeNode.SetLabelMap(1) labelmapVolumeDisplayNode = slicer.vtkMRMLLabelMapVolumeDisplayNode() slicer.mrmlScene.AddNode(labelmapVolumeDisplayNode) colorNode = slicer.util.getNode('GenericAnatomyColors') labelmapVolumeDisplayNode.SetAndObserveColorNodeID(colorNode.GetID()) labelmapVolumeDisplayNode.VisibilityOn() sampleVolumeNode.SetAndObserveDisplayNodeID( labelmapVolumeDisplayNode.GetID()) count = slicer.mrmlScene.GetNumberOfNodesByClass( 'vtkMRMLSliceCompositeNode') for n in xrange(count): compNode = slicer.mrmlScene.GetNthNodeByClass( n, 'vtkMRMLSliceCompositeNode') compNode.SetBackgroundVolumeID(sampleVolumeNode.GetID())
def loadFilesWithPyDICOM(self): """ Experimental method - not ready to be used yet. * Goal is to perform timing comparisons between ITK dicom loading vs something that bypasses ITK """ import dicom import numpy import vtk.util.numpy_support dataset0 = dicom.read_file(self.files[0]) dims = (dataset0.Columns, dataset0.Rows, len(self.files)) originLPS = dataset0.ImagePositionPatient rowToLPS = dataset0.ImageOrientationPatient[:3] colToLPS = dataset0.ImageOrientationPatient[3:] originRAS = [-1 * originLPS[0], -1 * originLPS[1], originLPS[2]] rowToRAS = [-1 * rowToLPS[0], -1 * rowToLPS[1], rowToLPS[2]] colToRAS = [-1 * colToLPS[0], -1 * colToLPS[1], rowToLPS[2]] sliceToRAS = numpy.cross(rowToRAS, colToRAS) spacing = dataset0.PixelSpacing if len(self.files) > 1: dataset1 = dicom.read_file(self.files[1]) o0 = numpy.array(originLPS) o1 = numpy.array(dataset1.ImagePositionPatient) sliceSpacing = numpy.sqrt(abs(numpy.sum(o1-o0))) else: sliceSpacing = 1. spacing.append(sliceSpacing) typeMap = {'int16': 4, 'uint16' : 5} imageData = vtk.vtkImageData() imageData.SetDimensions(dims) imageData.SetScalarType(typeMap[str(dataset0.pixel_array.dtype)]) imageData.AllocateScalars() imageArray = vtk.util.numpy_support.vtk_to_numpy(imageData.GetPointData().GetScalars()) imageArray = imageArray.reshape(dims[::-1]) slice = 0 for f in self.files: dataset = dicom.read_file(f) imageArray[slice] = dataset.pixel_array slice += 1 #TODO: # figure out datatype... # set window/level # any error checking? # multi-frame data? # check number of components # detect DWI # add progress self.volumeNode = slicer.vtkMRMLScalarVolumeNode() self.volumeNode.SetName(self.name) self.volumeNode.SetOrigin(originRAS) self.volumeNode.SetIToRASDirection(rowToRAS[0], rowToRAS[1], rowToRAS[2]) self.volumeNode.SetJToRASDirection(colToRAS[0], colToRAS[1], colToRAS[2]) self.volumeNode.SetKToRASDirection(sliceToRAS[0], sliceToRAS[1], sliceToRAS[2]) self.volumeNode.SetSpacing(spacing) self.volumeNode.SetAndObserveImageData(imageData) displayNode = slicer.vtkMRMLScalarVolumeDisplayNode() colorLogic = slicer.modules.colors.logic() displayNode.SetAndObserveColorNodeID(colorLogic.GetDefaultVolumeColorNodeID()) slicer.mrmlScene.AddNode(displayNode) slicer.mrmlScene.AddNode(self.volumeNode) self.volumeNode.SetAndObserveDisplayNodeID(displayNode.GetID())
def load(self, loadable): """Load the selection as a MultiVolume, if multivolume attribute is present """ mvNode = '' try: mvNode = loadable.multivolume except AttributeError: return None nFrames = int(mvNode.GetAttribute('MultiVolume.NumberOfFrames')) files = string.split(mvNode.GetAttribute('MultiVolume.FrameFileList'), ',') nFiles = len(files) filesPerFrame = nFiles / nFrames frames = [] mvImage = vtk.vtkImageData() mvImageArray = None scalarVolumePlugin = slicer.modules.dicomPlugins[ 'DICOMScalarVolumePlugin']() instanceUIDs = "" for file in files: uid = slicer.dicomDatabase.fileValue(file, self.tags['instanceUID']) if uid == "": uid = "Unknown" instanceUIDs += uid + " " instanceUIDs = instanceUIDs[:-1] mvNode.SetAttribute("DICOM.instanceUIDs", instanceUIDs) # read each frame into scalar volume for frameNumber in range(nFrames): sNode = slicer.vtkMRMLVolumeArchetypeStorageNode() sNode.ResetFileNameList() frameFileList = files[frameNumber * filesPerFrame:(frameNumber + 1) * filesPerFrame] # sv plugin will sort the filenames by geometric order svLoadables = scalarVolumePlugin.examine([frameFileList]) if len(svLoadables) == 0: return None for f in svLoadables[0].files: sNode.AddFileName(f) sNode.SetFileName( frameFileList[0]) # only used when num files/frame = 1 sNode.SetSingleFile(0) frame = slicer.vtkMRMLScalarVolumeNode() sNode.ReadData(frame) if frame.GetImageData() == None: print('Failed to read a multivolume frame!') return None if frameNumber == 0: frameImage = frame.GetImageData() frameExtent = frameImage.GetExtent() frameSize = frameExtent[1] * frameExtent[3] * frameExtent[5] mvImage.SetExtent(frameExtent) if vtk.VTK_MAJOR_VERSION <= 5: mvImage.SetNumberOfScalarComponents(nFrames) mvImage.SetScalarType(frame.GetImageData().GetScalarType()) mvImage.AllocateScalars() else: mvImage.AllocateScalars( frame.GetImageData().GetScalarType(), nFrames) mvImageArray = vtk.util.numpy_support.vtk_to_numpy( mvImage.GetPointData().GetScalars()) mvNode.SetScene(slicer.mrmlScene) mat = vtk.vtkMatrix4x4() frame.GetRASToIJKMatrix(mat) mvNode.SetRASToIJKMatrix(mat) frame.GetIJKToRASMatrix(mat) mvNode.SetIJKToRASMatrix(mat) frameImage = frame.GetImageData() frameImageArray = vtk.util.numpy_support.vtk_to_numpy( frameImage.GetPointData().GetScalars()) mvImageArray.T[frameNumber] = frameImageArray mvDisplayNode = slicer.mrmlScene.CreateNodeByClass( 'vtkMRMLMultiVolumeDisplayNode') mvDisplayNode.SetReferenceCount(mvDisplayNode.GetReferenceCount() - 1) mvDisplayNode.SetScene(slicer.mrmlScene) mvDisplayNode.SetDefaultColorMap() slicer.mrmlScene.AddNode(mvDisplayNode) mvNode.SetAndObserveDisplayNodeID(mvDisplayNode.GetID()) mvNode.SetAndObserveImageData(mvImage) mvNode.SetNumberOfFrames(nFrames) mvNode.SetName(loadable.name) slicer.mrmlScene.AddNode(mvNode) # # automatically select the volume to display # appLogic = slicer.app.applicationLogic() selNode = appLogic.GetSelectionNode() selNode.SetReferenceActiveVolumeID(mvNode.GetID()) appLogic.PropagateVolumeSelection() # file list is no longer needed - remove the attribute mvNode.RemoveAttribute('MultiVolume.FrameFileList') return mvNode
def loadDevelopmentalAtlas(self): # get the header - this reader doesn't support 4D # but can query the header. reader = vtk.vtkNIFTIImageReader() reader.SetFileName(self.developmentalPath) reader.Update() niftiHeader = reader.GetNIFTIHeader() print(self.developmentalPath) if niftiHeader.GetDataType() != 16: print(niftiHeader.GetDataType()) raise Exception('Can only load float data') # create the correct size and shape vtkImageData columns = niftiHeader.GetDim(1) rows = niftiHeader.GetDim(2) slices = niftiHeader.GetDim(3) frames = niftiHeader.GetDim(4) fp = open(self.developmentalPath, 'rb') headerThrowaway = fp.read(niftiHeader.GetVoxOffset()) niiArray = numpy.fromfile(fp, numpy.dtype('float32')) niiShape = (frames, slices, rows, columns) niiArray = niiArray.reshape(niiShape) image = vtk.vtkImageData() image.SetDimensions(columns, rows, slices) image.AllocateScalars(vtk.VTK_FLOAT, frames) from vtk.util.numpy_support import vtk_to_numpy imageShape = (slices, rows, columns, frames) imageArray = vtk_to_numpy( image.GetPointData().GetScalars()).reshape(imageShape) # copy the data from numpy to vtk (need to shuffle frames to components) for frame in range(frames): imageArray[:, :, :, frame] = niiArray[frame] # create the multivolume node and display it multiVolumeNode = slicer.vtkMRMLMultiVolumeNode() volumeLabels = vtk.vtkDoubleArray() volumeLabels.SetNumberOfTuples(frames) volumeLabels.SetNumberOfComponents(1) volumeLabels.Allocate(frames) for frame in xrange(frames): volumeLabels.SetComponent(frame, 0, self.agesInYears[frame]) multiVolumeNode.SetScene(slicer.mrmlScene) multiVolumeDisplayNode = slicer.mrmlScene.CreateNodeByClass( 'vtkMRMLMultiVolumeDisplayNode') multiVolumeDisplayNode.SetReferenceCount( multiVolumeDisplayNode.GetReferenceCount() - 1) multiVolumeDisplayNode.SetScene(slicer.mrmlScene) multiVolumeDisplayNode.SetDefaultColorMap() slicer.mrmlScene.AddNode(multiVolumeDisplayNode) multiVolumeNode.SetAndObserveDisplayNodeID( multiVolumeDisplayNode.GetID()) multiVolumeNode.SetAndObserveImageData(image) multiVolumeNode.SetNumberOfFrames(frames) multiVolumeNode.SetName("DevelopmentalAtlas") multiVolumeNode.SetLabelArray(volumeLabels) multiVolumeNode.SetLabelName("Years") multiVolumeNode.SetAttribute("MultiVolume.FrameLabels", str(self.agesInYears)[1:-1]) multiVolumeNode.SetAttribute("MultiVolume.NumberOfFrames", str(frames)) multiVolumeNode.SetAttribute( "MultiVolume.FrameIdentifyingDICOMTagName", "Age") multiVolumeNode.SetAttribute( "MultiVolume.FrameIdentifyingDICOMTagUnits", "(Years)") slicer.mrmlScene.AddNode(multiVolumeNode) return multiVolumeNode
def createAcquisitionTransform(self, volumeNode, metadata): # Creates transform that applies scan conversion transform probeRadius = metadata['CurvatureRadiusProbe'] trackRadius = metadata['CurvatureRadiusTrack'] if trackRadius != 0.0: raise ValueError( f"Curvature Radius (Track) is {trackRadius}. Currently, only volume with zero radius can be imported." ) # Create a sampling grid for the transform import numpy as np spacing = np.array(volumeNode.GetSpacing()) averageSpacing = (spacing[0] + spacing[1] + spacing[2]) / 3.0 voxelsPerTransformControlPoint = 20 # the transform is changing smoothly, so we don't need to add too many control points gridSpacingMm = averageSpacing * voxelsPerTransformControlPoint gridSpacingVoxel = np.floor(gridSpacingMm / spacing).astype(int) gridAxesIJK = [] imageData = volumeNode.GetImageData() extent = imageData.GetExtent() for axis in range(3): gridAxesIJK.append( list( range(extent[axis * 2], extent[axis * 2 + 1] + gridSpacingVoxel[axis], gridSpacingVoxel[axis]))) samplingPoints_shape = [ len(gridAxesIJK[0]), len(gridAxesIJK[1]), len(gridAxesIJK[2]), 3 ] # create a grid transform with one vector at the corner of each slice # the transform is in the same space and orientation as the volume node from __main__ import vtk gridImage = vtk.vtkImageData() gridImage.SetOrigin(*volumeNode.GetOrigin()) gridImage.SetDimensions(samplingPoints_shape[:3]) gridImage.SetSpacing(gridSpacingVoxel[0] * spacing[0], gridSpacingVoxel[1] * spacing[1], gridSpacingVoxel[2] * spacing[2]) gridImage.AllocateScalars(vtk.VTK_DOUBLE, 3) transform = slicer.vtkOrientedGridTransform() directionMatrix = vtk.vtkMatrix4x4() volumeNode.GetIJKToRASDirectionMatrix(directionMatrix) transform.SetGridDirectionMatrix(directionMatrix) transform.SetDisplacementGridData(gridImage) # create the grid transform node gridTransform = slicer.vtkMRMLGridTransformNode() gridTransform.SetName( slicer.mrmlScene.GenerateUniqueName(volumeNode.GetName() + ' acquisition transform')) slicer.mrmlScene.AddNode(gridTransform) gridTransform.SetAndObserveTransformToParent(transform) # populate the grid so that each corner of each slice # is mapped from the source corner to the target corner nshape = tuple(reversed(gridImage.GetDimensions())) import vtk.util.numpy_support nshape = nshape + (3, ) displacements = vtk.util.numpy_support.vtk_to_numpy( gridImage.GetPointData().GetScalars()).reshape(nshape) # Get displacements from math import sin, cos ijkToRas = vtk.vtkMatrix4x4() volumeNode.GetIJKToRASMatrix(ijkToRas) spacing = volumeNode.GetSpacing() center_IJK = [(extent[0] + extent[1]) / 2.0, extent[2], (extent[4] + extent[5]) / 2.0] sourcePoints_RAS = numpy.zeros(shape=samplingPoints_shape) targetPoints_RAS = numpy.zeros(shape=samplingPoints_shape) for k in range(samplingPoints_shape[2]): for j in range(samplingPoints_shape[1]): for i in range(samplingPoints_shape[0]): samplingPoint_IJK = [ gridAxesIJK[0][i], gridAxesIJK[1][j], gridAxesIJK[2][k], 1 ] sourcePoint_RAS = np.array( ijkToRas.MultiplyPoint(samplingPoint_IJK)[:3]) radius = probeRadius - (samplingPoint_IJK[1] - center_IJK[1]) * spacing[1] angleRad = (samplingPoint_IJK[0] - center_IJK[0]) * spacing[0] / probeRadius targetPoint_RAS = np.array([ -radius * sin(angleRad), radius * cos(angleRad) - probeRadius, spacing[2] * (samplingPoint_IJK[2] - center_IJK[2]) ]) displacements[k][j][i] = targetPoint_RAS - sourcePoint_RAS return gridTransform
def makeMaskImage(self, polyData): """ Create a screen space (2D) mask image for the given polydata. Need to know the mapping from RAS into polygon space so the painter can use this as a mask - need the bounds in RAS space - need to get an IJKToRAS for just the mask area - directions are the XYToRAS for this slice - origin is the lower left of the polygon bounds - TODO: need to account for the boundary pixels Note: uses the slicer2-based vtkImageFillROI filter """ labelLogic = self.sliceLogic.GetLabelLayer() sliceNode = self.sliceLogic.GetSliceNode() maskIJKToRAS = vtk.vtkMatrix4x4() maskIJKToRAS.DeepCopy(sliceNode.GetXYToRAS()) polyData.GetPoints().Modified() bounds = polyData.GetBounds() xlo = bounds[0] - 1 xhi = bounds[1] ylo = bounds[2] - 1 yhi = bounds[3] originRAS = self.xyToRAS((xlo, ylo)) maskIJKToRAS.SetElement(0, 3, originRAS[0]) maskIJKToRAS.SetElement(1, 3, originRAS[1]) maskIJKToRAS.SetElement(2, 3, originRAS[2]) # # get a good size for the draw buffer # - needs to include the full region of the polygon # - plus a little extra # # round to int and add extra pixel for both sides # -- TODO: figure out why we need to add buffer pixels on each # side for the width in order to end up with a single extra # pixel in the rasterized image map. Probably has to # do with how boundary conditions are handled in the filler w = int(xhi - xlo) + 32 h = int(yhi - ylo) + 32 imageData = vtk.vtkImageData() imageData.SetDimensions(w, h, 1) labelNode = labelLogic.GetVolumeNode() if not labelNode: return labelImage = labelNode.GetImageData() if not labelImage: return if vtk.VTK_MAJOR_VERSION <= 5: imageData.SetScalarType(labelImage.GetScalarType()) imageData.AllocateScalars() else: imageData.AllocateScalars(labelImage.GetScalarType(), 1) # # move the points so the lower left corner of the # bounding box is at 1, 1 (to avoid clipping) # translate = vtk.vtkTransform() translate.Translate(-1. * xlo, -1. * ylo, 0) drawPoints = vtk.vtkPoints() drawPoints.Reset() translate.TransformPoints(polyData.GetPoints(), drawPoints) drawPoints.Modified() fill = slicer.vtkImageFillROI() if vtk.VTK_MAJOR_VERSION <= 5: fill.SetInput(imageData) else: fill.SetInputData(imageData) fill.SetValue(1) fill.SetPoints(drawPoints) fill.Update() mask = vtk.vtkImageData() mask.DeepCopy(fill.GetOutput()) return [maskIJKToRAS, mask]
def computeAverage(self, inputFieldNodes, roi, outputAverageVolume, outputVarianceVolume): referenceVolume = self.createVectorVolumeFromRoi( roi, self.ReferenceVolumeSpacingMm) referenceVolume.SetName('ReferenceVolume') slicer.mrmlScene.AddNode(referenceVolume) fieldNodes = [] fieldImageData = [] for fieldNode in inputFieldNodes: resampledFieldNode = self.resampleVolume(fieldNode, referenceVolume) fieldNodes.append(resampledFieldNode) fieldImageData.append(resampledFieldNode.GetImageData()) ijkToRasMatrix = vtk.vtkMatrix4x4() # Average volume averageImageData = vtk.vtkImageData() averageImageData.DeepCopy(referenceVolume.GetImageData()) outputAverageVolume.SetAndObserveImageData(averageImageData) referenceVolume.GetIJKToRASMatrix(ijkToRasMatrix) outputAverageVolume.SetIJKToRASMatrix(ijkToRasMatrix) # Variance volume varianceImageData = vtk.vtkImageData() varianceImageData.SetExtent(averageImageData.GetExtent()) if vtk.VTK_MAJOR_VERSION <= 5: varianceImageData.SetScalarType(vtk.VTK_DOUBLE) varianceImageData.SetNumberOfScalarComponents(1) varianceImageData.AllocateScalars() else: varianceImageData.AllocateScalars(vtk.VTK_DOUBLE, 1) outputVarianceVolume.SetIJKToRASMatrix(ijkToRasMatrix) outputVarianceVolume.SetAndObserveImageData(varianceImageData) # Compute dims = averageImageData.GetDimensions() # [field, component] voxelValues = numpy.zeros([len(fieldImageData), 3]) for z in xrange(dims[2]): for y in xrange(dims[1]): for x in xrange(dims[0]): fieldIndex = 0 for imageData in fieldImageData: voxelValues[fieldIndex, 0] = imageData.GetScalarComponentAsDouble( x, y, z, 0) voxelValues[fieldIndex, 1] = imageData.GetScalarComponentAsDouble( x, y, z, 1) voxelValues[fieldIndex, 2] = imageData.GetScalarComponentAsDouble( x, y, z, 2) fieldIndex = fieldIndex + 1 meanVoxelValues = numpy.mean(voxelValues, axis=0) averageImageData.SetScalarComponentFromDouble( x, y, z, 0, meanVoxelValues[0]) averageImageData.SetScalarComponentFromDouble( x, y, z, 1, meanVoxelValues[1]) averageImageData.SetScalarComponentFromDouble( x, y, z, 2, meanVoxelValues[2]) # Compute the mean of the magnitude of the error vectors errorValues = voxelValues - meanVoxelValues errorVectorMagnitudes = numpy.sqrt( numpy.sum(errorValues * errorValues, axis=1)) varianceImageData.SetScalarComponentFromDouble( x, y, z, 0, numpy.mean(errorVectorMagnitudes)) averageImageData.Modified() varianceImageData.Modified() # Create display node if they have not created yet if not outputAverageVolume.GetNthDisplayNode(0): outputAverageVolumeDisplayNode = slicer.vtkMRMLVectorVolumeDisplayNode( ) slicer.mrmlScene.AddNode(outputAverageVolumeDisplayNode) outputAverageVolumeDisplayNode.SetAndObserveColorNodeID( "vtkMRMLColorTableNodeRainbow") outputAverageVolume.SetAndObserveNthDisplayNodeID( 0, outputAverageVolumeDisplayNode.GetID()) if not outputVarianceVolume.GetNthDisplayNode(0): outputVarianceVolumeDisplayNode = slicer.vtkMRMLScalarVolumeDisplayNode( ) slicer.mrmlScene.AddNode(outputVarianceVolumeDisplayNode) outputVarianceVolumeDisplayNode.SetAndObserveColorNodeID( "vtkMRMLColorTableNodeRainbow") outputVarianceVolume.SetAndObserveNthDisplayNodeID( 0, outputVarianceVolumeDisplayNode.GetID()) # Clean up temporary nodes for fieldNode in fieldNodes: slicer.mrmlScene.RemoveNode(fieldNode) slicer.mrmlScene.RemoveNode(referenceVolume)
def setupScene(self): logging.info("UltraSound.setupScene") ''' ReferenceToRas transform is used in almost all IGT applications. Reference is the coordinate system of a tool fixed to the patient. Tools are tracked relative to Reference, to compensate for patient motion. ReferenceToRas makes sure that everything is displayed in an anatomical coordinate system, i.e. R, A, and S (Right, Anterior, and Superior) directions in Slicer are correct relative to any images or tracked tools displayed. ReferenceToRas is needed for initialization, so we need to set it up before calling Guidelet.setupScene(). ''' if self.referenceToRas is None or ( self.referenceToRas and slicer.mrmlScene.GetNodeByID( self.referenceToRas.GetID()) is None): self.referenceToRas = slicer.mrmlScene.GetFirstNodeByName( 'ReferenceToRas') if self.referenceToRas is None: self.referenceToRas = slicer.vtkMRMLLinearTransformNode() self.referenceToRas.SetName("ReferenceToRas") m = self.guideletParent.logic.readTransformFromSettings( 'ReferenceToRas', self.guideletParent.configurationName) if m is None: m = self.guideletParent.logic.createMatrixFromString( '1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1') self.referenceToRas.SetMatrixTransformToParent(m) slicer.mrmlScene.AddNode(self.referenceToRas) # live ultrasound liveUltrasoundNodeName = self.guideletParent.parameterNode.GetParameter( 'LiveUltrasoundNodeName') self.liveUltrasoundNode_Reference = slicer.mrmlScene.GetFirstNodeByName( liveUltrasoundNodeName) if not self.liveUltrasoundNode_Reference: imageSpacing = [0.2, 0.2, 0.2] # Create an empty image volume imageData = vtk.vtkImageData() imageData.SetDimensions(self.DEFAULT_IMAGE_SIZE) imageData.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 1) thresholder = vtk.vtkImageThreshold() thresholder.SetInputData(imageData) thresholder.SetInValue(0) thresholder.SetOutValue(0) # Create volume node self.liveUltrasoundNode_Reference = slicer.vtkMRMLScalarVolumeNode( ) self.liveUltrasoundNode_Reference.SetName(liveUltrasoundNodeName) self.liveUltrasoundNode_Reference.SetSpacing(imageSpacing) self.liveUltrasoundNode_Reference.SetImageDataConnection( thresholder.GetOutputPort()) # Add volume to scene slicer.mrmlScene.AddNode(self.liveUltrasoundNode_Reference) displayNode = slicer.vtkMRMLScalarVolumeDisplayNode() slicer.mrmlScene.AddNode(displayNode) colorNode = slicer.mrmlScene.GetFirstNodeByName('Grey') displayNode.SetAndObserveColorNodeID(colorNode.GetID()) self.liveUltrasoundNode_Reference.SetAndObserveDisplayNodeID( displayNode.GetID()) self.plusRemoteNode = slicer.mrmlScene.GetFirstNodeByClass( 'vtkMRMLPlusRemoteNode') if self.plusRemoteNode is None: self.plusRemoteNode = slicer.vtkMRMLPlusRemoteNode() self.plusRemoteNode.SetName("PlusRemoteNode") slicer.mrmlScene.AddNode(self.plusRemoteNode) self.plusRemoteNode.AddObserver( slicer.vtkMRMLPlusRemoteNode.RecordingStartedEvent, self.recordingCommandCompleted) self.plusRemoteNode.AddObserver( slicer.vtkMRMLPlusRemoteNode.RecordingCompletedEvent, self.recordingCommandCompleted) self.plusRemoteNode.SetAndObserveOpenIGTLinkConnectorNode( self.guideletParent.connectorNode) self.setupResliceDriver()
def start( self, preview=False ): ''' ''' SlicerVmtkCommonLib.Helper.Debug( "Starting Vesselness Filtering.." ) # first we need the nodes currentVolumeNode = self.__inputVolumeNodeSelector.currentNode() currentSeedsNode = self.__seedFiducialsNodeSelector.currentNode() if preview: # if previewMode, get the node selector of the preview volume currentOutputVolumeNodeSelector = self.__previewVolumeNodeSelector else: currentOutputVolumeNodeSelector = self.__outputVolumeNodeSelector currentOutputVolumeNode = currentOutputVolumeNodeSelector.currentNode() if not currentVolumeNode: # we need a input volume node return 0 if not currentOutputVolumeNode or currentOutputVolumeNode.GetID() == currentVolumeNode.GetID(): # we need an output volume node newVolumeDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLScalarVolumeDisplayNode" ) newVolumeDisplayNode.SetDefaultColorMap() newVolumeDisplayNode.SetScene( slicer.mrmlScene ) slicer.mrmlScene.AddNode( newVolumeDisplayNode ) newVolumeNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLScalarVolumeNode" ) newVolumeNode.SetScene( slicer.mrmlScene ) newVolumeNode.SetName( slicer.mrmlScene.GetUniqueNameByString( currentOutputVolumeNodeSelector.baseName ) ) newVolumeNode.SetAndObserveDisplayNodeID( newVolumeDisplayNode.GetID() ) slicer.mrmlScene.AddNode( newVolumeNode ) currentOutputVolumeNode = newVolumeNode currentOutputVolumeNodeSelector.setCurrentNode( currentOutputVolumeNode ) if preview and not currentSeedsNode: # we need a seedsNode for preview SlicerVmtkCommonLib.Helper.Info( "A seed point is required to use the preview mode." ) return 0 # we get the fiducial coordinates if currentSeedsNode: currentCoordinatesRAS = [0, 0, 0] # grab the current coordinates currentSeedsNode.GetFiducialCoordinates( currentCoordinatesRAS ) inputImage = currentVolumeNode.GetImageData() # # vesselness parameters # # we need to convert diameter to mm, we use the minimum spacing to multiply the voxel value minimumDiameter = self.__minimumDiameterSpinBox.value * min( currentVolumeNode.GetSpacing() ) maximumDiameter = self.__maximumDiameterSpinBox.value * min( currentVolumeNode.GetSpacing() ) SlicerVmtkCommonLib.Helper.Debug( minimumDiameter ) SlicerVmtkCommonLib.Helper.Debug( maximumDiameter ) alpha = self.__alphaSlider.value beta = self.__betaSlider.value contrastMeasure = self.__contrastSlider.value # # end of vesselness parameters # # this image will later hold the inputImage image = vtk.vtkImageData() # this image will later hold the outputImage outImage = vtk.vtkImageData() # if we are in previewMode, we have to cut the ROI first for speed if preview: # we extract the ROI of currentVolumeNode and save it to currentOutputVolumeNode # we work in RAS space SlicerVmtkCommonLib.Helper.extractROI( currentVolumeNode.GetID(), currentOutputVolumeNode.GetID(), currentCoordinatesRAS, self.__maximumDiameterSpinBox.value ) # get the new cutted imageData image.DeepCopy( currentOutputVolumeNode.GetImageData() ) image.Update() else: # there was no ROI extraction, so just clone the inputImage image.DeepCopy( inputImage ) image.Update() # attach the spacing and origin to get accurate vesselness computation image.SetSpacing( currentVolumeNode.GetSpacing() ) image.SetOrigin( currentVolumeNode.GetOrigin() ) # we now compute the vesselness in RAS space, image has spacing and origin attached, the diameters are converted to mm # we use RAS space to support anisotropic datasets outImage.DeepCopy( self.GetLogic().performFrangiVesselness( image, minimumDiameter, maximumDiameter, 5, alpha, beta, contrastMeasure ) ) outImage.Update() # let's remove spacing and origin attached to outImage outImage.SetSpacing( 1, 1, 1 ) outImage.SetOrigin( 0, 0, 0 ) # we only want to copy the orientation from input to output when we are not in preview mode if not preview: currentOutputVolumeNode.CopyOrientation( currentVolumeNode ) # we set the outImage which has spacing 1,1,1. The ijkToRas matrix of the node will take care of that currentOutputVolumeNode.SetAndObserveImageData( outImage ) # for preview: show the inputVolume as background and the outputVolume as foreground in the slice viewers # note: that's the only way we can have the preview as an overlay of the originalvolume # for not preview: show the outputVolume as background and the inputVolume as foreground in the slice viewers if preview: fgVolumeID = currentOutputVolumeNode.GetID() bgVolumeID = currentVolumeNode.GetID() else: bgVolumeID = currentOutputVolumeNode.GetID() fgVolumeID = currentVolumeNode.GetID() selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceActiveVolumeID( bgVolumeID ) selectionNode.SetReferenceSecondaryVolumeID( fgVolumeID ) slicer.app.applicationLogic().PropagateVolumeSelection() # renew auto window/level for the output currentOutputVolumeNode.GetDisplayNode().AutoWindowLevelOff() currentOutputVolumeNode.GetDisplayNode().AutoWindowLevelOn() # show foreground volume numberOfCompositeNodes = slicer.mrmlScene.GetNumberOfNodesByClass( 'vtkMRMLSliceCompositeNode' ) for n in xrange( numberOfCompositeNodes ): compositeNode = slicer.mrmlScene.GetNthNodeByClass( n, 'vtkMRMLSliceCompositeNode' ) if compositeNode: if preview: # the preview is the foreground volume, so we want to show it fully compositeNode.SetForegroundOpacity( 1.0 ) else: # now the background volume is the vesselness output, we want to show it fully compositeNode.SetForegroundOpacity( 0.0 ) # fit slice to all sliceviewers slicer.app.applicationLogic().FitSliceToAll() # jump all sliceViewers to the fiducial point, if one was used if currentSeedsNode: numberOfSliceNodes = slicer.mrmlScene.GetNumberOfNodesByClass( 'vtkMRMLSliceNode' ) for n in xrange( numberOfSliceNodes ): sliceNode = slicer.mrmlScene.GetNthNodeByClass( n, "vtkMRMLSliceNode" ) if sliceNode: sliceNode.JumpSliceByOffsetting( currentCoordinatesRAS[0], currentCoordinatesRAS[1], currentCoordinatesRAS[2] ) SlicerVmtkCommonLib.Helper.Debug( "End of Vesselness Filtering.." )
def onHelloWorldButtonClicked(self): scene = slicer.mrmlScene inputModel = self.inputSelector.currentNode() bounds = [0, 0, 0, 0, 0, 0] inputModel.GetBounds(bounds) print('Model Name is:') print(inputModel.GetName()) X = bounds[1] - bounds[0] Y = bounds[3] - bounds[2] Z = bounds[5] - bounds[4] mid = (bounds[0] + X / 2, bounds[2] + Y / 2, bounds[4] + Z / 2) X_thick = .1 #TODO resolution input Y_thick = .1 #TODO resolution input Z_thick = .1 #TODO resolution input z_slices = int(math.ceil(Z / Z_thick)) y_slices = int(math.ceil(Y / Y_thick)) x_slices = int(math.ceil(X / X_thick)) x_thick = X / x_slices y_thick = Y / y_slices z_thick = Z / z_slices print('number of slices') print((x_slices, y_slices, z_slices)) print('midpoint') print(mid) #TODO Bounding box calculation imageSize = [x_slices, y_slices, z_slices] imageSpacing = [x_thick, y_thick, z_thick] voxelType = vtk.VTK_UNSIGNED_CHAR imageData = vtk.vtkImageData() imageData.SetDimensions(imageSize) imageData.AllocateScalars(voxelType, 1) thresholder = vtk.vtkImageThreshold() thresholder.SetInputData(imageData) thresholder.SetInValue(1) thresholder.SetOutValue(1) # Create volume node volumeNode = slicer.vtkMRMLScalarVolumeNode() volumeNode.SetSpacing(imageSpacing) volumeNode.SetImageDataConnection(thresholder.GetOutputPort()) # Add volume to scene slicer.mrmlScene.AddNode(volumeNode) displayNode = slicer.vtkMRMLScalarVolumeDisplayNode() slicer.mrmlScene.AddNode(displayNode) colorNode = slicer.util.getNode('Grey') displayNode.SetAndObserveColorNodeID(colorNode.GetID()) volumeNode.SetAndObserveDisplayNodeID(displayNode.GetID()) volumeNode.CreateDefaultStorageNode() #Transform the Volume to Fit Around the Model transform = slicer.vtkMRMLLinearTransformNode() scene.AddNode(transform) volumeNode.SetAndObserveTransformNodeID(transform.GetID()) vTransform = vtk.vtkTransform() vTransform.Translate( (-X / 2 + mid[0], -Y / 2 + mid[1], -Z / 2 + mid[2])) transform.SetAndObserveMatrixTransformToParent(vTransform.GetMatrix()) #Create a segmentation Node segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( volumeNode) #Add the model as a segmentation #sphereSource = vtk.vtkSphereSource() #sphereSource.SetRadius(10) #sphereSource.SetCenter(6,30,28) #sphereSource.Update() #segmentationNode.AddSegmentFromClosedSurfaceRepresentation(sphereSource.GetOutput(), "Test") segmentID = segmentationNode.GetSegmentation().GenerateUniqueSegmentID( "Test") segmentationNode.AddSegmentFromClosedSurfaceRepresentation( inputModel.GetPolyData(), segmentID) #TODO, Unique ID segmentationNode.SetMasterRepresentationToBinaryLabelmap() modelLabelMap = segmentationNode.GetBinaryLabelmapRepresentation( segmentID) #TODO Unique ID segmentationNode.SetMasterRepresentationToBinaryLabelmap() shape = list(modelLabelMap.GetDimensions()) shape.reverse() #why reverse? labelArray = vtk.util.numpy_support.vtk_to_numpy( modelLabelMap.GetPointData().GetScalars()).reshape(shape) for n in range(1, shape[0] - 1): labelArray[n, :, :] = numpy.maximum(labelArray[n, :, :], labelArray[n - 1, :, :]) outputPolyData = vtk.vtkPolyData() slicer.vtkSlicerSegmentationsModuleLogic.GetSegmentClosedSurfaceRepresentation( segmentationNode, segmentID, outputPolyData) # Create model node model = slicer.vtkMRMLModelNode() model.SetScene(scene) model.SetName(scene.GenerateUniqueName("Model_Undercuts_Removed")) model.SetAndObservePolyData(outputPolyData) # Create display node modelDisplay = slicer.vtkMRMLModelDisplayNode() modelDisplay.SetColor(1, 1, 0) # yellow modelDisplay.SetBackfaceCulling(0) modelDisplay.SetScene(scene) scene.AddNode(modelDisplay) model.SetAndObserveDisplayNodeID(modelDisplay.GetID()) # Add to scene scene.AddNode(model)
def start(self, preview=False): ''' ''' SlicerVmtkCommonLib.Helper.Debug("Starting Level Set Segmentation..") # first we need the nodes currentVolumeNode = self.__inputVolumeNodeSelector.currentNode() currentSeedsNode = self.__seedFiducialsNodeSelector.currentNode() currentVesselnessNode = self.__vesselnessVolumeNodeSelector.currentNode( ) currentStoppersNode = self.__stopperFiducialsNodeSelector.currentNode() currentLabelMapNode = self.__outputVolumeNodeSelector.currentNode() currentModelNode = self.__outputModelNodeSelector.currentNode() if not currentVolumeNode: # we need a input volume node return 0 if not currentSeedsNode: # we need a seeds node return 0 if not currentStoppersNode or currentStoppersNode.GetID( ) == currentSeedsNode.GetID(): # we need a current stopper node # self.__stopperFiducialsNodeSelector.addNode() pass if not currentLabelMapNode or currentLabelMapNode.GetID( ) == currentVolumeNode.GetID(): # we need a current labelMap node newLabelMapDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLLabelMapVolumeDisplayNode") newLabelMapDisplayNode.SetScene(slicer.mrmlScene) newLabelMapDisplayNode.SetDefaultColorMap() slicer.mrmlScene.AddNode(newLabelMapDisplayNode) newLabelMapNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLScalarVolumeNode") newLabelMapNode.CopyOrientation(currentVolumeNode) newLabelMapNode.SetScene(slicer.mrmlScene) newLabelMapNode.SetName( slicer.mrmlScene.GetUniqueNameByString( self.__outputVolumeNodeSelector.baseName)) newLabelMapNode.LabelMapOn() newLabelMapNode.SetAndObserveDisplayNodeID( newLabelMapDisplayNode.GetID()) slicer.mrmlScene.AddNode(newLabelMapNode) currentLabelMapNode = newLabelMapNode self.__outputVolumeNodeSelector.setCurrentNode(currentLabelMapNode) if not currentModelNode: # we need a current model node, the display node is created later newModelNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelNode") newModelNode.SetScene(slicer.mrmlScene) newModelNode.SetName( slicer.mrmlScene.GetUniqueNameByString( self.__outputModelNodeSelector.baseName)) slicer.mrmlScene.AddNode(newModelNode) currentModelNode = newModelNode self.__outputModelNodeSelector.setCurrentNode(currentModelNode) # now we need to convert the fiducials to vtkIdLists seeds = SlicerVmtkCommonLib.Helper.convertFiducialHierarchyToVtkIdList( currentSeedsNode, currentVolumeNode) # stoppers = SlicerVmtkCommonLib.Helper.convertFiducialHierarchyToVtkIdList(currentStoppersNode, currentVolumeNode) stoppers = vtk.vtkIdList() # TODO # the input image for the initialization inputImage = vtk.vtkImageData() # check if we have a vesselnessNode - this will be our input for the initialization then if currentVesselnessNode: # yes, there is one inputImage.DeepCopy(currentVesselnessNode.GetImageData()) else: # no, there is none - we use the original image inputImage.DeepCopy(currentVolumeNode.GetImageData()) inputImage.Update() # initialization initImageData = vtk.vtkImageData() # evolution evolImageData = vtk.vtkImageData() # perform the initialization initImageData.DeepCopy(self.GetLogic().performInitialization( inputImage, self.__thresholdSlider.minimumValue, self.__thresholdSlider.maximumValue, seeds, stoppers, 0)) # TODO sidebranch ignore feature initImageData.Update() if not initImageData.GetPointData().GetScalars(): # something went wrong, the image is empty SlicerVmtkCommonLib.Helper.Info( "Segmentation failed - the output was empty..") return -1 # check if it is a preview call if preview: # if this is a preview call, we want to skip the evolution evolImageData.DeepCopy(initImageData) else: # no preview, run the whole thing! we never use the vesselness node here, just the original one evolImageData.DeepCopy(self.GetLogic().performEvolution( currentVolumeNode.GetImageData(), initImageData, self.__iterationSpinBox.value, self.__inflationSlider.value, self.__curvatureSlider.value, self.__attractionSlider.value, 'geodesic')) evolImageData.Update() # create segmentation labelMap labelMap = vtk.vtkImageData() labelMap.DeepCopy(self.GetLogic().buildSimpleLabelMap( evolImageData, 0, 5)) labelMap.Update() currentLabelMapNode.CopyOrientation(currentVolumeNode) # propagate the label map to the node currentLabelMapNode.SetAndObserveImageData(labelMap) currentLabelMapNode.Modified() # deactivate the threshold in the GUI self.resetThresholdOnDisplayNode() # self.onInputVolumeChanged() # show the segmentation results in the GUI selectionNode = slicer.app.applicationLogic().GetSelectionNode() if preview and currentVesselnessNode: # if preview and a vesselnessNode was configured, show it selectionNode.SetReferenceActiveVolumeID( currentVesselnessNode.GetID()) else: # if not preview, show the original volume if currentVesselnessNode: selectionNode.SetReferenceSecondaryVolumeID( currentVesselnessNode.GetID()) selectionNode.SetReferenceActiveVolumeID(currentVolumeNode.GetID()) selectionNode.SetReferenceActiveLabelVolumeID( currentLabelMapNode.GetID()) slicer.app.applicationLogic().PropagateVolumeSelection() # generate 3D model model = vtk.vtkPolyData() # we need the ijkToRas transform for the marching cubes call ijkToRasMatrix = vtk.vtkMatrix4x4() currentLabelMapNode.GetIJKToRASMatrix(ijkToRasMatrix) # call marching cubes model.DeepCopy(self.GetLogic().marchingCubes(evolImageData, ijkToRasMatrix, 0.0)) model.Update() # propagate model to nodes currentModelNode.SetAndObservePolyData(model) currentModelNode.Modified() currentModelDisplayNode = currentModelNode.GetDisplayNode() if not currentModelDisplayNode: # create new displayNode currentModelDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelDisplayNode") slicer.mrmlScene.AddNode(currentModelDisplayNode) # always configure the displayNode to show the model currentModelDisplayNode.SetInputPolyData( currentModelNode.GetPolyData()) currentModelDisplayNode.SetColor(1.0, 0.55, 0.4) # red currentModelDisplayNode.SetBackfaceCulling(0) currentModelDisplayNode.SetSliceIntersectionVisibility(0) currentModelDisplayNode.SetVisibility(1) currentModelDisplayNode.SetOpacity(1.0) currentModelDisplayNode.Modified() # update the reference between model node and it's display node currentModelNode.SetAndObserveDisplayNodeID( currentModelDisplayNode.GetID()) currentModelNode.Modified() # fit slice to all sliceviewers slicer.app.applicationLogic().FitSliceToAll() # jump all sliceViewers to the first fiducial point, if one was used if currentSeedsNode: currentCoordinatesRAS = [0, 0, 0] if isinstance(currentSeedsNode, slicer.vtkMRMLAnnotationHierarchyNode): childrenNodes = vtk.vtkCollection() currentSeedsNode.GetChildrenDisplayableNodes(childrenNodes) # now we have the children, let's get the first one currentFiducial = childrenNodes.GetItemAsObject(0) # grab the current coordinates currentFiducial.GetFiducialCoordinates(currentCoordinatesRAS) elif isinstance(currentSeedsNode, slicer.vtkMRMLAnnotationFiducialNode): # grab the current coordinates currentSeedsNode.GetFiducialCoordinates(currentCoordinatesRAS) numberOfSliceNodes = slicer.mrmlScene.GetNumberOfNodesByClass( 'vtkMRMLSliceNode') for n in xrange(numberOfSliceNodes): sliceNode = slicer.mrmlScene.GetNthNodeByClass( n, "vtkMRMLSliceNode") if sliceNode: sliceNode.JumpSliceByOffsetting(currentCoordinatesRAS[0], currentCoordinatesRAS[1], currentCoordinatesRAS[2]) # center 3D view(s) on the new model if currentCoordinatesRAS: for d in range(slicer.app.layoutManager().threeDViewCount): threeDView = slicer.app.layoutManager().threeDWidget( d).threeDView() # reset the focal point threeDView.resetFocalPoint() # and fly to our seed point interactor = threeDView.interactor() renderer = threeDView.renderWindow().GetRenderers( ).GetItemAsObject(0) interactor.FlyTo(renderer, currentCoordinatesRAS[0], currentCoordinatesRAS[1], currentCoordinatesRAS[2]) SlicerVmtkCommonLib.Helper.Debug("End of Level Set Segmentation..")
def __init__(self,parent=None,width=400,height=400,showWidget=False,scale=False): super(ROIManager,self).__init__() self.width = width self.height = height self.showWidget = showWidget self.scale = scale self.renderer = None self.ROIRadius = 20.0 self.minValueBG=0 self.maxValueBG=0 self.minValueFG=0 self.maxValueFG=0 self.probeWidget = None self.drawOverlay = 0 # utility Qt instances for use in methods self.gray = qt.QColor() self.gray.setRedF(0.5) self.gray.setGreenF(0.5) self.gray.setBlueF(0.5) # a painter to use for various jobs self.painter = qt.QPainter() # make a qwidget display if self.showWidget: self.frame = qt.QFrame(parent) mw = slicer.util.mainWindow() self.frame.setGeometry(mw.x, mw.y, self.width, self.height) self.frameLayout = qt.QVBoxLayout(self.frame) self.label = qt.QLabel() self.frameLayout.addWidget(self.label) self.frame.show() # make an image actor in the slice view self.vtkImage = vtk.vtkImageData() self.mrmlUtils = slicer.qMRMLUtils() self.imageMapper = vtk.vtkImageMapper() self.imageMapper.SetColorLevel(128) self.imageMapper.SetColorWindow(255) if vtk.VTK_MAJOR_VERSION <= 5: self.imageMapper.SetInput(self.vtkImage) else: self.imageMapper.SetInputData(self.vtkImage) self.actor2D = vtk.vtkActor2D() self.actor2D.SetMapper(self.imageMapper) # make a circle actor self.circle = vtk.vtkRegularPolygonSource() self.circle.SetNumberOfSides(50) self.circle.SetRadius(5) self.circle.SetCenter(0,0,0) self.circle.GeneratePolylineOn() self.circle.GeneratePolygonOff() self.circle.Update() self.mapper = vtk.vtkPolyDataMapper2D() self.actor = vtk.vtkActor2D() if vtk.VTK_MAJOR_VERSION <= 5: self.mapper.SetInput(self.circle.GetOutput()) else: self.mapper.SetInputConnection(self.circle.GetOutputPort()) self.actor.SetMapper(self.mapper) property_ = self.actor.GetProperty() property_.SetColor(1,1,0) property_.SetLineWidth(1)
def loadPhilips4DUSAsMultiVolume(self, loadable): """Load the selection as an Ultrasound, store in MultiVolume """ # get the key info from the "fake" dicom file filePath = loadable.files[0] ds = dicom.read_file(filePath, stop_before_pixels=True) columns = ds.Columns rows = ds.Rows slices = ds[(0x3001, 0x1001)].value # private tag! spacing = ( ds.PhysicalDeltaX * 10, ds.PhysicalDeltaY * 10, ds[(0x3001, 0x1003)].value * 10 # private tag! ) frames = int(ds.NumberOfFrames) imageComponents = frames # create the correct size and shape vtkImageData image = vtk.vtkImageData() imageShape = (slices, rows, columns, frames) image.SetDimensions(columns, rows, slices) image.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, imageComponents) from vtk.util.numpy_support import vtk_to_numpy imageArray = vtk_to_numpy( image.GetPointData().GetScalars()).reshape(imageShape) # put the data in a numpy array # -- we need to read the file as raw bytes pixelShape = (frames, slices, rows, columns) pixels = numpy.fromfile(filePath, dtype=numpy.uint8) pixelSize = pixelShape[0] * pixelShape[1] * pixelShape[2] * pixelShape[ 3] headerSize = len(pixels) - pixelSize pixels = pixels[headerSize:] pixels = pixels.reshape(pixelShape) slicer.modules.imageArray = imageArray slicer.modules.pixels = pixels # copy the data from numpy to vtk (need to shuffle frames to components) for frame in range(frames): imageArray[:, :, :, frame] = pixels[frame] # create the multivolume node and display it multiVolumeNode = slicer.vtkMRMLMultiVolumeNode() multiVolumeNode.SetScene(slicer.mrmlScene) multiVolumeDisplayNode = slicer.mrmlScene.CreateNodeByClass( 'vtkMRMLMultiVolumeDisplayNode') multiVolumeDisplayNode.SetReferenceCount( multiVolumeDisplayNode.GetReferenceCount() - 1) multiVolumeDisplayNode.SetScene(slicer.mrmlScene) multiVolumeDisplayNode.SetDefaultColorMap() slicer.mrmlScene.AddNode(multiVolumeDisplayNode) multiVolumeNode.SetAndObserveDisplayNodeID( multiVolumeDisplayNode.GetID()) multiVolumeNode.SetAndObserveImageData(image) multiVolumeNode.SetNumberOfFrames(frames) multiVolumeNode.SetName(loadable.name) slicer.mrmlScene.AddNode(multiVolumeNode) # # automatically select the volume to display # appLogic = slicer.app.applicationLogic() selNode = appLogic.GetSelectionNode() selNode.SetReferenceActiveVolumeID(multiVolumeNode.GetID()) appLogic.PropagateVolumeSelection() return multiVolumeNode
def onImportButtonClicked(self): # check if the output container exists mvNode = self.__mvSelector.currentNode() if mvNode == None: self.__status.text = 'Status: Select output node!' return # Series of frames alpha-ordered, all in the input directory # Assume here that the last mode in the list is for parsing a list of # non-DICOM frames fileNames = [] # file names on disk frameList = [] # frames as MRMLScalarVolumeNode's frameFolder = "" volumeLabels = vtk.vtkDoubleArray() frameLabelsAttr = '' frameFileListAttr = '' dicomTagNameAttr = self.__dicomTag.text dicomTagUnitsAttr = self.__veLabel.text teAttr = self.__te.text trAttr = self.__tr.text faAttr = self.__fa.text # each frame is saved as a separate volume for f in os.listdir(self.__fDialog.directory): if not f.startswith('.'): fileNames.append(f) frameFileListAttr += f + ',' fileNames.sort() frameFileListAttr = frameFileListAttr[:-1] frameFolder = self.__fDialog.directory nFrames = len(fileNames) volumeLabels.SetNumberOfTuples(nFrames) volumeLabels.SetNumberOfComponents(1) volumeLabels.Allocate(nFrames) for i in range(len(fileNames)): frameId = self.__veInitial.value + self.__veStep.value * i volumeLabels.SetComponent(i, 0, frameId) frameLabelsAttr += str(frameId) + ',' frameLabelsAttr = frameLabelsAttr[:-1] # read the first frame to get the extent fullName = frameFolder + '/' + fileNames[0] volumesLogic = slicer.modules.volumes.logic() frame = self.readFrame(fullName) frameImage = frame.GetImageData() frameExtent = frameImage.GetExtent() frameSize = frameExtent[1] * frameExtent[3] * frameExtent[5] nFrames = len(fileNames) mvImage = vtk.vtkImageData() mvImage.SetExtent(frameExtent) mvImage.SetNumberOfScalarComponents(nFrames) mvImage.AllocateScalars() mvImageArray = vtk.util.numpy_support.vtk_to_numpy( mvImage.GetPointData().GetScalars()) mat = vtk.vtkMatrix4x4() frame.GetRASToIJKMatrix(mat) mvNode.SetRASToIJKMatrix(mat) frame.GetIJKToRASMatrix(mat) mvNode.SetIJKToRASMatrix(mat) for frameId in range(0, nFrames): fullName = frameFolder + '/' + fileNames[frameId] print("Processing frame %d: %s" % (frameId, fullName)) frame = self.readFrame(fullName) frameImage = frame.GetImageData() frameImageArray = vtk.util.numpy_support.vtk_to_numpy( frameImage.GetPointData().GetScalars()) mvImageArray.T[frameId] = frameImageArray mvDisplayNode = slicer.mrmlScene.CreateNodeByClass( 'vtkMRMLMultiVolumeDisplayNode') mvDisplayNode.SetScene(slicer.mrmlScene) slicer.mrmlScene.AddNode(mvDisplayNode) mvDisplayNode.SetReferenceCount(mvDisplayNode.GetReferenceCount() - 1) mvDisplayNode.SetDefaultColorMap() mvNode.SetAndObserveDisplayNodeID(mvDisplayNode.GetID()) mvNode.SetAndObserveImageData(mvImage) mvNode.SetNumberOfFrames(nFrames) mvNode.SetLabelArray(volumeLabels) mvNode.SetLabelName(self.__veLabel.text) mvNode.SetAttribute('MultiVolume.FrameLabels', frameLabelsAttr) mvNode.SetAttribute('MultiVolume.NumberOfFrames', str(nFrames)) mvNode.SetAttribute('MultiVolume.FrameIdentifyingDICOMTagName', dicomTagNameAttr) mvNode.SetAttribute('MultiVolume.FrameIdentifyingDICOMTagUnits', dicomTagUnitsAttr) if dicomTagNameAttr == 'TriggerTime' or dicomTagNameAttr == 'AcquisitionTime': if teTag != '': mvNode.SetAttribute('MultiVolume.DICOM.EchoTime', teTag) if trTag != '': mvNode.SetAttribute('MultiVolume.DICOM.RepetitionTime', trTag) if faTag != '': mvNode.SetAttribute('MultiVolume.DICOM.FlipAngle', faTag) mvNode.SetName(str(nFrames) + ' frames MultiVolume') Helper.SetBgFgVolumes(mvNode.GetID(), None)
def load(self, loadable): """Load the selection as a MultiVolume, if multivolume attribute is present """ mvNode = '' try: mvNode = loadable.multivolume except AttributeError: return nFrames = int(mvNode.GetAttribute('MultiVolume.NumberOfFrames')) files = string.split(mvNode.GetAttribute('MultiVolume.FrameFileList'), ',') nFiles = len(files) filesPerFrame = nFiles / nFrames frames = [] mvImage = vtk.vtkImageData() mvImageArray = None scalarVolumePlugin = slicer.modules.dicomPlugins[ 'DICOMScalarVolumePlugin']() # read each frame into scalar volume for frameNumber in range(nFrames): sNode = slicer.vtkMRMLVolumeArchetypeStorageNode() sNode.ResetFileNameList() frameFileList = files[frameNumber * filesPerFrame:(frameNumber + 1) * filesPerFrame] # sv plugin will sort the filenames by geometric order svLoadables = scalarVolumePlugin.examine([frameFileList]) if len(svLoadables) == 0: return for f in svLoadables[0].files: sNode.AddFileName(f) sNode.SetFileName( frameFileList[0]) # only used when num files/frame = 1 sNode.SetSingleFile(0) frame = slicer.vtkMRMLScalarVolumeNode() sNode.ReadData(frame) if frame == None: print('Failed to read a multivolume frame!') return False if frameNumber == 0: frameImage = frame.GetImageData() frameExtent = frameImage.GetExtent() frameSize = frameExtent[1] * frameExtent[3] * frameExtent[5] mvImage.SetExtent(frameExtent) mvImage.SetNumberOfScalarComponents(nFrames) mvImage.AllocateScalars() mvImageArray = vtk.util.numpy_support.vtk_to_numpy( mvImage.GetPointData().GetScalars()) mvNode.SetScene(slicer.mrmlScene) mat = vtk.vtkMatrix4x4() frame.GetRASToIJKMatrix(mat) mvNode.SetRASToIJKMatrix(mat) frame.GetIJKToRASMatrix(mat) mvNode.SetIJKToRASMatrix(mat) frameImage = frame.GetImageData() frameImageArray = vtk.util.numpy_support.vtk_to_numpy( frameImage.GetPointData().GetScalars()) mvImageArray.T[frameNumber] = frameImageArray mvDisplayNode = slicer.mrmlScene.CreateNodeByClass( 'vtkMRMLMultiVolumeDisplayNode') mvDisplayNode.SetReferenceCount(mvDisplayNode.GetReferenceCount() - 1) mvDisplayNode.SetScene(slicer.mrmlScene) mvDisplayNode.SetDefaultColorMap() slicer.mrmlScene.AddNode(mvDisplayNode) mvNode.SetAndObserveDisplayNodeID(mvDisplayNode.GetID()) mvNode.SetAndObserveImageData(mvImage) mvNode.SetNumberOfFrames(nFrames) slicer.mrmlScene.AddNode(mvNode) return True
def applyImageMask(self, maskIJKToRAS, mask, bounds): """ apply a pre-rasterized image to the current label layer - maskIJKToRAS tells the mapping from image pixels to RAS - mask is a vtkImageData - bounds are the xy extents of the mask (zlo and zhi ignored) """ backgroundLogic = self.sliceLogic.GetBackgroundLayer() backgroundNode = backgroundLogic.GetVolumeNode() if not backgroundNode: return backgroundImage = backgroundNode.GetImageData() if not backgroundImage: return labelLogic = self.sliceLogic.GetLabelLayer() labelNode = labelLogic.GetVolumeNode() if not labelNode: return labelImage = labelNode.GetImageData() if not labelImage: return # # at this point, the mask vtkImageData contains a rasterized # version of the polygon and now needs to be added to the label # image # # 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() # # get the mask bounding box in ijk coordinates # - get the xy bounds # - transform to ijk # - clamp the bounds to the dimensions of the label image # xlo, xhi, ylo, yhi, zlo, zhi = bounds labelLogic = self.sliceLogic.GetLabelLayer() xyToIJK = labelLogic.GetXYToIJKTransform() tlIJK = xyToIJK.TransformDoublePoint((xlo, yhi, 0)) trIJK = xyToIJK.TransformDoublePoint((xhi, yhi, 0)) blIJK = xyToIJK.TransformDoublePoint((xlo, ylo, 0)) brIJK = xyToIJK.TransformDoublePoint((xhi, ylo, 0)) # do the clamping of the four corners dims = labelImage.GetDimensions() tl = [ 0, ] * 3 tr = [ 0, ] * 3 bl = [ 0, ] * 3 br = [ 0, ] * 3 corners = ((tlIJK, tl), (trIJK, tr), (blIJK, bl), (brIJK, br)) for corner, clampedCorner in corners: for d in xrange(3): clamped = int(round(corner[d])) if clamped < 0: clamped = 0 if clamped >= dims[d]: clamped = dims[d] - 1 clampedCorner[d] = clamped # # get the ijk to ras matrices including transforms # (use the maskToRAS calculated above) # labelLogic = self.sliceLogic.GetLabelLayer() labelNode = labelLogic.GetVolumeNode() backgroundLogic = self.sliceLogic.GetLabelLayer() backgroundNode = backgroundLogic.GetVolumeNode() backgroundIJKToRAS = self.getIJKToRASMatrix(backgroundNode) labelIJKToRAS = self.getIJKToRASMatrix(labelNode) # # create an exract image for undo if it doesn't exist yet. # if not self.extractImage: self.extractImage = vtk.vtkImageData() parameterNode = self.editUtil.getParameterNode() paintLabel = int(parameterNode.GetParameter("label")) paintOver = int(parameterNode.GetParameter("LabelEffect,paintOver")) paintThreshold = int( parameterNode.GetParameter("LabelEffect,paintThreshold")) paintThresholdMin = float( parameterNode.GetParameter("LabelEffect,paintThresholdMin")) paintThresholdMax = float( parameterNode.GetParameter("LabelEffect,paintThresholdMax")) # # set up the painter class and let 'r rip! # self.painter.SetBackgroundImage(backgroundImage) self.painter.SetBackgroundIJKToWorld(backgroundIJKToRAS) self.painter.SetWorkingImage(labelImage) self.painter.SetWorkingIJKToWorld(labelIJKToRAS) self.painter.SetMaskImage(mask) self.painter.SetExtractImage(self.extractImage) self.painter.SetReplaceImage(None) self.painter.SetMaskIJKToWorld(maskIJKToRAS) self.painter.SetTopLeft(tl) self.painter.SetTopRight(tr) self.painter.SetBottomLeft(bl) self.painter.SetBottomRight(br) self.painter.SetPaintLabel(paintLabel) self.painter.SetPaintOver(paintOver) self.painter.SetThresholdPaint(paintThreshold) self.painter.SetThresholdPaintRange(paintThresholdMin, paintThresholdMax) self.painter.Paint() self.editUtil.markVolumeNodeAsModified(labelNode)
def load(self, loadable): """Load the selection as a scalar volume, but rescale the values """ scalarVolumePlugin = slicer.modules.dicomPlugins[ 'DICOMScalarVolumePlugin']() vNode = scalarVolumePlugin.loadFilesWithArchetype( loadable.files, loadable.name) if vNode: intercept = float( slicer.dicomDatabase.fileValue(loadable.files[0], self.tags['ScaleIntercept'])) slope = float( slicer.dicomDatabase.fileValue(loadable.files[0], self.tags['ScaleSlope'])) privateIntercept = float( slicer.dicomDatabase.fileValue( loadable.files[0], self.tags['PrivateScaleIntercept'])) privateSlope = float( slicer.dicomDatabase.fileValue(loadable.files[0], self.tags['PrivateScaleSlope'])) print('Slope: ' + str(slope) + ' private: ' + str(privateSlope) + ' Intercept: ' + str(intercept) + ' private: ' + str(privateIntercept)) # vtkImageShiftScale first shifts, then scales # First, revert the scaling applied on ITK-level read reverseShift = vtk.vtkImageShiftScale() reverseShift.SetShift(-1. * intercept) reverseShift.SetScale(1) reverseShift.SetInput(vNode.GetImageData()) reverseShift.SetOutputScalarTypeToFloat() reverseScale = vtk.vtkImageShiftScale() reverseScale.SetShift(0) reverseScale.SetScale(1. / slope) reverseScale.SetInput(reverseShift.GetOutput()) reverseScale.SetOutputScalarTypeToFloat() # Second, apply scaling using the private tags information rescale = vtk.vtkImageShiftScale() rescale.SetShift(-1. * privateIntercept) rescale.SetScale(1. / privateSlope) rescale.SetOutputScalarTypeToFloat() rescale.SetInput(reverseScale.GetOutput()) rescale.Update() imageData = vtk.vtkImageData() imageData.DeepCopy(rescale.GetOutput()) # Note: the assumption here is that intercept/slope are identical for all # slices in the series. According to Tom Chenevert, this is typically the # case: "The exception is when there are multiple image types in a series, # such as real, imaginary, magnitude and phase images all stored in the # series. But this is not common." vNode.SetAndObserveImageData(imageData) return vNode
def clipVolumeWithModel(self, inputVolume, clippingModel, clipOutsideSurface, fillOutsideValue, clipInsideSurface, fillInsideValue, outputVolume): """ Fill voxels of the input volume inside/outside the clipping model with the provided fill value """ # Determine the transform between the box and the image IJK coordinate systems rasToModel = vtk.vtkMatrix4x4() if clippingModel.GetTransformNodeID() != None: modelTransformNode = slicer.mrmlScene.GetNodeByID( clippingModel.GetTransformNodeID()) boxToRas = vtk.vtkMatrix4x4() modelTransformNode.GetMatrixTransformToWorld(boxToRas) rasToModel.DeepCopy(boxToRas) rasToModel.Invert() ijkToRas = vtk.vtkMatrix4x4() inputVolume.GetIJKToRASMatrix(ijkToRas) ijkToModel = vtk.vtkMatrix4x4() vtk.vtkMatrix4x4.Multiply4x4(rasToModel, ijkToRas, ijkToModel) modelToIjkTransform = vtk.vtkTransform() modelToIjkTransform.SetMatrix(ijkToModel) modelToIjkTransform.Inverse() transformModelToIjk = vtk.vtkTransformPolyDataFilter() transformModelToIjk.SetTransform(modelToIjkTransform) transformModelToIjk.SetInputConnection( clippingModel.GetPolyDataConnection()) # Use the stencil to fill the volume # Convert model to stencil polyToStencil = vtk.vtkPolyDataToImageStencil() polyToStencil.SetInputConnection(transformModelToIjk.GetOutputPort()) polyToStencil.SetOutputSpacing(inputVolume.GetImageData().GetSpacing()) polyToStencil.SetOutputOrigin(inputVolume.GetImageData().GetOrigin()) polyToStencil.SetOutputWholeExtent( inputVolume.GetImageData().GetExtent()) # Apply the stencil to the volume stencilToImage = vtk.vtkImageStencil() stencilToImage.SetInputConnection(inputVolume.GetImageDataConnection()) stencilToImage.SetStencilConnection(polyToStencil.GetOutputPort()) # Create a copy of the input volume to work on outputImageData = vtk.vtkImageData() outputImageData.DeepCopy(inputVolume.GetImageData()) outputVolume.SetAndObserveImageData(outputImageData) outputVolume.SetIJKToRASMatrix(ijkToRas) # Update volume with the stencil operation result depending on user choices if clipOutsideSurface: stencilToImage.ReverseStencilOff() stencilToImage.SetBackgroundValue(fillOutsideValue) stencilToImage.Update() outputImageData.DeepCopy(stencilToImage.GetOutput()) outputVolume.SetAndObserveImageData(outputImageData) outputVolume.SetIJKToRASMatrix(ijkToRas) if clipInsideSurface: stencilToImage.SetInputConnection( outputVolume.GetImageDataConnection()) stencilToImage.ReverseStencilOn() stencilToImage.SetBackgroundValue(fillInsideValue) stencilToImage.Update() outputImageData.DeepCopy(stencilToImage.GetOutput()) outputVolume.SetAndObserveImageData(outputImageData) outputVolume.SetIJKToRASMatrix(ijkToRas) # Add a default display node to output volume node if it does not exist yet if not outputVolume.GetDisplayNode: displayNode = slicer.vtkMRMLScalarVolumeDisplayNode() displayNode.SetAndObserveColorNodeID("vtkMRMLColorTableNodeGrey") slicer.mrmlScene.AddNode(displayNode) outputVolume.SetAndObserveDisplayNodeID(displayNode.GetID()) return True
def extractROI(originalVolumeID, newVolumeID, rasCoordinates, diameter): ''' ''' originalVolume = slicer.mrmlScene.GetNodeByID(originalVolumeID) newVolume = slicer.mrmlScene.GetNodeByID(newVolumeID) # code below converted from cropVolume module by A. Fedorov # optimized after that :) inputRASToIJK = vtk.vtkMatrix4x4() inputIJKToRAS = vtk.vtkMatrix4x4() outputIJKToRAS = vtk.vtkMatrix4x4() outputRASToIJK = vtk.vtkMatrix4x4() volumeXform = vtk.vtkMatrix4x4() T = vtk.vtkMatrix4x4() originalVolume.GetRASToIJKMatrix(inputRASToIJK) originalVolume.GetIJKToRASMatrix(inputIJKToRAS) outputIJKToRAS.Identity() outputRASToIJK.Identity() volumeXform.Identity() T.Identity() # if the originalVolume is under a transform volumeTransformNode = originalVolume.GetParentTransformNode() if volumeTransformNode: volumeTransformNode.GetMatrixTransformToWorld(volumeXform) volumeXform.Invert() maxSpacing = max(originalVolume.GetSpacing()) # build our box rX = diameter * 4 * maxSpacing rY = diameter * 4 * maxSpacing rZ = diameter * 4 * maxSpacing cX = rasCoordinates[0] cY = rasCoordinates[1] cZ = rasCoordinates[2] inputSpacingX = originalVolume.GetSpacing()[0] inputSpacingY = originalVolume.GetSpacing()[1] inputSpacingZ = originalVolume.GetSpacing()[2] outputExtentX = int(2.0 * rX / inputSpacingX) outputExtentY = int(2.0 * rY / inputSpacingY) outputExtentZ = int(2.0 * rZ / inputSpacingZ) # configure spacing outputIJKToRAS.SetElement(0, 0, inputSpacingX) outputIJKToRAS.SetElement(1, 1, inputSpacingY) outputIJKToRAS.SetElement(2, 2, inputSpacingZ) # configure origin outputIJKToRAS.SetElement(0, 3, (cX - rX + inputSpacingX * 0.5)) outputIJKToRAS.SetElement(1, 3, (cY - rY + inputSpacingY * 0.5)) outputIJKToRAS.SetElement(2, 3, (cZ - rZ + inputSpacingZ * 0.5)) outputRASToIJK.DeepCopy(outputIJKToRAS) outputRASToIJK.Invert() T.DeepCopy(outputIJKToRAS) T.Multiply4x4(volumeXform, T, T) T.Multiply4x4(inputRASToIJK, T, T) resliceT = vtk.vtkTransform() resliceT.SetMatrix(T) reslicer = vtk.vtkImageReslice() reslicer.SetInterpolationModeToLinear() reslicer.SetInput(originalVolume.GetImageData()) reslicer.SetOutputExtent(0, int(outputExtentX), 0, int(outputExtentY), 0, int(outputExtentZ)) reslicer.SetOutputOrigin(0, 0, 0) reslicer.SetOutputSpacing(1, 1, 1) #reslicer.SetOutputOrigin(image.GetOrigin()) #reslicer.SetOutputSpacing(image.GetSpacing()) reslicer.SetResliceTransform(resliceT) reslicer.UpdateWholeExtent() changer = vtk.vtkImageChangeInformation() changer.SetInput(reslicer.GetOutput()) changer.SetOutputOrigin(0, 0, 0) changer.SetOutputSpacing(1, 1, 1) #changer.SetOutputOrigin(image.GetOrigin()) # changer.SetOutputSpacing(image.GetSpacing()) changer.Update() outImageData = vtk.vtkImageData() outImageData.DeepCopy(changer.GetOutput()) outImageData.Update() newVolume.SetAndObserveImageData(outImageData) newVolume.SetIJKToRASMatrix(outputIJKToRAS) newVolume.SetRASToIJKMatrix(outputRASToIJK) newVolume.Modified() newVolume.SetModifiedSinceRead(1)
def removeIslandsMorphologyDecruft(self,image,foregroundLabel,backgroundLabel,iterations=1): # # make binary mask foregroundLabel->1, backgroundLabel->0 # binThresh = vtk.vtkImageThreshold() if vtk.VTK_MAJOR_VERSION <= 5: binThresh.SetInput( image ) else: binThresh.SetInputData( image ) binThresh.ThresholdBetween(foregroundLabel,foregroundLabel) binThresh.SetInValue( 1 ) binThresh.SetOutValue( 0 ) binThresh.Update() # # first, erode iterations number of times # eroder = slicer.vtkImageErode() eroderImage = vtk.vtkImageData() eroderImage.DeepCopy(binThresh.GetOutput()) if vtk.VTK_MAJOR_VERSION <= 5: eroder.SetInput(eroderImage) else: eroder.SetInputData(eroderImage) for iteration in range(iterations): eroder.SetForeground( 1 ) eroder.SetBackground( 0 ) eroder.SetNeighborTo8() eroder.Update() eroderImage.DeepCopy(eroder.GetOutput()) # # now save only islands bigger than a specified size # # note that island operation happens in unsigned long space # but the slicer editor works in Short castIn = vtk.vtkImageCast() if vtk.VTK_MAJOR_VERSION <= 5: castIn.SetInput( eroderImage ) else: castIn.SetInputConnection( eroder.GetInputConnection(0,0) ) castIn.SetOutputScalarTypeToUnsignedLong() # now identify the islands in the inverted volume # and find the pixel that corresponds to the background islandMath = vtkITK.vtkITKIslandMath() if vtk.VTK_MAJOR_VERSION <= 5: islandMath.SetInput( castIn.GetOutput() ) else: islandMath.SetInputConnection( castIn.GetOutputPort() ) islandMath.SetFullyConnected( self.fullyConnected ) islandMath.SetMinimumSize( self.minimumSize ) # note that island operation happens in unsigned long space # but the slicer editor works in Short castOut = vtk.vtkImageCast() if vtk.VTK_MAJOR_VERSION <= 5: castOut.SetInput( islandMath.GetOutput() ) else: castOut.SetInputConnection( islandMath.GetOutputPort() ) castOut.SetOutputScalarTypeToShort() castOut.Update() islandCount = islandMath.GetNumberOfIslands() islandOrigCount = islandMath.GetOriginalNumberOfIslands() ignoredIslands = islandOrigCount - islandCount print( "%d islands created (%d ignored)" % (islandCount, ignoredIslands) ) # # now map everything back to 0 and 1 # thresh = vtk.vtkImageThreshold() if vtk.VTK_MAJOR_VERSION <= 5: thresh.SetInput( castOut.GetOutput() ) else: thresh.SetInputConnection( castOut.GetOutputPort() ) thresh.ThresholdByUpper(1) thresh.SetInValue( 1 ) thresh.SetOutValue( 0 ) thresh.Update() # # now, dilate back (erode background) iterations_plus_one number of times # dilater = slicer.vtkImageErode() dilaterImage = vtk.vtkImageData() dilaterImage.DeepCopy(thresh.GetOutput()) if vtk.VTK_MAJOR_VERSION <= 5: dilater.SetInput(dilaterImage) else: dilater.SetInputData(dilaterImage) for iteration in range(1+iterations): dilater.SetForeground( 0 ) dilater.SetBackground( 1 ) dilater.SetNeighborTo8() dilater.Update() dilaterImage.DeepCopy(dilater.GetOutput()) # # only keep pixels in both original and dilated result # logic = vtk.vtkImageLogic() if vtk.VTK_MAJOR_VERSION <= 5: logic.SetInput1(dilaterImage) logic.SetInput2(binThresh.GetOutput()) else: logic.SetInputConnection(0, dilater.GetInputConnection(0,0)) logic.SetInputConnection(1, binThresh.GetOutputPort()) #if foregroundLabel == 0: # logic.SetOperationToNand() #else: logic.SetOperationToAnd() logic.SetOutputTrueValue(1) logic.Update() # # convert from binary mask to 1->foregroundLabel, 0->backgroundLabel # unbinThresh = vtk.vtkImageThreshold() if vtk.VTK_MAJOR_VERSION <= 5: unbinThresh.SetInput( logic.GetOutput() ) else: unbinThresh.SetInputConnection( logic.GetOutputPort() ) unbinThresh.ThresholdBetween( 1,1 ) unbinThresh.SetInValue( foregroundLabel ) unbinThresh.SetOutValue( backgroundLabel ) unbinThresh.Update() image.DeepCopy(unbinThresh.GetOutput())
def previewOn(self, xy=(100,100)): if not self.editUtil.getBackgroundImage() or not self.editUtil.getLabelImage(): return # # get the visible section of the background (pre-window/level) # to use as input to the shader code # sliceLogic = self.sliceWidget.sliceLogic() backgroundLogic = sliceLogic.GetBackgroundLayer() backgroundLogic.GetReslice().Update() backgroundImage = backgroundLogic.GetReslice().GetOutputDataObject(0) backgroundDimensions = backgroundImage.GetDimensions() self.backgroundTextureImage.SetImageData(backgroundImage) self.backgroundTextureImage.Activate(0) labelLogic = sliceLogic.GetLabelLayer() labelLogic.GetReslice().Update() labelImage = labelLogic.GetReslice().GetOutputDataObject(0) labelDimensions = labelImage.GetDimensions() self.labelTextureImage.SetImageData(labelImage) self.labelTextureImage.Activate(1) # make a result image to match dimensions and type resultImage = vtk.vtkImageData() resultImage.SetDimensions(backgroundDimensions) resultImage.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 4) self.shaderComputation.SetResultImageData(resultImage) self.shaderComputation.AcquireResultRenderbuffer() self.resultImageTexture.SetImageData(resultImage) self.resultImageTexture.Activate(2) # make another result image for iteration iterationImage = vtk.vtkImageData() iterationImage.SetDimensions(backgroundDimensions) iterationImage.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 4) self.iterationImageTexture.SetImageData(iterationImage) self.iterationImageTexture.Activate(3) fragmentShaderSource = """ #version 120 varying vec3 interpolatedTextureCoordinate; uniform sampler3D textureUnit0; // background uniform sampler3D textureUnit1; // label uniform sampler3D %(iterationTextureUnit)s; // where to get previous iteration image void main() { vec3 referenceTextureCoordinate = vec3(%(referenceX)f, %(referenceY)f, .5); vec3 samplePoint = interpolatedTextureCoordinate; // background samples vec4 referenceSample = %(sampleScale)f * texture3D(textureUnit0, referenceTextureCoordinate); vec4 volumeSample = %(sampleScale)f * texture3D(textureUnit0, interpolatedTextureCoordinate); // previous result sample vec4 previousSample = %(sampleScale)f * texture3D(%(iterationTextureUnit)s, interpolatedTextureCoordinate); gl_FragColor = vec4(0.); float brushDistance = distance(vec2(0.,0.), vec2( %(radiusX)f, %(radiusY)f)); float pixelDistance = distance(referenceTextureCoordinate, interpolatedTextureCoordinate); // if the current pixel is in the reference point, always paint it if (pixelDistance < brushDistance) { gl_FragColor = vec4(1., 1., 0., .5); } // if the current pixel is in the overall radius // and the intensity matches // and a neighbor is non-zero then set it if (pixelDistance < %(radius)f) { if (abs(referenceSample.r - volumeSample.r) < %(similarityThreshold)f) { vec3 neighbor; neighbor = interpolatedTextureCoordinate + vec3(-brushDistance, 0., 0.); if (texture3D(%(iterationTextureUnit)s, neighbor).r > 0.) { gl_FragColor = vec4(1., 1., 0., .5); } neighbor = interpolatedTextureCoordinate + vec3( brushDistance, 0., 0.); if (texture3D(%(iterationTextureUnit)s, neighbor).r > 0.) { gl_FragColor = vec4(1., 1., 0., .5); } neighbor = interpolatedTextureCoordinate + vec3( 0, -brushDistance, 0.); if (texture3D(%(iterationTextureUnit)s, neighbor).r > 0.) { gl_FragColor = vec4(1., 1., 0., .5); } neighbor = interpolatedTextureCoordinate + vec3( 0, brushDistance, 0.); if (texture3D(%(iterationTextureUnit)s, neighbor).r > 0.) { gl_FragColor = vec4(1., 1., 0., .5); } } } } """ % { 'sampleScale' : 500., 'similarityThreshold' : 0.1, 'referenceX' : xy[0] / float(backgroundDimensions[0]), 'referenceY' : xy[1] / float(backgroundDimensions[1]), 'radiusX' : 1. / backgroundDimensions[0], 'radiusY' : 1. / backgroundDimensions[1], 'radius' : 0.5, 'iterationTextureUnit' : "%(iterationTextureUnit)s", } for iteration in range(29): if iteration % 2: self.iterationImageTexture.AttachAsDrawTarget() iterationTextureUnit = "textureUnit2" else: self.resultImageTexture.AttachAsDrawTarget() iterationTextureUnit = "textureUnit3" self.shaderComputation.SetFragmentShaderSource(fragmentShaderSource % { 'iterationTextureUnit' : iterationTextureUnit }) self.shaderComputation.Compute() self.shaderComputation.AcquireResultRenderbuffer() self.shaderComputation.SetFragmentShaderSource(fragmentShaderSource % { 'iterationTextureUnit' : "textureUnit3" }) self.shaderComputation.Compute() self.shaderComputation.ReadResult() self.shaderComputation.ReleaseResultRenderbuffer() self.cursorMapper.SetInputDataObject(resultImage) self.cursorActor.VisibilityOn() self.sliceView.forceRender()
def onImportButtonClicked(self): # check if the output container exists mvNode = self.__mvSelector.currentNode() if mvNode == None: self.__status.text = 'Status: Select output node!' return # Series of frames alpha-ordered, all in the input directory # Assume here that the last mode in the list is for parsing a list of # non-DICOM frames fileNames = [] # file names on disk frameList = [] # frames as MRMLScalarVolumeNode's frameFolder = "" volumeLabels = vtk.vtkDoubleArray() frameLabelsAttr = '' frameFileListAttr = '' dicomTagNameAttr = self.__dicomTag.text dicomTagUnitsAttr = self.__veLabel.text teAttr = self.__te.text trAttr = self.__tr.text faAttr = self.__fa.text # each frame is saved as a separate volume # first filter valid file names and sort alphabetically frames = [] frame0 = None inputDir = self.__fDialog.directory for f in os.listdir(inputDir): if not f.startswith('.'): fileName = inputDir + '/' + f fileNames.append(fileName) self.humanSort(fileNames) # check for nifti file that may be 4D as special case niftiFiles = [] for fileName in fileNames: if fileName.lower().endswith( '.nii.gz') or fileName.lower().endswith('.nii'): niftiFiles.append(fileName) if len(niftiFiles) == 1: self.read4DNIfTI(mvNode, niftiFiles[0]) return # not 4D nifti, so keep trying for fileName in fileNames: (s, f) = self.readFrame(fileName) if s: if not frame0: frame0 = f frame0Image = frame0.GetImageData() frame0Extent = frame0Image.GetExtent() else: frameImage = f.GetImageData() frameExtent = frameImage.GetExtent() if frameExtent[1] != frame0Extent[1] or frameExtent[ 3] != frame0Extent[3] or frameExtent[ 5] != frame0Extent[5]: continue frames.append(f) nFrames = len(frames) print('Successfully read ' + str(nFrames) + ' frames') if nFrames == 1: print('Single frame dataset - not reading as multivolume!') return # convert seconds data to milliseconds, which is expected by pkModeling.cxx line 81 if dicomTagUnitsAttr == 's': frameIdMultiplier = 1000.0 dicomTagUnitsAttr = 'ms' else: frameIdMultiplier = 1.0 volumeLabels.SetNumberOfComponents(1) volumeLabels.SetNumberOfTuples(nFrames) for i in range(nFrames): frameId = frameIdMultiplier * (self.__veInitial.value + self.__veStep.value * i) volumeLabels.SetComponent(i, 0, frameId) frameLabelsAttr += str(frameId) + ',' frameLabelsAttr = frameLabelsAttr[:-1] # allocate multivolume mvImage = vtk.vtkImageData() mvImage.SetExtent(frame0Extent) mvImage.AllocateScalars(frame0.GetImageData().GetScalarType(), nFrames) extent = frame0.GetImageData().GetExtent() numPixels = float(extent[1] + 1) * (extent[3] + 1) * (extent[5] + 1) * nFrames scalarType = frame0.GetImageData().GetScalarType() print('Will now try to allocate memory for ' + str(numPixels) + ' pixels of VTK scalar type ' + str(scalarType)) print('Memory allocated successfully') mvImageArray = vtk.util.numpy_support.vtk_to_numpy( mvImage.GetPointData().GetScalars()) mat = vtk.vtkMatrix4x4() frame0.GetRASToIJKMatrix(mat) mvNode.SetRASToIJKMatrix(mat) frame0.GetIJKToRASMatrix(mat) mvNode.SetIJKToRASMatrix(mat) for frameId in range(nFrames): # TODO: check consistent size and orientation! frame = frames[frameId] frameImage = frame.GetImageData() frameImageArray = vtk.util.numpy_support.vtk_to_numpy( frameImage.GetPointData().GetScalars()) mvImageArray.T[frameId] = frameImageArray mvDisplayNode = slicer.mrmlScene.CreateNodeByClass( 'vtkMRMLMultiVolumeDisplayNode') mvDisplayNode.SetScene(slicer.mrmlScene) slicer.mrmlScene.AddNode(mvDisplayNode) mvDisplayNode.SetReferenceCount(mvDisplayNode.GetReferenceCount() - 1) mvDisplayNode.SetDefaultColorMap() mvNode.SetAndObserveDisplayNodeID(mvDisplayNode.GetID()) mvNode.SetAndObserveImageData(mvImage) mvNode.SetNumberOfFrames(nFrames) mvNode.SetLabelArray(volumeLabels) mvNode.SetLabelName(self.__veLabel.text) mvNode.SetAttribute('MultiVolume.FrameLabels', frameLabelsAttr) mvNode.SetAttribute('MultiVolume.NumberOfFrames', str(nFrames)) mvNode.SetAttribute('MultiVolume.FrameIdentifyingDICOMTagName', dicomTagNameAttr) mvNode.SetAttribute('MultiVolume.FrameIdentifyingDICOMTagUnits', dicomTagUnitsAttr) if dicomTagNameAttr == 'TriggerTime' or dicomTagNameAttr == 'AcquisitionTime': if teAttr != '': mvNode.SetAttribute('MultiVolume.DICOM.EchoTime', teAttr) if trAttr != '': mvNode.SetAttribute('MultiVolume.DICOM.RepetitionTime', trAttr) if faAttr != '': mvNode.SetAttribute('MultiVolume.DICOM.FlipAngle', faAttr) mvNode.SetName(str(nFrames) + ' frames MultiVolume') Helper.SetBgFgVolumes(mvNode.GetID(), None)
def importFunction(self): # check if the output container exists mvNode = self.outputSelector.currentNode() if mvNode == None: self.__status.text = 'Status: Select output node!' return fileNames = [] # file names on disk frameList = [] # frames as MRMLScalarVolumeNode's frameFolder = "" volumeLabels = vtk.vtkDoubleArray() frameLabelsAttr = '' frameFileListAttr = '' dicomTagNameAttr = self.__dicomTag.text dicomTagUnitsAttr = self.__veLabel.text teAttr = self.__te.text trAttr = self.__tr.text faAttr = self.__fa.text # each frame is saved as a separate volume # first filter valid file names and sort alphabetically frames = [] frame0 = None inputDir = self.__fDialog.directory for f in os.listdir(inputDir): if not f.startswith('.'): fileName = inputDir + '/' + f fileNames.append(fileName) self.humanSort(fileNames) n = 0 nFrames = 0 for fileName in fileNames: #f: información de cada scalar volume de cada corte (s, f) = self.readFrame(fileName) if s: if not frame0: ## print("valor de f: "+ str(f)); frame0 = f ## print("frame0: "+str(frame0)); frame0Image = frame0.GetImageData() frame0Extent = frame0Image.GetExtent() ## print("frame0Extent: " + str(frame0Extent)); else: ## print("valor de f1: "+ str(f)) frameImage = f.GetImageData() ## print("frameImage: "+str(frameImage)) frameExtent = frameImage.GetExtent() ## print("frameExtent: " + str(frameExtent)); if frameExtent[1] != frame0Extent[1] or frameExtent[ 3] != frame0Extent[3] or frameExtent[ 5] != frame0Extent[5]: continue ## n=n+1 ## print("for: "+str(n)) #frames.append(f) nFrames += 1 #nFrames = len(frames) ## print("nFrames: "+str(nFrames)) print('Successfully read ' + str(nFrames) + ' frames') if nFrames == 1: print('Single frame dataset - not reading as multivolume!') return # convert seconds data to milliseconds, which is expected by pkModeling.cxx line 81 if dicomTagUnitsAttr == 's': frameIdMultiplier = 1000.0 dicomTagUnitsAttr = 'ms' else: frameIdMultiplier = 1.0 ## print("volumeLabelsAntes: "+ str(volumeLabels)) volumeLabels.SetNumberOfTuples(nFrames) ## print("volumeLabelsIntermedio: "+ str(volumeLabels)) volumeLabels.SetNumberOfComponents(1) ## print("volumeLabelsDespues: "+ str(volumeLabels)) volumeLabels.Allocate(nFrames) ## print("volumeLabelsTotal: "+ str(volumeLabels)) ### Después de los 3 pasos el único cambio es size, en vez de 0 pasa a ser nFrames for i in range(nFrames): frameId = frameIdMultiplier * (self.__veInitial.value + self.__veStep.value * i) ## print("frameId: "+str(frameId)) ## volumeLabels.SetComponent(i, 0, frameId) ##no hay necesidad #### print("volumeLabelsTotal: "+ str(volumeLabels))##Aparentemente no hay cambio en volumeLabels frameLabelsAttr += str(frameId) + ',' ## print("frameLabelsAttr: "+str(frameLabelsAttr)) frameLabelsAttr = frameLabelsAttr[:-1] ##No hay cambio ## print("frameLabelsAttrTOTAL: "+str(frameLabelsAttr)) # allocate multivolume mvImage = vtk.vtkImageData() ## print("mvImage: "+str(mvImage)) mvImage.SetExtent(frame0Extent) ## print("mvImageExtent: "+str(mvImage)) ## print("vtk.VTK_MAJOR_VERSION: "+str(vtk.VTK_MAJOR_VERSION)) if vtk.VTK_MAJOR_VERSION <= 5: ##Versión 7 mvImage.SetNumberOfScalarComponents(nFrames) print("mvImageSC: " + str(mvImage)) mvImage.SetScalarType(frame0.GetImageData().GetScalarType()) print("mvImageST: " + str(mvImage)) mvImage.AllocateScalars() print("mvImageAllocate: " + str(mvImage)) else: mvImage.AllocateScalars(frame0.GetImageData().GetScalarType(), nFrames) ## print("mvImageElse: "+str(mvImage)) extent = frame0.GetImageData().GetExtent() numPixels = float(extent[1] + 1) * (extent[3] + 1) * (extent[5] + 1) * nFrames scalarType = frame0.GetImageData().GetScalarType() print('Will now try to allocate memory for ' + str(numPixels) + ' pixels of VTK scalar type' + str(scalarType)) print('Memory allocated successfully') mvImageArray = vtk.util.numpy_support.vtk_to_numpy( mvImage.GetPointData().GetScalars()) ## print("mvImageEArray: "+str(mvImageArray)) ## print("mvImage.GetPointData().GetScalars(): " + str(mvImage.GetPointData().GetScalars())); ## print("ID mvImagearray " + str(id(mvImageArray))); ## print("ID 2: " + str(mvImage.GetPointData().GetScalars())); ## print("Que es frame0: " + str(frame0)); ##EMPIEZA A FORMARCE EL VOLUMEN############### mat = vtk.vtkMatrix4x4() frame0.GetRASToIJKMatrix(mat) mvNode.SetRASToIJKMatrix(mat) frame0.GetIJKToRASMatrix(mat) mvNode.SetIJKToRASMatrix(mat) print("frameId: " + str(frameId)) print("# imag: " + str(nFrames)) ## print("Long frame: "+str(len(frame))) for fileName in fileNames: #f: información de cada scalar volume de cada corte (s, f) = self.readFrame(fileName) if s: #frames.append(f) #for frameId in range(nFrames): # TODO: check consistent size and orientation! frame = f #rames[frameId] filterrameImage = frame.GetImageData() frameImageArray = vtk.util.numpy_support.vtk_to_numpy( frameImage.GetPointData().GetScalars()) mvImageArray.T[frameId] = frameImageArray mvDisplayNode = slicer.mrmlScene.CreateNodeByClass( 'vtkMRMLMultiVolumeDisplayNode') mvDisplayNode.SetScene(slicer.mrmlScene) slicer.mrmlScene.AddNode(mvDisplayNode) mvDisplayNode.SetReferenceCount(mvDisplayNode.GetReferenceCount() - 1) mvDisplayNode.SetDefaultColorMap() mvNode.SetAndObserveDisplayNodeID(mvDisplayNode.GetID()) mvNode.SetAndObserveImageData(mvImage) mvNode.SetNumberOfFrames(nFrames) mvNode.SetLabelArray(volumeLabels) mvNode.SetLabelName(self.__veLabel.text) mvNode.SetAttribute('MultiVolume.FrameLabels', frameLabelsAttr) mvNode.SetAttribute('MultiVolume.NumberOfFrames', str(nFrames)) mvNode.SetAttribute('MultiVolume.FrameIdentifyingDICOMTagName', dicomTagNameAttr) mvNode.SetAttribute('MultiVolume.FrameIdentifyingDICOMTagUnits', dicomTagUnitsAttr) if dicomTagNameAttr == 'TriggerTime' or dicomTagNameAttr == 'AcquisitionTime': if teAttr != '': mvNode.SetAttribute('MultiVolume.DICOM.EchoTime', teAttr) if trAttr != '': mvNode.SetAttribute('MultiVolume.DICOM.RepetitionTime', trAttr) if faAttr != '': mvNode.SetAttribute('MultiVolume.DICOM.FlipAngle', faAttr) mvNode.SetName(str(nFrames) + ' frames MultiVolume') Helper.SetBgFgVolumes(mvNode.GetID(), None)
def takeUSSnapshot2(self,name): snapshotDisp = slicer.vtkMRMLModelDisplayNode() slicer.mrmlScene.AddNode(snapshotDisp) snapshotDisp.SetScene(slicer.mrmlScene) snapshotDisp.SetDisableModifiedEvent(1) snapshotDisp.SetOpacity(1.0) snapshotDisp.SetColor(1.0, 1.0, 1.0) snapshotDisp.SetAmbient(1.0) snapshotDisp.SetBackfaceCulling(0) snapshotDisp.SetDiffuse(0) snapshotDisp.SetSaveWithScene(0) snapshotDisp.SetDisableModifiedEvent(0) snapshotModel = slicer.vtkMRMLModelNode() snapshotModel.SetName(name) snapshotModel.SetDescription("Live Ultrasound Snapshot") snapshotModel.SetScene(slicer.mrmlScene) snapshotModel.SetAndObserveDisplayNodeID(snapshotDisp.GetID()) snapshotModel.SetHideFromEditors(0) snapshotModel.SetSaveWithScene(0) slicer.mrmlScene.AddNode(snapshotModel) image_RAS = slicer.util.getNode("Image_Image") dim = [0, 0, 0] imageData = image_RAS.GetImageData() imageData.GetDimensions(dim) plane = vtk.vtkPlaneSource() plane.Update() snapshotModel.SetAndObservePolyData(plane.GetOutput()) slicePolyData = snapshotModel.GetPolyData() slicePoints = slicePolyData.GetPoints() # In parent transform is saved the ReferenceToRAS transform parentTransform = vtk.vtkTransform() parentTransform.Identity() if not image_RAS.GetParentTransformNode() == None: parentMatrix = vtk.vtkMatrix4x4() parentTransformNode = image_RAS.GetParentTransformNode() parentTransformNode.GetMatrixTransformToWorld(parentMatrix) # aux=parentTransform.GetMatrix() # aux.DeepCopy(parentMatrix) # parentTransform.Update() parentTransform.SetMatrix(parentMatrix) inImageTransform = vtk.vtkTransform() inImageTransform.Identity() image_RAS.GetIJKToRASMatrix(inImageTransform.GetMatrix()) tImageToRAS = vtk.vtkTransform() tImageToRAS.Identity() tImageToRAS.PostMultiply() tImageToRAS.Concatenate(inImageTransform) tImageToRAS.Concatenate(parentTransform) tImageToRAS.Update() point1Image = [0.0, 0.0, 0.0, 1.0] point2Image = [dim[0], 0.0, 0.0, 1.0] point3Image = [0.0, dim[1], 0.0, 1.0] point4Image = [dim[0], dim[1], 0.0, 1.0] point1RAS = [0.0, 0.0, 0.0, 0.0] point2RAS = [0.0, 0.0, 0.0, 0.0] point3RAS = [0.0, 0.0, 0.0, 0.0] point4RAS = [0.0, 0.0, 0.0, 0.0] tImageToRAS.MultiplyPoint(point1Image, point1RAS) tImageToRAS.MultiplyPoint(point2Image, point2RAS) tImageToRAS.MultiplyPoint(point3Image, point3RAS) tImageToRAS.MultiplyPoint(point4Image, point4RAS) p1RAS = [point1RAS[0], point1RAS[1], point1RAS[2]] p2RAS = [point2RAS[0], point2RAS[1], point2RAS[2]] p3RAS = [point3RAS[0], point3RAS[1], point3RAS[2]] p4RAS = [point4RAS[0], point4RAS[1], point4RAS[2]] slicePoints.SetPoint(0, p1RAS) slicePoints.SetPoint(1, p2RAS) slicePoints.SetPoint(2, p3RAS) slicePoints.SetPoint(3, p4RAS) # # Add image texture. image = vtk.vtkImageData() image.DeepCopy(imageData) modelDisplayNode = snapshotModel.GetModelDisplayNode() modelDisplayNode.SetAndObserveTextureImageData(image) snapshotTexture = slicer.vtkMRMLScalarVolumeNode() snapshotTexture.SetAndObserveImageData(image) snapshotTexture.SetName(name + "_Texture") slicer.mrmlScene.AddNode(snapshotTexture) snapshotTexture.CopyOrientation( image_RAS ) snapshotTextureDisplayNode = slicer.vtkMRMLScalarVolumeDisplayNode() snapshotTextureDisplayNode.SetName(name + "_TextureDisplay") snapshotTextureDisplayNode.SetAutoWindowLevel(0); snapshotTextureDisplayNode.SetWindow(256); snapshotTextureDisplayNode.SetLevel(128); snapshotTextureDisplayNode.SetDefaultColorMap(); slicer.mrmlScene.AddNode(snapshotTextureDisplayNode) snapshotTexture.AddAndObserveDisplayNodeID( snapshotTextureDisplayNode.GetID() ) snapshotModel.SetAttribute( "TextureNodeID", snapshotTexture.GetID() ) snapshotModelDisplayNode= snapshotModel.GetModelDisplayNode() snapshotModelDisplayNode.SetAndObserveTextureImageData( snapshotTexture.GetImageData() )
def makeMaskVolumeFromROI(self, refVolumeNode, maskVolumeNode, roiNode): # Create a box implicit function that will be used as a stencil to fill the volume roiBox = vtk.vtkBox() roiCenter = [0, 0, 0] roiNode.GetXYZ( roiCenter ) roiRadius = [0, 0, 0] roiNode.GetRadiusXYZ( roiRadius ) roiBox.SetBounds(roiCenter[0] - roiRadius[0], roiCenter[0] + roiRadius[0], roiCenter[1] - roiRadius[1], roiCenter[1] + roiRadius[1], roiCenter[2] - roiRadius[2], roiCenter[2] + roiRadius[2]) # Determine the transform between the box and the image IJK coordinate systems rasToBox = vtk.vtkMatrix4x4() if roiNode.GetTransformNodeID() != None: roiBoxTransformNode = slicer.mrmlScene.GetNodeByID(roiNode.GetTransformNodeID()) boxToRas = vtk.vtkMatrix4x4() roiBoxTransformNode.GetMatrixTransformToWorld(boxToRas) rasToBox.DeepCopy(boxToRas) rasToBox.Invert() ijkToRas = vtk.vtkMatrix4x4() refVolumeNode.GetIJKToRASMatrix( ijkToRas ) ijkToBox = vtk.vtkMatrix4x4() vtk.vtkMatrix4x4.Multiply4x4(rasToBox,ijkToRas,ijkToBox) ijkToBoxTransform = vtk.vtkTransform() ijkToBoxTransform.SetMatrix(ijkToBox) roiBox.SetTransform(ijkToBoxTransform) # Use the stencil to fill the volume imageData = vtk.vtkImageData() refImageData = refVolumeNode.GetImageData() imageData.SetOrigin(refImageData.GetOrigin()) imageData.SetSpacing(refImageData.GetSpacing()) if vtk.VTK_MAJOR_VERSION <= 5: imageData.SetExtent(refImageData.GetWholeExtent()) imageData.SetScalarTypeToUnsignedChar() imageData.AllocateScalars() else: imageData.SetExtent(refImageData.GetExtent()) imageData.AllocateScalars(vtk.VTK_UNSIGNED_CHAR,1) # Convert the implicit function to a stencil functionToStencil = vtk.vtkImplicitFunctionToImageStencil() functionToStencil.SetInput(roiBox) functionToStencil.SetOutputOrigin(refImageData.GetOrigin()) functionToStencil.SetOutputSpacing(refImageData.GetSpacing()) if vtk.VTK_MAJOR_VERSION <= 5: functionToStencil.SetOutputWholeExtent(refImageData.GetWholeExtent()) else: functionToStencil.SetOutputWholeExtent(refImageData.GetExtent()) functionToStencil.Update() # Apply the stencil to the volume stencilToImage=vtk.vtkImageStencil() if vtk.VTK_MAJOR_VERSION <= 5: stencilToImage.SetInput(imageData) stencilToImage.SetStencil(functionToStencil.GetOutput()) else: stencilToImage.SetInputData(imageData) stencilToImage.SetStencilData(functionToStencil.GetOutput()) stencilToImage.ReverseStencilOn() stencilToImage.SetBackgroundValue(1) stencilToImage.Update() # Update the volume with the stencil operation result maskVolumeNode.SetAndObserveImageData(stencilToImage.GetOutput()) maskVolumeNode.CopyOrientation(refVolumeNode)
def __init__(self, sliceWidget): self.initialized = False super(IsobrushEffectTool, self).__init__(sliceWidget) # create a logic instance to do the non-gui work self.logic = IsobrushEffectLogic(self.sliceWidget.sliceLogic()) # interaction state variables - track if painting or not self.actionState = None self.mode = 'isograph' # TODO: could be a node setting controlled by gui # # cursor actor (paint preview) # self.cursorMapper = vtk.vtkImageMapper() self.cursorDummyImage = vtk.vtkImageData() self.cursorDummyImage.AllocateScalars(vtk.VTK_UNSIGNED_INT, 1) self.cursorMapper.SetInputData(self.cursorDummyImage) self.cursorActor = vtk.vtkActor2D() self.cursorActor.VisibilityOff() self.cursorActor.SetMapper(self.cursorMapper) self.cursorMapper.SetColorWindow(255) self.cursorMapper.SetColorLevel(128) self.actors.append(self.cursorActor) self.renderer.AddActor2D(self.cursorActor) # # Shader computation # - need to import class from module here since it may not be in sys.path # at startup time # - uses dummy render window for framebuffer object context # try: from vtkSlicerShadedActorModuleLogicPython import vtkOpenGLShaderComputation from vtkSlicerShadedActorModuleLogicPython import vtkOpenGLTextureImage except ImportError: import vtkAddon vtkOpenGLShaderComputation = vtkAddon.vtkOpenGLShaderComputation vtkOpenGLTextureImage = vtkAddon.vtkOpenGLTextureImage self.shaderComputation = vtkOpenGLShaderComputation() self.backgroundTextureImage = vtkOpenGLTextureImage() self.labelTextureImage = vtkOpenGLTextureImage() self.resultImageTexture = vtkOpenGLTextureImage() self.iterationImageTexture = vtkOpenGLTextureImage() self.backgroundTextureImage.SetShaderComputation( self.shaderComputation) self.labelTextureImage.SetShaderComputation(self.shaderComputation) self.resultImageTexture.SetShaderComputation(self.shaderComputation) self.iterationImageTexture.SetShaderComputation(self.shaderComputation) self.shaderComputation.SetVertexShaderSource(""" #version 120 attribute vec3 vertexAttribute; attribute vec2 textureCoordinateAttribute; varying vec3 interpolatedTextureCoordinate; void main() { interpolatedTextureCoordinate = vec3(textureCoordinateAttribute, .5); gl_Position = vec4(vertexAttribute, 1.); } """) self.initialized = True self.previewOn()
def performInitialization(self, image, lowerThreshold, upperThreshold, sourceSeedIds, targetSeedIds, ignoreSideBranches=0): ''' ''' # import the vmtk libraries try: import vtkvmtkSegmentationPython as vtkvmtkSegmentation except ImportError: logging.error("Unable to import the SlicerVmtk libraries") cast = vtk.vtkImageCast() cast.SetInputData(image) cast.SetOutputScalarTypeToFloat() cast.Update() image = cast.GetOutput() scalarRange = image.GetScalarRange() imageDimensions = image.GetDimensions() maxImageDimensions = max(imageDimensions) threshold = vtk.vtkImageThreshold() threshold.SetInputData(image) threshold.ThresholdBetween(lowerThreshold, upperThreshold) threshold.ReplaceInOff() threshold.ReplaceOutOn() threshold.SetOutValue(scalarRange[0] - scalarRange[1]) threshold.Update() thresholdedImage = threshold.GetOutput() scalarRange = thresholdedImage.GetScalarRange() shiftScale = vtk.vtkImageShiftScale() shiftScale.SetInputData(thresholdedImage) shiftScale.SetShift(-scalarRange[0]) shiftScale.SetScale(1.0 / (scalarRange[1] - scalarRange[0])) shiftScale.Update() speedImage = shiftScale.GetOutput() if ignoreSideBranches: # ignore sidebranches, use colliding fronts fastMarching = vtkvmtkSegmentation.vtkvmtkCollidingFrontsImageFilter( ) fastMarching.SetInputData(speedImage) fastMarching.SetSeeds1(sourceSeedIds) fastMarching.SetSeeds2(targetSeedIds) fastMarching.ApplyConnectivityOn() fastMarching.StopOnTargetsOn() fastMarching.Update() subtract = vtk.vtkImageMathematics() subtract.SetInputData(fastMarching.GetOutput()) subtract.SetOperationToAddConstant() subtract.SetConstantC(-10 * fastMarching.GetNegativeEpsilon()) subtract.Update() else: fastMarching = vtkvmtkSegmentation.vtkvmtkFastMarchingUpwindGradientImageFilter( ) fastMarching.SetInputData(speedImage) fastMarching.SetSeeds(sourceSeedIds) fastMarching.GenerateGradientImageOn() fastMarching.SetTargetOffset(0.0) fastMarching.SetTargets(targetSeedIds) if targetSeedIds.GetNumberOfIds() > 0: fastMarching.SetTargetReachedModeToOneTarget() else: fastMarching.SetTargetReachedModeToNoTargets() fastMarching.Update() if targetSeedIds.GetNumberOfIds() > 0: subtract = vtk.vtkImageMathematics() subtract.SetInputData(fastMarching.GetOutput()) subtract.SetOperationToAddConstant() subtract.SetConstantC(-fastMarching.GetTargetValue()) subtract.Update() else: subtract = vtk.vtkImageThreshold() subtract.SetInputData(fastMarching.GetOutput()) subtract.ThresholdByLower(2000) # TODO find robuste value subtract.ReplaceInOff() subtract.ReplaceOutOn() subtract.SetOutValue(-1) subtract.Update() outImageData = vtk.vtkImageData() outImageData.DeepCopy(subtract.GetOutput()) return outImageData
def registrarButton(self): mvNode = self.outputRegSelector.currentNode() inputVolume = self.inputRegSelector.currentNode() """ Run the actual algorithm """ #se obtiene la escena y se obtiene el volumen 4D a partir del Volumen 4D de #entrada de la ventana desplegable escena = slicer.mrmlScene imagenvtk4D = inputVolume.GetImageData() #Se obtiene el número de volúmenes que tiene el volumen 4D numero_imagenes = inputVolume.GetNumberOfFrames() print('imagenes: ' + str(numero_imagenes)) #filtro vtk para descomponer un volumen 4D extract1 = vtk.vtkImageExtractComponents() extract1.SetInputData(imagenvtk4D) #matriz de transformación ras2ijk = vtk.vtkMatrix4x4() ijk2ras = vtk.vtkMatrix4x4() #le solicitamos al volumen original que nos devuelva sus matrices inputVolume.GetRASToIJKMatrix(ras2ijk) inputVolume.GetIJKToRASMatrix(ijk2ras) #creo un volumen nuevo volumenFijo = slicer.vtkMRMLScalarVolumeNode() volumenSalida = slicer.vtkMRMLMultiVolumeNode() #le asigno las transformaciones volumenFijo.SetRASToIJKMatrix(ras2ijk) volumenFijo.SetIJKToRASMatrix(ijk2ras) #le asigno el volumen 3D fijo imagen_fija = extract1.SetComponents(0) extract1.Update() volumenFijo.SetName('fijo') volumenFijo.SetAndObserveImageData(extract1.GetOutput()) #anado el nuevo volumen a la escena escena.AddNode(volumenFijo) #se crea un vector para guardar el número del volumen que tenga un #desplazamiento de mas de 4mm en cualquier dirección v = [] #se hace un ciclo for para registrar todos los demás volúmenes del volumen 4D #con el primer volumen que se definió como fijo frameLabelsAttr = '' frames = [] volumeLabels = vtk.vtkDoubleArray() volumeLabels.SetNumberOfTuples(numero_imagenes) volumeLabels.SetNumberOfComponents(1) volumeLabels.Allocate(numero_imagenes) for i in range(numero_imagenes): # extraigo la imagen móvil en la posición i+1 ya que el primero es el fijo imagen_movil = extract1.SetComponents( i + 1) #Seleccionar un volumen i+1 extract1.Update() #Creo el volumen móvil, y realizo el mismo procedimiento que con el fijo volumenMovil = slicer.vtkMRMLScalarVolumeNode() volumenMovil.SetRASToIJKMatrix(ras2ijk) volumenMovil.SetIJKToRASMatrix(ijk2ras) volumenMovil.SetAndObserveImageData(extract1.GetOutput()) volumenMovil.SetName('movil ' + str(i + 1)) escena.AddNode(volumenMovil) #creamos la transformada para alinear los volúmenes transformadaSalida = slicer.vtkMRMLLinearTransformNode() transformadaSalida.SetName('Transformadaderegistro' + str(i + 1)) slicer.mrmlScene.AddNode(transformadaSalida) #parámetros para la operación de registro parameters = {} #parameters['InitialTransform'] = transI.GetID() parameters['fixedVolume'] = volumenFijo.GetID() parameters['movingVolume'] = volumenMovil.GetID() parameters['transformType'] = 'Rigid' parameters['outputTransform'] = transformadaSalida.GetID() frames.append(volumenMovil) ## parameters['outputVolume']=volumenSalida.GetID() #Realizo el registro cliNode = slicer.cli.run(slicer.modules.brainsfit, None, parameters, wait_for_completion=True) #obtengo la transformada lineal que se usó en el registro transformada = escena.GetFirstNodeByName('Transformadaderegistro' + str(i + 1)) #Obtengo la matriz de la transformada, esta matriz es de dimensiones 4x4 #en la cual estan todos los desplazamientos y rotaciones que se hicieron #en la transformada, a partir de ella se obtienen los volumenes que se #desplazaron mas de 4mm en cualquier direccion hm = vtk.vtkMatrix4x4() transformadaSalida.GetMatrixTransformToWorld(hm) volumenMovil.ApplyTransformMatrix(hm) volumenMovil.SetAndObserveTransformNodeID(None) frameId = i volumeLabels.SetComponent(i, 0, frameId) frameLabelsAttr += str(frameId) + ',' ## Matriz=transformada.GetMatrixTransformToParent() ## LR=Matriz.GetElement(0,3)#dirección izquierda o derecha en la fila 1, columna 4 ## PA=Matriz.GetElement(1,3)#dirección anterior o posterior en la fila 2, columna 4 ## IS=Matriz.GetElement(2,3)#dirección inferior o superior en la fila 3, columna 4 ## #Se mira si el volumen "i" en alguna dirección tuvo un desplazamiento ## #mayor a 4mm, en caso de ser cierto se guarda en el vector "v" ## if abs(LR)>4: ## v.append(i+2) ## elif abs(PA)>4: ## v.append(i+2) ## elif abs(IS)>4: ## v.append(i+2) ## print("MovilExtent: "+str(volumenMovil.GetImageData().GetExtent())) #### print("valor de f: "+ str(volumenMovil)) ## frameLabelsAttr = frameLabelsAttr[:-1] mvImage = vtk.vtkImageData() mvImage.SetExtent(volumenMovil.GetImageData().GetExtent() ) ##Se le asigna la dimensión del miltuvolumen mvImage.AllocateScalars( volumenMovil.GetImageData().GetScalarType(), numero_imagenes ) ##Se le asigna el tipo y número de cortes al multivolumen mvImageArray = vtk.util.numpy_support.vtk_to_numpy( mvImage.GetPointData().GetScalars() ) ## Se crea la matriz de datos donde va a ir la imagen mat = vtk.vtkMatrix4x4() ##Se hace la conversión y se obtiene la matriz de transformación del nodo volumenMovil.GetRASToIJKMatrix(mat) mvNode.SetRASToIJKMatrix(mat) volumenMovil.GetIJKToRASMatrix(mat) mvNode.SetIJKToRASMatrix(mat) print("frameId: " + str(frameId)) print("# imag: " + str(numero_imagenes)) ## print("Long frame1: "+str(len(frame))) print("Long frames: " + str(len(frames))) ## for frameId in range(numero_imagenes): # TODO: check consistent size and orientation! frame = frames[frameId] frameImage = frame.GetImageData() frameImageArray = vtk.util.numpy_support.vtk_to_numpy( frameImage.GetPointData().GetScalars()) mvImageArray.T[frameId] = frameImageArray ##Se crea el nodo del multivolumen mvDisplayNode = slicer.mrmlScene.CreateNodeByClass( 'vtkMRMLMultiVolumeDisplayNode') mvDisplayNode.SetScene(slicer.mrmlScene) slicer.mrmlScene.AddNode(mvDisplayNode) mvDisplayNode.SetReferenceCount(mvDisplayNode.GetReferenceCount() - 1) mvDisplayNode.SetDefaultColorMap() mvNode.SetAndObserveDisplayNodeID(mvDisplayNode.GetID()) mvNode.SetAndObserveImageData(mvImage) mvNode.SetNumberOfFrames(numero_imagenes) mvNode.SetLabelArray(volumeLabels) mvNode.SetLabelName('na') mvNode.SetAttribute('MultiVolume.FrameLabels', frameLabelsAttr) mvNode.SetAttribute('MultiVolume.NumberOfFrames', str(numero_imagenes)) mvNode.SetAttribute('MultiVolume.FrameIdentifyingDICOMTagName', 'NA') mvNode.SetAttribute('MultiVolume.FrameIdentifyingDICOMTagUnits', 'na') mvNode.SetName('MultiVolume Registrado') Helper.SetBgFgVolumes(mvNode.GetID(), None) print('Registro completo') #al terminar el ciclo for con todos los volúmenes registrados se genera una #ventana emergente con un mensaje("Registro completo!") y mostrando los #volúmenes que se desplazaron mas de 4mm qt.QMessageBox.information(slicer.util.mainWindow(), 'Slicer Python', 'Registro completo') return True
def imageSlice(self, cmd): """return a png for a slice view. Args: id=volumeID offset=mm offset relative to slice origin (position of slice slider) size=pixel size of output png """ pngMethod = 'PIL' if not hasImage: pngMethod = 'VTK' import vtk.util.numpy_support import numpy import slicer p = urlparse.urlparse(cmd) q = urlparse.parse_qs(p.query) try: id = q['id'][0].strip() except KeyError: id = 'vtkMRMLScalarVolumeNode2' try: mode = str(q['mode'][0].strip()) except (KeyError, ValueError): mode = None try: offset = int(q['offset'][0].strip()) except (KeyError, ValueError): offset = 10 try: size = int(q['size'][0].strip()) except (KeyError, ValueError): size = None try: orientation = q['orientation'][0].strip() except (KeyError, ValueError): orientation = None volumeNode = slicer.mrmlScene.GetNodeByID(id) if orientation: sliceNode = sliceLogic.GetSliceNode() if orientation.lower() == 'axial': sliceNode.SetOrientationToAxial() if orientation.lower() == 'sagittal': sliceNode.SetOrientationToSagittal() if orientation.lower() == 'coronal': sliceNode.SetOrientationToCoronal() #grab slice from image data vtkImage = volumeNode.GetImageData() vtkImageSlice = vtk.vtkImageData() vtkImageSlice.SetSpacing(vtkImage.GetSpacing()) vtkImageSlice.SetExtent(vtkImage.GetExtent()[0], vtkImage.GetExtent()[1], vtkImage.GetExtent()[2], vtkImage.GetExtent()[3], 0, 0) vtkImageSlice.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 3) kSlice = offset if (vtkImage.GetDimensions()[2] < 10): kSlice = vtkImage.GetDimensions()[2] / 2 for i in range(0, vtkImage.GetDimensions()[0]): for j in range(0, vtkImage.GetDimensions()[1]): vtkImageSlice.SetScalarComponentFromFloat( i, j, 0, 0, vtkImage.GetScalarComponentAsFloat(i, j, kSlice, 0)) vtkImageSlice.SetScalarComponentFromFloat( i, j, 0, 1, vtkImage.GetScalarComponentAsFloat(i, j, kSlice, 0)) vtkImageSlice.SetScalarComponentFromFloat( i, j, 0, 2, vtkImage.GetScalarComponentAsFloat(i, j, kSlice, 0)) pngData = self.vtkImageDataToPNG(vtkImageSlice, method=pngMethod) self.logMessage('returning an image of %d length' % len(pngData)) return pngData