Andrej Studen @ Win7 5 lat temu
rodzic
commit
b958feca91

+ 1 - 1
labkeySlicerPythonExtension/labkeySlicerPythonExtension.py

@@ -308,7 +308,7 @@ class labkeySlicerPythonExtensionWidget(ScriptedLoadableModuleWidget):
       properties={}
       localPath=self.network.DownloadFileToCache(self.selectedFile.text)
       slicer.util.loadNodeFromFile(localPath,self.fileTypeSelector.currentText,
-        properties,returnNode=false)
+        properties,returnNode=False)
       if not self.keepCachedFileCheckBox.isChecked():
               os.remove(localPath)
 

+ 210 - 1
labkeySlicerPythonExtension/loadDicom.py

@@ -2,6 +2,7 @@ import slicer
 import os
 import subprocess
 import re
+import dicom
 
 dicomModify=os.getenv("HOME")
 if not dicomModify==None:
@@ -36,6 +37,75 @@ class loadDicomLogic(slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic):
     def __init__(self,parent):
       slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic.__init__(self, parent)
 
+      self.tag={
+              'studyDate': "0008,0020",
+              'studyTime': "0008,0030",
+              'seriesTime':"0008,0031",
+              'modality': "0008,0060",
+              'presentationIntentType':"0008,0068",
+              'manufacturer':"0008,0070",
+              'studyDescription': "0008,1030",
+              'seriesDescription': "0008,103e",
+              'patientName':"0010,0010",
+              'patientId':"0010,0020",
+              'patientBirthDate': "0010,0030",
+              'patientSex': "0010,0040",
+              'patientAge': "0010,1010",
+              'patientComments': "0010,4000",
+              'sequenceName':"0018,0024",
+              'kVP':"0018,0060",
+              'percentPhaseFieldOfView':"0018,0094",
+              'xRayTubeCurrent':"0018,1151",
+              'exposure':"0018,1152",
+              'imagerPixelSpacing':"0018,1164",
+              'bodyPartThickness':"0018,11a0",
+              'compressionForce':"0018,11a2",
+              'viewPosition':"0018,5101",
+              'fieldOfViewHorizontalFlip':"0018,7034",
+              'studyInstanceUid':"0020,000d",
+              'seriesInstanceUid':"0020,000e",
+              'studyId': "0020,0010",
+              'seriesNumber':"0020,0011",
+              'instanceNumber':"0020,0013",
+              'frameOfReferenceInstanceUid':"0020,0052",
+              'imageLaterality':"0020,0060",
+              'imagesInAcquisition':"0020,1002",
+              'photometricInterpretation':"0028,0004"
+      }
+      self.tagPyDicom={
+              'studyDate': 0x00080020,
+              'studyTime': 0x00080030,
+              'modality': 0x00080060,
+              'presentationIntentType': 0x00080068,
+              'manufacturer': 0x00080070,
+              'studyDescription': 0x00081030,
+              'seriesDescription': 0x0008103e,
+              'patientName': 0x00100010,
+              'patientId': 0x00100020,
+              'patientBirthDate': 0x00100030,
+              'patientSex': 0x00100040,
+              'patientComments': 0x00104000,
+              'sequenceName': 0x00180024,
+              'kVP': 0x00180060,
+              'percentPhaseFieldOfView': 0x00180094,
+              'xRayTubeCurrent': 0x00181151,
+              'exposure': 0x00181152,
+              'imagerPixelSpacing': 0x00181164,
+              'bodyPartThickness': 0x001811a0,
+              'compressionForce': 0x001811a2,
+              'viewPosition': 0x00185101,
+              'studyInstanceUid': 0x0020000d,
+              'seriesInstanceUid': 0x0020000e,
+              'studyId': 0x00200010,
+              'seriesNumber': 0x00200011,
+              'instanceNumber': 0x00200013,
+              'frameOfReferenceInstanceUid': 0x00200052
+              }
+      #new_dict_items={
+      #        0x001811a0: ('DS','BodyPartThickness','Body Part Thickness')
+      #}
+      #dicom.datadict.add_dict_entries(new_dict_items)
+
     def load(self,sNet,dir,doRemove=True):
         print("Loading dir {}").format(dir)
         dicomFiles=sNet.listRelativeDir(dir)
@@ -58,11 +128,13 @@ class loadDicomLogic(slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic):
 
         for loadable in loadables:
             #TODO check if it makes sense to load a particular loadable
+            fileBuffer = open(loadable.files[0])
+            plan=dicom.read_file(fileBuffer)
             if loadable.name.find('imageOrientationPatient')>-1:
                 continue
             volumeNode=self.volumePlugin.load(loadable)
             if volumeNode != None:
