loadDicom.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. import pydicom
  2. import numpy
  3. import sys
  4. import os
  5. import nibabel
  6. import json
  7. import datetime
  8. import re
  9. # load the DICOM files
  10. def load(dir):
  11. files = []
  12. print('Loading: {}'.format(dir))
  13. for fname in os.listdir(dir):
  14. print("loading: {}".format(fname))
  15. files.append(pydicom.dcmread(os.path.join(dir,fname)))
  16. print("file count: {}".format(len(files)))
  17. # skip files with no SliceLocation (eg scout views)
  18. slices = []
  19. skipcount = 0
  20. for f in files:
  21. if hasattr(f, 'SliceLocation'):
  22. slices.append(f)
  23. else:
  24. skipcount = skipcount + 1
  25. print("skipped, no SliceLocation: {}".format(skipcount))
  26. # ensure they are in the correct order
  27. slices = sorted(slices, key=lambda s: s.SliceLocation)
  28. return slices;
  29. # pixel aspects, assuming all slices are the same
  30. for s in slices:
  31. print("Pixel spacing: {}".format(s.PixelSpacing))
  32. return;
  33. def convertToNIfTI(slices):
  34. # create 3D array
  35. img_shape = list(slices[0].pixel_array.shape)
  36. img_shape.append(len(slices))
  37. img3d = numpy.zeros(img_shape)
  38. # get position and orientation parameters
  39. x0=numpy.array([float(f) for f in slices[0].ImagePositionPatient])
  40. x1=numpy.array([float(f) for f in slices[-1].ImagePositionPatient])
  41. n=(x1-x0)/(len(slices)-1.);
  42. f=numpy.array([float(f) for f in slices[0].ImageOrientationPatient])
  43. s=numpy.array([float(f) for f in slices[0].PixelSpacing])
  44. #create affine
  45. a=numpy.zeros((4,4))
  46. f1=numpy.zeros(4)
  47. f1[0:3]=f[0:3]
  48. #swap to account for row/column to (c,r) position mismatch
  49. a[:,1]=f1*s[1]
  50. f2=numpy.zeros(4)
  51. f2[0:3]=f[3:6]
  52. a[:,0]=f2*s[0]
  53. nn=numpy.zeros(4)
  54. nn[0:3]=n[0:3]
  55. a[:,2]=nn
  56. xn=numpy.ones(4)
  57. xn[0:3]=x0[0:3]
  58. a[:,3]=xn
  59. # fill 3D array with the images from the files
  60. for i, s in enumerate(slices):
  61. img2d = s.pixel_array
  62. img3d[:, :, i] = img2d
  63. #orientation and pixel spacing
  64. img = nibabel.Nifti1Image(img3d, a)
  65. return img
  66. def writeAnonymousSeries(slices,path,studyUID, fields):
  67. uid=uuid()
  68. seriesUID=uid.generateSeriesUUID('volume')
  69. i=0;
  70. for s in slices:
  71. outFile="DCM{:04d}.dcm".format(i)
  72. outFile=os.path.join(path,outFile)
  73. writeAnonymousDicomFile(s,studyUID,seriesUID,outFile,fields)
  74. i=i+1
  75. def writeAnonymousDicomFile(slice, studyUID, seriesUID, outFile, fields):
  76. uid=uuid()
  77. instanceUID=uid.generateSOPInstanceUUID('volume')
  78. file_meta = pydicom.Dataset()
  79. file_meta.MediaStorageSOPClassUID = slice.file_meta.MediaStorageSOPClassUID
  80. file_meta.MediaStorageSOPInstanceUID = instanceUID
  81. file_meta.ImplementationClassUID = slice.file_meta.ImplementationClassUID
  82. file_meta.TransferSyntaxUID=pydicom.uid.ImplicitVRLittleEndian
  83. print("Setting dataset values...")
  84. # Create the FileDataset instance (initially no data elements, but file_meta
  85. # supplied)
  86. ds = pydicom.FileDataset(outFile, {},
  87. file_meta=file_meta, preamble=b"\0" * 128)
  88. # Add the data elements -- not trying to set all required here. Check DICOM
  89. # standard
  90. ds.PatientName = "XXXXX"
  91. ds.PatientID = "xxxxxx"
  92. ds.StudyUID=studyUID
  93. ds.SeriesUID=seriesUID
  94. ds.SOPInstanceUID=instanceUID
  95. # Set the transfer syntax
  96. ds.is_little_endian = True
  97. ds.is_implicit_VR = True
  98. # Set creation date/time
  99. #dt = datetime.datetime.now()
  100. #ds.ContentDate = dt.strftime('%Y%m%d')
  101. #timeStr = dt.strftime('%H%M%S.%f') # long format with micro seconds
  102. ds.ContentTime = slice.ContentTime
  103. #add variables from Daniel's list (fields)
  104. for f in fields:
  105. try:
  106. ds[f]=slice[f];
  107. except:
  108. print("Field {} missing".format(f))
  109. ds.PixelData=slice.PixelData
  110. print("Writing test file", outFile)
  111. ds.save_as(outFile)
  112. print("File saved.")
  113. class uuid:
  114. def __init__(self):
  115. fhome=os.path.expanduser('~')
  116. fconfig=os.path.join(fhome,'.uuid','config.json')
  117. self.basePath=os.path.join(fhome,'.uuid')
  118. with open(fconfig,'r') as f:
  119. self.config=json.load(f)
  120. self.labelUUID={'series':'1','study':'2','instance':'3','frameOfReference':4}
  121. self.dataUUID={'volume':'1','segmentation':'2','transformation':'3'}
  122. def getTimeCode(x):
  123. hour=x.strftime("%H")
  124. hour=re.sub('^0','',hour)
  125. return hour+x.strftime("%M%S")
  126. def generateStudyUUID(self,type):
  127. x=datetime.datetime.now()
  128. date=x.strftime("%Y%m%d")
  129. studyFile=os.path.join(self.basePath,'studyCount'+date+'.txt')
  130. try:
  131. f=open(studyFile,"r")
  132. id=int(f.readline())
  133. id=id+k
  134. f.close()
  135. except:
  136. id=0
  137. studyId="{}.{}.{}.{}.{}".format(self.config["baseUUID"],self.labelUUID['study'],
  138. self.dataUUID[type],date,id)
  139. f=open(studyFile,"w")
  140. f.write("{}".format(id))
  141. f.close()
  142. return studyId
  143. def generateSOPInstanceUUID(self,type):
  144. baseUUID=self.config["baseUUID"]
  145. x=datetime.datetime.now()
  146. date=x.strftime("%Y%m%d")
  147. instanceFile=os.path.join(self.basePath,'instanceCount'+date+'.txt')
  148. try:
  149. f=open(instanceFile,"r")
  150. id=int(f.readline())
  151. id=id+1
  152. f.close()
  153. except:
  154. id=0
  155. instanceId="{}.{}.{}.{}.{}".format(baseUUID,self.labelUUID['instance'],
  156. self.dataUUID[type],date,id)
  157. f=open(instanceFile,"w")
  158. f.write("{}".format(id))
  159. f.close()
  160. return instanceId
  161. def generateFrameOfReferenceUUID(self,type):
  162. baseUUID=self.config["baseUUID"]
  163. basePath=self.basePath
  164. x=datetime.datetime.now()
  165. date=x.strftime("%Y%m%d")
  166. forFile=os.path.join(basePath,'frameCount'+date+'.txt')
  167. try:
  168. f=open(studyFile,"r")
  169. id=int(f.readline())
  170. id=id+1
  171. f.close()
  172. except:
  173. id=0
  174. forId="{}.{}.{}.{}.{}".format(baseUUID,self.labelUUID['frameOfReference'],
  175. self.dataUUID[type],date,id)
  176. f=open(forFile,"w")
  177. f.write("{}".format(id))
  178. f.close()
  179. return forId
  180. def generateSeriesUUID(self,type):
  181. baseUUID=self.config["baseUUID"]
  182. x=datetime.datetime.now()
  183. seriesInstanceUid=baseUUID+'.'+self.labelUUID['series']+'.'
  184. seriesInstanceUid+=self.dataUUID[type]+'.'+x.strftime("%Y%m%d")+'.'+uuid.getTimeCode(x)
  185. return seriesInstanceUid