Преглед изворни кода

Updating to recent version

NIX User пре 4 година
родитељ
комит
53fb46eaa9

+ 159 - 0
dicomUtils/loadDicom.py

@@ -3,6 +3,9 @@ import numpy
 import sys
 import os
 import nibabel
+import json
+import datetime
+import re
 
 # load the DICOM files
 def load(dir):
@@ -81,3 +84,159 @@ def convertToNIfTI(slices):
 
     return img
 
+def writeAnonymousSeries(slices,path,studyUID, fields):
+    uid=uuid()
+    seriesUID=uid.generateSeriesUUID('volume')
+    i=0;
+    for s in slices:
+        outFile="DCM{:04d}.dcm".format(i)
+        outFile=os.path.join(path,outFile)
+        writeAnonymousDicomFile(s,studyUID,seriesUID,outFile,fields)
+        i=i+1
+
+
+
+
+def writeAnonymousDicomFile(slice, studyUID, seriesUID, outFile, fields):
+    uid=uuid()
+    instanceUID=uid.generateSOPInstanceUUID('volume')
+
+
+    file_meta = pydicom.Dataset()
+    file_meta.MediaStorageSOPClassUID = slice.file_meta.MediaStorageSOPClassUID
+    file_meta.MediaStorageSOPInstanceUID = instanceUID
+    file_meta.ImplementationClassUID = slice.file_meta.ImplementationClassUID
+    file_meta.TransferSyntaxUID=pydicom.uid.ImplicitVRLittleEndian
+
+    print("Setting dataset values...")
+    # Create the FileDataset instance (initially no data elements, but file_meta
+    # supplied)
+    ds = pydicom.FileDataset(outFile, {},
+                         file_meta=file_meta, preamble=b"\0" * 128)
+
+    # Add the data elements -- not trying to set all required here. Check DICOM
+    # standard
+    ds.PatientName = "XXXXX"
+    ds.PatientID = "xxxxxx"
+    ds.StudyUID=studyUID
+    ds.SeriesUID=seriesUID
+    ds.SOPInstanceUID=instanceUID
+
+    # Set the transfer syntax
+    ds.is_little_endian = True
+    ds.is_implicit_VR = True
+
+    # Set creation date/time
+    #dt = datetime.datetime.now()
+    #ds.ContentDate = dt.strftime('%Y%m%d')
+    #timeStr = dt.strftime('%H%M%S.%f')  # long format with micro seconds
+    ds.ContentTime = slice.ContentTime
+    #add variables from Daniel's list (fields)
+    for f in fields:
+        try:
+            ds[f]=slice[f];
+        except:
+            print("Field {} missing".format(f))
+
+    ds.PixelData=slice.PixelData
+    print("Writing test file", outFile)
+    ds.save_as(outFile)
+    print("File saved.")
+
+class uuid:
+
+    def __init__(self):
+        fhome=os.path.expanduser('~')
+        fconfig=os.path.join(fhome,'.uuid','config.json')
+        self.basePath=os.path.join(fhome,'.uuid')
+        with open(fconfig,'r') as f:
+            self.config=json.load(f)
+        self.labelUUID={'series':'1','study':'2','instance':'3','frameOfReference':4}
+        self.dataUUID={'volume':'1','segmentation':'2','transformation':'3'}
+
+    def getTimeCode(x):
+        hour=x.strftime("%H")
+        hour=re.sub('^0','',hour)
+        return hour+x.strftime("%M%S")
+ 
+    def generateStudyUUID(self,type):
+
+        x=datetime.datetime.now()
+        date=x.strftime("%Y%m%d")
+        studyFile=os.path.join(self.basePath,'studyCount'+date+'.txt')
+
+        try:
+            f=open(studyFile,"r")
+            id=int(f.readline())
+            id=id+k
+            f.close()
+        except:
+            id=0
+
+        studyId="{}.{}.{}.{}.{}".format(self.config["baseUUID"],self.labelUUID['study'],
+                        self.dataUUID[type],date,id)
+
+        f=open(studyFile,"w")
+        f.write("{}".format(id))
+        f.close()
+        return studyId
+
+
+    def generateSOPInstanceUUID(self,type):
+
+        baseUUID=self.config["baseUUID"]
+        x=datetime.datetime.now()
+        date=x.strftime("%Y%m%d")
+        instanceFile=os.path.join(self.basePath,'instanceCount'+date+'.txt')
+
+        try:
+            f=open(instanceFile,"r")
+            id=int(f.readline())
+            id=id+1
+            f.close()
+        except:
+            id=0
+
+        instanceId="{}.{}.{}.{}.{}".format(baseUUID,self.labelUUID['instance'],
+                        self.dataUUID[type],date,id)
+
+        f=open(instanceFile,"w")
+        f.write("{}".format(id))
+        f.close()
+        return instanceId
+
+
+    def generateFrameOfReferenceUUID(self,type):
+
+        baseUUID=self.config["baseUUID"]
+        basePath=self.basePath
+        x=datetime.datetime.now()
+        date=x.strftime("%Y%m%d")
+        forFile=os.path.join(basePath,'frameCount'+date+'.txt')
+
+        try:
+            f=open(studyFile,"r")
+            id=int(f.readline())
+            id=id+1
+            f.close()
+        except:
+            id=0
+
+        forId="{}.{}.{}.{}.{}".format(baseUUID,self.labelUUID['frameOfReference'],
+                        self.dataUUID[type],date,id)
+
+        f=open(forFile,"w")
+        f.write("{}".format(id))
+        f.close()
+        return forId
+  
+    def generateSeriesUUID(self,type):
+
+        baseUUID=self.config["baseUUID"]
+        x=datetime.datetime.now()
+        seriesInstanceUid=baseUUID+'.'+self.labelUUID['series']+'.'
+        seriesInstanceUid+=self.dataUUID[type]+'.'+x.strftime("%Y%m%d")+'.'+uuid.getTimeCode(x)
+        return seriesInstanceUid
+
+
+

