Browse Source

Standardizing cardiacSPECT layout

Andrej 4 years ago
parent
commit
ebe9dbe036

+ 32 - 35
cardiacSPECT/parseDicom.py → parseDicom/parseDicom.py

@@ -1,10 +1,11 @@
 import os
 import sys
-import dicom
+import pydicom
 import numpy as np
 import re
 import slicer
 from slicer.ScriptedLoadableModule import *
+import pathlib
 
 #rom os import listdir
 #from os.path import isfile, join
@@ -42,45 +43,43 @@ class parseDicomLogic(ScriptedLoadableModuleLogic):
     def __init__(self,parent):
         ScriptedLoadableModuleLogic.__init__(self, parent)
 
-    def setURIHandler(self,net):
-        self.net=net
+    def setFileBrowser(self,fb):
+        self.fb=fb
 
-    def filelist(self,mypath):
-        if mypath.find('labkey://')==0:
+    def filelist(self,mypath,remote=True):
+        if remote:
             print("Using labkey")
-            labkeyPath=re.sub('labkey://','',mypath)
             #not sure if labkey is available, so try it
-            #url=slicer.modules.labkeySlicerPythonExtensionWidget.serverURL.text
-            #print("Seting url={}".format(url))
-            ok, files=self.net.listRemoteDir(labkeyPath)
+            ok, files=self.fb.listRemoteDir(labkeyPath)
             if not ok:
                 print "Error accessing path"
                 return []
-            files=[self.net.GetRelativePathFromLabkeyPath(f) for f in files]
+            #files=[self.net.GetRelativePathFromLabkeyPath(f) for f in files]
 
-        if mypath.find('file://')==0:
+        else:
             print("Using local files")
-            localPath=re.sub('file://','',mypath)
+            #localPath=re.sub('file://','',mypath)
+            localPath=mypath
             files = [os.path.join(localPath,f) for f in os.listdir(localPath)
                 if os.path.isfile(os.path.join(localPath, f))]
 
         return files
 
-    def getfile(self,origin,f):
+    def getfile(self,f,remote=True):
 
-        if origin.find('labkey')==0:
+        if remote:
             try:
                 #not sure if labkey is available, but try it
                 print("Using labkey")
-                print("Server:{0}, file:{1}".format(self.net.GetHostName(),f))
-                localPath=self.net.DownloadFileToCache(f)
-                #return [self.net.readFileToBuffer(f),1]
+                p=pathlib.Path(f)
+                localPath=os.path.join(self.tempBase,p.name)
+                self.fb.readFileToFile(f,localPath)
                 return [open(localPath,'rb'),1]
             except:
                 print('Could not access labkey. Exiting')
                 return ['NULL',0]
 
-        if origin.find('file')==0:
+        else:
             print("Using local directory")
             return [open(f,'rb'),1]
 
@@ -91,7 +90,7 @@ class parseDicomLogic(ScriptedLoadableModuleLogic):
         #here we found out the duration of the frame and their distribution through
         #phases and cycles
         try:
-            plan = dicom.read_file(g)
+            plan = pydicom.dcmread(g)
         except:
             print ("{}: Not a dicom file").format(g)
             return False
@@ -125,7 +124,7 @@ class parseDicomLogic(ScriptedLoadableModuleLogic):
     def readNMFile(self,g):
 
         try:
-            plan = dicom.read_file(g)
+            plan = pydicom.dcmread(g)
         except:
             print ("{}: Not a dicom file").format(g)
             return False
@@ -204,7 +203,7 @@ class parseDicomLogic(ScriptedLoadableModuleLogic):
     def readCTFile(self,g):
 
         try:
-            plan = dicom.read_file(g)
+            plan = pydicom.dcmread(g)
         except:
             print ("{}: Not a dicom file").format(g)
             return False
@@ -267,17 +266,16 @@ class parseDicomLogic(ScriptedLoadableModuleLogic):
 
         return True
 
-    def readMasterDirectory(self,mypath):
+    def readMasterDirectory(self,mypath,remote=True):
         self.axisShift=(2,1,0)
 
         print("Reading master from {}").format(mypath)
-        origin=re.sub('([^:/])://(.*)$',r'\1',mypath)
 
-        relativeFiles=self.filelist(mypath)
-        for f in relativeFiles:
+        filelist=self.filelist(mypath,remote)
+        for f in filelist:
             print '{}:'.format(f)
 
-            g,ok=self.getfile(origin,f)
+            g,ok=self.getfile(f,remote)
             if not(ok):
                 return
 
@@ -285,13 +283,13 @@ class parseDicomLogic(ScriptedLoadableModuleLogic):
                 break
 
 
-    def readNMDirectory(self,mypath):
+    def readNMDirectory(self,mypath,remote=True):
 
