123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- import pydicom
- import numpy
- import sys
- import os
- import nibabel
- import json
- import datetime
- import re
- # load the DICOM files
- def load(dir):
- files = []
- print('Loading: {}'.format(dir))
- for fname in os.listdir(dir):
- print("loading: {}".format(fname))
- files.append(pydicom.dcmread(os.path.join(dir,fname)))
- print("file count: {}".format(len(files)))
- # skip files with no SliceLocation (eg scout views)
- slices = []
- skipcount = 0
- for f in files:
- if hasattr(f, 'SliceLocation'):
- slices.append(f)
- else:
- skipcount = skipcount + 1
- print("skipped, no SliceLocation: {}".format(skipcount))
- # ensure they are in the correct order
- slices = sorted(slices, key=lambda s: s.SliceLocation)
- return slices;
- # pixel aspects, assuming all slices are the same
- for s in slices:
- print("Pixel spacing: {}".format(s.PixelSpacing))
- return;
- def convertToNIfTI(slices):
- # create 3D array
- img_shape = list(slices[0].pixel_array.shape)
- img_shape.append(len(slices))
- img3d = numpy.zeros(img_shape)
- # get position and orientation parameters
- x0=numpy.array([float(f) for f in slices[0].ImagePositionPatient])
- x1=numpy.array([float(f) for f in slices[-1].ImagePositionPatient])
- n=(x1-x0)/(len(slices)-1.);
- f=numpy.array([float(f) for f in slices[0].ImageOrientationPatient])
- s=numpy.array([float(f) for f in slices[0].PixelSpacing])
-
- #create affine
- a=numpy.zeros((4,4))
- f1=numpy.zeros(4)
- f1[0:3]=f[0:3]
- #swap to account for row/column to (c,r) position mismatch
- a[:,1]=f1*s[1]
- f2=numpy.zeros(4)
- f2[0:3]=f[3:6]
- a[:,0]=f2*s[0]
- nn=numpy.zeros(4)
- nn[0:3]=n[0:3]
- a[:,2]=nn
- xn=numpy.ones(4)
- xn[0:3]=x0[0:3]
- a[:,3]=xn
-
- # fill 3D array with the images from the files
- for i, s in enumerate(slices):
- img2d = s.pixel_array
- img3d[:, :, i] = img2d
- #orientation and pixel spacing
- img = nibabel.Nifti1Image(img3d, a)
- img.header.set_slope_inter(float(slices[0].RescaleSlope),float(slices[0].RescaleIntercept))
- return img
- def writeAnonymousSeries(slices,path,patientID, studyUID, fields):
- uid=uuid()
- seriesUID=uid.generateSeriesUUID('volume')
- i=0;
- for s in slices:
- outFile="DCM{:04d}.dcm".format(i)
- outFile=os.path.join(path,outFile)
- writeAnonymousDicomFile(s,patientID,studyUID,seriesUID,outFile,fields)
- i=i+1
- def writeAnonymousDicomFile(slice, patientID, studyUID, seriesUID, outFile, fields):
- uid=uuid()
- instanceUID=uid.generateSOPInstanceUUID('volume')
- file_meta = pydicom.Dataset()
- file_meta.MediaStorageSOPClassUID = slice.file_meta.MediaStorageSOPClassUID
- file_meta.MediaStorageSOPInstanceUID = instanceUID
- file_meta.ImplementationClassUID = slice.file_meta.ImplementationClassUID
- file_meta.TransferSyntaxUID=pydicom.uid.ImplicitVRLittleEndian
- print("Setting dataset values...")
- # Create the FileDataset instance (initially no data elements, but file_meta
- # supplied)
- ds = pydicom.FileDataset(outFile, {},
- file_meta=file_meta, preamble=b"\0" * 128)
- # Add the data elements -- not trying to set all required here. Check DICOM
- # standard
- ds.PatientName = patientID
- ds.PatientID = patientID
- ds.StudyInstanceUID=studyUID
- ds.SeriesInstanceUID=seriesUID
- ds.SOPInstanceUID=instanceUID
- # Set the transfer syntax
- ds.is_little_endian = True
- ds.is_implicit_VR = True
- # Set creation date/time
- #dt = datetime.datetime.now()
- #ds.ContentDate = dt.strftime('%Y%m%d')
- #timeStr = dt.strftime('%H%M%S.%f') # long format with micro seconds
- ds.ContentTime = slice.ContentTime
- #add variables from Daniel's list (fields)
- for f in fields:
- try:
- ds[f]=slice[f];
- except:
- print("Field {} missing".format(f))
- ds.PixelData=slice.PixelData
- print("Writing test file", outFile)
- ds.save_as(outFile)
- print("File saved.")
- class uuid:
- def __init__(self):
- fhome=os.path.expanduser('~')
- fconfig=os.path.join(fhome,'.uuid','config.json')
- self.basePath=os.path.join(fhome,'.uuid')
- with open(fconfig,'r') as f:
- self.config=json.load(f)
- self.labelUUID={'series':'1','study':'2','instance':'3','frameOfReference':4}
- self.dataUUID={'volume':'1','segmentation':'2','transformation':'3'}
- def getTimeCode(x):
- hour=x.strftime("%H")
- hour=re.sub('^0','',hour)
- return hour+x.strftime("%M%S")
-
- def generateStudyUUID(self,type):
- x=datetime.datetime.now()
- date=x.strftime("%Y%m%d")
- studyFile=os.path.join(self.basePath,'studyCount'+date+'.txt')
- try:
- f=open(studyFile,"r")
- id=int(f.readline())
- id=id+1
- f.close()
- except:
- id=0
- studyId="{}.{}.{}.{}.{}".format(self.config["baseUUID"],self.labelUUID['study'],
- self.dataUUID[type],date,id)
- f=open(studyFile,"w")
- f.write("{}".format(id))
- f.close()
- return studyId
- def generateSOPInstanceUUID(self,type):
- baseUUID=self.config["baseUUID"]
- x=datetime.datetime.now()
- date=x.strftime("%Y%m%d")
- instanceFile=os.path.join(self.basePath,'instanceCount'+date+'.txt')
- try:
- f=open(instanceFile,"r")
- id=int(f.readline())
- id=id+1
- f.close()
- except:
- id=0
- instanceId="{}.{}.{}.{}.{}".format(baseUUID,self.labelUUID['instance'],
- self.dataUUID[type],date,id)
- f=open(instanceFile,"w")
- f.write("{}".format(id))
- f.close()
- return instanceId
- def generateFrameOfReferenceUUID(self,type):
- baseUUID=self.config["baseUUID"]
- basePath=self.basePath
- x=datetime.datetime.now()
- date=x.strftime("%Y%m%d")
- forFile=os.path.join(basePath,'frameCount'+date+'.txt')
- try:
- f=open(studyFile,"r")
- id=int(f.readline())
- id=id+1
- f.close()
- except:
- id=0
- forId="{}.{}.{}.{}.{}".format(baseUUID,self.labelUUID['frameOfReference'],
- self.dataUUID[type],date,id)
- f=open(forFile,"w")
- f.write("{}".format(id))
- f.close()
- return forId
-
- def generateSeriesUUID(self,type):
- baseUUID=self.config["baseUUID"]
- x=datetime.datetime.now()
- seriesInstanceUid=baseUUID+'.'+self.labelUUID['series']+'.'
- seriesInstanceUid+=self.dataUUID[type]+'.'+x.strftime("%Y%m%d")+'.'+uuid.getTimeCode(x)
- return seriesInstanceUid
|