def create_dvh(structure, dcm_struct, dcm_dose): structure_dose_values = find_dose_within_structure(structure, dcm_struct, dcm_dose) hist = np.histogram(structure_dose_values, 100) freq = hist[0] bin_edge = hist[1] bin_mid = (bin_edge[1::] + bin_edge[:-1:]) / 2 cumulative = np.cumsum(freq[::-1]) cumulative = cumulative[::-1] bin_mid = np.append([0], bin_mid) cumulative = np.append(cumulative[0], cumulative) percent_cumulative = cumulative / cumulative[0] * 100 plt.plot(bin_mid, percent_cumulative, label=structure) plt.title("DVH") plt.xlabel("Dose (Gy)") plt.ylabel("Relative Volume (%)")
def angle_dd2dcm(angle): diff = np.append(np.diff(angle), 0) movement = (np.empty_like(angle)).astype(str) movement[diff > 0] = "CW" movement[diff < 0] = "CC" movement[diff == 0] = "NONE" converted_angle = np.array(angle, copy=False) converted_angle[ converted_angle < 0] = converted_angle[converted_angle < 0] + 360 converted_angle = converted_angle.astype(str).tolist() return converted_angle, movement
def visual_alignment_of_equivalent_ellipse(x, y, width, length, callback): """Visually align the equivalent ellipse to the insert.""" insert = shapely_insert(x, y) unit_circle = shapely.geometry.Point(0, 0).buffer(1) initial_ellipse = shapely.affinity.scale(unit_circle, xfact=width / 2, yfact=length / 2) def minimising_function(optimiser_input): x_shift, y_shift, rotation_angle = optimiser_input rotated = shapely.affinity.rotate(initial_ellipse, rotation_angle, use_radians=True) translated = shapely.affinity.translate(rotated, xoff=x_shift, yoff=y_shift) disjoint_area = (translated.difference(insert).area + insert.difference(translated).area) return disjoint_area / 400 x0 = np.append(np.squeeze(insert.centroid.coords), np.pi / 4) niter = 10 T = insert.area / 40000 stepsize = 3 niter_success = 2 output = scipy.optimize.basinhopping( minimising_function, x0, niter=niter, T=T, stepsize=stepsize, niter_success=niter_success, callback=callback, ) x_shift, y_shift, rotation_angle = output.x return x_shift, y_shift, rotation_angle
def read_mapcheck_txt(file_name): """ Read native MapCheck data file and return dose array. Parameters ---------- file_name : string | file name of MapCheck file including path Returns ------- MapCheck : named tuple | MapCheck.x = np.array, float x-coords | MapCheck.y = np.array, float y-coords | MapCheck.dose = np.array (x,y), float dose """ Mapcheck = namedtuple("Mapcheck", ["x", "y", "dose"]) with open(file_name, "r") as mapcheck_file: m_chk = "\n".join(mapcheck_file.readlines()) m_chk = m_chk.split("Dose Interpolated")[-1] m_chk = m_chk.split("\n")[2:] temp = [r for r in csv.reader(m_chk, delimiter="\t") if "Xcm" in r] x_coord = np.array(temp[0][2:]).astype(float) y_coord, dose = np.array([]), np.array([]) for line in csv.reader(m_chk, delimiter="\t"): if len(line) > 1: try: line = [float(r) for r in line] y_coord = np.insert(y_coord, 0, float(line[0])) dose = np.append(dose, line[2:]) except ValueError: pass dose = np.array(dose).flatten().astype(float) dose.shape = (len(x_coord), len(y_coord)) return Mapcheck(x_coord, y_coord, dose)
def _from_pandas(cls: Type[DeliveryGeneric], table) -> DeliveryGeneric: raw_monitor_units = table["Step Dose/Actual Value (Mu)"] diff = np.append([0], np.diff(raw_monitor_units)) diff[diff < 0] = 0 monitor_units = np.cumsum(diff) gantry = table[GANTRY_NAME] collimator = table[COLLIMATOR_NAME] y1_bank = [table[name] for name in Y1_LEAF_BANK_NAMES] y2_bank = [table[name] for name in Y2_LEAF_BANK_NAMES] mlc = [y1_bank, y2_bank] mlc = np.swapaxes(mlc, 0, 2) jaw = [table[name] for name in JAW_NAMES] jaw = np.swapaxes(jaw, 0, 1) return cls(monitor_units, gantry, collimator, mlc, jaw)
def _single_calculate_deformability(x_test, y_test, x_data, y_data, z_data): """Return the result of the deformability test for a single test point. The deformability test applies a shift to the spline to determine whether or not sufficient information for modelling is available. For further details on the deformability test see the *Methods: Defining valid prediction regions of the spline* section within <http://dx.doi.org/10.1016/j.ejmp.2015.11.002>. Parameters ---------- x_test : float The x coordinate of the point to test y_test : float The y coordinate of the point to test x_data : np.ndarray The x coordinates of the model data to test y_data : np.ndarray The y coordinates of the model data to test z_data : np.ndarray The z coordinates of the model data to test Returns ------- deformability : float The resulting deformability between 0 and 1 representing the ratio of deviation the spline model underwent at the point in question by introducing an outlier at the point in question. """ deviation = 0.02 adjusted_x_data = np.append(x_data, x_test) adjusted_y_data = np.append(y_data, y_test) bbox = [ min(adjusted_x_data), max(adjusted_x_data), min(adjusted_y_data), max(adjusted_y_data), ] initial_model = scipy.interpolate.SmoothBivariateSpline(x_data, y_data, z_data, bbox=bbox, kx=2, ky=1).ev( x_test, y_test) pos_adjusted_z_data = np.append(z_data, initial_model + deviation) neg_adjusted_z_data = np.append(z_data, initial_model - deviation) pos_adjusted_model = scipy.interpolate.SmoothBivariateSpline( adjusted_x_data, adjusted_y_data, pos_adjusted_z_data, kx=2, ky=1).ev(x_test, y_test) neg_adjusted_model = scipy.interpolate.SmoothBivariateSpline( adjusted_x_data, adjusted_y_data, neg_adjusted_z_data, kx=2, ky=1).ev(x_test, y_test) deformability_from_pos_adjustment = (pos_adjusted_model - initial_model) / deviation deformability_from_neg_adjustment = (initial_model - neg_adjusted_model) / deviation deformability = np.max( [deformability_from_pos_adjustment, deformability_from_neg_adjustment]) return deformability
def image_analyze(volume, i_opt): xfield = [] yfield = [] rotfield = [] if i_opt.startswith(("y", "yeah", "yes")): kx = 0 ky = 0 krot = 0 for item in range(0, volume.shape[2]): stack1 = np.sum( volume[ int( np.shape(volume)[0] / 2 - np.amin([np.shape(volume)[0], np.shape(volume)[1]]) / 2 ) : int( np.shape(volume)[0] / 2 + np.amin([np.shape(volume)[0], np.shape(volume)[1]]) / 2 ), int( np.shape(volume)[1] / 2 - np.amin([np.shape(volume)[0], np.shape(volume)[1]]) / 2 ) : int( np.shape(volume)[1] / 2 + np.amin([np.shape(volume)[0], np.shape(volume)[1]]) / 2 ), item, ], axis=0, ) maxstack1 = np.amax(stack1) # stack2 = np.sum(volume[:, :, item], axis=1) stack2 = np.sum( volume[ int( np.shape(volume)[0] / 2 - np.amin([np.shape(volume)[0], np.shape(volume)[1]]) / 2 ) : int( np.shape(volume)[0] / 2 + np.amin([np.shape(volume)[0], np.shape(volume)[1]]) / 2 ), int( np.shape(volume)[1] / 2 - np.amin([np.shape(volume)[0], np.shape(volume)[1]]) / 2 ) : int( np.shape(volume)[1] / 2 + np.amin([np.shape(volume)[0], np.shape(volume)[1]]) / 2 ), item, ], axis=1, ) maxstack2 = np.amax(stack2) if maxstack2 / maxstack1 > 1.1: # It is a Y field folder if ky == 0: yfield = volume[:, :, item] yfield = yfield[:, :, np.newaxis] else: volappend = volume[:, :, item] yfield = np.append(yfield, volappend[:, :, np.newaxis], axis=2) ky = ky + 1 elif maxstack2 / maxstack1 < 0.9: # It is a X field folder if kx == 0: xfield = volume[:, :, item] xfield = xfield[:, :, np.newaxis] else: # xfield=xfield[:,:,np.newaxis] volappend = volume[:, :, item] xfield = np.append(xfield, volappend[:, :, np.newaxis], axis=2) kx = kx + 1 else: # It is a field rotation folder if krot == 0: rotfield = volume[:, :, item] rotfield = rotfield[:, :, np.newaxis] else: # rotfield = rotfield[:, :, np.newaxis] volappend = volume[:, :, item] rotfield = np.append(rotfield, volappend[:, :, np.newaxis], axis=2) krot = krot + 1 else: kx = 0 ky = 0 krot = 0 for item in range(0, volume.shape[2]): stack1 = np.sum( volume[ int( np.shape(volume)[0] / 2 - np.amin([np.shape(volume)[0], np.shape(volume)[1]]) / 2 ) : int( np.shape(volume)[0] / 2 + np.amin([np.shape(volume)[0], np.shape(volume)[1]]) / 2 ), int( np.shape(volume)[1] / 2 - np.amin([np.shape(volume)[0], np.shape(volume)[1]]) / 2 ) : int( np.shape(volume)[1] / 2 + np.amin([np.shape(volume)[0], np.shape(volume)[1]]) / 2 ), item, ], axis=0, ) maxstack1 = np.amax(stack1) # stack2 = np.sum(volume[:, :, item], axis=1) stack2 = np.sum( volume[ int( np.shape(volume)[0] / 2 - np.amin([np.shape(volume)[0], np.shape(volume)[1]]) / 2 ) : int( np.shape(volume)[0] / 2 + np.amin([np.shape(volume)[0], np.shape(volume)[1]]) / 2 ), int( np.shape(volume)[1] / 2 - np.amin([np.shape(volume)[0], np.shape(volume)[1]]) / 2 ) : int( np.shape(volume)[1] / 2 + np.amin([np.shape(volume)[0], np.shape(volume)[1]]) / 2 ), item, ], axis=1, ) maxstack2 = np.amax(stack2) if maxstack2 / maxstack1 > 1.5: # It is a Y field folder if ky == 0: yfield = volume[:, :, item] yfield = yfield[:, :, np.newaxis] else: volappend = volume[:, :, item] yfield = np.append(yfield, volappend[:, :, np.newaxis], axis=2) ky = ky + 1 elif maxstack2 / maxstack1 < 0.5: # It is a X field folder if kx == 0: xfield = volume[:, :, item] xfield = xfield[:, :, np.newaxis] else: # xfield=xfield[:,:,np.newaxis] volappend = volume[:, :, item] xfield = np.append(xfield, volappend[:, :, np.newaxis], axis=2) kx = kx + 1 else: # It is a field rotation folder if krot == 0: rotfield = volume[:, :, item] rotfield = rotfield[:, :, np.newaxis] else: # rotfield = rotfield[:, :, np.newaxis] volappend = volume[:, :, item] rotfield = np.append(rotfield, volappend[:, :, np.newaxis], axis=2) krot = krot + 1 return xfield, yfield, rotfield