NIX User пре 4 година
комит
1fd9314ca6

+ 83 - 0
dicomUtils/loadDicom.py

@@ -0,0 +1,83 @@
+import pydicom
+import numpy
+import sys
+import os
+import nibabel
+
+# load the DICOM files
+def load(dir):
+    files = []
+    print('Loading: {}'.format(dir))
+    for fname in os.listdir(dir):
+        print("loading: {}".format(fname))
+        files.append(pydicom.dcmread(os.path.join(dir,fname)))
+
+    print("file count: {}".format(len(files)))
+
+    # skip files with no SliceLocation (eg scout views)
+    slices = []
+    skipcount = 0
+    for f in files:
+        if hasattr(f, 'SliceLocation'):
+            slices.append(f)
+        else:
+            skipcount = skipcount + 1
+
+    print("skipped, no SliceLocation: {}".format(skipcount))
+
+    # ensure they are in the correct order
+    slices = sorted(slices, key=lambda s: s.SliceLocation)
+    return slices;
+
+    # pixel aspects, assuming all slices are the same
+
+    for s in slices:
+        print("Pixel spacing: {}".format(s.PixelSpacing))
+
+    return;
+
+def convertToNIfTI(slices):
+
+    # create 3D array
+    img_shape = list(slices[0].pixel_array.shape)
+    img_shape.append(len(slices))
+    img3d = numpy.zeros(img_shape)
+
+    # get position and orientation parameters
+
+    x0=numpy.array([float(f) for f in slices[0].ImagePositionPatient])
+    x1=numpy.array([float(f) for f in slices[-1].ImagePositionPatient])
+    n=(x1-x0)/(len(slices)-1.);
+
+    f=numpy.array([float(f) for f in slices[0].ImageOrientationPatient])
+
+    s=numpy.array([float(f) for f in slices[0].PixelSpacing])
+    
+    #create affine 
+    a=numpy.zeros((4,4))
+    f1=numpy.zeros(4)
+    f1[0:3]=f[0:3]
+    #swap to account for row/column to (c,r) position mismatch
+    a[:,1]=f1*s[1]
+    f2=numpy.zeros(4)
+    f2[0:3]=f[3:6]
+    a[:,0]=f2*s[0]
+    nn=numpy.zeros(4)
+    nn[0:3]=n[0:3]
+    a[:,2]=nn
+
+    xn=numpy.ones(4)
+    xn[0:3]=x0[0:3]
+    a[:,3]=xn
+
+     
+
+    # fill 3D array with the images from the files
+    for i, s in enumerate(slices):
+        img2d = s.pixel_array
+        img3d[:, :, i] = img2d
+    #orientation and pixel spacing
+    img = nibabel.Nifti1Image(img3d, a)
+
+    return img
+

+ 2 - 0
pythonScripts/README

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

+ 92 - 0
pythonScripts/anonymizeImages.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")

+ 84 - 0
pythonScripts/copyToOrthanc.py

@@ -0,0 +1,84 @@
+#basic python
+import os
+import subprocess
+import re
+import datetime
+import sys
+
+
+fhome=os.path.expanduser('~')
+
+sys.path.insert(1,fhome+'/software/src/labkeyInterface')
+import labkeyInterface
+import labkeyDatabaseBrowser
+
+sys.path.insert(1,fhome+'/software/src/orthancInterface')
+import orthancInterface
+import orthancDatabaseBrowser
+
+
+net=labkeyInterface.labkeyInterface()
+net.init(fhome+'/.labkey/network.json')
+
+db=labkeyDatabaseBrowser.labkeyDB(net)
+
+#by default uses .labkey/Remote.json configuration
+
+oNet=orthancInterface.orthancInterface()
+#orthanc only looks at orthanc part of the configuration, so it is the same file
+oNet.init(fhome+'/.labkey/network.json')
+oDb=orthancDatabaseBrowser.orthancDB(oNet)
+
+
+dicomBase='/data/dicom/database/dicom'
+project='IPNUMMretro/Study'
+ds=db.selectRows(project,'lists','imageList',{})
+
+
+storescu='storescu'
+peer='onko-nix.onko-i.si'#this is actually localhost
+port='11112'#this is for orthanc
+
+i=0
+for row in ds['rows']:
+    if row['statusflag']=='ORTHANC':
+        continue
+    
+    if row['file']=='dump.txt':
+        row['statusflag']='DUMP'
+        db.modifyRows('update',project,'lists','imageList',[row])
+        continue
+    
+    print("ID: {}".format(row['patientid']))
+    f=os.path.join(dicomBase,row['study'],row['series'],row['file'])
+
+    print("Instance: {} ".format(f))
+    #add files to orthanc via PACS
+    try:
+        outText=subprocess.check_output([storescu,peer,port,f])
+    
+    except subprocess.CalledProcessError:
+        jsonStatus=oDb.upload(f)
+        
+
+    #check if the file made it to orthanc
+    qfilter={}
+    qfilter['SOPInstanceUID']=row['file']
+    rsp=oDb.selectRows(qfilter)
+
+    if len(rsp):
+        print("OK")
+        row['statusflag']='ORTHANC'
+    else:
+        print("Failed")
+
+    #update labkey database
+    db.modifyRows('update',project,'lists','imageList',[row])
+    if i==-1:
+        break
+    i=i+1
+
+   
+print("Done")
+quit()
+