+ 1 - 1
pythonScripts/README

@@ -1,2 +1,2 @@
-Run with ~/scripts/runPython.sh script.py
+Run with ./runPython.sh script.py
 

+ 37 - 11
pythonScripts/anonymizeImages.py

@@ -41,16 +41,29 @@ tempBase=os.path.join(fhome,'temp')
 ds=db.selectRows(project,'study','Imaging',[])
 imageSelector=["CT","PETWB"];
 
-niftiBase='/data/nifti'
+outputBase='/data/dicom/anonymous'
 labkeyBase='/data/labkey'
-projectNIfTIBase=os.path.join(labkeyBase,'files',project,'@files/nifti')
+#for links
+projectAnonymousBase=os.path.join(labkeyBase,'files',project,'@files/anonymous')
+
+
+#selected dicom fields
+dsFields=db.selectRows(project,'lists','dicomFields',[])
+try:
+    fields=[r['dicomTagName'] for r in dsFields['rows']]
+except KeyError:
+    fields=[r['dicomtagname'] for r in dsFields['rows']]
 
 i=0
+uid=loadDicom.uuid()
 for row in ds["rows"]:
+    #link dicoms with a common studiyID
+    studyUID=uid.generateStudyUUID('volume')
+
     for im in imageSelector:
-        linkField=im+"1"
+        linkField=im+"2"
         print("Checking row[{}]={}".format(linkField,row[linkField]))
-        if row[linkField]=="[NIFTI]":
+        if row[linkField]=="[DICOM]":
             print("Skipping {}".format(im))
             continue
 
@@ -72,20 +85,33 @@ for row in ds["rows"]:
             print("unzip failed for {}".format(fname))
             continue
         slices=loadDicom.load(unzipDir)
-        img=loadDicom.convertToNIfTI(slices)
-        outNIfTI=os.path.join(niftiBase,seriesId+'.nii.gz')
-        nibabel.save(img,outNIfTI) 
+
+        anonymousDir=os.path.join(tempBase,seriesId+'-a')
+        try: 
+            os.mkdir(anonymousDir)
+        except FileExistsError:
+            shutil.rmtree(anonymousDir)
+            os.mkdir(anonymousDir)
+
+        loadDicom.writeAnonymousSeries(slices,anonymousDir,studyUID,fields)
+        anonymousZip=os.path.join(outputBase,seriesId+".zip")
+        try:
+            outTxt=subprocess.check_output(["zip","-rj",anonymousZip,anonymousDir])
+        except subprocess.CalledProcessError:
+            print("zip failed for {}, dir {}".format(anonymousZip,anonymousDir))
+            
         shutil.rmtree(unzipDir)
+        shutil.rmtree(anonymousDir)
         os.remove(fname)
-        labkeyNIfTI=os.path.join(projectNIfTIBase,seriesId+'.nii.gz')
+        labkeyAnonymousZip=os.path.join(projectAnonymousBase,seriesId+'.zip')
         try:
-            os.symlink(outNIfTI,labkeyNIfTI)
+            os.symlink(anonymousZip,labkeyAnonymousZip)
         except FileExistsError:
             pass
-        row[linkField]="[NIFTI]"
+        row[linkField]="[DICOM]"
        
     db.modifyRows("update",project,"study","Imaging",[row])
-    if i==-1:
+    if i==0:
         break
     i=i+1
 

+ 92 - 0
pythonScripts/anonymizeImagesNIfTI.py

