def __init__(self, database, fileToBeAddedCallback=None, fileAddedCallback=None): super(DICOMListener, self).__init__() self.dicomDatabase = database self.indexer = ctk.ctkDICOMIndexer() self.fileToBeAddedCallback = fileToBeAddedCallback self.fileAddedCallback = fileAddedCallback self.lastFileAdded = None settings = qt.QSettings() dir = settings.value('DatabaseDirectory') if not dir: raise (UserWarning( 'Database directory not set: cannot start DICOMListener')) if not os.path.exists(dir): os.mkdir(dir) self.incomingDir = dir + "/incoming" if not os.path.exists(self.incomingDir): os.mkdir(self.incomingDir) self.port = settings.value('StoragePort') if not self.port: settings.setValue('StoragePort', '11112') self.port = settings.value('StoragePort')
def addFilesToDatabase(self): indexer = ctk.ctkDICOMIndexer() destinationDir = os.path.dirname(slicer.dicomDatabase.databaseFilename) if self.sdbFile: files = [self.sdbFile] else: files = glob.glob("%s/*" % self.dicomDirectory) for file in files: indexer.addFile(slicer.dicomDatabase, file, destinationDir) slicer.util.showStatusMessage("Loaded: %s" % file, 1000)
def importDicomDir(self, outputDirPath): """ Utility function to import DICOM files from a directory """ self.addLog('Directory: '+outputDirPath) self.addLog('DICOM importing started...') dicomWidget = slicer.modules.dicom.widgetRepresentation().self() indexer = ctk.ctkDICOMIndexer() indexer.addDirectory( slicer.dicomDatabase, outputDirPath ) self.addLog('DICOM importing completed.')
def addFilesToDatabase(self): indexer = ctk.ctkDICOMIndexer() destinationDir = os.path.dirname(slicer.dicomDatabase.databaseFilename) if self.sdbFile: files = [self.sdbFile] else: files = glob.glob('%s/*' % self.dicomDirectory) for file in files: indexer.addFile(slicer.dicomDatabase, file, destinationDir) slicer.util.showStatusMessage("Loaded: %s" % file, 1000)
def TestSection_2ImportStudy(self): self.delayDisplay("Import study",self.delayMs) indexer = ctk.ctkDICOMIndexer() self.assertIsNotNone( indexer ) # Import study to database indexer.addDirectory( slicer.dicomDatabase, self.dataDir ) indexer.waitForImportFinished() self.assertEqual( len(slicer.dicomDatabase.patients()), 1 ) self.assertIsNotNone( slicer.dicomDatabase.patients()[0] )
def importStudy(self, inputDir, progressCallback=None): self.progressCallback = progressCallback self.canceled = False print('Database location: '+self.dicomDatabaseDir) print('FIXME: revert back to the original DB location when done!') self.openDatabase() print('Input directory: ' + inputDir) if not self.indexer: self.indexer = ctk.ctkDICOMIndexer() self.indexer.connect("progress(int)", self.updateProgress) self.indexer.addDirectory(slicer.dicomDatabase, inputDir) self.patients = slicer.dicomDatabase.patients() print('Import completed, total '+str(len(slicer.dicomDatabase.patients()))+' patients imported')
def ImportStudy(self, dicomDataDir): indexer = ctk.ctkDICOMIndexer() # Import study to database indexer.addDirectory( slicer.dicomDatabase, dicomDataDir ) indexer.waitForImportFinished() # Check if import added any new patients to the database if len(slicer.dicomDatabase.patients()) > self.databases[self.dbCounter]['NumberPatients']: patientsAdded = slicer.dicomDatabase.patients()[self.databases[self.dbCounter]['NumberPatients']:] self.databases[self.dbCounter]['NumberPatients'] = len(slicer.dicomDatabase.patients()) return patientsAdded else: return 0
def loadCheckedLoadables(self): """Invoke the load method on each plugin for the DICOMLoadable instances that are selected""" if self.advancedViewButton.checkState() == 0: self.examineForLoading() self.loadableTable.updateSelectedFromCheckstate() loadableCount = 0 for plugin in self.loadablesByPlugin: for loadable in self.loadablesByPlugin[plugin]: if loadable.selected: loadableCount += 1 self.progress = qt.QProgressDialog(self.window) self.progress.minimumDuration = 0 self.progress.show() self.progress.setValue(0) self.progress.setMaximum(loadableCount) step = 0 loadingResult = '' for plugin in self.loadablesByPlugin: for loadable in self.loadablesByPlugin[plugin]: if self.progress.wasCanceled: break slicer.app.processEvents() self.progress.setValue(step) slicer.app.processEvents() if loadable.selected: self.progress.labelText = '\nLoading %s' % loadable.name slicer.app.processEvents() if not plugin.load(loadable): loadingResult = '%s\nCould not load: %s as a %s' % (loadingResult,loadable.name,plugin.loadType) step += 1 self.progress.setValue(step) slicer.app.processEvents() try: for derivedItem in loadable.derivedItems: indexer = ctk.ctkDICOMIndexer() self.progress.labelText = '\nIndexing %s' % derivedItem slicer.app.processEvents() indexer.addFile(slicer.dicomDatabase, derivedItem) except AttributeError: # no derived items or some other attribute error pass self.progress.close() self.progress = None if loadingResult: qt.QMessageBox.warning(slicer.util.mainWindow(), 'DICOM loading', loadingResult) if not self.browserPersistent: self.close()
def loadCheckedLoadables(self): """Invoke the load method on each plugin for the loadable (DICOMLoadable or qSlicerDICOMLoadable) instances that are selected""" if self.advancedViewButton.checkState() == 0: self.examineForLoading() self.loadableTable.updateSelectedFromCheckstate() loadableCount = 0 for plugin in self.loadablesByPlugin: for loadable in self.loadablesByPlugin[plugin]: if loadable.selected: loadableCount += 1 self.progress = qt.QProgressDialog(self.window) self.progress.minimumDuration = 0 self.progress.show() self.progress.setValue(0) self.progress.setMaximum(loadableCount) step = 0 loadingResult = '' for plugin in self.loadablesByPlugin: for loadable in self.loadablesByPlugin[plugin]: if self.progress.wasCanceled: break slicer.app.processEvents() self.progress.setValue(step) slicer.app.processEvents() if loadable.selected: self.progress.labelText = '\nLoading %s' % loadable.name slicer.app.processEvents() if not plugin.load(loadable): loadingResult = '%s\nCould not load: %s as a %s' % (loadingResult,loadable.name,plugin.loadType) step += 1 self.progress.setValue(step) slicer.app.processEvents() try: for derivedItem in loadable.derivedItems: indexer = ctk.ctkDICOMIndexer() self.progress.labelText = '\nIndexing %s' % derivedItem slicer.app.processEvents() indexer.addFile(slicer.dicomDatabase, derivedItem) except AttributeError: # no derived items or some other attribute error pass self.progress.close() self.progress = None if loadingResult: qt.QMessageBox.warning(slicer.util.mainWindow(), 'DICOM loading', loadingResult) if not self.browserPersistent: self.close()
def ImportStudy(self, dicomDataDir): indexer = ctk.ctkDICOMIndexer() # Import study to database indexer.addDirectory(slicer.dicomDatabase, dicomDataDir) indexer.waitForImportFinished() # Check if import added any new patients to the database if len(slicer.dicomDatabase.patients()) > self.databases[ self.dbCounter]['NumberPatients']: patientsAdded = slicer.dicomDatabase.patients( )[self.databases[self.dbCounter]['NumberPatients']:] self.databases[self.dbCounter]['NumberPatients'] = len( slicer.dicomDatabase.patients()) return patientsAdded else: return 0
def __init__(self,database,fileToBeAddedCallback=None,fileAddedCallback=None): super(DICOMListener,self).__init__() self.dicomDatabase = database self.indexer = ctk.ctkDICOMIndexer() self.fileToBeAddedCallback = fileToBeAddedCallback self.fileAddedCallback = fileAddedCallback self.lastFileAdded = None settings = qt.QSettings() dir = settings.value('DatabaseDirectory') if not dir: raise( UserWarning('Database directory not set: cannot start DICOMListener') ) if not os.path.exists(dir): os.mkdir(dir) self.incomingDir = dir + "/incoming" if not os.path.exists(self.incomingDir): os.mkdir(self.incomingDir) self.port = settings.value('StoragePort') if not self.port: settings.setValue('StoragePort', '11112')
def DoIt(inputDir, rgbDir, outputDir): # # Read the input DICOM series as a volume # dcmList = [] for dcm in os.listdir(inputDir): if len(dcm)-dcm.rfind('.dcm') == 4: dcmList.append(inputDir+'/'+dcm) scalarVolumePlugin = slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']() print 'Will examine: ',dcmList indexer = ctk.ctkDICOMIndexer() indexer.addDirectory(slicer.dicomDatabase, inputDir) indexer.waitForImportFinished() loadables = scalarVolumePlugin.examine([dcmList]) if len(loadables) == 0: print 'Could not parse the DICOM Study!' exit() inputVolume = scalarVolumePlugin.load(loadables[0]) sNode = slicer.vtkMRMLVolumeArchetypeStorageNode() ''' sNode.ResetFileNameList() for f in loadables[0].files: sNode.AddFileName(f) sNode.SetFileName(loadables[0].files[0]) sNode.SetSingleFile(0) inputVolume = slicer.vtkMRMLScalarVolumeNode() sNode.ReadData(inputVolume) ''' sNode.SetWriteFileFormat('nrrd') sNode.SetFileName(os.path.join(outputDir,'input_volume.nrrd')) sNode.WriteData(inputVolume) # # Order the input RGBs and rename in a temp directory # rgbList = [] for rgb in os.listdir(rgbDir): if len(rgb)-rgb.rfind('.bmp') == 4: rgbList.append(rgb) tmpDir = slicer.app.settings().value('Modules/TemporaryDirectory') tmpDir = tmpDir+'/PNGStackLabelConverter' if not os.path.exists(tmpDir): os.mkdir(tmpDir) oldFiles = os.listdir(tmpDir) # just in case there is anything in that directory for f in oldFiles: os.unlink(tmpDir+'/'+f) rgbOrdered = [None] * len(loadables[0].files) rgbCnt = 0 rgbExt = rgbList[0][rgbList[0].rfind('.')+1:len(rgbList[0])] print 'Extension for RGBs: ',rgbExt dcmFileList = loadables[0].files rgbRenamedList = [] print 'Number of dcm files: ',len(dcmFileList), ' and rgb files: ',len(rgbOrdered) dcmIdx = 0 for dcm in dcmFileList: rgbIdx = 0 for rgb in rgbList: dcmPrefix = dcm[dcm.rfind('/')+1:dcm.rfind('.')] if rgb.find(dcmPrefix) != -1: name = string.zfill(str(dcmIdx),5) rgbCnt = rgbCnt+1 src = rgbDir+'/'+rgb dest = tmpDir+'/'+name+'.'+rgbExt rgbRenamedList.append(dest) shutil.copy(src,dest) break rgbIdx = rgbIdx+1 # remove the matched DICOM file from the list if rgbIdx == len(rgbList): print('ERROR: failed to find matching label file for DICOM file '+dcm) return del rgbList[rgbIdx] dcmIdx = dcmIdx+1 if len(rgbRenamedList) == 0: print 'Could not parse the DICOM Study!' return sNode = slicer.vtkMRMLVolumeArchetypeStorageNode() sNode.ResetFileNameList() for f in rgbRenamedList: sNode.AddFileName(f) sNode.SetFileName(rgbRenamedList[0]) sNode.SetSingleFile(0) inputRGBVolume = slicer.vtkMRMLVectorVolumeNode() sNode.ReadData(inputRGBVolume) # run the filter # - extract the RGB portions extract = vtk.vtkImageExtractComponents() extract.SetComponents(0,1,2) if vtk.vtkVersion().GetVTKMajorVersion() < 6: extract.SetInput(inputRGBVolume.GetImageData()) else: extract.SetInputData(inputRGBVolume.GetImageData()) luminance = vtk.vtkImageLuminance() if vtk.vtkVersion().GetVTKMajorVersion() < 6: luminance.SetInput(extract.GetOutput()) else: luminance.SetInputData(extract.GetOutput()) cast = vtk.vtkImageCast() if vtk.vtkVersion().GetVTKMajorVersion() < 6: cast.SetInput(luminance.GetOutput()) else: cast.SetInputData(luminance.GetOutput()) cast.SetOutputScalarTypeToShort() cast.GetOutput().Update() ijkToRAS = vtk.vtkMatrix4x4() inputVolume.GetIJKToRASMatrix(ijkToRAS) outputLabel = slicer.vtkMRMLLabelMapVolumeNode() outputLabel.SetIJKToRASMatrix(ijkToRAS) outputLabel.SetAndObserveImageData(cast.GetOutput()) reportingLogic = slicer.modules.reporting.logic() displayNode = slicer.vtkMRMLLabelMapVolumeDisplayNode() displayNode.SetAndObserveColorNodeID(reportingLogic.GetDefaultColorNode().GetID()) slicer.mrmlScene.AddNode(displayNode) outputLabel.SetAndObserveDisplayNodeID(displayNode.GetID()) sNode.SetWriteFileFormat('nrrd') sNode.SetFileName(os.path.join(outputDir,'label_output.nrrd')) sNode.WriteData(outputLabel) # save as DICOM SEG labelCollection = vtk.vtkCollection() labelCollection.AddItem(outputLabel) slicer.mrmlScene.AddNode(inputVolume) outputLabel.SetAttribute('AssociatedNodeID',inputVolume.GetID()) slicer.mrmlScene.AddNode(outputLabel) # initialize the DICOM DB for Reporting logic settings = qt.QSettings() dbFileName = settings.value('DatabaseDirectory','') if dbFileName =='': print('ERROR: database must be initialized') else: dbFileName = dbFileName +'/ctkDICOM.sql' reportingLogic.InitializeDICOMDatabase(dbFileName) reportingLogic.DicomSegWrite(labelCollection, outputDir)
def test_Part1DICOM(self): """ Test the DICOM part of the test using the head atlas """ import os self.delayDisplay("Starting the DICOM test") # # first, get the data - a zip file of dicom data # import urllib downloads = ( ('http://slicer.kitware.com/midas3/download?items=8610', 'dicom.zip'), ) self.delayDisplay("Downloading") for url,name in downloads: filePath = slicer.app.temporaryPath + '/' + name if not os.path.exists(filePath) or os.stat(filePath).st_size == 0: self.delayDisplay('Requesting download %s from %s...\n' % (name, url)) urllib.urlretrieve(url, filePath) self.delayDisplay('Finished with download\n') self.delayDisplay("Unzipping") dicomFilesDirectory = slicer.app.temporaryPath + '/dicomFiles' qt.QDir().mkpath(dicomFilesDirectory) slicer.app.applicationLogic().Unzip(filePath, dicomFilesDirectory) try: self.delayDisplay("Switching to temp database directory") tempDatabaseDirectory = slicer.app.temporaryPath + '/tempDICOMDatbase' qt.QDir().mkpath(tempDatabaseDirectory) if slicer.dicomDatabase: originalDatabaseDirectory = os.path.split(slicer.dicomDatabase.databaseFilename)[0] else: originalDatabaseDirectory = None settings = qt.QSettings() settings.setValue('DatabaseDirectory', tempDatabaseDirectory) dicomWidget = slicer.modules.dicom.widgetRepresentation().self() dicomWidget.onDatabaseDirectoryChanged(tempDatabaseDirectory) self.delayDisplay('Importing DICOM') mainWindow = slicer.util.mainWindow() mainWindow.moduleSelector().selectModule('DICOM') dicomWidget.dicomApp.suspendModel() indexer = ctk.ctkDICOMIndexer() indexer.addDirectory(slicer.dicomDatabase, dicomFilesDirectory, None) indexer.waitForImportFinished() dicomWidget.dicomApp.resumeModel() dicomWidget.detailsPopup.open() # click on the first row of the tree index = dicomWidget.tree.indexAt(qt.QPoint(0,0)) dicomWidget.onTreeClicked(index) self.delayDisplay('Loading Selection') dicomWidget.detailsPopup.loadCheckedLoadables() self.delayDisplay('Change Level') layoutManager = slicer.app.layoutManager() redWidget = layoutManager.sliceWidget('Red') self.clickAndDrag(redWidget,start=(10,10),end=(10,40)) self.delayDisplay('Change Window') self.clickAndDrag(redWidget,start=(10,10),end=(40,10)) self.delayDisplay('Change Layout') layoutManager = slicer.app.layoutManager() layoutManager.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutOneUpRedSliceView) self.delayDisplay('Zoom') self.clickAndDrag(redWidget,button='Right',start=(10,10),end=(10,40)) self.delayDisplay('Pan') self.clickAndDrag(redWidget,button='Middle',start=(10,10),end=(40,40)) self.delayDisplay('Center') redWidget.sliceController().fitSliceToBackground() self.delayDisplay('Lightbox') redWidget.sliceController().setLightboxTo6x6() self.delayDisplay('Conventional Layout') layoutManager.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalView) self.delayDisplay('No Lightbox') redWidget.sliceController().setLightboxTo1x1() self.delayDisplay('Four Up Layout') layoutManager.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutFourUpView) self.delayDisplay('Shift Mouse') self.clickAndDrag(redWidget,button='None',start=(100,100),end=(140,140),modifiers=['Shift']) self.delayDisplay('Conventional, Link, Slice Model') layoutManager.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalView) redWidget.sliceController().setSliceLink(True) redWidget.sliceController().setSliceVisible(True); self.delayDisplay('Rotate') threeDView = layoutManager.threeDWidget(0).threeDView() self.clickAndDrag(threeDView) self.delayDisplay('Zoom') threeDView = layoutManager.threeDWidget(0).threeDView() self.clickAndDrag(threeDView,button='Right') self.delayDisplay('Test passed!') except Exception, e: import traceback traceback.print_exc() self.delayDisplay('Test caused exception!\n' + str(e))
def proceedWithReferencedLoadablesSelection(self): # each check box corresponds to a referenced loadable # that was selected by examine; if the user confirmed # that reference should be loaded, add it to the self.loadablesByPlugin # dictionary if self.referencesDialog: children = self.referencesDialog.children() loadableCnt = 0 for plugin in self.referencedLoadables: for loadable in self.referencedLoadables[plugin]: if loadable.selected: if children[loadableCnt+2].checked: self.loadablesByPlugin[plugin].append(loadable) self.referencesDialog.close() self.referencesDialog = None loadableCount = 0 for plugin in self.loadablesByPlugin: for loadable in self.loadablesByPlugin[plugin]: if loadable.selected: loadableCount += 1 self.progress = qt.QProgressDialog(self.window) self.progress.minimumDuration = 0 self.progress.show() self.progress.setValue(0) self.progress.setMaximum(loadableCount) step = 0 loadingResult = '' for plugin in self.loadablesByPlugin: for loadable in self.loadablesByPlugin[plugin]: if self.progress.wasCanceled: break slicer.app.processEvents() self.progress.setValue(step) slicer.app.processEvents() if loadable.selected: self.progress.labelText = '\nLoading %s' % loadable.name slicer.app.processEvents() if not plugin.load(loadable): loadingResult = '%s\nCould not load: %s as a %s' % (loadingResult,loadable.name,plugin.loadType) step += 1 self.progress.setValue(step) slicer.app.processEvents() try: for derivedItem in loadable.derivedItems: indexer = ctk.ctkDICOMIndexer() self.progress.labelText = '\nIndexing %s' % derivedItem slicer.app.processEvents() indexer.addFile(slicer.dicomDatabase, derivedItem) except AttributeError: # no derived items or some other attribute error pass self.progress.close() self.progress = None if loadingResult: qt.QMessageBox.warning(slicer.util.mainWindow(), 'DICOM loading', loadingResult) if not self.browserPersistent: self.close() return
def proceedWithReferencedLoadablesSelection(self): # each check box corresponds to a referenced loadable # that was selected by examine; if the user confirmed # that reference should be loaded, add it to the self.loadablesByPlugin # dictionary if self.referencesDialog: children = self.referencesDialog.children() loadableCnt = 0 for plugin in self.referencedLoadables: for loadable in self.referencedLoadables[plugin]: if loadable.selected: if children[loadableCnt+2].checked: self.loadablesByPlugin[plugin].append(loadable) self.referencesDialog.close() self.referencesDialog = None loadableCount = 0 for plugin in self.loadablesByPlugin: for loadable in self.loadablesByPlugin[plugin]: if loadable.selected: loadableCount += 1 self.progress = qt.QProgressDialog(self.window) self.progress.minimumDuration = 0 self.progress.show() self.progress.setValue(0) self.progress.setMaximum(loadableCount) step = 0 loadingResult = '' loadedNodeIDs = [] @vtk.calldata_type(vtk.VTK_OBJECT) def onNodeAdded(caller, event, calldata): node = calldata if isinstance(node, slicer.vtkMRMLVolumeNode): loadedNodeIDs.append(node.GetID()) self.addObserver(slicer.mrmlScene, slicer.vtkMRMLScene.NodeAddedEvent, onNodeAdded); for plugin in self.loadablesByPlugin: for loadable in self.loadablesByPlugin[plugin]: if self.progress.wasCanceled: break slicer.app.processEvents() self.progress.setValue(step) slicer.app.processEvents() if loadable.selected: self.progress.labelText = '\nLoading %s' % loadable.name slicer.app.processEvents() if not plugin.load(loadable): loadingResult = '%s\nCould not load: %s as a %s' % (loadingResult,loadable.name,plugin.loadType) step += 1 self.progress.setValue(step) slicer.app.processEvents() try: for derivedItem in loadable.derivedItems: indexer = ctk.ctkDICOMIndexer() self.progress.labelText = '\nIndexing %s' % derivedItem slicer.app.processEvents() indexer.addFile(slicer.dicomDatabase, derivedItem) except AttributeError: # no derived items or some other attribute error pass self.removeObserver(slicer.mrmlScene, slicer.vtkMRMLScene.NodeAddedEvent, onNodeAdded); loadedFileParameters = {} loadedFileParameters['nodeIDs'] = loadedNodeIDs slicer.app.ioManager().emitNewFileLoaded(loadedFileParameters) self.progress.close() self.progress = None if loadingResult: qt.QMessageBox.warning(slicer.util.mainWindow(), 'DICOM loading', loadingResult) if not self.browserPersistent: self.close() return
def test_Part1DICOM(self, enableScreenshotsFlag=0, screenshotScaleFactor=1): """ Test the DICOM part of the test using the head atlas """ self.enableScreenshots = enableScreenshotsFlag self.screenshotScaleFactor = screenshotScaleFactor import os self.delayDisplay("Starting the DICOM test") # # first, get the data - a zip file of dicom data # import urllib downloads = (('http://slicer.kitware.com/midas3/download?items=124183', 'dataset1_Thorax_Abdomen.zip'), ) self.delayDisplay("Downloading") for url, name in downloads: filePath = slicer.app.temporaryPath + '/' + name if not os.path.exists(filePath) or os.stat(filePath).st_size == 0: self.delayDisplay('Requesting download %s from %s...\n' % (name, url)) urllib.urlretrieve(url, filePath) self.delayDisplay('Finished with download\n') self.delayDisplay("Unzipping") dicomFilesDirectory = slicer.app.temporaryPath + '/dicomFiles' qt.QDir().mkpath(dicomFilesDirectory) slicer.app.applicationLogic().Unzip(filePath, dicomFilesDirectory) try: self.delayDisplay("Switching to temp database directory") tempDatabaseDirectory = slicer.app.temporaryPath + '/tempDICOMDatabase' qt.QDir().mkpath(tempDatabaseDirectory) if slicer.dicomDatabase: originalDatabaseDirectory = os.path.split( slicer.dicomDatabase.databaseFilename)[0] else: originalDatabaseDirectory = None settings = qt.QSettings() settings.setValue('DatabaseDirectory', tempDatabaseDirectory) dicomWidget = slicer.modules.dicom.widgetRepresentation().self() dicomWidget.onDatabaseDirectoryChanged(tempDatabaseDirectory) self.delayDisplay('Importing DICOM') mainWindow = slicer.util.mainWindow() mainWindow.moduleSelector().selectModule('DICOM') indexer = ctk.ctkDICOMIndexer() indexer.addDirectory(slicer.dicomDatabase, dicomFilesDirectory, None) indexer.waitForImportFinished() dicomWidget.detailsPopup.open() # load the data by series UID dicomWidget.detailsPopup.offerLoadables( '1.3.12.2.1107.5.1.4.50025.30000005060811542834300000776', 'Series') dicomWidget.detailsPopup.examineForLoading() self.delayDisplay('Loading Selection') dicomWidget.detailsPopup.loadCheckedLoadables() self.takeScreenshot('LoadingADICOMVolume-Loaded', 'Loaded DICOM Volume', -1) layoutManager = slicer.app.layoutManager() redWidget = layoutManager.sliceWidget('Red') self.clickAndDrag(redWidget, start=(10, 10), end=(10, 40)) self.clickAndDrag(redWidget, start=(10, 10), end=(40, 10)) self.takeScreenshot('LoadingADICOMVolume-WL', 'Changed level and window', -1) redWidget.sliceController().setSliceLink(True) redWidget.sliceController().setSliceVisible(True) self.takeScreenshot('LoadingADICOMVolume-LinkView', 'Linked and visible', -1) self.clickAndDrag(redWidget, button='Right', start=(10, 10), end=(10, 40)) self.takeScreenshot('LoadingADICOMVolume-Zoom', 'Zoom', -1) threeDView = layoutManager.threeDWidget(0).threeDView() self.clickAndDrag(threeDView) self.takeScreenshot('LoadingADICOMVolume-Rotate', 'Rotate', -1) threeDView.resetFocalPoint() self.takeScreenshot('LoadingADICOMVolume-Center', 'Center the view', -1) layoutManager.setLayout(slicer.vtkMRMLLayoutNode. SlicerLayoutConventionalWidescreenView) self.takeScreenshot('LoadingADICOMVolume-ConventionalWidescreen', 'Conventional Widescreen Layout', -1) slicer.util.mainWindow().moduleSelector().selectModule( 'VolumeRendering') self.takeScreenshot('VolumeRendering-Module', 'Volume Rendering', -1) volumeRenderingWidgetRep = slicer.modules.volumerendering.widgetRepresentation( ) abdomenVolume = slicer.mrmlScene.GetFirstNodeByName( '6: CT_Thorax_Abdomen') volumeRenderingWidgetRep.setMRMLVolumeNode(abdomenVolume) self.takeScreenshot('VolumeRendering-SelectVolume', 'Select the volume 6: CT_Thorax_Abdomen', -1) presetsScene = slicer.modules.volumerendering.logic( ).GetPresetsScene() ctCardiac3 = presetsScene.GetFirstNodeByName('CT-Cardiac3') volumeRenderingWidgetRep.applyPreset(ctCardiac3) self.takeScreenshot('VolumeRendering-SelectPreset', 'Select the Preset CT-Cardiac-3') self.delayDisplay('Skipping: Select VTK CPU Ray Casting') volumeRenderingNode = slicer.mrmlScene.GetFirstNodeByName( 'VolumeRendering') volumeRenderingNode.SetVisibility(1) self.takeScreenshot('VolumeRendering-ViewRendering', 'View Volume Rendering', -1) self.delayDisplay('Skipping Move the Shift slider') redWidget.sliceController().setSliceVisible(False) self.takeScreenshot('VolumeRendering-SlicesOff', 'Turn off visibility of slices in 3D', -1) threeDView = layoutManager.threeDWidget(0).threeDView() self.clickAndDrag(threeDView) self.takeScreenshot('VolumeRendering-RotateVolumeRendering', 'Rotate volume rendered image', -1) volumeRenderingNode.SetVisibility(0) self.takeScreenshot('VolumeRendering-TurnOffVolumeRendering', 'Turn off volume rendered image', -1) volumeRenderingNode.SetCroppingEnabled(1) annotationROI = slicer.mrmlScene.GetFirstNodeByName( 'AnnotationROI') annotationROI.SetDisplayVisibility(1) self.takeScreenshot('VolumeRendering-DisplayROI', 'Enable cropping and display ROI', -1) redWidget.sliceController().setSliceVisible(True) self.takeScreenshot('VolumeRendering-SlicesOn', 'Turn on visibility of slices in 3D', -1) annotationROI.SetXYZ(-79.61, 154.16, -232.591) annotationROI.SetRadiusXYZ(43.4, 65.19, 70.5) self.takeScreenshot('VolumeRendering-SizedROI', 'Position the ROI over a kidney', -1) volumeRenderingNode.SetVisibility(1) self.takeScreenshot('VolumeRendering-ROIRendering', 'ROI volume rendered', -1) annotationROI.SetXYZ(15, 146, -186) annotationROI.SetRadiusXYZ(138, 57, 61) self.takeScreenshot('VolumeRendering-BothKidneys', 'Rendered both kidneys', -1) self.delayDisplay('Test passed!') except Exception, e: import traceback traceback.print_exc() self.delayDisplay('Test caused exception!\n' + str(e))
def DoIt(inputDir, rgbDir, outputDir): # # Read the input DICOM series as a volume # dcmList = [] for dcm in os.listdir(inputDir): if len(dcm) - dcm.rfind('.dcm') == 4: dcmList.append(inputDir + '/' + dcm) scalarVolumePlugin = slicer.modules.dicomPlugins[ 'DICOMScalarVolumePlugin']() print 'Will examine: ', dcmList indexer = ctk.ctkDICOMIndexer() indexer.addDirectory(slicer.dicomDatabase, inputDir) indexer.waitForImportFinished() loadables = scalarVolumePlugin.examine([dcmList]) if len(loadables) == 0: print 'Could not parse the DICOM Study!' exit() inputVolume = scalarVolumePlugin.load(loadables[0]) sNode = slicer.vtkMRMLVolumeArchetypeStorageNode() ''' sNode.ResetFileNameList() for f in loadables[0].files: sNode.AddFileName(f) sNode.SetFileName(loadables[0].files[0]) sNode.SetSingleFile(0) inputVolume = slicer.vtkMRMLScalarVolumeNode() sNode.ReadData(inputVolume) ''' sNode.SetWriteFileFormat('nrrd') sNode.SetFileName(os.path.join(outputDir, 'input_volume.nrrd')) sNode.WriteData(inputVolume) # # Order the input RGBs and rename in a temp directory # rgbList = [] for rgb in os.listdir(rgbDir): if len(rgb) - rgb.rfind('.bmp') == 4: rgbList.append(rgb) tmpDir = slicer.app.settings().value('Modules/TemporaryDirectory') tmpDir = tmpDir + '/PNGStackLabelConverter' if not os.path.exists(tmpDir): os.mkdir(tmpDir) oldFiles = os.listdir(tmpDir) # just in case there is anything in that directory for f in oldFiles: os.unlink(tmpDir + '/' + f) rgbOrdered = [None] * len(loadables[0].files) rgbCnt = 0 rgbExt = rgbList[0][rgbList[0].rfind('.') + 1:len(rgbList[0])] print 'Extension for RGBs: ', rgbExt dcmFileList = loadables[0].files rgbRenamedList = [] print 'Number of dcm files: ', len(dcmFileList), ' and rgb files: ', len( rgbOrdered) dcmIdx = 0 for dcm in dcmFileList: rgbIdx = 0 for rgb in rgbList: dcmPrefix = dcm[dcm.rfind('/') + 1:dcm.rfind('.')] if rgb.find(dcmPrefix) != -1: name = string.zfill(str(dcmIdx), 5) rgbCnt = rgbCnt + 1 src = rgbDir + '/' + rgb dest = tmpDir + '/' + name + '.' + rgbExt rgbRenamedList.append(dest) shutil.copy(src, dest) break rgbIdx = rgbIdx + 1 # remove the matched DICOM file from the list if rgbIdx == len(rgbList): print('ERROR: failed to find matching label file for DICOM file ' + dcm) return del rgbList[rgbIdx] dcmIdx = dcmIdx + 1 if len(rgbRenamedList) == 0: print 'Could not parse the DICOM Study!' return sNode = slicer.vtkMRMLVolumeArchetypeStorageNode() sNode.ResetFileNameList() for f in rgbRenamedList: sNode.AddFileName(f) sNode.SetFileName(rgbRenamedList[0]) sNode.SetSingleFile(0) inputRGBVolume = slicer.vtkMRMLVectorVolumeNode() sNode.ReadData(inputRGBVolume) # run the filter # - extract the RGB portions extract = vtk.vtkImageExtractComponents() extract.SetComponents(0, 1, 2) if vtk.vtkVersion().GetVTKMajorVersion() < 6: extract.SetInput(inputRGBVolume.GetImageData()) else: extract.SetInputData(inputRGBVolume.GetImageData()) luminance = vtk.vtkImageLuminance() if vtk.vtkVersion().GetVTKMajorVersion() < 6: luminance.SetInput(extract.GetOutput()) else: luminance.SetInputData(extract.GetOutput()) cast = vtk.vtkImageCast() if vtk.vtkVersion().GetVTKMajorVersion() < 6: cast.SetInput(luminance.GetOutput()) else: cast.SetInputData(luminance.GetOutput()) cast.SetOutputScalarTypeToShort() cast.GetOutput().Update() ijkToRAS = vtk.vtkMatrix4x4() inputVolume.GetIJKToRASMatrix(ijkToRAS) outputLabel = slicer.vtkMRMLLabelMapVolumeNode() outputLabel.SetIJKToRASMatrix(ijkToRAS) outputLabel.SetAndObserveImageData(cast.GetOutput()) reportingLogic = slicer.modules.reporting.logic() displayNode = slicer.vtkMRMLLabelMapVolumeDisplayNode() displayNode.SetAndObserveColorNodeID( reportingLogic.GetDefaultColorNode().GetID()) slicer.mrmlScene.AddNode(displayNode) outputLabel.SetAndObserveDisplayNodeID(displayNode.GetID()) sNode.SetWriteFileFormat('nrrd') sNode.SetFileName(os.path.join(outputDir, 'label_output.nrrd')) sNode.WriteData(outputLabel) # save as DICOM SEG labelCollection = vtk.vtkCollection() labelCollection.AddItem(outputLabel) slicer.mrmlScene.AddNode(inputVolume) outputLabel.SetAttribute('AssociatedNodeID', inputVolume.GetID()) slicer.mrmlScene.AddNode(outputLabel) # initialize the DICOM DB for Reporting logic settings = qt.QSettings() dbFileName = settings.value('DatabaseDirectory', '') if dbFileName == '': print('ERROR: database must be initialized') else: dbFileName = dbFileName + '/ctkDICOM.sql' reportingLogic.InitializeDICOMDatabase(dbFileName) reportingLogic.DicomSegWrite(labelCollection, outputDir)
def test_Part1DICOM(self, enableScreenshotsFlag=0, screenshotScaleFactor=1): """ Test the DICOM part of the test using the head atlas """ self.enableScreenshots = enableScreenshotsFlag self.screenshotScaleFactor = screenshotScaleFactor import os self.delayDisplay("Starting the DICOM test") # # first, get the data - a zip file of dicom data # import urllib downloads = (("http://slicer.kitware.com/midas3/download?items=124183", "dataset1_Thorax_Abdomen.zip"),) self.delayDisplay("Downloading") for url, name in downloads: filePath = slicer.app.temporaryPath + "/" + name if not os.path.exists(filePath) or os.stat(filePath).st_size == 0: self.delayDisplay("Requesting download %s from %s...\n" % (name, url)) urllib.urlretrieve(url, filePath) self.delayDisplay("Finished with download\n") self.delayDisplay("Unzipping") dicomFilesDirectory = slicer.app.temporaryPath + "/dicomFiles" qt.QDir().mkpath(dicomFilesDirectory) slicer.app.applicationLogic().Unzip(filePath, dicomFilesDirectory) try: self.delayDisplay("Switching to temp database directory") tempDatabaseDirectory = slicer.app.temporaryPath + "/tempDICOMDatabase" qt.QDir().mkpath(tempDatabaseDirectory) if slicer.dicomDatabase: originalDatabaseDirectory = os.path.split(slicer.dicomDatabase.databaseFilename)[0] else: originalDatabaseDirectory = None settings = qt.QSettings() settings.setValue("DatabaseDirectory", tempDatabaseDirectory) dicomWidget = slicer.modules.dicom.widgetRepresentation().self() dicomWidget.onDatabaseDirectoryChanged(tempDatabaseDirectory) self.delayDisplay("Importing DICOM") mainWindow = slicer.util.mainWindow() mainWindow.moduleSelector().selectModule("DICOM") indexer = ctk.ctkDICOMIndexer() indexer.addDirectory(slicer.dicomDatabase, dicomFilesDirectory, None) indexer.waitForImportFinished() dicomWidget.detailsPopup.open() # load the data by series UID dicomWidget.detailsPopup.offerLoadables("1.3.12.2.1107.5.1.4.50025.30000005060811542834300000776", "Series") dicomWidget.detailsPopup.examineForLoading() self.delayDisplay("Loading Selection") dicomWidget.detailsPopup.loadCheckedLoadables() self.takeScreenshot("LoadingADICOMVolume-Loaded", "Loaded DICOM Volume", -1) layoutManager = slicer.app.layoutManager() redWidget = layoutManager.sliceWidget("Red") self.clickAndDrag(redWidget, start=(10, 10), end=(10, 40)) self.clickAndDrag(redWidget, start=(10, 10), end=(40, 10)) self.takeScreenshot("LoadingADICOMVolume-WL", "Changed level and window", -1) redWidget.sliceController().setSliceLink(True) redWidget.sliceController().setSliceVisible(True) self.takeScreenshot("LoadingADICOMVolume-LinkView", "Linked and visible", -1) self.clickAndDrag(redWidget, button="Right", start=(10, 10), end=(10, 40)) self.takeScreenshot("LoadingADICOMVolume-Zoom", "Zoom", -1) threeDView = layoutManager.threeDWidget(0).threeDView() self.clickAndDrag(threeDView) self.takeScreenshot("LoadingADICOMVolume-Rotate", "Rotate", -1) threeDView.resetFocalPoint() self.takeScreenshot("LoadingADICOMVolume-Center", "Center the view", -1) layoutManager.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalWidescreenView) self.takeScreenshot("LoadingADICOMVolume-ConventionalWidescreen", "Conventional Widescreen Layout", -1) slicer.util.mainWindow().moduleSelector().selectModule("VolumeRendering") self.takeScreenshot("VolumeRendering-Module", "Volume Rendering", -1) volumeRenderingWidgetRep = slicer.modules.volumerendering.widgetRepresentation() abdomenVolume = slicer.mrmlScene.GetFirstNodeByName("6: CT_Thorax_Abdomen") volumeRenderingWidgetRep.setMRMLVolumeNode(abdomenVolume) self.takeScreenshot("VolumeRendering-SelectVolume", "Select the volume 6: CT_Thorax_Abdomen", -1) presetsScene = slicer.modules.volumerendering.logic().GetPresetsScene() ctCardiac3 = presetsScene.GetFirstNodeByName("CT-Cardiac3") volumeRenderingWidgetRep.applyPreset(ctCardiac3) self.takeScreenshot("VolumeRendering-SelectPreset", "Select the Preset CT-Cardiac-3") self.delayDisplay("Skipping: Select VTK CPU Ray Casting") volumeRenderingNode = slicer.mrmlScene.GetFirstNodeByName("VolumeRendering") volumeRenderingNode.SetVisibility(1) self.takeScreenshot("VolumeRendering-ViewRendering", "View Volume Rendering", -1) self.delayDisplay("Skipping Move the Shift slider") redWidget.sliceController().setSliceVisible(False) self.takeScreenshot("VolumeRendering-SlicesOff", "Turn off visibility of slices in 3D", -1) threeDView = layoutManager.threeDWidget(0).threeDView() self.clickAndDrag(threeDView) self.takeScreenshot("VolumeRendering-RotateVolumeRendering", "Rotate volume rendered image", -1) volumeRenderingNode.SetVisibility(0) self.takeScreenshot("VolumeRendering-TurnOffVolumeRendering", "Turn off volume rendered image", -1) volumeRenderingNode.SetCroppingEnabled(1) annotationROI = slicer.mrmlScene.GetFirstNodeByName("AnnotationROI") annotationROI.SetDisplayVisibility(1) self.takeScreenshot("VolumeRendering-DisplayROI", "Enable cropping and display ROI", -1) redWidget.sliceController().setSliceVisible(True) self.takeScreenshot("VolumeRendering-SlicesOn", "Turn on visibility of slices in 3D", -1) annotationROI.SetXYZ(-79.61, 154.16, -232.591) annotationROI.SetRadiusXYZ(43.4, 65.19, 70.5) self.takeScreenshot("VolumeRendering-SizedROI", "Position the ROI over a kidney", -1) volumeRenderingNode.SetVisibility(1) self.takeScreenshot("VolumeRendering-ROIRendering", "ROI volume rendered", -1) annotationROI.SetXYZ(15, 146, -186) annotationROI.SetRadiusXYZ(138, 57, 61) self.takeScreenshot("VolumeRendering-BothKidneys", "Rendered both kidneys", -1) self.delayDisplay("Test passed!") except Exception, e: import traceback traceback.print_exc() self.delayDisplay("Test caused exception!\n" + str(e))
def onHButtonClicked(self): i = ctk.ctkDICOMIndexer() i.addDirectory(slicer.dicomDatabase, '/Users/Research/Documents/DICOM Files/TAC MONSERRAT') m = slicer.util.mainWindow() m.moduleSelector().selectModule('DICOM')
def importDICOM(self, dicomDatabase, dicomFilesDirectory): dicomWidget = slicer.modules.dicom.widgetRepresentation().self() indexer = ctk.ctkDICOMIndexer() indexer.addDirectory(dicomDatabase, dicomFilesDirectory, None) indexer.waitForImportFinished()
def test_ReportingAIMRoundTrip(self): print ("CTEST_FULL_OUTPUT") """ Load the data using DICOM module """ import os self.delayDisplay("Starting the DICOM test") # # first, get the data - a zip file of dicom data # import urllib downloads = (("http://slicer.kitware.com/midas3/download?items=10881", "JANCT-CT.zip"),) self.delayDisplay("Downloading") for url, name in downloads: filePath = slicer.app.temporaryPath + "/" + name if not os.path.exists(filePath) or os.stat(filePath).st_size == 0: self.delayDisplay("Requesting download %s from %s...\n" % (name, url)) urllib.urlretrieve(url, filePath) self.delayDisplay("Finished with download\n") reportingTempDir = slicer.app.temporaryPath + "/Reporting" print ("Temporary directory location: " + reportingTempDir) qt.QDir().mkpath(reportingTempDir) dicomFilesDirectory = reportingTempDir + "/dicomFiles" self.cleanupDir(dicomFilesDirectory) qt.QDir().mkpath(dicomFilesDirectory) slicer.app.applicationLogic().Unzip(filePath, dicomFilesDirectory) try: self.delayDisplay("Switching to temp database directory") tempDatabaseDirectory = reportingTempDir + "/tempDICOMDatbase" qt.QDir().mkpath(tempDatabaseDirectory) self.cleanupDir(tempDatabaseDirectory) if slicer.dicomDatabase: self.originalDatabaseDirectory = os.path.split(slicer.dicomDatabase.databaseFilename)[0] else: self.originalDatabaseDirectory = None settings = qt.QSettings() settings.setValue("DatabaseDirectory", tempDatabaseDirectory) dicomWidget = slicer.modules.dicom.widgetRepresentation().self() dicomWidget.onDatabaseDirectoryChanged(tempDatabaseDirectory) self.delayDisplay("Importing DICOM") mainWindow = slicer.util.mainWindow() mainWindow.moduleSelector().selectModule("DICOM") # dicomWidget.dicomApp.suspendModel() indexer = ctk.ctkDICOMIndexer() indexer.addDirectory(slicer.dicomDatabase, dicomFilesDirectory, None) indexer.waitForImportFinished() patient = slicer.dicomDatabase.patients()[0] studies = slicer.dicomDatabase.studiesForPatient(patient) series = [slicer.dicomDatabase.seriesForStudy(study) for study in studies] seriesUIDs = [uid for uidList in series for uid in uidList] dicomWidget.detailsPopup.offerLoadables(seriesUIDs, "SeriesUIDList") dicomWidget.detailsPopup.examineForLoading() loadablesByPlugin = dicomWidget.detailsPopup.loadablesByPlugin self.delayDisplay("Loading Selection") dicomWidget.detailsPopup.loadCheckedLoadables() # initialize the module with the report and volume volumes = slicer.util.getNodes("vtkMRMLScalarVolumeNode*") self.assertTrue(len(volumes) == 1) (name, volume) = volumes.items()[0] self.delayDisplay("Loaded volume name %s" % volume.GetName()) self.delayDisplay("Configure Module") mainWindow = slicer.util.mainWindow() mainWindow.moduleSelector().selectModule("Reporting") reporting = slicer.modules.reporting.widgetRepresentation().self() report = slicer.mrmlScene.CreateNodeByClass("vtkMRMLReportingReportNode") report.SetReferenceCount(report.GetReferenceCount() - 1) slicer.mrmlScene.AddNode(report) report.SetFindingLabel(7) reporting.reportSelector.setCurrentNode(report) self.delayDisplay("Setting volume to %s" % volume.GetName()) reporting.volumeSelector.setCurrentNode(volume) slicer.app.processEvents() # place some markups and add a segmentation label # add fiducial fidNode = slicer.vtkMRMLAnnotationFiducialNode() fidName = "AIM Round Trip Test Fiducial" fidNode.SetName(fidName) fidNode.SetSelected(1) fidNode.SetDisplayVisibility(1) fidNode.SetLocked(0) # TODO: ask Nicole where this is assigned in the regular workflow fidNode.SetAttribute("AssociatedNodeID", volume.GetID()) print ("Calling set fid coords") startCoords = [15.8, 70.8, -126.7] fidNode.SetFiducialCoordinates(startCoords[0], startCoords[1], startCoords[2]) print ("Starting fiducial coordinates: " + str(startCoords)) slicer.mrmlScene.AddNode(fidNode) # add ruler rulerNode = slicer.vtkMRMLAnnotationRulerNode() rulerNode.SetName("Test Ruler") m = vtk.vtkMatrix4x4() volume.GetIJKToRASMatrix(m) ijk0 = [0, 0, 1, 1] ijk1 = [50, 50, 1, 1] ras0 = m.MultiplyPoint(ijk0) ras1 = m.MultiplyPoint(ijk1) rulerNode.SetPosition1(19.386751174926758, 68.528785705566406, -127.69000244140625) rulerNode.SetPosition2(132.72709655761719, -34.349384307861328, -127.69000244140625) rulerNode.SetAttribute("AssociatedNodeID", volume.GetID()) slicer.mrmlScene.AddNode(rulerNode) slicer.app.processEvents() # add label node volumesLogic = slicer.modules.volumes.logic() labelNode = volumesLogic.CreateAndAddLabelVolume(slicer.mrmlScene, volume, "Segmentation") labelDisplayNode = labelNode.GetDisplayNode() labelDisplayNode.SetAndObserveColorNodeID("vtkMRMLColorTableNodeFileGenericAnatomyColors.txt") image = volume.GetImageData() thresh = vtk.vtkImageThreshold() if vtk.vtkVersion().GetVTKMajorVersion() < 6: thresh.SetInput(image) else: thresh.SetInputData(image) thresh.ThresholdBetween(10, 400) thresh.SetInValue(report.GetFindingLabel()) thresh.SetOutValue(0) thresh.Update() labelNode.SetAndObserveImageData(thresh.GetOutput()) reporting.segmentationSelector.setCurrentNode(labelNode) # Save the report exportDir = reportingTempDir + "/Output" qt.QDir().mkpath(exportDir) self.cleanupDir(exportDir) report.SetStorageDirectoryName(exportDir) reportingLogic = slicer.modules.reporting.logic() print ("Before saving report") reportingLogic.SaveReportToAIM(report) self.delayDisplay("Report saved") slicer.mrmlScene.Clear(0) # parse on patient level, find segmentation object, load and make sure # it matches the input # close the scene and load the report, check consistency # try to load back the saved AIM import glob print glob.glob(exportDir + "/*") xmlFiles = glob.glob(exportDir + "/*xml") print xmlFiles self.assertTrue(len(xmlFiles) == 1) reporting.importAIMFile = xmlFiles[0] reporting.onReportImport() self.delayDisplay("Report loaded from AIM! Test passed.") self.delayDisplay("Restoring original database directory") if self.originalDatabaseDirectory: dicomWidget.onDatabaseDirectoryChanged(self.originalDatabaseDirectory) except Exception, e: if self.originalDatabaseDirectory: dicomWidget.onDatabaseDirectoryChanged(self.originalDatabaseDirectory) import traceback traceback.print_exc() self.delayDisplay("Test caused exception!\n" + str(e)) self.assertTrue(False)
def ImportStudy(self,dicomDataDir): indexer = ctk.ctkDICOMIndexer() # Import study to database indexer.addDirectory( slicer.dicomDatabase, dicomDataDir ) indexer.waitForImportFinished()
def DoIt(inputDir, labelFile, outputDir, forceLabel, forceResample): dbDir1 = slicer.app.temporaryPath+'/LabelConverter' if not hasattr(slicer.modules, 'reporting'): print 'The Reporting module has not been loaded into Slicer, script cannot run!\n\tTry setting the --additional-module-path parameter.' sys.exit(1) reportingLogic = slicer.modules.reporting.logic() print('Temporary directory location: '+dbDir1) qt.QDir().mkpath(dbDir1) dbDir0 = None if slicer.dicomDatabase: dbDir0 = os.path.split(slicer.dicomDatabase.databaseFilename)[0] dicomWidget = slicer.modules.dicom.widgetRepresentation().self() dicomWidget.onDatabaseDirectoryChanged(dbDir1) # import DICOM study indexer = ctk.ctkDICOMIndexer() indexer.addDirectory(slicer.dicomDatabase, inputDir, None) indexer.waitForImportFinished() print('DICOM import finished!') # # Read the input DICOM series as a volume # dcmList = [] for dcm in os.listdir(inputDir): if len(dcm)-dcm.rfind('.dcm') == 4: dcmList.append(inputDir+'/'+dcm) scalarVolumePlugin = slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']() loadables = scalarVolumePlugin.examine([dcmList]) if len(loadables) == 0: print 'Could not parse the DICOM Study!' sys.exit(1) inputVolume = scalarVolumePlugin.load(loadables[0]) print 'Input volume loaded! ID = ', inputVolume.GetID() # read the label volume labelVolume = slicer.vtkMRMLLabelMapVolumeNode() sNode = slicer.vtkMRMLVolumeArchetypeStorageNode() sNode.SetFileName(labelFile) sNode.ReadData(labelVolume) if forceLabel>0: # print('Forcing label to '+str(forceLabel)) labelImage = labelVolume.GetImageData() thresh = vtk.vtkImageThreshold() if vtk.vtkVersion().GetVTKMajorVersion() < 6: thresh.SetInput(labelImage) else: thresh.SetInputData(labelImage) thresh.ThresholdBetween(1, labelImage.GetScalarRange()[1]) thresh.SetInValue(int(forceLabel)) thresh.SetOutValue(0) thresh.ReplaceInOn() thresh.ReplaceOutOn() thresh.Update() labelImage = thresh.GetOutput() labelVolume.SetAndObserveImageData(labelImage) slicer.mrmlScene.AddNode(labelVolume) print 'Label volume added, id = ', labelVolume.GetID() # ensure that the label volume scalar type is unsigned short if labelVolume.GetImageData() != None: scalarType = labelVolume.GetImageData().GetScalarType() if scalarType != vtk.VTK_UNSIGNED_SHORT: print 'Label volume has pixel type of ',vtk.vtkImageScalarTypeNameMacro(scalarType),', casting to unsigned short' cast = vtk.vtkImageCast() cast.SetOutputScalarTypeToUnsignedShort() if vtk.vtkVersion().GetVTKMajorVersion() < 6: cast.SetInput(labelVolume.GetImageData()) cast.Update() labelVolume.SetAndObserveImageData(cast.GetOutput()) else: cast.SetInputConnection(labelVolume.GetImageDataConnection()) cast.Update() labelVolume.SetImageDataConnection(cast.GetOutputPort()) if labelVolume.GetImageData().GetScalarType() != vtk.VTK_UNSIGNED_SHORT: print 'Failed to cast label volume to unsigned short, type is ', vtk.vtkImageScalarTypeNameMacro(labelVolume.GetImageData().GetScalarType()) sys.exit(1) volumesLogic = slicer.modules.volumes.logic() geometryCheckString = volumesLogic.CheckForLabelVolumeValidity(inputVolume, labelVolume) if geometryCheckString != "": # has the user specified that forced resampling is okay? if forceResample == False: print 'Label volume mismatch with input volume:\n',geometryCheckString,'\nForced resample not specified, aborting. Re-run with --force option to ignore geometric inconsistencies' sys.exit(1) # resample label to the input volume raster resampledLabel = slicer.vtkMRMLLabelMapVolumeNode() slicer.mrmlScene.AddNode(resampledLabel) print 'Resampled label added, id = ', resampledLabel.GetID() resampledLabel = volumesLogic.ResampleVolumeToReferenceVolume(labelVolume, inputVolume) labelVolume = resampledLabel displayNode = slicer.vtkMRMLLabelMapVolumeDisplayNode() displayNode.SetAndObserveColorNodeID(reportingLogic.GetDefaultColorNode().GetID()) slicer.mrmlScene.AddNode(displayNode) labelVolume.SetAttribute('AssociatedNodeID',inputVolume.GetID()) labelVolume.SetAndObserveDisplayNodeID(displayNode.GetID()) # initialize the DICOM DB for Reporting logic, save as DICOM SEG labelCollection = vtk.vtkCollection() labelCollection.AddItem(labelVolume) print('About to write DICOM SEG!') dbFileName = slicer.dicomDatabase.databaseFilename reportingLogic.InitializeDICOMDatabase(dbFileName) reportingLogic.DicomSegWrite(labelCollection, outputDir) dicomWidget.onDatabaseDirectoryChanged(dbDir0) exit()
def DoIt(inputDir, labelFile, outputDir, forceLabel): dbDir1 = slicer.app.temporaryPath+'/LabelConverter' reportingLogic = slicer.modules.reporting.logic() print('Temporary directory location: '+dbDir1) qt.QDir().mkpath(dbDir1) dbDir0 = None if slicer.dicomDatabase: dbDir0 = os.path.split(slicer.dicomDatabase.databaseFilename)[0] try: dicomWidget = slicer.modules.dicom.widgetRepresentation().self() dicomWidget.onDatabaseDirectoryChanged(dbDir1) # import DICOM study indexer = ctk.ctkDICOMIndexer() indexer.addDirectory(slicer.dicomDatabase, inputDir, None) indexer.waitForImportFinished() print('DICOM import finished!') # # Read the input DICOM series as a volume # dcmList = [] for dcm in os.listdir(inputDir): if len(dcm)-dcm.rfind('.dcm') == 4: dcmList.append(inputDir+'/'+dcm) scalarVolumePlugin = slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']() loadables = scalarVolumePlugin.examine([dcmList]) if len(loadables) == 0: print 'Could not parse the DICOM Study!' exit() inputVolume = scalarVolumePlugin.load(loadables[0]) slicer.mrmlScene.AddNode(inputVolume) print('Input volume loaded!') # read the label volume labelVolume = slicer.vtkMRMLScalarVolumeNode() sNode = slicer.vtkMRMLVolumeArchetypeStorageNode() sNode.SetFileName(labelFile) sNode.ReadData(labelVolume) labelVolume.LabelMapOn() if forceLabel>0: print('Forcing label to '+str(forceLabel)) labelImage = labelVolume.GetImageData() thresh = vtk.vtkImageThreshold() thresh.SetInput(labelImage) thresh.ThresholdBetween(1, labelImage.GetScalarRange()[1]) thresh.SetInValue(int(forceLabel)) thresh.SetOutValue(0) thresh.ReplaceInOn() thresh.ReplaceOutOn() thresh.Update() labelImage = thresh.GetOutput() labelVolume.SetAndObserveImageData(labelImage) slicer.mrmlScene.AddNode(labelVolume) # resample label to the input volume raster resampledLabel = slicer.vtkMRMLScalarVolumeNode() slicer.mrmlScene.AddNode(resampledLabel) eye = slicer.vtkMRMLLinearTransformNode() slicer.mrmlScene.AddNode(eye) parameters = {} parameters['inputVolume'] = labelVolume.GetID() parameters['referenceVolume'] = inputVolume.GetID() parameters['outputVolume'] = resampledLabel.GetID() parameters['warpTransform'] = eye.GetID() parameters['interpolationMode'] = 'NearestNeighbor' parameters['pixelType'] = 'ushort' cliNode = None cliNode = slicer.cli.run(slicer.modules.brainsresample, None, parameters, 1) labelVolume = resampledLabel displayNode = slicer.vtkMRMLLabelMapVolumeDisplayNode() displayNode.SetAndObserveColorNodeID(reportingLogic.GetDefaultColorNode().GetID()) slicer.mrmlScene.AddNode(displayNode) labelVolume.SetAttribute('AssociatedNodeID',inputVolume.GetID()) labelVolume.LabelMapOn() labelVolume.SetAndObserveDisplayNodeID(displayNode.GetID()) # initialize the DICOM DB for Reporting logic, save as DICOM SEG labelCollection = vtk.vtkCollection() labelCollection.AddItem(labelVolume) print('About to write DICOM SEG!') dbFileName = slicer.dicomDatabase.databaseFilename reportingLogic.InitializeDICOMDatabase(dbFileName) reportingLogic.DicomSegWrite(labelCollection, outputDir) except: print('Error occurred!') dicomWidget.onDatabaseDirectoryChanged(dbDir0) exit()
def section_LoadDicomData(self): try: # Download and unzip test CT DICOM data import urllib downloads = ( ('http://slicer.kitware.com/midas3/download/item/137843/TestDicomCT.zip', self.dicomZipFilePath), ) downloaded = 0 for url,filePath in downloads: if not os.path.exists(filePath) or os.stat(filePath).st_size == 0: if downloaded == 0: self.delayDisplay('Downloading input data to folder\n' + self.dicomZipFilePath + '.\n\n It may take a few minutes...',self.delayMs) print('Requesting download from %s...' % (url)) urllib.urlretrieve(url, filePath) downloaded += 1 else: self.delayDisplay('Input data has been found in folder ' + self.dicomZipFilePath, self.delayMs) if downloaded > 0: self.delayDisplay('Downloading input data finished',self.delayMs) numOfFilesInDicomDataDir = len([name for name in os.listdir(self.dicomDataDir) if os.path.isfile(self.dicomDataDir + '/' + name)]) if (numOfFilesInDicomDataDir != self.expectedNumOfFilesInDicomDataDir): slicer.app.applicationLogic().Unzip(self.dicomZipFilePath, self.dicomDataDir) self.delayDisplay("Unzipping done",self.delayMs) numOfFilesInDicomDataDirTest = len([name for name in os.listdir(self.dicomDataDir) if os.path.isfile(self.dicomDataDir + '/' + name)]) self.assertTrue( numOfFilesInDicomDataDirTest == self.expectedNumOfFilesInDicomDataDir ) # Open test database and empty it qt.QDir().mkpath(self.dicomDatabaseDir) if slicer.dicomDatabase: self.originalDatabaseDirectory = os.path.split(slicer.dicomDatabase.databaseFilename)[0] else: self.originalDatabaseDirectory = None settings = qt.QSettings() settings.setValue('DatabaseDirectory', self.dicomDatabaseDir) dicomWidget = slicer.modules.dicom.widgetRepresentation().self() dicomWidget.onDatabaseDirectoryChanged(self.dicomDatabaseDir) self.assertTrue( slicer.dicomDatabase.isOpen ) # Import test data in database indexer = ctk.ctkDICOMIndexer() self.assertTrue( indexer ) indexer.addDirectory( slicer.dicomDatabase, self.dicomDataDir ) self.assertTrue( len(slicer.dicomDatabase.patients()) == 1 ) self.assertTrue( slicer.dicomDatabase.patients()[0] ) # Load test data numOfScalarVolumeNodesBeforeLoad = len( slicer.util.getNodes('vtkMRMLScalarVolumeNode*') ) numOfSubjectHierarchyNodesBeforeLoad = len( slicer.util.getNodes('vtkMRMLSubjectHierarchyNode*') ) patient = slicer.dicomDatabase.patients()[0] studies = slicer.dicomDatabase.studiesForPatient(patient) series = [slicer.dicomDatabase.seriesForStudy(study) for study in studies] seriesUIDs = [uid for uidList in series for uid in uidList] dicomWidget.detailsPopup.offerLoadables(seriesUIDs, 'SeriesUIDList') dicomWidget.detailsPopup.loadCheckedLoadables() self.assertTrue( len( slicer.util.getNodes('vtkMRMLScalarVolumeNode*') ) == numOfScalarVolumeNodesBeforeLoad + 1 ) self.assertTrue( len( slicer.util.getNodes('vtkMRMLSubjectHierarchyNode*') ) == numOfSubjectHierarchyNodesBeforeLoad + 3 ) except Exception, e: import traceback traceback.print_exc() self.delayDisplay('Test caused exception!\n' + str(e),self.delayMs*2)
def test_ReportingAIMRoundTrip(self): print("CTEST_FULL_OUTPUT") """ Load the data using DICOM module """ import os self.delayDisplay("Starting the DICOM test") # # first, get the data - a zip file of dicom data # import urllib downloads = ( ('http://slicer.kitware.com/midas3/download?items=10881', 'JANCT-CT.zip'), ) self.delayDisplay("Downloading") for url,name in downloads: filePath = slicer.app.temporaryPath + '/' + name if not os.path.exists(filePath) or os.stat(filePath).st_size == 0: self.delayDisplay('Requesting download %s from %s...\n' % (name, url)) urllib.urlretrieve(url, filePath) self.delayDisplay('Finished with download\n') reportingTempDir = slicer.app.temporaryPath+'/Reporting' print('Temporary directory location: '+reportingTempDir) qt.QDir().mkpath(reportingTempDir) dicomFilesDirectory = reportingTempDir + '/dicomFiles' self.cleanupDir(dicomFilesDirectory) qt.QDir().mkpath(dicomFilesDirectory) slicer.app.applicationLogic().Unzip(filePath, dicomFilesDirectory) try: self.delayDisplay("Switching to temp database directory") tempDatabaseDirectory = reportingTempDir + '/tempDICOMDatbase' qt.QDir().mkpath(tempDatabaseDirectory) self.cleanupDir(tempDatabaseDirectory) if slicer.dicomDatabase: self.originalDatabaseDirectory = os.path.split(slicer.dicomDatabase.databaseFilename)[0] else: self.originalDatabaseDirectory = None settings = qt.QSettings() settings.setValue('DatabaseDirectory', tempDatabaseDirectory) dicomWidget = slicer.modules.dicom.widgetRepresentation().self() dicomWidget.onDatabaseDirectoryChanged(tempDatabaseDirectory) self.delayDisplay('Importing DICOM') mainWindow = slicer.util.mainWindow() mainWindow.moduleSelector().selectModule('DICOM') #dicomWidget.dicomApp.suspendModel() indexer = ctk.ctkDICOMIndexer() indexer.addDirectory(slicer.dicomDatabase, dicomFilesDirectory, None) indexer.waitForImportFinished() patient = slicer.dicomDatabase.patients()[0] studies = slicer.dicomDatabase.studiesForPatient(patient) series = [slicer.dicomDatabase.seriesForStudy(study) for study in studies] seriesUIDs = [uid for uidList in series for uid in uidList] dicomWidget.detailsPopup.offerLoadables(seriesUIDs, 'SeriesUIDList') dicomWidget.detailsPopup.examineForLoading() loadablesByPlugin = dicomWidget.detailsPopup.loadablesByPlugin self.delayDisplay('Loading Selection') dicomWidget.detailsPopup.loadCheckedLoadables() # initialize the module with the report and volume volumes = slicer.util.getNodes('vtkMRMLScalarVolumeNode*') self.assertTrue(len(volumes) == 1) (name,volume) = volumes.items()[0] self.delayDisplay('Loaded volume name %s' % volume.GetName()) self.delayDisplay('Configure Module') mainWindow = slicer.util.mainWindow() mainWindow.moduleSelector().selectModule('Reporting') reporting = slicer.modules.reporting.widgetRepresentation().self() report = slicer.mrmlScene.CreateNodeByClass('vtkMRMLReportingReportNode') report.SetReferenceCount(report.GetReferenceCount()-1) slicer.mrmlScene.AddNode(report) report.SetFindingLabel(7) reporting.reportSelector.setCurrentNode(report) self.delayDisplay('Setting volume to %s' % volume.GetName()) reporting.volumeSelector.setCurrentNode(volume) slicer.app.processEvents() # place some markups and add a segmentation label # add fiducial fidNode = slicer.vtkMRMLAnnotationFiducialNode() fidName = "AIM Round Trip Test Fiducial" fidNode.SetName(fidName) fidNode.SetSelected(1) fidNode.SetDisplayVisibility(1) fidNode.SetLocked(0) # TODO: ask Nicole where this is assigned in the regular workflow fidNode.SetAttribute('AssociatedNodeID',volume.GetID()) print("Calling set fid coords") startCoords = [15.8, 70.8, -126.7] fidNode.SetFiducialCoordinates(startCoords[0],startCoords[1],startCoords[2]) print("Starting fiducial coordinates: "+str(startCoords)) slicer.mrmlScene.AddNode(fidNode) # add ruler rulerNode = slicer.vtkMRMLAnnotationRulerNode() rulerNode.SetName('Test Ruler') m = vtk.vtkMatrix4x4() volume.GetIJKToRASMatrix(m) ijk0 = [0,0,1,1] ijk1 = [50,50,1,1] ras0 = m.MultiplyPoint(ijk0) ras1 = m.MultiplyPoint(ijk1) rulerNode.SetPosition1(19.386751174926758, 68.528785705566406, -127.69000244140625) rulerNode.SetPosition2(132.72709655761719, -34.349384307861328, -127.69000244140625) rulerNode.SetAttribute('AssociatedNodeID',volume.GetID()) slicer.mrmlScene.AddNode(rulerNode) slicer.app.processEvents() # add label node volumesLogic = slicer.modules.volumes.logic() labelNode = volumesLogic.CreateAndAddLabelVolume(slicer.mrmlScene, volume, "Segmentation") labelDisplayNode = labelNode.GetDisplayNode() labelDisplayNode.SetAndObserveColorNodeID('vtkMRMLColorTableNodeFileGenericAnatomyColors.txt') image = volume.GetImageData() thresh = vtk.vtkImageThreshold() if vtk.vtkVersion().GetVTKMajorVersion() < 6: thresh.SetInput(image) else: thresh.SetInputData(image) thresh.ThresholdBetween(10,400) thresh.SetInValue(report.GetFindingLabel()) thresh.SetOutValue(0) thresh.Update() labelNode.SetAndObserveImageData(thresh.GetOutput()) reporting.segmentationSelector.setCurrentNode(labelNode) # Save the report exportDir = reportingTempDir+'/Output' qt.QDir().mkpath(exportDir) self.cleanupDir(exportDir) report.SetStorageDirectoryName(exportDir) reportingLogic = slicer.modules.reporting.logic() print("Before saving report") reportingLogic.SaveReportToAIM(report) self.delayDisplay('Report saved') slicer.mrmlScene.Clear(0) # parse on patient level, find segmentation object, load and make sure # it matches the input # close the scene and load the report, check consistency # try to load back the saved AIM import glob print glob.glob(exportDir+'/*') xmlFiles = glob.glob(exportDir+'/*xml') print xmlFiles self.assertTrue(len(xmlFiles) == 1) reporting.importAIMFile = xmlFiles[0] reporting.onReportImport() self.delayDisplay('Report loaded from AIM! Test passed.') self.delayDisplay("Restoring original database directory") if self.originalDatabaseDirectory: dicomWidget.onDatabaseDirectoryChanged(self.originalDatabaseDirectory) except Exception, e: if self.originalDatabaseDirectory: dicomWidget.onDatabaseDirectoryChanged(self.originalDatabaseDirectory) import traceback traceback.print_exc() self.delayDisplay('Test caused exception!\n' + str(e)) self.assertTrue(False)
def section_LoadDicomData(self): try: # Download and unzip test CT DICOM data import urllib downloads = (( 'http://slicer.kitware.com/midas3/download/item/137843/TestDicomCT.zip', self.dicomZipFilePath), ) downloaded = 0 for url, filePath in downloads: if not os.path.exists(filePath) or os.stat( filePath).st_size == 0: if downloaded == 0: self.delayDisplay( 'Downloading input data to folder\n' + self.dicomZipFilePath + '.\n\n It may take a few minutes...', self.delayMs) print('Requesting download from %s...' % (url)) urllib.urlretrieve(url, filePath) downloaded += 1 else: self.delayDisplay( 'Input data has been found in folder ' + self.dicomZipFilePath, self.delayMs) if downloaded > 0: self.delayDisplay('Downloading input data finished', self.delayMs) numOfFilesInDicomDataDir = len([ name for name in os.listdir(self.dicomDataDir) if os.path.isfile(self.dicomDataDir + '/' + name) ]) if (numOfFilesInDicomDataDir != self.expectedNumOfFilesInDicomDataDir): slicer.app.applicationLogic().Unzip(self.dicomZipFilePath, self.dicomDataDir) self.delayDisplay("Unzipping done", self.delayMs) numOfFilesInDicomDataDirTest = len([ name for name in os.listdir(self.dicomDataDir) if os.path.isfile(self.dicomDataDir + '/' + name) ]) self.assertTrue(numOfFilesInDicomDataDirTest == self.expectedNumOfFilesInDicomDataDir) # Open test database and empty it qt.QDir().mkpath(self.dicomDatabaseDir) if slicer.dicomDatabase: self.originalDatabaseDirectory = os.path.split( slicer.dicomDatabase.databaseFilename)[0] else: self.originalDatabaseDirectory = None settings = qt.QSettings() settings.setValue('DatabaseDirectory', self.dicomDatabaseDir) dicomWidget = slicer.modules.dicom.widgetRepresentation().self() dicomWidget.onDatabaseDirectoryChanged(self.dicomDatabaseDir) self.assertTrue(slicer.dicomDatabase.isOpen) # Import test data in database indexer = ctk.ctkDICOMIndexer() self.assertTrue(indexer) indexer.addDirectory(slicer.dicomDatabase, self.dicomDataDir) self.assertTrue(len(slicer.dicomDatabase.patients()) == 1) self.assertTrue(slicer.dicomDatabase.patients()[0]) # Load test data numOfScalarVolumeNodesBeforeLoad = len( slicer.util.getNodes('vtkMRMLScalarVolumeNode*')) numOfSubjectHierarchyNodesBeforeLoad = len( slicer.util.getNodes('vtkMRMLSubjectHierarchyNode*')) patient = slicer.dicomDatabase.patients()[0] studies = slicer.dicomDatabase.studiesForPatient(patient) series = [ slicer.dicomDatabase.seriesForStudy(study) for study in studies ] seriesUIDs = [uid for uidList in series for uid in uidList] dicomWidget.detailsPopup.offerLoadables(seriesUIDs, 'SeriesUIDList') dicomWidget.detailsPopup.loadCheckedLoadables() self.assertTrue( len(slicer.util.getNodes('vtkMRMLScalarVolumeNode*')) == numOfScalarVolumeNodesBeforeLoad + 1) self.assertTrue( len(slicer.util.getNodes('vtkMRMLSubjectHierarchyNode*')) == numOfSubjectHierarchyNodesBeforeLoad + 3) except Exception, e: import traceback traceback.print_exc() self.delayDisplay('Test caused exception!\n' + str(e), self.delayMs * 2)