-                vName='Series'+dicomValue(loadable.files[0],"0020,0011")
+                vName='Series'+plan[0x00200011].value
                 volumeNode.SetName(vName)
 
         try:
@@ -82,12 +154,149 @@ class loadDicomLogic(slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic):
         for f in filelist:
             os.remove(f)
 
+    def applyFilter(self,loadable,filter,nodeMetadata):
+
+        filterOK=True
+
+        fileBuffer = open(loadable.files[0])
+        try:
+            plan = dicom.read_file(fileBuffer)
+        except:
+            return False
+
+        for key in filter:
+            #try:
+            #    fileValue=plan[self.tag[key]].value
+            #except KeyError:
+            #        fileValue=None
+            fileValue=dicomValue(loadable.files[0],self.tag[key])
+
+
+            if filter[key]=="SeriesLabel":
+                nodeMetadata['seriesLabel']=fileValue
+                continue
+
+            if not filter[key]==None:
+                if not fileValue==filter[key]:
+                    print("File {} failed for tag {}: {}/{}").format(
+                        loadable.files[0],key,fileValue,filter[key])
+                    filterOK=False
+                    break
+
+            nodeMetadata[key]=fileValue
+
+
+        return filterOK
+
+
+    def loadVolumes(self,sNet,dir,filter,doRemove=True):
+    #returns all series from the directory, each as a separate node in a node list
+    #filter is a dictionary of speciifed dicom values, if filter(key)=None, that values
+    #get set, if it isn't, the file gets checked for a match
+
+        print("Loading dir {}").format(dir)
+        dicomFiles=sNet.listRelativeDir(dir)
+        #filelist=[os.path.join(dir,f) for f in os.listdir(dir)]
+        filelist=[]
+        for f in dicomFiles:
+            localPath=sNet.DownloadFileToCache(f)
+            f0=localPath
+            f1=f0+"1"
+            if not dicomModify==None:
+                subprocess.call(dicomModify+" "+f0+" "+f1+" && mv "+f1+" "+f0+";", shell=True)
+            filelist.append(localPath)
+
+        try:
+            loadables=self.volumePlugin.examineForImport([filelist])
+        except AttributeError:
+            self.volumePlugin=slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']()
+            loadables=self.volumePlugin.examineForImport([filelist])
+
+
+        volumeNodes=[]
+        print("Number of loadables:{}").format(len(loadables))
+        for loadable in loadables:
+            #TODO check if it makes sense to load a particular loadable
+
+            print "Loading {} number of files: {}".format(loadable.name,len(loadable.files))
+            for f in loadable.files:
+                print "\t {}".format(f)
+            #perform checks
+            nodeMetadata={}
+            filterOK=self.applyFilter(loadable,filter,nodeMetadata)
+
+            if not filterOK:
+                #skip this loadable
+                continue
+
+            volumeNode=self.volumePlugin.load(loadable,"DCMTK")
+            if volumeNode != None:
+                vName='Series'+nodeMetadata['seriesLabel']
+                volumeNode.SetName(vName)
+                volume={'node':volumeNode,'metadata':nodeMetadata}
+                volumeNodes.append(volume)
+
+        if doRemove:
+            for f in filelist:
+                os.remove(f)
+
+        return volumeNodes
+
+    def loadSegmentations(self,net,dir,filter,doRemove=True):
+
+        print("Loading dir {}").format(dir)
+        dicomFiles=net.listRelativeDir(dir)
+        filelist=[net.DownloadFileToCache(f) for f in dicomFiles]
+        segmentationNodes=[]
+
+        try:
+            loadableRTs=self.RTPlugin.examineForImport([filelist])
+        except:
+            self.RTPlugin=plugin=slicer.modules.dicomPlugins['DicomRtImportExportPlugin']()
+            loadableRTs=self.RTPlugin.examineForImport([filelist])
+
+        for loadable in loadableRTs:
+
+            nodeMetadata={}
+            filterOK=self.applyFilter(loadable,filter,nodeMetadata)
+
+            if not filterOK:
+                continue
+
+            success=self.RTPlugin.load(loadable)
+
+            if not success:
+                print("Could not load RT structure set")
+                return
+
+            segNodes=slicer.util.getNodesByClass("vtkMRMLSegmentationNode")
+            segmentationNode=segNodes[0]
+            #assume we loaded the first node in list
+
+            if segmentationNode != None:
+                sName='Segmentation'+nodeMetadata['seriesLabel']
+                segmentationNode.SetName(sName)
+                segmentation={'node':segmentationNode,'metadata':nodeMetadata}
+                segmentationNodes.append(segmentation)
+
+        if not doRemove:
+            return segmentationNodes
+
+        for f in filelist:
+            os.remove(f)
+
+        return segmentationNodes
+
 def dicomValue(file,tag):
     dcmdump=os.path.join(os.environ['SLICER_HOME'],"bin")
     dcmdump=os.path.join(dcmdump,"dcmdump")
     try:
         out=subprocess.check_output([dcmdump,'+P',tag,file])
         out=re.sub(r'^.*\[(.*)\].*\n$',r'\1',out)