@@ -0,0 +1,92 @@
+import os
+import json
+import re
+import subprocess
+import nibabel
+import shutil
+import sys
+
+shome=os.path.expanduser('~nixUser')
+sys.path.insert(1,shome+'/software/src/labkeyInterface')
+import labkeyInterface
+import labkeyDatabaseBrowser
+
+sys.path.insert(1,shome+'/software/src/orthancInterface')
+import orthancInterface
+import orthancFileBrowser
+
+sys.path.insert(1,shome+'/software/src/IPNUMM/dicomUtils')
+import loadDicom
+
+
+fhome=os.path.expanduser('~')
+fconfig=os.path.join(fhome,'.labkey','network.json')
+
+net=labkeyInterface.labkeyInterface()
+net.init(fconfig)
+db=labkeyDatabaseBrowser.labkeyDB(net)
+
+
+onet=orthancInterface.orthancInterface()
+onet.init(fconfig)
+ofb=orthancFileBrowser.orthancFileBrowser(onet)
+
+hi=0
+project='iPNUMMretro/Study'
+#project='Orthanc/Database'
+
+tempBase=os.path.join(fhome,'temp')
+
+#all images from database
+ds=db.selectRows(project,'study','Imaging',[])
+imageSelector=["CT","PETWB"];
+
+niftiBase='/data/nifti'
+labkeyBase='/data/labkey'
+projectNIfTIBase=os.path.join(labkeyBase,'files',project,'@files/nifti')
+
+i=0
+for row in ds["rows"]:
+    for im in imageSelector:
+        linkField=im+"1"
+        print("Checking row[{}]={}".format(linkField,row[linkField]))
+        if row[linkField]=="[NIFTI]":
+            print("Skipping {}".format(im))
+            continue
+
+        seriesId=row[im];
+        if seriesId=="0":
+            continue
+
+        print("{}: {}".format(im,seriesId))
+        fname=os.path.join(tempBase,seriesId+".zip");
+        ofb.getZip('series',seriesId,fname)
+        unzipDir=os.path.join(tempBase,seriesId)
+        try:
+            os.mkdir(unzipDir)
+        except FileExistsError:
+            shutil.rmtree(unzipDir)
+        try:
+            outTxt=subprocess.check_output(["unzip","-d",unzipDir,"-xj",fname])
+        except subprocess.CalledProcessError:
+            print("unzip failed for {}".format(fname))
+            continue
+        slices=loadDicom.load(unzipDir)
+        img=loadDicom.convertToNIfTI(slices)
+        outNIfTI=os.path.join(niftiBase,seriesId+'.nii.gz')
+        nibabel.save(img,outNIfTI) 
+        shutil.rmtree(unzipDir)
+        os.remove(fname)
+        labkeyNIfTI=os.path.join(projectNIfTIBase,seriesId+'.nii.gz')
+        try:
+            os.symlink(outNIfTI,labkeyNIfTI)
+        except FileExistsError:
+            pass
+        row[linkField]="[NIFTI]"
+       
+    db.modifyRows("update",project,"study","Imaging",[row])
+    if i==-1:
+        break
+    i=i+1
+
+print("Done")

+ 15 - 1
pythonScripts/linkOrthanc.py

@@ -37,13 +37,14 @@ for row in ds['rows']:
         qfilter['variable']='seriesDescription'
         qfilter['value']=varList[var][1]
         qfilter['oper']=varList[var][0]
+        
         qfilter1={}
         qfilter1['variable']='PatientId'
         qfilter1['value']=row['PatientId']
         qfilter1['oper']='eq'
+
         qfilter2={}
         qfilter2['variable']='studyDate'
-
         qfilter2['oper']='dateeq'
         fdate=row['date']
         fdate=re.sub(r' (.*)$','',fdate)
@@ -55,13 +56,26 @@ for row in ds['rows']:
         ds1=db.selectRows(projectOrthanc,'study','Imaging',tfilter)
         print('[{}][{}][{}]: {}'.format(\
                 row['PatientId'],var,fdate,len(ds1['rows'])))
+        
+        
         for r1 in ds1['rows']:
             print("ID: {}, DESC: {}, DATE: {}".format(\
                 r1['PatientId'],r1['seriesDescription'],r1['studyDate']))
             #print("Study date {}/{}".format(row['date'],r1['studyDate']))
+
+
+            
         row[var]=len(ds1['rows'])
         if len(ds1['rows'])==1:
             row[var]=ds1['rows'][0]['orthancSeries']
+
+        if len(ds1['rows'])>1:
+            if var=='CT':
+                varC=[r1['orthancSeries']  for r1 in ds1['rows']\
+                        if r1['seriesDescription'].find('fov')<0] 
+                if len(varC)==1:
+                    row[var]=varC[0]
+
        
     db.modifyRows('update',projectIPNU,'study','Imaging',[row])