+ 59 - 0
pythonScripts/getImages.py

@@ -0,0 +1,59 @@
+#basic python
+import os
+import subprocess
+import re
+import datetime
+import sys
+
+
+fhome=os.path.expanduser('~')
+
+sys.path.insert(1,fhome+'/software/src/labkeyInterface')
+import labkeyInterface
+import labkeyDatabaseBrowser
+
+
+def getValue(filename,tags):
+    #extract value of tags (list of tags) from dcmdump-ed file
+    #supply tags without braces ie. 0002,0008
+    #rows is a list of lines from file
+    with open(filename,"r") as f:
+        out=f.read()
+        lst=out.split('\n')
+        for tag in tags.keys():
+            tags[tag]=loadDicom.getTagValue(lst,tag)
+    return True
+
+
+net=labkeyInterface.labkeyInterface()
+net.init(fhome+'/.labkey/network.json')
+
+db=labkeyDatabaseBrowser.labkeyDB(net)
+
+#by default uses .labkey/Remote.json configuration
+
+
+dicomBase='/data/dicom/database/dicom'
+ds=db.selectRows('IPNUMMretro/Study','lists','imageList',{})
+
+
+storescu='storescu'
+peer='onko-nix.onko-i.si'#this is actually localhost
+port='11112'#this is for orthanc
+
+i=0
+for row in ds['rows']:
+    print("ID: {}".format(row['patientid']))
+    f=os.path.join(dicomBase,row['study'],row['series'],row['file'])
+
+    print("Instance: {} ".format(f))
+    #add files to orthanc via PACS
+    outText=subprocess.check_output([storescu,peer,port,f])
+    if i==0:
+        break
+    i=i+1
+
+   
+print("Done")
+quit()
+

+ 68 - 0
pythonScripts/linkOrthanc.py

@@ -0,0 +1,68 @@
+import os
+import json
+import re
+import sys
+import datetime
+import re
+
+fhome=os.path.expanduser('~')
+sys.path.insert(1,fhome+'/software/src/labkeyInterface')
+import labkeyInterface
+import labkeyDatabaseBrowser
+
+fconfig=os.path.join(fhome,'.labkey','network.json')
+
+net=labkeyInterface.labkeyInterface()
+net.init(fconfig)
+db=labkeyDatabaseBrowser.labkeyDB(net)
+
+
+i=0
+projectOrthanc='Orthanc/Database'
+projectIPNU='iPNUMMretro/Study'
+
+ds=db.selectRows(projectIPNU,'study','Imaging',[])
+
+varList={'CT':['startswith','CT'],'PETWB':['eq','PET%20WB'],
+        'PETWBUncorrected':['eq','PET%20WB%20Uncorrected'],
+        'Topogram':['startswith','Topogram']}
+
+i=0
+
+for row in ds['rows']:
+
+    for var in varList:
+        print('Filtering for {}/{}'.format(var,varList[var][1]))
+        qfilter={}
+        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)
+        fdate=re.sub(r'/',r'-',fdate)
+        qfilter2['value']=fdate
+
+
+        tfilter=[qfilter,qfilter1,qfilter2]
+        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']
+       
+    db.modifyRows('update',projectIPNU,'study','Imaging',[row])
+        
+print("Done")

+ 69 - 0
pythonScripts/listImages.py