+        #separate out series
+        if out.find('\\')>-1:
+            out=out.split('\\')
+
         return out
     except:
         return None

+ 22 - 8
labkeySlicerPythonExtension/slicerNetwork.py

@@ -162,17 +162,26 @@ class labkeyURIHandler(slicer.vtkURIHandler):
 
     #was GetLabkeyPathFromLocalPath
     def GetRelativePathFromLocalPath(self,f):
+        debug=True
         #report it with URL separator, forward-slash
         if f.find(self.localCacheDirectory)<-1:
             print("Localpath misformation. Exiting")
             return "NULL"
-        relativePath=re.sub(self.localCacheDirectory,'',f)
+        f0=re.sub('\\\\','\\\\\\\\',self.localCacheDirectory)
+        relativePath=re.sub(re.compile(f0),'',f)
+        if debug:
+            print("[SEP] Relative path {}").format(relativePath)
         #leaves /ContextPath/%40files/subdirectory_list/files
         #remove first separator
         sp=os.path.sep
+        f1=re.sub('\\\\','\\\\\\\\',sp)
         if relativePath[0]==sp:
-            relativePath=relativePath[1:len(dest)]
-        return re.sub(sp,'/',relativePath)
+            relativePath=relativePath[1:len(relativePath)]
+
+        if debug:
+            print("[SLASH] Relative path {}").format(relativePath)
+
+        return re.sub(f1,'/',relativePath)
 
     #was GetLabkeyPathFromRemotePath
     def GetRelativePathFromLabkeyPath(self,f):
@@ -230,10 +239,11 @@ class labkeyURIHandler(slicer.vtkURIHandler):
 
     def put(self,url,data):
 
-        print("PUT: {0}").format(url)
+        print("PUT: {}").format(url)
         r=MethodRequest(url.encode('utf-8'),method="PUT")
         #makes it a post
         r.add_data(data)
+        print("PUT: data size: {}").format(len(data))
         r.add_header("content-type","application/octet-stream")
         base64string = base64.b64encode('%s:%s' % (self.auth_name, self.auth_pass))
         r.add_header("Authorization", "Basic %s" % base64string)
@@ -278,11 +288,14 @@ class labkeyURIHandler(slicer.vtkURIHandler):
 	         sz=remoteBuffer.tell()
 	         print("Remote size: {0}").format(sz)
 
+
         remoteBuffer.seek(0)
+
         shutil.copyfileobj(remoteBuffer,localBuffer)
         if debug:
 	         print("Local size: {0}").format(localBuffer.tell())
         localBuffer.close()
+        return localPath
 
     def fileTypesAvailable(self):
         return ('VolumeFile','SegmentationFile','TransformFile')
@@ -315,7 +328,7 @@ class labkeyURIHandler(slicer.vtkURIHandler):
         return True
 
     def mkdirs(self,remoteDir):
-        relativePath=self.GetRelativePathFromRemotePath(remoteDir)
+        relativePath=self.GetRelativePathFromLabkeyPath(remoteDir)
         s=0
         while True:
             s1=relativePath.find('/',s)
@@ -469,7 +482,7 @@ class labkeyURIHandler(slicer.vtkURIHandler):
         if (self.isRemoteDir(remotePath)):
             remotePath=remotePath+'/'+os.path.basename(localPath)
 
-        with open(localPath, 'r') as f:
+        with open(localPath, 'rb') as f:
             data=f.read()
         self.put(remotePath,data)
 
@@ -494,11 +507,12 @@ class labkeyURIHandler(slicer.vtkURIHandler):
         url+='/query-selectRows.api?schemaName=study&query.queryName='+dataset
         return json.load(self.get(url))
 
-    def filterDataset(self,project,dataset,variable,value,oper="eq"):
+    def filterDataset(self,project,dataset,filter):
         debug=True
         url=self.GetLabkeyUrl()+'/'+project
         url+='/query-selectRows.api?schemaName=study&query.queryName='+dataset
-        url+="&query."+variable+"~"+oper+"="+value
+        for f in filter:
+            url+="&query."+f['variable']+"~"+f['oper']+"="+f['value']
         if debug:
             print("Sending {}").format(url)
         return json.load(self.get(url))