def calcdvh(dose1, dose2, mask=None): plandose = image(dose1) otherdose = image(dose2) if mask == None or not mask.is_file(): print( 'No mask or maskregion specified; using isodose 50 volume of plandose for DVH analysis.' ) maskim = plandose.copy() maskim.tomask_atthreshold((50 / 100.) * maskim.max()) else: maskim = image(mask) plandose.applymask(maskim) otherdose.applymask(maskim) # note: array is sorted in reverse for DVHs, i.e. compute 100-n% planD2, planD50, planD98 = plandose.percentiles([98, 50, 2]) otherD2, otherD50, otherD98 = otherdose.percentiles([98, 50, 2]) labels = ["Dmax", "D2", "D50", "D98", "Dmean"] planres = plandose.max(), planD2, planD50, planD98, plandose.mean() otherres = otherdose.max(), otherD2, otherD50, otherD98, otherdose.mean() diffres = [ label + "=" + str(i - j) for label, i, j in zip(labels, planres, otherres) ] print(diffres) result = "files=" + str(dose1) + ";" + str(dose2) + " " + ' '.join(diffres) return result
def dvhcompare(casedir, *args, **kwargs): dose1 = '' dose2 = '' if len(args) == 0: #assume casedir is a dosia dumpdir assert os.path.isdir(casedir) dose1 = os.path.join(casedir, 'sum_dose.xdr') dose2 = os.path.join(casedir, 'sum_gpumcd_dose.xdr') else: #assume casedir is a file and secondfile also assert os.path.isfile(casedir) dose1 = casedir dose2 = args[0] #secondfile assert os.path.isfile(dose1) assert os.path.isfile(dose2) plandose = image(dose1) otherdose = image(dose2) maskim = None #is there a mask? if os.path.isfile(os.path.join(casedir, 'ptv.xdr')): maskim = image(os.path.absos.path(os.path.join(casedir, 'ptv.xdr'))) else: print( 'No mask or maskregion specified; using isodose 50 volume of plandose for DVH analysis.' ) maskim = plandose.copy() maskim.tomask_atthreshold((50 / 100.) * maskim.max()) plandose.applymask(maskim) otherdose.applymask(maskim) # note: array is sorted in reverse for DVHs, i.e. compute 100-n% planD2, planD50, planD98 = plandose.percentiles([98, 50, 2]) otherD2, otherD50, otherD98 = otherdose.percentiles([98, 50, 2]) labels = ["Dmax", "D2", "D50", "D98", "Dmean"] planres = plandose.max(), planD2, planD50, planD98, plandose.mean() otherres = otherdose.max(), otherD2, otherD50, otherD98, otherdose.mean() diffres = [ label + "=" + str(i - j) for label, i, j in zip(labels, planres, otherres) ] print(diffres) result = "files=" + dose1 + ";" + dose2 + " " + ' '.join(diffres) return result
def build_casedir(dname, loadimages=True): ct_dirs = glob.glob(path.join(dname, "*PLAN*")) upi_dirs = glob.glob(path.join(dname, "*UPI*")) studies = collections.defaultdict(dict) for ct_dir in ct_dirs: a = pydicom_object(ct_dir) if a.modality == 'CT': studies[a.studyid]['ct'] = a if loadimages: if a.PatientPosition != 'HFS': raise NotImplementedError( "Patient (Dose) is not in HFS position.") studies[a.studyid]['ct_im'] = image.image(ct_dir) # studies[a.studyid]['ct_im'].ct_to_hu(a.RescaleIntercept,a.RescaleSlope) else: IOError("Expected CT image, but", a.modality, "was found.") for upi_dir in upi_dirs: files_in_upi = glob.glob(path.join(upi_dir, '*')) for f in files_in_upi: a = pydicom_object(f) try: studies[a.studyid][a.sopid] except: studies[a.studyid][a.sopid] = {} if a.modality == "RTDOSE": studies[a.studyid][a.sopid]['dose'] = a if loadimages: # if str(a.data.DoseUnits) != "GY": # raise NotImplementedError("The provided dicom dose image has relative units.") # if str(a.data.DoseType) != "PHYSICAL": # raise NotImplementedError("The provided dicom dose image is not in physical units.") # if str(a.data.DoseSummationType) not in ["PLAN","FRACTION"]: # raise NotImplementedError("Dose was not computed for 'PLAN' or 'FRACTION'.") studies[a.studyid][a.sopid]['dose_im'] = image.image(f) studies[a.studyid][a.sopid]['dose_im'].mul( a.data.DoseGridScaling) elif a.modality == "RTPLAN": studies[a.studyid][a.sopid]['plan'] = a # if loadimages and a.PatientPosition != 'HFS': # raise NotImplementedError("Patient (Plan) is not in HFS position.") else: IOError("Expected RTDOSE or RTPLAN, but", a.modality, "was found.") return studies
def makedose_old(casedir, recalcdose=True, sumdoses=True): import glob, os from shutil import copyfile beamdirs = [ os.path.split(i)[0] for i in glob.glob(os.path.join(casedir, "**", "dbtype.dump"), recursive=True) ] print("recalcdose", "=", recalcdose) print("beamdirs", "=", beamdirs) if recalcdose or not os.path.isfile( os.path.join(beamdirs[0], "gpumcd_dose.xdr")): for beamdir in beamdirs: arrgs = "-i " + beamdir execute(dosiaengine, arrgs) #copy mask if exists. if os.path.isfile(os.path.join(beamdirs[0], 'ptvmask.xdr')): copyfile(os.path.join(beamdirs[0], 'ptvmask.xdr'), os.path.join(casedir, 'ptvmask.xdr')) tpsdosesum_fn = os.path.join(casedir, 'sum_dose.xdr') gpumcddosesum_fn = os.path.join(casedir, 'sum_gpumcd_dose.xdr') tpsdosesum = image(os.path.join(beamdirs[0], 'dose.xdr')) gpumcddosesum = image(os.path.join(beamdirs[0], 'gpumcd_dose.xdr')) if len(beamdirs) > 1: for beamdir in beamdirs[1:]: print(os.path.join(beamdir, 'dose.xdr')) imaget = image(os.path.join(beamdir, 'dose.xdr')) imageg = image(os.path.join(beamdir, 'gpumcd_dose.xdr')) tpsdosesum.add(imaget) gpumcddosesum.add(imageg) tpsdosesum.saveas(tpsdosesum_fn) gpumcddosesum.saveas(gpumcddosesum_fn) return [tpsdosesum_fn, gpumcddosesum_fn, beamdirs]
def calcgamma(dose1, dose2, outf, mask=None, overwrite=True): if overwrite: arrgs = "/dose1 " + str(dose1) + " /dose2 " + str( dose2) + " /outf " + str(outf) + " 2>&1" print(arrgs) execute(xdr_gamma, arrgs) gammamap = image(outf) if mask == None or not mask.is_file(): print( 'No mask or maskregion specified; using isodose 50 volume of gammamap for gamma statistical analysis.' ) maskim = image(dose1) maskim.tomask_atthreshold((50 / 100.) * maskim.max()) else: maskim = image(mask) gammamap.applymask(maskim) result = 'mean=' + str(gammamap.mean()) + ' passrate=' + str( gammamap.passrate()) result = "files=" + str(dose1) + ";" + str(dose2) + " " + result gammamap.saveas(str(outf) + '.masked.xdr') return result
def __init__(self, settings, ct_image): #,intercept=0,slope=1): ''' The supplied image is assumed to have its voxels set to HU. ''' assert (isinstance(ct_image, image)) assert (isinstance(settings, Settings)) hu2dens_table = [[], []] with open( path.join(settings.directories['hounsfield_conversion'], 'hu2dens.ini'), 'r') as f: for line in f.readlines(): if line.startswith('#'): continue hu2dens_table[0].append(float(line.split()[0])) hu2dens_table[1].append(float(line.split()[1])) dens2mat_table = [[], []] with open( path.join(settings.directories['hounsfield_conversion'], 'dens2mat.ini'), 'r') as f: for line in f.readlines(): if line.startswith('#'): continue dens2mat_table[0].append(float(line.split()[0])) dens2mat_table[1].append(line.split()[1]) dens = ct_image.copy() # dens.ct_to_hu(intercept,slope) if path.isdir(settings.debug['output']): dens.saveas(path.join(settings.debug['output'], 'ct_as_hu.xdr')) dens.hu_to_density(hu2dens_table) med = dens.copy() self.materials = med.density_to_materialindex(dens2mat_table) #self.materials.append("Tungsten") # collimator material self.phantom = Phantom(massDensityArray_image=dens, mediumIndexArray_image=med) self.dosemap = image(DimSize=med.header['DimSize'], ElementSpacing=med.header['ElementSpacing'], Offset=med.header['Offset'], dt='<f4') if path.isdir(settings.debug['output']): dens.saveas(path.join(settings.debug['output'], 'dens.xdr')) med.saveas(path.join(settings.debug['output'], 'med.xdr'))
def get_dose(self, dosemap): ''' Add dose to provided dosemap voxel by voxel. ''' #cant write to self.ct.dosemap directly, because self will be destroyed after this function exits! assert (isinstance(dosemap, image.image)) assert (self.ct.phantom.nvox() == dosemap.nvox()) newdose = image.image(DimSize=dosemap.header['DimSize'], ElementSpacing=dosemap.header['ElementSpacing'], Offset=dosemap.header['Offset'], dt='<f4') self.__gpumcd_object__.get_dose(newdose.get_ctypes_pointer_to_data()) newdose.imdata = np.asarray(newdose.imdata, order='F').reshape( tuple(reversed(newdose.imdata.shape))).swapaxes( 0, len(newdose.imdata.shape) - 1) dosemap.add(newdose)
def __init__(self, fname, *args, **kwargs): super().__init__(*args, **kwargs) if isinstance(fname, image.image): self.image = fname.copy() else: self.image = image.image(fname) x, y, z = self.image.get_slices_at_index() # import scipy.misc # scipy.misc.imsave("d:/slicex.png",x) # scipy.misc.imsave("d:/slicey.png",y) # scipy.misc.imsave("d:/slicez.png",z) s = np.uint8(np.interp(x, (x.min(), x.max()), (0, 255)).T) im = np.copy(np.rot90(np.rot90(s)), order='C') self.qimage = QImage(im.data, im.shape[1], im.shape[0], im.shape[1] * 1, QImage.Format_Grayscale8) self.ready = True
def resample(self, new_ElementSpacing=[2,2,2], allowcrop=True, order=1): ''' Resample image. Provide the desired ElementSpacing to which will be interpolated. Note that the spacing will be adjusted to obtain an integer image grid. Set allowcrop to True if you want to fix your new spacing and prefer to crop (subpixel distances) around the edges if necesary. ''' old_ElementSpacing = np.array(self.header['ElementSpacing']) new_ElementSpacing = np.array(new_ElementSpacing) new_req_shape = self.imdata.shape * old_ElementSpacing / new_ElementSpacing new_shape = np.round(new_req_shape) if not allowcrop: #We keep the extent of the image fixed, so we'll adjust the new_ElementSpacing such that it fits into the new shape. real_resize_factor = new_shape / self.imdata.shape new_ElementSpacing = old_ElementSpacing / real_resize_factor new_shape = tuple(int(i) for i in new_shape) #new image expects tuples self.crop_as(image.image(ElementSpacing=new_ElementSpacing,Offset=self.header['Offset'],DimSize=new_shape)) for s in self.imdata.shape: if s < 1: raise Exception('invalid image shape {}'.format(self.imdata.shape))
import ctypes,numpy as np,os,math,time from os import path import gpumcd import medimage as image print('Start of program.') sett = gpumcd.Settings("d:\\postdoc\\gpumcd_data") print(sett.planSettings.goalSfom) casedir = "d:\\postdoc\\analyses\\gpumcd_python" ct_image=image.image(path.join(casedir,'ct.xdr')) ct_image.ct_to_hu(1000,1) ct_image.resample([3,3,3]) ct = gpumcd.CT(sett,ct_image) #for dicoms, dont set intercept,slope. machfile = "d:/postdoc/gpumcd_data/machines/machine_van_sami/brentAgility.beamlets.gpumdt" engine = gpumcd.Engine(sett,ct,machfile) print('gpumcd init done.') print (engine.lasterror()) start_time = time.time() frame1size = 5
def __init__(self, input_, sett, *args, **kwargs): super().__init__(*args, **kwargs) self.sett = sett self.image = [] if isinstance(input_, image.image): self.image.append(input_.copy()) self.fname = "GPUMCD" elif isinstance(input_, list): self.fname = "GPUMCD" for im in input_: assert (isinstance(im, image.image)) self.image.append(im.copy()) else: self.image.append(image.image(input_)) self.fname = str(input_) self.imi = 0 self.axi = 0 self.slicei = int(self.image[self.imi].imdata.shape[self.axi] / 2) #FIXME isoc imnav = QHBoxLayout() imnav.setContentsMargins(0, 0, 0, 0) self.imselect = QComboBox() for i, im in enumerate(self.image): self.imselect.addItem(str(i)) self.imselect.currentIndexChanged.connect(self.setim) self.axselect = QComboBox() self.axselect.addItems(["x", "y", "z"]) self.axselect.currentIndexChanged.connect(self.setax) # self.sliceselect = QSpinBox() self.sliceselect = QSlider(Qt.Horizontal, self) self.sliceselect.setTickPosition(QSlider.TicksBelow) self.sliceselect.setMinimum(0) self.sliceselect.setMaximum( self.image[self.imi].imdata.shape[self.axi]) self.sliceselect.setValue(self.slicei) self.sliceselect.valueChanged.connect(self.setslice) self.savebutton = QPushButton('Save (.xdr)', self) self.savebutton.setToolTip('Save this image or images as XDR') self.savebutton.clicked.connect(self.save) imnav.addWidget(self.imselect, 0) imnav.addWidget(self.axselect, 0) imnav.addWidget(self.sliceselect, 0) imnav.addWidget(self.savebutton, 0) l = QVBoxLayout() self.fname_label = QLabel(self.fname) self.canvas = ImageCanvas() #blank for now self.setimagecanvas() l.addWidget(self.fname_label, 0) l.addLayout(imnav, 0) l.addWidget(self.canvas, 1) self.setLayout(l) self.ready = True
import medimage as image tps = image.image( "D:/postdoc/analyses/gpumcd_python/dicom/20181101 CTRT KNO-hals/1. UPI263538/2.25.117736802457958133832899838499337503296" ) xdr = image.image("D:/postdoc/analyses/gpumcd_python/ct.xdr") tps.saveas("D:/postdoc/analyses/gpumcd_python/TEST2.dcm") xdr.saveas("D:/postdoc/analyses/gpumcd_python/TEST.dcm")
BeamFrames[1] = gpumcd.BeamFrame(1) BeamFrames[1].beamInfo[0].relativeWeight = 100 BeamFrames[1].beamInfo[0].isoCenter.x = 0 BeamFrames[1].beamInfo[0].isoCenter.y = 0 BeamFrames[1].beamInfo[0].isoCenter.z = 0 BeamFrames[1].beamInfo[0].collimatorAngle.first = 0 BeamFrames[1].beamInfo[0].collimatorAngle.second = 0 BeamFrames[1].beamInfo[0].couchAngle.first = 0 BeamFrames[1].beamInfo[0].couchAngle.second = 0 BeamFrames[1].beamInfo[0].gantryAngle.first = 90 BeamFrames[1].beamInfo[0].gantryAngle.second = 90 BeamFrames[1].beamInfo[0].fieldMax.first = 1 BeamFrames[1].beamInfo[0].fieldMax.second = 1 BeamFrames[1].beamInfo[0].fieldMin.first = -1 BeamFrames[1].beamInfo[0].fieldMin.second = -1 print('executing simulation...') retval = Engine.execute_beamlets(*gpumcd.c_array_to_pointer(BeamFrames, True), planSettings) print(retval) dose = image.image(DimSize=[50, 50, 50], ElementSpacing=[0.2, 0.2, 0.2], dt='<f4') Engine.get_dose(dose.get_ctypes_pointer_to_data()) dose.saveas(path.join(outputdir, 'dose.xdr')) dose.saveas(path.join(outputdir, 'dose.mhd'))
for dirpath, dirnames, filenames in os.walk(dumpdir): if len(filenames) > 0: firstfname = os.path.join(dirpath, filenames[0]) try: #catch any problematic dcm # test if in CT dir dicomobj = dicom.pydicom_object(firstfname) if dicomobj.valid and dicomobj.sopid is None: #we've got a CT on our hands boys, yeehaw dcms.append(firstfname) studies[dicomobj.studyid]['ct'] = dirpath if loadimages: if dicomobj.PatientPosition != 'HFS': NotImplementedError( "Patient (Dose) is not in HFS position.") studies[dicomobj.studyid]['ct_im'] = image.image(dirpath) elif dicomobj.valid and dicomobj.sopid is not None: #this aint no CT-dir, therefore, iterate over all files to see whats what. for filename in filenames: fname = os.path.join(dirpath, filename) dicomobj = dicom.pydicom_object(fname) if dicomobj.valid: dcms.append(fname) else: notdcms.append(fname) #did we make a dict for this sopid already? try: studies[dicomobj.studyid][dicomobj.sopid] except:
# parser.add_argument('--perc', action='store_true') # opt = parser.parse_args() dose_threshold = 50 #in percentage volume rungpu = False noiselevels = [0.2, 0.5, 1.0, 2.0, 5.0] # noiselevels = [5.0] realisations = 10 # realisations =1 if rungpu: for nlevel in noiselevels: for real in range(realisations): im_art = image.image(DimSize=[50, 50, 50], ElementSpacing=[2, 2, 2]) im_art.fill_gaussian_noise(1000, nlevel) im_art.saveas(r'D:\postdoc\analyses\unc_study\artnoise' + str(nlevel) + '_' + str(real) + '.xdr') outname = r'D:\postdoc\analyses\unc_study\gpunoise' + str( nlevel) + '_' + str(real) + '.xdr' runners.execute( r"D:\postdoc\analyses\unc_study\BeamletLibraryConsumer\x64\Release\BeamletLibraryConsumer.exe", "-o \"" + outname + "\" -p " + str(nlevel)) mask = image.image(r"D:\postdoc\analyses\unc_study\gpunoise0.2_0.xdr") mask.tomask_atvolume(dose_threshold) for nlevel in noiselevels: print(nlevel)