organ_percentile.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import numpy
  2. import sys
  3. import os
  4. import json
  5. import nibabel
  6. def organ_percentile(img, mask, level, p):
  7. #ORGAN_PERCENTILE - computes suv_x the pth percentile of the distribution of
  8. # image intensity values in img from within some ROI mask
  9. #
  10. # Inputs:
  11. # img - image. ndarray
  12. # mask - ROI mask. Must be same dimension as img. Must be binary ndarray
  13. # p - percentile. Between 0-100
  14. #
  15. # Outputs:
  16. # suv_x - percentile of distribution. Defined by:
  17. #
  18. # suv_x
  19. # p/100 = ∫ H(x) dx
  20. # 0
  21. #
  22. # where H(x) is the normalized distribution of image values within mask
  23. #img = np.array(img)
  24. #mask = np.array(mask)
  25. h = img[mask == level]
  26. suv_x = numpy.percentile(h, p)
  27. return suv_x
  28. def main(parameterFile):
  29. fhome=os.path.expanduser('~')
  30. with open(os.path.join(fhome,".labkey","setup.json")) as f:
  31. setup=json.load(f)
  32. sys.path.insert(0,setup["paths"]["nixWrapper"])
  33. import nixWrapper
  34. nixWrapper.loadLibrary("labkeyInterface")
  35. import labkeyInterface
  36. import labkeyDatabaseBrowser
  37. import labkeyFileBrowser
  38. fconfig=os.path.join(fhome,'.labkey','network.json')
  39. net=labkeyInterface.labkeyInterface()
  40. net.init(fconfig)
  41. db=labkeyDatabaseBrowser.labkeyDB(net)
  42. fb=labkeyFileBrowser.labkeyFileBrowser(net)
  43. with open(parameterFile) as f:
  44. pars=json.load(f)
  45. #segmentation layout
  46. project=pars['project']
  47. dataset=pars['targetQuery']
  48. schema=pars['targetSchema']
  49. view=pars['viewName']
  50. segSchema=pars['segmentationSchema']
  51. segQuery=pars['segmentationQuery']
  52. qQuery=pars['percentileQuery']
  53. segVersion=pars['version']
  54. segVersionI=int(pars['versionNumber'])
  55. participantField=pars['participantField']
  56. tempBase=pars['tempBase']
  57. if not os.path.isdir(tempBase):
  58. os.makedirs(tempBase)
  59. qFilter=[]
  60. try:
  61. vList=';'.join(pars['participants'])
  62. qFilter.append({'variable':participantField,'value':vList,'oper':'in'})
  63. except KeyError:
  64. pass
  65. try:
  66. vList=';'.join(pars['visits'])
  67. qFilter.append({'variable':'visitCode','value':vList,'oper':'in'})
  68. except KeyError:
  69. pass
  70. #all images from database
  71. ds=db.selectRows(project,schema,dataset,qFilter,view)
  72. petField=pars['images']['PET']['queryField']
  73. rows=ds['rows']
  74. print('Selected {} rows'.format(len(rows)))
  75. #rows=[ds['rows'][0]]
  76. pv=numpy.concatenate((numpy.linspace(10,50,5),
  77. numpy.linspace(55,80,6),
  78. numpy.linspace(82,90,5),
  79. numpy.linspace(91,100,10)))
  80. #debug, select
  81. #rows1=[r for r in rows \
  82. # if r['patientCode']=='NIX-LJU-D2002-IRAE-A010' \
  83. # and r['visitCode']=='VISIT_6']
  84. #rows=rows1
  85. #rows=[r for r in rows if r[participantField]=='956/18']
  86. for r in rows:
  87. #is segmentation available
  88. localPET=os.path.join(tempBase,'PET.nii.gz')
  89. localSeg=os.path.join(tempBase,'Seg.nii.gz')
  90. for f in [localPET,localSeg]:
  91. if os.path.isfile(f):
  92. os.remove(f)
  93. #build image path
  94. try:
  95. remoteDir=fb.buildPathURL(project,[pars['imageDir'],\
  96. r['patientCode'],r['visitCode']])
  97. except TypeError:
  98. print('[{}/{}]: Skipping - Failed to build remote dir'.\
  99. format(r[participantField],r['SequenceNum']))
  100. continue
  101. print('{}: {}'.format(petField,r[petField]))
  102. if r[petField]==None:
  103. print('[{}/{}]: Skipping - Missing PET'.\
  104. format(r[participantField],r['SequenceNum']))
  105. continue
  106. remotePET=remoteDir+'/'+r[petField]
  107. print('{}:{}'.format(remotePET,fb.entryExists(remotePET)))
  108. vFilter={'variable':'version','value':segVersion,'oper':'eq'}
  109. idFilter={'variable':'patientCode','value':r['patientCode'], 'oper':'eq'}
  110. visitFilter={'variable':'visitCode','value':r['visitCode'], 'oper':'eq'}
  111. dsSeg=db.selectRows(project,segSchema,segQuery,[idFilter,visitFilter,vFilter])
  112. if len(dsSeg['rows'])!=1:
  113. print('[{}/{}] Skipping - missing segmentation, version [{}]'.\
  114. format(r[participantField],r['SequenceNum'],segVersion))
  115. continue
  116. remoteSeg=remoteDir+'/'+dsSeg['rows'][0]['segmentation']
  117. print('{}:{}'.format(remoteSeg,fb.entryExists(remoteSeg)))
  118. fb.readFileToFile(remotePET,localPET)
  119. fb.readFileToFile(remoteSeg,localSeg)
  120. niPET=nibabel.load(localPET)
  121. niSeg=nibabel.load(localSeg)
  122. #3 lungs
  123. #4 thyroid
  124. #5 bowel
  125. dsP=db.selectRows(project,schema,qQuery,[idFilter,visitFilter,vFilter])
  126. print('Deleting {} rows'.format(len(dsP['rows'])))
  127. db.modifyRows('delete',project,schema,qQuery,dsP['rows'])
  128. dspRows=[]
  129. for level in [1,2,3,4,5,6,7,8]:
  130. try:
  131. v=organ_percentile(niPET.get_fdata(),niSeg.get_fdata(),level,pv)
  132. except IndexError:
  133. print('Error for {}/{}: {}'.format(r['patientCode'],r['visitCode'],level))
  134. continue
  135. for (x,y) in zip(pv,v):
  136. #get existing entry
  137. seqNum=r['SequenceNum']+0.0001*x+0.01*segVersionI
  138. #print('[{:.8f}] {}/{}: {}/{}'.format(seqNum,r['patientCode'],r['visitCode'],x,y))
  139. # sFilter={'variable':'SequenceNum','value':'{}'.format(seqNum),'oper':'eq'}
  140. # oFilter={'variable':'organ','value':'{}'.format(level),'oper':'eq'}
  141. # mode='update'
  142. # if len(dsP['rows'])==0:
  143. # mode='insert'
  144. rowDSP={x:r[x] for x in [participantField,'patientCode','visitCode']}
  145. rowDSP['SequenceNum']=seqNum
  146. rowDSP['segmentationVersion']=segVersion
  147. # else:
  148. # rowDSP=dsP['rows'][0]
  149. rowDSP['percentile']=x
  150. rowDSP['value']=y
  151. rowDSP['organ']=level
  152. dspRows.append(rowDSP)
  153. print('Inserting {} rows'.format(len(dspRows)))
  154. db.modifyRows('insert',project,schema,qQuery,dspRows)
  155. print('Done')
  156. if __name__ == '__main__':
  157. main(sys.argv[1])