123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- #labkey/orthanc interface
- #scans the orthanc internal database and fills labkey table
- #"Orthanc" section expected in the configuration file, with
- #"queryName": query to be filled for each image
- #"demographicsQuery": query to be filled for every patient
- #"schemaName": the schema both queries are part of
- #"project": name of the project under labkey that collects Orthanc data,
- # typically named Orthanc or similar
- #"participantField": sorting participant field label in labkey study
- import os
- import json
- import re
- import sys
- import datetime
- def main(parameterFile):
- fhome=os.path.expanduser('~')
- fsetup=os.path.join(fhome,'.labkey','setup.json')
- with open(fsetup,'r') as f:
- setup=json.load(f)
- sys.path.insert(0,setup['paths']['nixWrapper'])
- sys.path.insert(0,setup['paths']['orthancInterface'])
- sys.path.insert(0,setup['paths']['labkeyInterface'])
- import nixWrapper
- #nixWrapper.loadLibrary("labkeyInterface")
- import labkeyInterface
- import labkeyDatabaseBrowser
- #nixWrapper.loadLibrary('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)
- with open(parameterFile) as f:
- pars=json.load(f)
- opars=pars['Orthanc']
- project=opars['project']
- participantField=opars['participantField']
- patients=odb.getPatients()
- #equivalent for labkey side?
- dsDemo=db.selectRows(project,opars['schemaName'],\
- opars['demographicsQuery'],[])
- dsPatients=[row['OrthancId'] for row in dsDemo['rows']]
- pMissing=[p for p in patients if p not in dsPatients]
- print('Missing : {}'.format(len(pMissing)))
- #we need details for all patients (some might have just a study uploaded
- pdata={p:odb.getPatientData(p) for p in patients}
- #update patient data for missing patients
- prows=[]
- for p in pMissing:
- dicom=pdata[p]['MainDicomTags']
- row={}
- pid=dicom['PatientID']
- if len(pid)>32:
- pid=pid[:32]
- row[participantField]=pid
-
- try:
- row['birthDate']=datetime.datetime.strptime(dicom['PatientBirthDate'],'%Y-%m-%d %H:%M')
- except (KeyError,ValueError):
- pass
-
- row['PatientName']=dicom['PatientName']
- row['OrthancId']=p
- prows.append(row)
- if len(prows)>0:
- resp=db.modifyRows('insert',project,opars['schemaName'],\
- opars['demographicsQuery'],prows)
- print(resp)
- n=len(patients)
- i=0
- #download the full images dataset (~1000 rows)
- ds=db.selectRows(project,opars['schemaName'],opars['queryName'],[])
- for p in patients:
- dicom=pdata[p]['MainDicomTags']
- patientId=dicom['PatientID']
- if len(patientId)>32:
- patientId=patientId[:32]
- #get all studies for pateint
- #qfilter={'variable':participantField,'value':patientId,'oper':'eq'}
- dsStudies=[row['orthancStudy'] for row in ds['rows'] if row[participantField]==patientId]
- #number of entries for patient (if new must be inserted)
- seqNum=len(dsStudies)
- #unique
- dsStudies=list(set(dsStudies))
- studies=pdata[p]['Studies']
- pHex=p.split('-')
- print("[{:>3d}/{:>3d}] ID: {:>10s} [{}] Studies: {:>2}/{:>2} Entries in DB: {:>4d}".format(i,n,patientId,pHex[-1],len(dsStudies),len(studies),seqNum))
- missingStudies=[s for s in studies if s not in dsStudies]
- #print('Missing studies: {}'.format(len(missingStudies)))
- srows=[]
- for s in missingStudies:
- sdata=odb.getStudyData(s)
- sdicom=sdata['MainDicomTags']
- sid=sdicom['StudyInstanceUID']
- #print('Data: {}'.format(sdata))
- #this is try/except protetcted in previous version...
- sdate="19700101"
- try:
- sdate=datetime.datetime.strptime(sdicom['StudyDate'],'%Y-%m-%d %H:%M')
- except (KeyError,ValueError):
- pass
- #continue
- print('\tStudy[{}]: {}/{}'.format(sdate,s,sid))
- for se in sdata['Series']:
- sedata=odb.getSeriesData(se)
- sedicom=sedata['MainDicomTags']
-
- seid=sedicom['SeriesInstanceUID']
- #print('Data: {}'.format(sedata))
- seDesc="NONE"
- try:
- seDesc=sedicom['SeriesDescription']
- except KeyError:
- pass
- #replace letters that might trip the database
- spanishOAcute=''.join([chr(3619),chr(3603)])
- spanishAAcute=''.join([chr(3619),chr(3585)])
- seDesc=re.sub(spanishOAcute,'o',seDesc)
- seDesc=re.sub(spanishAAcute,'a',seDesc)
- #this is a weird O that appears sometimes
- seDesc=seDesc.replace(chr(212),'O')
- print('\t\tSeries[{}]: {}/{}'.format(seDesc,se,seid))
-
- #qfilter={'variable':'orthancSeries','value':se,'oper':'eq'}
- #ds=db.selectRows(project,opars['schemaName'],\
- # opars['queryName'],[qfilter])
- #count existing entries for patient
- #qfilter={'variable':participantField,'value':patientId,'oper':'eq'}
- #ds=db.selectRows(project,opars['schemaName'],\
- #opars['queryName'],[qfilter])
- # seqNum=len(ds['rows'])
-
- #create new row
- row={}
- row[participantField]=patientId
- row['sequenceNum']=seqNum
- row['orthancSeries']=se
- row['dicomStudy']=sid
- row['orthancStudy']=s
- row['dicomSeries']=seid
- row['studyDate']=sdate
- row['seriesDescription']=seDesc
- srows.append(row)
- seqNum+=1
- #upload updates
- if len(srows)>0:
- db.modifyRows('insert',project,opars['schemaName'],\
- opars['queryName'],srows)
- i+=1
- print("Done")
- if __name__=="__main__":
- main(sys.argv[1])
|