-        onlyfiles=self.filelist(mypath)
-        origin=re.sub('([^:/])://(.*)$',r'\1',mypath)
-        for f in onlyfiles:
+        files=self.filelist(mypath,remote)
+        
+        for f in files:
 
-            g,ok=self.getfile(origin,f)
+            g,ok=self.getfile(f,remote)
             if not(ok):
                 continue
 
@@ -304,9 +302,8 @@ class parseDicomLogic(ScriptedLoadableModuleLogic):
         return [self.frame_data,self.frame_time,self.frame_duration,self.center,
             self.pixel_size,self.frame_orientation]
 
-    def readCTDirectory(self,mypath):
-        onlyfiles=self.filelist(mypath)
-        origin=re.sub('([^:/])://(.*)$',r'\1',mypath)
+    def readCTDirectory(self,mypath,remote=True):
+        onlyfiles=self.filelist(mypath,remote)
 
         self.ct_data = []
         self.ct_idx = []
@@ -318,7 +315,7 @@ class parseDicomLogic(ScriptedLoadableModuleLogic):
         for f in onlyfiles:
             print '{}:'.format(f)
 
-            g,ok=self.getfile(origin,f)
+            g,ok=self.getfile(f,remote)
             if not(ok):
                 return
 

+ 0 - 0
cardiacSPECT/CMakeLists.txt → slicerModules/CMakeLists.txt


+ 0 - 0
cardiacSPECT/Resources/Icons/cardiacSPECT.png → slicerModules/Resources/Icons/cardiacSPECT.png


+ 0 - 0
cardiacSPECT/Testing/CMakeLists.txt → slicerModules/Testing/CMakeLists.txt


+ 0 - 0
cardiacSPECT/Testing/Python/CMakeLists.txt → slicerModules/Testing/Python/CMakeLists.txt


+ 78 - 77
cardiacSPECT/cardiacSPECT.py → slicerModules/cardiacSPECT.py

@@ -4,13 +4,9 @@ import unittest
 import vtk, qt, ctk, slicer
 from slicer.ScriptedLoadableModule import *
 import logging
-import parseDicom
 import vtkInterface as vi
-import fileIO
 import slicer
 import numpy as np
-import slicerNetwork
-import resample
 import json
 import re
 #
@@ -51,17 +47,12 @@ class cardiacSPECTWidget(ScriptedLoadableModuleWidget):
     ScriptedLoadableModuleWidget.setup(self)
 
 
-    self.selectRemote=fileIO.remoteFileSelector()
-    try:
-        self.network=slicer.modules.labkeySlicerPythonExtensionWidget.network
-    except:
-        self.network=slicerNetwork.labkeyURIHandler()
-
-    configFile=os.path.join(os.path.expanduser('~'),'.cardiacSPECT','cardiacSPECT.json')
-    self.logic=cardiacSPECTLogic(configFile)
-    self.logic.setURIHandler(self.network)
-    self.selectRemote.setMaster(self)
-
+    #load config
+    configFile=os.path.join(os.path.expanduser('~'),\
+              '.cardiacSPECT','cardiacSPECT.json')
+    with open(configFile) as f:
+          self.cfg=json.load(f)
+    
     # Instantiate and connect widgets ...
     dataButton = ctk.ctkCollapsibleButton()
     dataButton.text = "Data"
@@ -241,6 +232,9 @@ class cardiacSPECTWidget(ScriptedLoadableModuleWidget):
 
     self.resetPosition=1
 
+    #add logic aware of all GUI elements on page
+    self.logic=cardiacSPECTLogic(self.cfg)
+
   def cleanup(self):
     pass
 