@@ -0,0 +1,69 @@
+#basic python
+import os
+import subprocess
+import re
+import datetime
+import sys
+
+
+fhome=os.path.expanduser('~')
+
+sys.path.insert(1,fhome+'/software/src/labkeyInterface')
+import labkeyInterface
+import labkeyDatabaseBrowser
+
+
+def getValue(filename,tags):
+    #extract value of tags (list of tags) from dcmdump-ed file
+    #supply tags without braces ie. 0002,0008
+    #rows is a list of lines from file
+    with open(filename,"r") as f:
+        out=f.read()
+        lst=out.split('\n')
+        for tag in tags.keys():
+            tags[tag]=loadDicom.getTagValue(lst,tag)
+    return True
+
+
+net=labkeyInterface.labkeyInterface()
+net.init(fhome+'/.labkey/network.json')
+
+db=labkeyDatabaseBrowser.labkeyDB(net)
+
+#by default uses .labkey/Remote.json configuration
+
+
+dicomBase='/data/dicom/database/dicom'
+project='IPNUMMretro/Study'
+schema='study'
+outputList='imageList'
+
+ds=db.selectRows(project,schema,'Imaging',{})
+
+dicomProject='Test/Transfer'
+dicomDataset='Imaging'
+
+
+for row in ds['rows']:
+    print("ID: {}".format(row['PatientId']))
+    nfilter=[{'variable':'PatientId','value':row['PatientId'],'oper':'eq'}]
+    ds1=db.selectRows(dicomProject,'study',dicomDataset,nfilter)
+    for fi in ds1['rows']:
+        fdir=os.path.join(dicomBase,fi['Study'],fi['Series'])
+        #print("Instance: {} ".format(fdir))
+        files=os.listdir(fdir)
+        for f in files:
+            tfile=os.path.join(fdir,f)
+            print("{}".format(tfile))
+            #add files to orthanc via PACS
+            #outText=subprocess.check_output([storescu,peer,port,tfile])
+            oRow={'PatientId':row['PatientId'],'Series':fi['Series'],'Study':fi['Study'],'file':f,'statusFlag':'AVAILABLE'}
+            ds2=db.selectRows(project,'lists',outputList,[{'variable':'file','value':f,'oper':'eq'}])
+            if len(ds2['rows']):
+                continue
+            db.modifyRows('insert',project,'lists',outputList,[oRow])
+
+   
+print("Done")
+quit()
+

+ 69 - 0
pythonScripts/listOrthanc.py

@@ -0,0 +1,69 @@
+#basic python
+import os
+import subprocess
+import re
+import datetime
+import sys
+
+
+fhome=os.path.expanduser('~')
+
+sys.path.insert(1,fhome+'/software/src/labkeyInterface')
+import labkeyInterface
+import labkeyDatabaseBrowser
+
+
+def getValue(filename,tags):
+    #extract value of tags (list of tags) from dcmdump-ed file
+    #supply tags without braces ie. 0002,0008
+    #rows is a list of lines from file
+    with open(filename,"r") as f:
+        out=f.read()
+        lst=out.split('\n')
+        for tag in tags.keys():
+            tags[tag]=loadDicom.getTagValue(lst,tag)
+    return True
+
+
+net=labkeyInterface.labkeyInterface()
+net.init(fhome+'/.labkey/network.json')
+
+db=labkeyDatabaseBrowser.labkeyDB(net)
+
+#by default uses .labkey/Remote.json configuration
+
+
+dicomBase='/data/dicom/database/dicom'
+project='IPNUMMretro/Study'
+schema='study'
+outputList='imageList'
+
+ds=db.selectRows(project,schema,'Imaging',{})
+
+dicomProject='Test/Transfer'
+dicomDataset='Imaging'
+
+
+for row in ds['rows']:
+    print("ID: {}".format(row['PatientId']))
+    nfilter=[{'variable':'PatientId','value':row['PatientId'],'oper':'eq'}]
+    ds1=db.selectRows(dicomProject,'study',dicomDataset,nfilter)
+    for fi in ds1['rows']:
+        fdir=os.path.join(dicomBase,fi['Study'],fi['Series'])
+        #print("Instance: {} ".format(fdir))
+        files=os.listdir(fdir)
+        for f in files:
+            tfile=os.path.join(fdir,f)
+            print("{}".format(tfile))
+            #add files to orthanc via PACS
+            #outText=subprocess.check_output([storescu,peer,port,tfile])
+            oRow={'PatientId':row['PatientId'],'Series':fi['Series'],'Study':fi['Study'],'file':f,'statusFlag':'AVAILABLE'}
+            ds2=db.selectRows(project,'lists',outputList,[{'variable':'file','value':f,'oper':'eq'}])
+            if len(ds2['rows']):
+                continue
+            db.modifyRows('insert',project,'lists',outputList,[oRow])
+
+   
+print("Done")
+quit()
+

