scanOrthancQuick.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #labkey/orthanc interface
  2. #scans the orthanc internal database and fills labkey table
  3. #"Orthanc" section expected in the configuration file, with
  4. #"queryName": query to be filled for each image
  5. #"demographicsQuery": query to be filled for every patient
  6. #"schemaName": the schema both queries are part of
  7. #"project": name of the project under labkey that collects Orthanc data,
  8. # typically named Orthanc or similar
  9. #"participantField": sorting participant field label in labkey study
  10. import os
  11. import json
  12. import re
  13. import sys
  14. def main(parameterFile):
  15. fhome=os.path.expanduser('~')
  16. fsetup=os.path.join(fhome,'.labkey','setup.json')
  17. with open(fsetup,'r') as f:
  18. setup=json.load(f)
  19. sys.path.insert(0,setup['paths']['nixWrapper'])
  20. import nixWrapper
  21. nixWrapper.loadLibrary("labkeyInterface")
  22. import labkeyInterface
  23. import labkeyDatabaseBrowser
  24. nixWrapper.loadLibrary('orthancInterface')
  25. import orthancInterface
  26. import orthancDatabaseBrowser
  27. fconfig=os.path.join(fhome,'.labkey','network.json')
  28. net=labkeyInterface.labkeyInterface()
  29. net.init(fconfig)
  30. db=labkeyDatabaseBrowser.labkeyDB(net)
  31. onet=orthancInterface.orthancInterface()
  32. onet.init(fconfig)
  33. odb=orthancDatabaseBrowser.orthancDB(onet)
  34. with open(parameterFile) as f:
  35. pars=json.load(f)
  36. opars=pars['Orthanc']
  37. project=opars['project']
  38. participantField=opars['participantField']
  39. patients=odb.getPatients()
  40. #equivalent for labkey side?
  41. dsDemo=db.selectRows(project,opars['schemaName'],\
  42. opars['demographicsQuery'],[])
  43. dsPatients=[row['OrthancId'] for row in dsDemo['rows']]
  44. pMissing=[p for p in patients if p not in dsPatients]
  45. print('Missing : {}'.format(len(pMissing)))
  46. #we need details for all patients (some might have just a study uploaded
  47. pdata={p:odb.getPatientData(p) for p in patients}
  48. #update patient data for missing patients
  49. prows=[]
  50. for p in pMissing:
  51. dicom=pdata[p]['MainDicomTags']
  52. row={}
  53. row[participantField]=dicom['PatientID']
  54. row['birthDate']=dicom['PatientBirthDate']
  55. row['PatientName']=dicom['PatientName']
  56. row['OrthancId']=p
  57. prows.append(row)
  58. db.modifyRows('insert',project,opars['schemaName'],\
  59. opars['demographicsQuery'],prows)
  60. n=len(patients)
  61. i=0
  62. #download the full images dataset (~1000 rows)
  63. ds=db.selectRows(project,opars['schemaName'],opars['queryName'],[])
  64. for p in patients:
  65. dicom=pdata[p]['MainDicomTags']
  66. patientId=dicom['PatientID']
  67. #get all studies for pateint
  68. #qfilter={'variable':participantField,'value':patientId,'oper':'eq'}
  69. dsStudies=[row['orthancStudy'] for row in ds['rows'] if row[participantField]==patientId]
  70. #number of entries for patient (if new must be inserted)
  71. seqNum=len(dsStudies)
  72. #unique
  73. dsStudies=list(set(dsStudies))
  74. studies=pdata[p]['Studies']
  75. pHex=p.split('-')
  76. print("[{:>3d}/{:>3d}] ID: {:>10s} [{}] Studies: {:>2}/{:>2} Entries in DB: {:>4d}".format(i,n,patientId,pHex[-1],len(dsStudies),len(studies),seqNum))
  77. missingStudies=[s for s in studies if s not in dsStudies]
  78. #print('Missing studies: {}'.format(len(missingStudies)))
  79. srows=[]
  80. for s in missingStudies:
  81. sdata=odb.getStudyData(s)
  82. sdicom=sdata['MainDicomTags']
  83. sid=sdicom['StudyInstanceUID']
  84. #print('Data: {}'.format(sdata))
  85. #this is try/except protetcted in previous version...
  86. sdate="19700101"
  87. try:
  88. sdate=sdicom['StudyDate']
  89. except KeyError:
  90. pass
  91. #continue
  92. print('\tStudy[{}]: {}/{}'.format(sdate,s,sid))
  93. for se in sdata['Series']:
  94. sedata=odb.getSeriesData(se)
  95. sedicom=sedata['MainDicomTags']
  96. seid=sedicom['SeriesInstanceUID']
  97. #print('Data: {}'.format(sedata))
  98. seDesc="NONE"
  99. try:
  100. seDesc=sedicom['SeriesDescription']
  101. except KeyError:
  102. pass
  103. #replace letters that might trip the database
  104. spanishOAcute=''.join([chr(3619),chr(3603)])
  105. spanishAAcute=''.join([chr(3619),chr(3585)])
  106. seDesc=re.sub(spanishOAcute,'o',seDesc)
  107. seDesc=re.sub(spanishAAcute,'a',seDesc)
  108. print('\t\tSeries[{}]: {}/{}'.format(seDesc,se,seid))
  109. #qfilter={'variable':'orthancSeries','value':se,'oper':'eq'}
  110. #ds=db.selectRows(project,opars['schemaName'],\
  111. # opars['queryName'],[qfilter])
  112. #count existing entries for patient
  113. #qfilter={'variable':participantField,'value':patientId,'oper':'eq'}
  114. #ds=db.selectRows(project,opars['schemaName'],\
  115. #opars['queryName'],[qfilter])
  116. # seqNum=len(ds['rows'])
  117. #create new row
  118. row={}
  119. row[participantField]=patientId
  120. row['sequenceNum']=seqNum
  121. row['orthancSeries']=se
  122. row['dicomStudy']=sid
  123. row['orthancStudy']=s
  124. row['dicomSeries']=seid
  125. row['studyDate']=sdate
  126. row['seriesDescription']=seDesc
  127. srows.append(row)
  128. seqNum+=1
  129. #upload updates
  130. if len(srows)>0:
  131. db.modifyRows('insert',project,opars['schemaName'],\
  132. opars['queryName'],srows)
  133. i+=1
  134. print("Done")
  135. if __name__=="__main__":
  136. main(sys.argv[1])