def addSequenceFromImageData(self, imageData, tempFrameVolume, filePath, name, singleFileInLoadable): # Rotate 180deg, otherwise the image would appear upside down ijkToRas = vtk.vtkMatrix4x4() ijkToRas.SetElement(0, 0, -1.0) ijkToRas.SetElement(1, 1, -1.0) tempFrameVolume.SetIJKToRASMatrix(ijkToRas) # z axis is time [spacingX, spacingY, frameTimeMsec] = imageData.GetSpacing() imageData.SetSpacing(1.0, 1.0, 1.0) tempFrameVolume.SetSpacing(spacingX, spacingY, 1.0) # Create new sequence outputSequenceNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLSequenceNode") # Get sequence name if singleFileInLoadable: outputSequenceNode.SetName(name) else: ds = dicom.read_file(filePath, stop_before_pixels=True) if hasattr(ds, 'PositionerPrimaryAngle') and hasattr( ds, 'PositionerSecondaryAngle'): outputSequenceNode.SetName( f'{name} ({ds.PositionerPrimaryAngle}/{ds.PositionerSecondaryAngle})' ) else: outputSequenceNode.SetName(name) if frameTimeMsec == 1.0: # frame time is not found, set it to 1.0fps frameTime = 1 outputSequenceNode.SetIndexName("frame") outputSequenceNode.SetIndexUnit("") playbackRateFps = 10 else: # frame time is set, use it frameTime = frameTimeMsec * 0.001 outputSequenceNode.SetIndexName("time") outputSequenceNode.SetIndexUnit("s") playbackRateFps = 1.0 / frameTime # Add frames to the sequence numberOfFrames = imageData.GetDimensions()[2] extent = imageData.GetExtent() numberOfFrames = extent[5] - extent[4] + 1 for frame in range(numberOfFrames): # get current frame from multiframe crop = vtk.vtkImageClip() crop.SetInputData(imageData) crop.SetOutputWholeExtent(extent[0], extent[1], extent[2], extent[3], extent[4] + frame, extent[4] + frame) crop.ClipDataOn() crop.Update() croppedOutput = crop.GetOutput() croppedOutput.SetExtent(extent[0], extent[1], extent[2], extent[3], 0, 0) croppedOutput.SetOrigin(0.0, 0.0, 0.0) tempFrameVolume.SetAndObserveImageData(croppedOutput) # get timestamp if type(frameTime) == int: timeStampSec = str(frame * frameTime) else: timeStampSec = f"{frame * frameTime:.3f}" outputSequenceNode.SetDataNodeAtValue(tempFrameVolume, timeStampSec) # Create storage node that allows saving node as nrrd outputSequenceStorageNode = slicer.vtkMRMLVolumeSequenceStorageNode() slicer.mrmlScene.AddNode(outputSequenceStorageNode) outputSequenceNode.SetAndObserveStorageNodeID( outputSequenceStorageNode.GetID()) return outputSequenceNode, playbackRateFps
def load(self,loadable): """Load the selection """ outputSequenceNodes = [] for filePath in loadable.files: import vtkITK if loadable.grayscale: reader = vtkITK.vtkITKArchetypeImageSeriesScalarReader() else: reader = vtkITK.vtkITKArchetypeImageSeriesVectorReaderFile() reader.SetArchetype(filePath) reader.AddFileName(filePath) reader.SetSingleFile(True) reader.SetOutputScalarTypeToNative() reader.SetDesiredCoordinateOrientationToNative() reader.SetUseNativeOriginOn() # GDCM is not particularly better in this than DCMTK, we just select one explicitly # so that we know which one is used reader.SetDICOMImageIOApproachToGDCM() reader.Update() if reader.GetErrorCode() != vtk.vtkErrorCode.NoError: errorString = vtk.vtkErrorCode.GetStringFromErrorCode(reader.GetErrorCode()) raise ValueError("Could not read image {0} from file {1}. Error is: {2}".format(loadable.name, filePath, errorString)) volume = reader.GetOutput() [spacingX, spacingY, frameTimeMsec] = volume.GetSpacing() volume.SetSpacing(1.0, 1.0, 1.0) outputSequenceNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSequenceNode") if frameTimeMsec == 1.0: # frame time is not found, set it to 1.0fps frameTime = 1 outputSequenceNode.SetIndexName("frame") outputSequenceNode.SetIndexUnit("") playbackRateFps = 10 else: frameTime = frameTimeMsec * 0.001 outputSequenceNode.SetIndexName("time") outputSequenceNode.SetIndexUnit("s") playbackRateFps = 1.0/frameTime if loadable.grayscale: tempFrameVolume = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLScalarVolumeNode") else: tempFrameVolume = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLVectorVolumeNode") # Rotate 180deg, otherwise the image would appear upside down ijkToRAS = vtk.vtkMatrix4x4() ijkToRAS.SetElement(0,0,-1.0) ijkToRAS.SetElement(1,1,-1.0) tempFrameVolume.SetIJKToRASMatrix(ijkToRAS) tempFrameVolume.SetSpacing(spacingX, spacingY, 1.0) numberOfFrames = volume.GetDimensions()[2] extent = volume.GetExtent() numberOfFrames = extent[5]-extent[4]+1 for frame in range(numberOfFrames): crop = vtk.vtkImageClip() crop.SetInputData(volume) crop.SetOutputWholeExtent(extent[0], extent[1], extent[2], extent[3], extent[4]+frame, extent[4]+frame) crop.ClipDataOn() crop.Update() croppedOutput = crop.GetOutput() croppedOutput.SetExtent(extent[0], extent[1], extent[2], extent[3], 0, 0) tempFrameVolume.SetAndObserveImageData(croppedOutput) if type(frameTime)==int: timeStampSec = str(frame * frameTime) else: timeStampSec = "{:.3f}".format(frame * frameTime) outputSequenceNode.SetDataNodeAtValue(tempFrameVolume, timeStampSec) slicer.mrmlScene.RemoveNode(tempFrameVolume) if len(loadable.files) == 1: outputSequenceNode.SetName(loadable.name) else: ds = dicom.read_file(filePath, stop_before_pixels=True) if hasattr(ds, 'PositionerPrimaryAngle') and hasattr(ds, 'PositionerSecondaryAngle'): outputSequenceNode.SetName('{0} ({1}/{2})'.format(loadable.name, ds.PositionerPrimaryAngle,ds.PositionerSecondaryAngle)) else: outputSequenceNode.SetName(loadable.name) slicer.mrmlScene.AddNode(outputSequenceNode) # Create storage node that allows saving node as nrrd outputSequenceStorageNode = slicer.vtkMRMLVolumeSequenceStorageNode() slicer.mrmlScene.AddNode(outputSequenceStorageNode) outputSequenceNode.SetAndObserveStorageNodeID(outputSequenceStorageNode.GetID()) outputSequenceNodes.append(outputSequenceNode) if not hasattr(loadable, 'createBrowserNode') or loadable.createBrowserNode: # Add a browser node and show the volume in the slice viewer for user convenience outputSequenceBrowserNode = slicer.vtkMRMLSequenceBrowserNode() outputSequenceBrowserNode.SetName(slicer.mrmlScene.GenerateUniqueName(loadable.name+' browser')) outputSequenceBrowserNode.SetPlaybackRateFps(playbackRateFps) slicer.mrmlScene.AddNode(outputSequenceBrowserNode) # Add all sequences to the sequence browser first = True for outputSequenceNode in outputSequenceNodes: #outputSequenceBrowserNode.SetAndObserveMasterSequenceNodeID(outputSequenceNode.GetID()) outputSequenceBrowserNode.AddSynchronizedSequenceNode(outputSequenceNode) proxyVolumeNode = outputSequenceBrowserNode.GetProxyNode(outputSequenceNode) # create Subject hierarchy nodes for the loaded series self.addSeriesInSubjectHierarchy(loadable, proxyVolumeNode) if first: first = False # Automatically select the volume to display appLogic = slicer.app.applicationLogic() selNode = appLogic.GetSelectionNode() selNode.SetReferenceActiveVolumeID(proxyVolumeNode.GetID()) appLogic.PropagateVolumeSelection() appLogic.FitSliceToAll() slicer.modules.sequences.setToolBarActiveBrowserNode(outputSequenceBrowserNode) # Show sequence browser toolbar slicer.modules.sequences.showSequenceBrowser(outputSequenceBrowserNode) return outputSequenceNode
def loadPhilips4DUSAsSequence(self, loadable): """Load the selection as an Ultrasound, store in a Sequence node """ # 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 frameTimeMsec = ds.FrameTime pixelShape = (frames, slices, rows, columns) pixelSize = pixelShape[0] * pixelShape[1] * pixelShape[2] * pixelShape[ 3] totalFileSize = os.path.getsize(filePath) headerSize = totalFileSize - pixelSize outputSequenceNode = slicer.vtkMRMLSequenceNode() for frame in range(frames): imgReader = vtk.vtkImageReader() imgReader.SetFileDimensionality(3) imgReader.SetFileName(filePath) imgReader.SetNumberOfScalarComponents(1) imgReader.SetDataScalarTypeToUnsignedChar() imgReader.SetDataExtent(0, columns - 1, 0, rows - 1, 0, slices - 1) imgReader.SetHeaderSize(headerSize + frame * slices * rows * columns) imgReader.FileLowerLeftOn() imgReader.Update() outputNode = slicer.vtkMRMLScalarVolumeNode() outputNode.SetAndObserveImageData(imgReader.GetOutput()) outputNode.SetSpacing(spacing) timeStampSec = "{:.3f}".format(frame * frameTimeMsec * 0.001) outputSequenceNode.SetDataNodeAtValue(outputNode, timeStampSec) outputSequenceNode.SetName( slicer.mrmlScene.GenerateUniqueName(loadable.name)) slicer.mrmlScene.AddNode(outputSequenceNode) # Create storage node that allows saving node as nrrd outputSequenceStorageNode = slicer.vtkMRMLVolumeSequenceStorageNode() slicer.mrmlScene.AddNode(outputSequenceStorageNode) outputSequenceNode.SetAndObserveStorageNodeID( outputSequenceStorageNode.GetID()) if not hasattr(loadable, 'createBrowserNode') or loadable.createBrowserNode: # Add a browser node and show the volume in the slice viewer for user convenience outputSequenceBrowserNode = slicer.vtkMRMLSequenceBrowserNode() outputSequenceBrowserNode.SetName( slicer.mrmlScene.GenerateUniqueName( outputSequenceNode.GetName() + ' browser')) slicer.mrmlScene.AddNode(outputSequenceBrowserNode) outputSequenceBrowserNode.SetAndObserveMasterSequenceNodeID( outputSequenceNode.GetID()) masterOutputNode = outputSequenceBrowserNode.GetProxyNode( outputSequenceNode) # Automatically select the volume to display appLogic = slicer.app.applicationLogic() selNode = appLogic.GetSelectionNode() selNode.SetReferenceActiveVolumeID(masterOutputNode.GetID()) appLogic.PropagateVolumeSelection() appLogic.FitSliceToAll() slicer.modules.sequencebrowser.setToolBarActiveBrowserNode( outputSequenceBrowserNode) # create Subject hierarchy nodes for the loaded series self.addSeriesInSubjectHierarchy(loadable, masterOutputNode) return outputSequenceNode
def loadAsSequence(self,loadable): """Load the selection as an Ultrasound, store in a Sequence node """ # 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 frameTimeMsec = ds.FrameTime pixelShape = (frames, slices, rows, columns) pixelSize = reduce(lambda x,y : x*y, pixelShape) totalFileSize = os.path.getsize(filePath) headerSize = totalFileSize-pixelSize outputSequenceNode = slicer.vtkMRMLSequenceNode() for frame in range(frames): imgReader = vtk.vtkImageReader() imgReader.SetFileDimensionality(3) imgReader.SetFileName(filePath); imgReader.SetNumberOfScalarComponents(1) imgReader.SetDataScalarTypeToUnsignedChar() imgReader.SetDataExtent(0,columns-1, 0,rows-1, 0,slices-1) imgReader.SetHeaderSize(headerSize+frame*slices*rows*columns) imgReader.FileLowerLeftOn(); imgReader.Update() outputNode = slicer.vtkMRMLScalarVolumeNode() outputNode.SetAndObserveImageData(imgReader.GetOutput()) outputNode.SetSpacing(spacing) timeStampSec = "{:.3f}".format(frame * frameTimeMsec * 0.001) outputSequenceNode.SetDataNodeAtValue(outputNode, timeStampSec) outputSequenceNode.SetName(slicer.mrmlScene.GenerateUniqueName(loadable.name)) slicer.mrmlScene.AddNode(outputSequenceNode) # Create storage node that allows saving node as nrrd outputSequenceStorageNode = slicer.vtkMRMLVolumeSequenceStorageNode() slicer.mrmlScene.AddNode(outputSequenceStorageNode) outputSequenceNode.SetAndObserveStorageNodeID(outputSequenceStorageNode.GetID()) if not hasattr(loadable, 'createBrowserNode') or loadable.createBrowserNode: # Add a browser node and show the volume in the slice viewer for user convenience outputSequenceBrowserNode = slicer.vtkMRMLSequenceBrowserNode() outputSequenceBrowserNode.SetName(slicer.mrmlScene.GenerateUniqueName(outputSequenceNode.GetName()+' browser')) slicer.mrmlScene.AddNode(outputSequenceBrowserNode) outputSequenceBrowserNode.SetAndObserveMasterSequenceNodeID(outputSequenceNode.GetID()) masterOutputNode = outputSequenceBrowserNode.GetVirtualOutputDataNode(outputSequenceNode) # Automatically select the volume to display appLogic = slicer.app.applicationLogic() selNode = appLogic.GetSelectionNode() selNode.SetReferenceActiveVolumeID(masterOutputNode.GetID()) appLogic.PropagateVolumeSelection() appLogic.FitSliceToAll() outputSequenceBrowserNode.ScalarVolumeAutoWindowLevelOff() # for performance optimization # create Subject hierarchy nodes for the loaded series self.addSeriesInSubjectHierarchy(loadable, masterOutputNode) return outputSequenceNode