+ 81 - 0
pythonScripts/makeAnonymizeLinks.py

@@ -0,0 +1,81 @@
+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='/data1/labkey'
+projectNIfTIBase=os.path.join(labkeyBase,'/files/',project,'/@files/nifti')
+
+i=0
+for row in ds["rows"]:
+    for im in imageSelector:
+        seriesId=row[im];
+        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(labkeyNIfTI,outNIfTI)
+        except FileExistsError:
+            pass
+        
+    if i==0:
+        break
+    i=i+1
+
+print("Done")

+ 4 - 0
pythonScripts/runPython.sh

@@ -0,0 +1,4 @@
+#!/bin/bash
+
+
+nohup python3 $1  0<&- &> $HOME/logs/runPython.log &

+ 96 - 0
pythonScripts/scanOrthanc.py

@@ -0,0 +1,96 @@
+import os
+import json
+import re
+import sys
+
+
+fhome=os.path.expanduser('~')
+sys.path.insert(1,fhome+'/software/src/labkeyInterface')
+import labkeyInterface
+import labkeyDatabaseBrowser
+
+sys.path.insert(1,fhome+'/software/src/orthancInterface')
+import orthancInterface
+import orthancDatabaseBrowser
+
+fconfig=os.path.join(fhome,'.labkey','network.json')
+
+net=labkeyInterface.labkeyInterface()
+net.init(fconfig)
+db=labkeyDatabaseBrowser.labkeyDB(net)
+
+
+onet=orthancInterface.orthancInterface()
+onet.init(fconfig)
+odb=orthancDatabaseBrowser.orthancDB(onet)
+
+i=0
+project='Orthanc/Database'
+
+patients=odb.getPatients()
+
+for p in patients:
+    pdata=odb.getPatientData(p)
+    dicom=pdata['MainDicomTags']
+    patientId=dicom['PatientID']
+    
+    print("Patient: {} ID: {}".format(p,patientId))
+
+    qfilter={'variable':'PatientId','value':patientId,'oper':'eq'}
+    ds=db.selectRows(project,'study','Demographics',[qfilter])
+    if len(ds['rows'])==0:
+        row={}
+        row['PatientId']=patientId
+        row['birthDate']=dicom['PatientBirthDate']
+        row['PatientName']=dicom['PatientName']
+        row['OrthancId']=p
+        db.modifyRows('insert',project,'study','Demographics',[row])
+
+    for s in pdata['Studies']:
+        sdata=odb.getStudyData(s)
+        sdicom=sdata['MainDicomTags']
+        sid=sdicom['StudyInstanceUID']
+        print('Study: {}/{}'.format(s,sid))
+        #print('Data: {}'.format(sdata))
+        sdate=sdicom['StudyDate']
+        #continue
+        
+        
+        for se in sdata['Series']:
+
+            qfilter={'variable':'orthancSeries','value':se,'oper':'eq'}
+            ds=db.selectRows(project,'study','Imaging',[qfilter])
+            if len(ds['rows'])>0:
+                continue
+
+            #count existing entries for patient
+            qfilter={'variable':'PatientId','value':patientId,'oper':'eq'}
+            ds=db.selectRows(project,'study','Imaging',[qfilter])
+            seqNum=len(ds['rows'])
+
+            sedata=odb.getSeriesData(se)
+            sedicom=sedata['MainDicomTags']
+            seid=sedicom['SeriesInstanceUID']
+            print('Series: {}/{}'.format(se,seid))
+            #print('Data: {}'.format(sedata))
+            seDesc="NONE"
+            try:
+                seDesc=sedicom['SeriesDescription']
+            except KeyError:
+                pass
+
+            print('ID: {}.'.format(seDesc))
+
+            row={}
+            row['PatientId']=patientId
+            row['sequenceNum']=seqNum
+            row['dicomStudy']=sid
+            row['orthancStudy']=s
+            row['dicomSeries']=seid
+            row['orthancSeries']=se
+            row['studyDate']=sdate
+            row['seriesDescription']=seDesc
+            db.modifyRows('insert',project,'study','Imaging',[row])
+
+
+print("Done")