runStat.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. import statUtils
  2. import os
  3. import radiomics
  4. import SimpleITK
  5. import sys
  6. import json
  7. import numpy
  8. def main(parFile='../templates/statistics.json'):
  9. setup=statUtils.loadSetup(parFile)
  10. rFile='radiomics.json'
  11. #update threshold values if needed
  12. with open(rFile,'w') as f:
  13. f.write(json.dumps(setup['radiomics']))
  14. setup['db'],setup['fb']=statUtils.connectDB('onko-nix')
  15. users=statUtils.getUsers(setup['db'],setup['project'])
  16. qFilter=[]
  17. try:
  18. vList=';'.join(setup['participants'])
  19. qFilter.append({'variable':'ParticipantId','value':vList,'oper':'in'})
  20. except KeyError:
  21. pass
  22. try:
  23. vList=';'.join(setup['visits'])
  24. qFilter.append({'variable':'visitCode','value':vList,'oper':'in'})
  25. except KeyError:
  26. pass
  27. ds=setup['db'].selectRows(setup['project'],'study',setup['imagingDataset'],qFilter)
  28. if not os.path.isdir(setup['localDir']):
  29. os.mkdir(setup['localDir'])
  30. #select just the first row; debugging
  31. rows=ds['rows']
  32. setup['values']=['COM','MTV','TLG','SUVmean','SUVmax','voxelCount','SUVSD']
  33. #params=os.path.join('..','templates','radiomics.yaml')
  34. setup['featureExtractor']=radiomics.featureextractor.RadiomicsFeatureExtractor(rFile)
  35. n=setup.get('n',-1)
  36. if n>0:
  37. rows=rows[:n]
  38. for r in rows:
  39. #check if we have to do calculation
  40. setup['SUVdataset']='SUVanalysis_liver'
  41. liverDone=checkData(setup,r)
  42. setup['SUVdataset']='SUVanalysis_SUVmax'
  43. suvMaxDone=checkData(setup,r)
  44. setup['SUVdataset']='SUVanalysis_liver1p5'
  45. liver1p5Done=checkData(setup,r)
  46. if liverDone and suvMaxDone and liver1p5Done:
  47. print('Skipping {} {}'.format(r['ParticipantId'],r['visitCode']))
  48. continue
  49. doneCode=f'({liverDone}/{liver1p5Done}/{suvMaxDone})'
  50. print(f'Done: (liver/liver1p5/suvMax): {doneCode}')
  51. #PET
  52. for q in ['petResampled']:
  53. localPath=statUtils.getImage(setup,r,q)
  54. if localPath=="NONE":
  55. continue
  56. pet=SimpleITK.ReadImage(localPath)
  57. #Seg
  58. segPaths=statUtils.getSegmentations(setup,r)
  59. if "NONE" in segPaths.values():
  60. os.remove(localPath)
  61. continue
  62. segKeys=list(segPaths.keys())
  63. for x in segPaths:
  64. print('Loaded {}/{}'.format(users[x],segPaths[x]))
  65. seg={x:SimpleITK.ReadImage(segPaths[x]) for x in segPaths}
  66. try:
  67. thr=setup['radiomics']['setting']['resegmentRange'][0]
  68. except KeyError:
  69. thr=None
  70. setup['radiomics']['setting']['resegmentRange']=None
  71. firstOrder=setup['radiomics']['featureClass']['firstorder']
  72. if 'Variance' not in firstOrder:
  73. firstOrder.append('Variance')
  74. #get value for maximum in organs or liver mean and std
  75. outputs=getValues(setup,r,pet,seg)
  76. setup['SUVdataset']='SUVanalysis'
  77. #uploadData(setup,r,outputs)
  78. print(outputs)
  79. default={'SUVmax':0,'SUVmean':0,'SUVSD':0}
  80. #liver threshold
  81. liverId=1
  82. liverThreshold={x:outputs[x].get(liverId,default)['SUVmean']
  83. +2*outputs[x].get(liverId,default)['SUVSD']
  84. for x in outputs}
  85. liver1p5Threshold={x:outputs[x].get(liverId,default)['SUVmean']
  86. +1.5*outputs[x].get(liverId,default)['SUVSD']
  87. for x in outputs}
  88. lesionId=4
  89. bmId=3
  90. suvMax={x:numpy.max([outputs[x].get(lesionId,default)['SUVmax'],
  91. outputs[x].get(bmId,default)['SUVmax']])
  92. for x in outputs}
  93. suvMaxThreshold={x:0.41*suvMax[x] for x in suvMax}
  94. print('thr[liver]={} thr[liver/1.5]={} thr(suvmax)={}'.format(liverThreshold,liver1p5Threshold,suvMaxThreshold))
  95. if not liverDone:
  96. setup['SUVdataset']='SUVanalysis_liver'
  97. liverOutputs=thresholdAnalysis(setup,r,pet,seg,liverThreshold)
  98. uploadData(setup,r,liverOutputs)
  99. #also for threshold=1.5
  100. if not liver1p5Done:
  101. setup['SUVdataset']='SUVanalysis_liver1p5'
  102. liver1p5Outputs=thresholdAnalysis(setup,r,pet,seg,liver1p5Threshold)
  103. uploadData(setup,r,liver1p5Outputs)
  104. if not suvMaxDone:
  105. setup['SUVdataset']='SUVanalysis_SUVmax'
  106. suvMaxOutputs=thresholdAnalysis(setup,r,pet,seg,suvMaxThreshold)
  107. uploadData(setup,r,suvMaxOutputs)
  108. #skip threshold of 4
  109. doThreshold4=False
  110. if doThreshold4:
  111. #threshold of 4
  112. setup['radiomics']['setting']['resegmentRange']=[4]
  113. setup['radiomics']['setting']['resegmentShape']=True
  114. outputs4=getValues(setup,r,pet,seg)
  115. setup['SUVdataset']='SUVanalysis_SUV4'
  116. uploadData(setup,r,outputs4)
  117. #outputs=getValues(setup,users,r,pet)
  118. #uploadData(setup,r,outputs)
  119. #cleanup
  120. os.remove(localPath)
  121. for x in segPaths:
  122. os.remove(segPaths[x])
  123. def thresholdAnalysis(setup,r,pet,seg,thrs):
  124. #thresholds thrs are by participant and region
  125. outputs={}
  126. for s in thrs:
  127. #update radiomics setting
  128. setup['radiomics']['setting']['resegmentRange']=[thrs[s]]
  129. setup['radiomics']['setting']['resegmentShape']=True
  130. outputs[s]=getValuesForSegmentation(setup,r,pet,seg[s])
  131. _=[outputs[s][y].update({'threshold':thrs[s]}) for y in outputs[s]]
  132. return outputs
  133. def getValues(setup,row,pet,seg):
  134. rFile='radiomics.json'
  135. with open(rFile,'w') as f:
  136. f.write(json.dumps(setup['radiomics']))
  137. setup['featureExtractor']=radiomics.featureextractor.RadiomicsFeatureExtractor(rFile)
  138. #find labels associated with each (non-overlaping) segmentation
  139. ids=statUtils.getSegments(list(seg.values())[0])
  140. outputs={x:{} for x in seg}
  141. for x in seg:
  142. for id in ids:
  143. print('{} {}'.format(id,ids[id]))
  144. try:
  145. output=statUtils.getRadiomicsComponentStats(setup,pet,seg[x],ids[id])
  146. except ValueError:
  147. continue
  148. outputs[x][ids[id]]=output
  149. os.remove(rFile)
  150. return outputs
  151. def getValuesForSegmentation(setup,row,pet,seg):
  152. rFile='radiomics.json'
  153. with open(rFile,'w') as f:
  154. f.write(json.dumps(setup['radiomics']))
  155. setup['featureExtractor']=radiomics.featureextractor.RadiomicsFeatureExtractor(rFile)
  156. #find labels associated with each (non-overlaping) segmentation
  157. ids=statUtils.getSegments(seg)
  158. outputs={}
  159. for id in ids:
  160. print('{} {}'.format(id,ids[id]))
  161. try:
  162. output=statUtils.getRadiomicsComponentStats(setup,pet,seg,ids[id])
  163. except ValueError:
  164. continue
  165. outputs[ids[id]]=output
  166. os.remove(rFile)
  167. return outputs
  168. def uploadData(setup,r,outputs):
  169. baseVar=['ParticipantId','SequenceNum','patientCode','visitCode']
  170. for x in outputs:
  171. for s in outputs[x]:
  172. output=outputs[x][s]
  173. output.update({x:r[x] for x in baseVar})
  174. output['User']=x
  175. output['segment']=s
  176. statUtils.updateDatasetRows(setup['db'],setup['project'],setup['SUVdataset'],[output])
  177. def checkData(setup,r):
  178. qFilter=[]
  179. qFilter.append({'variable':'ParticipantId','value':r['ParticipantId'],'oper':'eq'})
  180. qFilter.append({'variable':'visitCode','value':r['visitCode'],'oper':'eq'})
  181. ds=setup['db'].selectRows(setup['project'],'study',setup['SUVdataset'],qFilter)
  182. n=len(ds['rows'])
  183. print('[{}:{}/{}] got {} rows.'.format(setup['SUVdataset'],r['ParticipantId'],r['visitCode'],n))
  184. return n>0
  185. if __name__=='__main__':
  186. main(sys.argv[1])