scanOrthancQuickLocal.py 5.8 KB

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