@@ -404,32 +398,46 @@ class cardiacSPECTLogic(ScriptedLoadableModuleLogic):
   """
   def __init__(self,config):
       ScriptedLoadableModuleLogic.__init__(self)
+      sconfig=os.path.join(os.path.expanduser('~'),'.labkey','setup.json')
+      with open(sconfig) as f:
+            setup=json.load(f)
+      sys.path.append(setup['paths']['labkeyInterface'])
+      import labkeyInterface
+      import labkeyDatabaseBrowser
+      import labkeyFileBrowser
+
+      self.net=labkeyInterface.labkeyInterface()
+      fconfig=os.path.join(os.path.expanduser('~'),'.labkey','network.json')
+      self.net.init(fconfig)
+      self.db=labkeyDatabaseBrowser.labkeyDB(self.net)
+      self.fb=labkeyFileBrowser.labkeyFileBrowser(self.net)
+
+      sys.path.append(setup['paths']['parseDicom'])
+      import parseDicom
+
       self.pd=parseDicom.parseDicomLogic(self)
+      self.pd.setFileBrowser(self.fb)
+      
+      sys.path.append(setup['paths']['resample'])
+      import resample
       self.resampler=resample.resampleLogic(None)
-
-      fname=config
-      try:
-
-          f=open(fname)
-      except OSError as e:
-          print "Confgiuration error: OS error({0}): {1}".format(e.errno, e.strerror)
-          return
-
-      self.cfg=json.load(f)
-      self.coreRelativePath=self.cfg["project"]+'/'+self.cfg['atFiles']
-
-
-
-  def setURIHandler(self,net):
-      self.net=net
-      self.pd.setURIHandler(net)
-
+      
+      
+      self.tempPath=os.path.join(os.path.expanduser('~'),\
+              'temp','cardiacSPECT')
+      if not os.path.isdir(self.tempPath):
+          os.makedirs(self.tempPath)
+      
+      self.cfg=config
+      
   def loadData(self,widget):
 
+    #calculate inputDir from data on form
     inputDir=str(widget.dataPath.text)
     self.pd.readMasterDirectory(inputDir)
     self.frame_data, self.frame_time, self.frame_duration, self.frame_origin, \
-        self.frame_pixel_size, self.frame_orientation=self.pd.readNMDirectory(inputDir)
+        self.frame_pixel_size, \
+        self.frame_orientation=self.pd.readNMDirectory(inputDir)
 
     self.ct_data,self.ct_origin,self.ct_pixel_size, \
         self.ct_orientation=self.pd.readCTDirectory(inputDir)
@@ -450,25 +458,26 @@ class cardiacSPECTLogic(ScriptedLoadableModuleLogic):
 
   def getFilespecPath(self,r):
       if self.cfg["remote"]==True:
-          path=r['_labkeyurl_Series']
-          path=path[:path.rfind('/')]
-          return "labkey://"+path
+          return self.fb.formatPathURL(self.cfg['project'],\
+                  '/'.join(self.cfg['imageDir'],r['Study'],r['Series']))
       else:
           path=os.path.join(self.cfg["dicomPath"],r["Study"],r["Series"])
-          return "file://"+path
+          return path
 
   def loadPatient(self,patientId):
       print("Loading {}").format(patientId)
-      ds=self.net.loadDataset("dinamic_spect/Patients","Imaging")
-      for r in ds['rows']:
-        if r['aliasID']==patientId:
-            visit=r
+      ds=self.db.selectRows(self.cfg['project'],self.cfg['schemaName'],
+              self.cfg['queryName'])
+      visit=[r for r in ds['rows'] if r['aliasID']==patientId][0]
 
       print visit
-      dicoms=self.net.loadDataset("Test/Transfer","Imaging")
+      idFilter={'variable':'PatientId','value':visit['aliasID'],'oper':'eq'}
+      dicoms=self.db.selectRows(self.cfg['transfer']['project'],
+              self.cfg['transfer']['schemaName'],
+              self.cfg['transfer']['queryName'],
+              [idFilter])
+      
       for r in dicoms['rows']:
-          if not r['PatientId']==visit['aliasID']:
-              continue
           if abs(r['SequenceNum']-float(visit['nmMaster']))<0.1:
               masterPath=self.getFilespecPath(r)
               #masterPath="labkey://"+path
@@ -533,13 +542,19 @@ class cardiacSPECTLogic(ScriptedLoadableModuleLogic):
       self.loadNode(patientId,'Heart','SegmentationFile')
 
   def loadNode(self,patientId,fName,type,suffix='.nrrd'):
-      relativePath=self.coreRelativePath+'/'+patientId
-      labkeyFile=relativePath+'/'+fName+suffix
+      remotePath=self.fb.formatPathURL(self.cfg['project'],
+              '/'.join([patientId]))
+      labkeyFile=remotePath+'/'+fName+suffix
+      localFile=os.path.join(self.tempPath+fName+suffix)
+      self.fb.readFileToFile(labkeyFile,localFile)
       print ("Remote: {}").format(labkeyFile)
-      return self.net.loadNode(labkeyFile,type,returnNode=True)
+      node=slicer.util.loadNodeFromFile(localFile,type)
+      os.remove(localFile)
+      return node
       
 
-  def addNode(self,nodeName,v, lpsOrigin, pixel_size, lpsOrientation, dataType):
+  def addNode(self,nodeName,v, lpsOrigin, pixel_size, \
+          lpsOrientation, dataType):
 
        # if dataType=0 it is CT data, which gets propagated to background an is
        #used to fit the view field dimensions
@@ -729,7 +744,7 @@ class cardiacSPECTLogic(ScriptedLoadableModuleLogic):
           return "NONE"
       return segNode.GetSegmentation().GetSegment(segNode.GetSegmentation().GetNthSegmentID(i)).GetName()
 
-  def storeNodeRemote(self,relativePath,nodeName):
+  def storeNodeRemote(self,pathList,nodeName):
     
     node=slicer.mrmlScene.GetFirstNodeByName(nodeName)
     if node==None:
@@ -745,47 +760,33 @@ class cardiacSPECTLogic(ScriptedLoadableModuleLogic):
 
     fileName=nodeName+suffix
 
-    localPath=self.getLocalPath(relativePath)
-    if not os.path.isdir(localPath):
-        os.mkdir(localPath)
+    localPath=os.path.join(self.tempPath,fileName)
 
     file=os.path.join(localPath,fileName)
     slicer.util.saveNode(node,file)
     print("Stored to: {}").format(file)
     if self.cfg["remote"]:
-        labkeyPath=self.pd.net.GetLabkeyPathFromRelativePath(relativePath)
+        labkeyPath=self.fb.buildPathURL(self.cfg['project'],pathList)
         print ("Remote: {}").format(labkeyPath)
         #checks if exists
-        self.pd.net.mkdir(labkeyPath)
         remoteFile=labkeyPath+'/'+fileName
-        f=open(file,"rb")
-        self.pd.net.put(remoteFile,f.read())
-
-  def getLocalPath(self,relativePath):
-    if self.cfg["remote"]:
-        localPath=self.pd.net.GetLocalPathFromRelativePath(relativePath)
-        localPath.replace('/',os.path.sep)
-        return localPath
-    
-    localPath=os.path.join(self.cfg["labkeyBase"],relativePath)
-    return localPath
-
+        self.fb.writeFileToFile(localPath,remoteFile)
 
   def storeVolumeNodes(self,patientId,n1,n2):
       #n1=self.time_frame.minimum;
       #n2=self.time_frame.maximum
-    relativePath=self.coreRelativePath+'/'+patientId
+    pathList=[patientId]
 
     print("Store CT")
     nodeName=patientId+'CT'
 
-    self.storeNodeRemote(relativePath,nodeName)
+    self.storeNodeRemote(pathList,nodeName)
 
     #prefer resampled
     testNode=slicer.util.getFirstNodeByName(nodeName+"_RS")
     if testNode:
         nodeName=nodeName+"_RS"
-        self.storeNodeRemote(relativePath,nodeName)
+        self.storeNodeRemote(pathList,nodeName)
 
     print("Storing NM from {} to {}").format(n1,n2)
     n=n2-n1+1
@@ -793,35 +794,35 @@ class cardiacSPECTLogic(ScriptedLoadableModuleLogic):
         it=i+n1
         nodeName=patientId+'Volume'+str(it)
 
-        self.storeNodeRemote(relativePath,nodeName)
+        self.storeNodeRemote(pathList,nodeName)
 
         #add resampled
         testNode=slicer.util.getFirstNodeByName(nodeName+"_RS")
         if testNode:
             nodeName=nodeName+"_RS"
-            self.storeNodeRemote(relativePath,nodeName)
+            self.storeNodeRemote(pathList,nodeName)
 
     self.storeDummyInputFunction(patientId)
 
   def storeSegmentation(self,patientId):
-      relativePath=self.coreRelativePath+'/'+patientId
+      pathList=[patientId]
       segNodeName="Heart"
-      self.storeNodeRemote(relativePath,segNodeName)
+      self.storeNodeRemote(pathList,segNodeName)
 
   def storeInputFunction(self,patientId):
       self.calculateInputFunction(patientId)
-      relativePath=self.coreRelativePath+'/'+patientId
+      relativePath=[patientId]
       doubleArrayNodeName=patientId+'_Ventricle'
       self.storeNodeRemote(relativePath,doubleArrayNodeName)
 
   def storeDummyInputFunction(self,patientId):
       self.calculateDummyInputFunction(patientId)
-      relativePath=self.coreRelativePath+'/'+patientId
+      relativePath=[patientId]
       doubleArrayNodeName=patientId+'_Dummy'
       self.storeNodeRemote(relativePath,doubleArrayNodeName)
 
   def storeTransformation(self,patientId):
-      relativePath=self.coreRelativePath+'/'+patientId
+      relativePath=[patientId]
       transformNodeName=patientId+"_DF"
       self.storeNodeRemote(relativePath,transformNodeName)
 

+ 11 - 0
template/cardiacSPECT.json

@@ -0,0 +1,11 @@
+{
+	"transfer":{
+		"project":"Test/Transfer",
+		"schemaName":"study",
+		"queryName":"Imaging"
+	},
+	"project":"dinamic_spect/Patients",
+	"queryName":"Imaging",
+	"schemaName":"study",
+	"imageDir":"images"
+}