### Tumor Generateion import random import cv2 import elasticdeform import numpy as np from scipy.ndimage import gaussian_filter def generate_prob_function(mask_shape): sigma = np.random.uniform(3,15) # uniform noise generate a = np.random.uniform(0, 1, size=(mask_shape[0],mask_shape[1],mask_shape[2])) # Gaussian filter # this taks some time a_2 = gaussian_filter(a, sigma=sigma) scale = np.random.uniform(0.19, 0.21) base = np.random.uniform(0.04, 0.06) a = scale * (a_2 - np.min(a_2)) / (np.max(a_2) - np.min(a_2)) + base return a # Step 1: Random select (numbers) location for tumor. def random_select(mask_scan): # we first find z index and then sample point with z slice z_start, z_end = np.where(np.any(mask_scan, axis=(0, 1)))[0][[0, -1]] # we need to strict number z's position (0.3 - 0.7 in the middle of liver) z = round(random.uniform(0.3, 0.7) * (z_end - z_start)) + z_start liver_mask = mask_scan[..., z] # erode the mask (we don't want the edge points) kernel = np.ones((5,5), dtype=np.uint8) liver_mask = cv2.erode(liver_mask, kernel, iterations=1) coordinates = np.argwhere(liver_mask == 1) random_index = np.random.randint(0, len(coordinates)) xyz = coordinates[random_index].tolist() # get x,y xyz.append(z) potential_points = xyz return potential_points # Step 2 : generate the ellipsoid def get_ellipsoid(x, y, z): """" x, y, z is the radius of this ellipsoid in x, y, z direction respectly. """ sh = (4*x, 4*y, 4*z) out = np.zeros(sh, int) aux = np.zeros(sh) radii = np.array([x, y, z]) com = np.array([2*x, 2*y, 2*z]) # center point # calculate the ellipsoid bboxl = np.floor(com-radii).clip(0,None).astype(int) bboxh = (np.ceil(com+radii)+1).clip(None, sh).astype(int) roi = out[tuple(map(slice,bboxl,bboxh))] roiaux = aux[tuple(map(slice,bboxl,bboxh))] logrid = *map(np.square,np.ogrid[tuple( map(slice,(bboxl-com)/radii,(bboxh-com-1)/radii,1j*(bboxh-bboxl)))]), dst = (1-sum(logrid)).clip(0,None) mask = dst>roiaux roi[mask] = 1 np.copyto(roiaux,dst,where=mask) return out def get_fixed_geo(mask_scan, tumor_type): enlarge_x, enlarge_y, enlarge_z = 160, 160, 160 geo_mask = np.zeros((mask_scan.shape[0] + enlarge_x, mask_scan.shape[1] + enlarge_y, mask_scan.shape[2] + enlarge_z), dtype=np.int8) # texture_map = np.zeros((mask_scan.shape[0] + enlarge_x, mask_scan.shape[1] + enlarge_y, mask_scan.shape[2] + enlarge_z), dtype=np.float16) tiny_radius, small_radius, medium_radius, large_radius = 4, 8, 16, 32 if tumor_type == 'tiny': num_tumor = random.randint(3,10) for _ in range(num_tumor): # Tiny tumor x = random.randint(int(0.75*tiny_radius), int(1.25*tiny_radius)) y = random.randint(int(0.75*tiny_radius), int(1.25*tiny_radius)) z = random.randint(int(0.75*tiny_radius), int(1.25*tiny_radius)) sigma = random.uniform(0.5,1) geo = get_ellipsoid(x, y, z) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(0,1)) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(1,2)) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(0,2)) point = random_select(mask_scan) new_point = [point[0] + enlarge_x//2, point[1] + enlarge_y//2, point[2] + enlarge_z//2] x_low, x_high = new_point[0] - geo.shape[0]//2, new_point[0] + geo.shape[0]//2 y_low, y_high = new_point[1] - geo.shape[1]//2, new_point[1] + geo.shape[1]//2 z_low, z_high = new_point[2] - geo.shape[2]//2, new_point[2] + geo.shape[2]//2 # paste small tumor geo into test sample geo_mask[x_low:x_high, y_low:y_high, z_low:z_high] += geo if tumor_type == 'small': num_tumor = random.randint(3,10) for _ in range(num_tumor): # Small tumor x = random.randint(int(0.75*small_radius), int(1.25*small_radius)) y = random.randint(int(0.75*small_radius), int(1.25*small_radius)) z = random.randint(int(0.75*small_radius), int(1.25*small_radius)) sigma = random.randint(1, 2) geo = get_ellipsoid(x, y, z) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(0,1)) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(1,2)) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(0,2)) # texture = get_texture((4*x, 4*y, 4*z)) point = random_select(mask_scan) new_point = [point[0] + enlarge_x//2, point[1] + enlarge_y//2, point[2] + enlarge_z//2] x_low, x_high = new_point[0] - geo.shape[0]//2, new_point[0] + geo.shape[0]//2 y_low, y_high = new_point[1] - geo.shape[1]//2, new_point[1] + geo.shape[1]//2 z_low, z_high = new_point[2] - geo.shape[2]//2, new_point[2] + geo.shape[2]//2 # paste small tumor geo into test sample geo_mask[x_low:x_high, y_low:y_high, z_low:z_high] += geo # texture_map[x_low:x_high, y_low:y_high, z_low:z_high] = texture if tumor_type == 'medium': num_tumor = random.randint(2, 5) for _ in range(num_tumor): # medium tumor x = random.randint(int(0.75*medium_radius), int(1.25*medium_radius)) y = random.randint(int(0.75*medium_radius), int(1.25*medium_radius)) z = random.randint(int(0.75*medium_radius), int(1.25*medium_radius)) sigma = random.randint(3, 6) geo = get_ellipsoid(x, y, z) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(0,1)) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(1,2)) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(0,2)) # texture = get_texture((4*x, 4*y, 4*z)) point = random_select(mask_scan) new_point = [point[0] + enlarge_x//2, point[1] + enlarge_y//2, point[2] + enlarge_z//2] x_low, x_high = new_point[0] - geo.shape[0]//2, new_point[0] + geo.shape[0]//2 y_low, y_high = new_point[1] - geo.shape[1]//2, new_point[1] + geo.shape[1]//2 z_low, z_high = new_point[2] - geo.shape[2]//2, new_point[2] + geo.shape[2]//2 # paste medium tumor geo into test sample geo_mask[x_low:x_high, y_low:y_high, z_low:z_high] += geo # texture_map[x_low:x_high, y_low:y_high, z_low:z_high] = texture if tumor_type == 'large': num_tumor = random.randint(1,3) for _ in range(num_tumor): # Large tumor x = random.randint(int(0.75*large_radius), int(1.25*large_radius)) y = random.randint(int(0.75*large_radius), int(1.25*large_radius)) z = random.randint(int(0.75*large_radius), int(1.25*large_radius)) sigma = random.randint(5, 10) geo = get_ellipsoid(x, y, z) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(0,1)) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(1,2)) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(0,2)) # texture = get_texture((4*x, 4*y, 4*z)) point = random_select(mask_scan) new_point = [point[0] + enlarge_x//2, point[1] + enlarge_y//2, point[2] + enlarge_z//2] x_low, x_high = new_point[0] - geo.shape[0]//2, new_point[0] + geo.shape[0]//2 y_low, y_high = new_point[1] - geo.shape[1]//2, new_point[1] + geo.shape[1]//2 z_low, z_high = new_point[2] - geo.shape[2]//2, new_point[2] + geo.shape[2]//2 # paste small tumor geo into test sample geo_mask[x_low:x_high, y_low:y_high, z_low:z_high] += geo # texture_map[x_low:x_high, y_low:y_high, z_low:z_high] = texture if tumor_type == "mix": # tiny num_tumor = random.randint(3,10) for _ in range(num_tumor): # Tiny tumor x = random.randint(int(0.75*tiny_radius), int(1.25*tiny_radius)) y = random.randint(int(0.75*tiny_radius), int(1.25*tiny_radius)) z = random.randint(int(0.75*tiny_radius), int(1.25*tiny_radius)) sigma = random.uniform(0.5,1) geo = get_ellipsoid(x, y, z) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(0,1)) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(1,2)) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(0,2)) point = random_select(mask_scan) new_point = [point[0] + enlarge_x//2, point[1] + enlarge_y//2, point[2] + enlarge_z//2] x_low, x_high = new_point[0] - geo.shape[0]//2, new_point[0] + geo.shape[0]//2 y_low, y_high = new_point[1] - geo.shape[1]//2, new_point[1] + geo.shape[1]//2 z_low, z_high = new_point[2] - geo.shape[2]//2, new_point[2] + geo.shape[2]//2 # paste small tumor geo into test sample geo_mask[x_low:x_high, y_low:y_high, z_low:z_high] += geo # small num_tumor = random.randint(5,10) for _ in range(num_tumor): # Small tumor x = random.randint(int(0.75*small_radius), int(1.25*small_radius)) y = random.randint(int(0.75*small_radius), int(1.25*small_radius)) z = random.randint(int(0.75*small_radius), int(1.25*small_radius)) sigma = random.randint(1, 2) geo = get_ellipsoid(x, y, z) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(0,1)) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(1,2)) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(0,2)) # texture = get_texture((4*x, 4*y, 4*z)) point = random_select(mask_scan) new_point = [point[0] + enlarge_x//2, point[1] + enlarge_y//2, point[2] + enlarge_z//2] x_low, x_high = new_point[0] - geo.shape[0]//2, new_point[0] + geo.shape[0]//2 y_low, y_high = new_point[1] - geo.shape[1]//2, new_point[1] + geo.shape[1]//2 z_low, z_high = new_point[2] - geo.shape[2]//2, new_point[2] + geo.shape[2]//2 # paste small tumor geo into test sample geo_mask[x_low:x_high, y_low:y_high, z_low:z_high] += geo # texture_map[x_low:x_high, y_low:y_high, z_low:z_high] = texture # medium num_tumor = random.randint(2, 5) for _ in range(num_tumor): # medium tumor x = random.randint(int(0.75*medium_radius), int(1.25*medium_radius)) y = random.randint(int(0.75*medium_radius), int(1.25*medium_radius)) z = random.randint(int(0.75*medium_radius), int(1.25*medium_radius)) sigma = random.randint(3, 6) geo = get_ellipsoid(x, y, z) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(0,1)) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(1,2)) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(0,2)) # texture = get_texture((4*x, 4*y, 4*z)) point = random_select(mask_scan) new_point = [point[0] + enlarge_x//2, point[1] + enlarge_y//2, point[2] + enlarge_z//2] x_low, x_high = new_point[0] - geo.shape[0]//2, new_point[0] + geo.shape[0]//2 y_low, y_high = new_point[1] - geo.shape[1]//2, new_point[1] + geo.shape[1]//2 z_low, z_high = new_point[2] - geo.shape[2]//2, new_point[2] + geo.shape[2]//2 # paste medium tumor geo into test sample geo_mask[x_low:x_high, y_low:y_high, z_low:z_high] += geo # texture_map[x_low:x_high, y_low:y_high, z_low:z_high] = texture # large num_tumor = random.randint(1,3) for _ in range(num_tumor): # Large tumor x = random.randint(int(0.75*large_radius), int(1.25*large_radius)) y = random.randint(int(0.75*large_radius), int(1.25*large_radius)) z = random.randint(int(0.75*large_radius), int(1.25*large_radius)) sigma = random.randint(5, 10) geo = get_ellipsoid(x, y, z) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(0,1)) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(1,2)) geo = elasticdeform.deform_random_grid(geo, sigma=sigma, points=3, order=0, axis=(0,2)) # texture = get_texture((4*x, 4*y, 4*z)) point = random_select(mask_scan) new_point = [point[0] + enlarge_x//2, point[1] + enlarge_y//2, point[2] + enlarge_z//2] x_low, x_high = new_point[0] - geo.shape[0]//2, new_point[0] + geo.shape[0]//2 y_low, y_high = new_point[1] - geo.shape[1]//2, new_point[1] + geo.shape[1]//2 z_low, z_high = new_point[2] - geo.shape[2]//2, new_point[2] + geo.shape[2]//2 # paste small tumor geo into test sample geo_mask[x_low:x_high, y_low:y_high, z_low:z_high] += geo # texture_map[x_low:x_high, y_low:y_high, z_low:z_high] = texture geo_mask = geo_mask[enlarge_x//2:-enlarge_x//2, enlarge_y//2:-enlarge_y//2, enlarge_z//2:-enlarge_z//2] # texture_map = texture_map[enlarge_x//2:-enlarge_x//2, enlarge_y//2:-enlarge_y//2, enlarge_z//2:-enlarge_z//2] geo_mask = (geo_mask * mask_scan) >=1 return geo_mask def SynthesisTumor(mask_scan, tumor_type, texture): # for speed_generate_tumor, we only send the liver part into the generate program x_start, x_end = np.where(np.any(mask_scan, axis=(1, 2)))[0][[0, -1]] y_start, y_end = np.where(np.any(mask_scan, axis=(0, 2)))[0][[0, -1]] z_start, z_end = np.where(np.any(mask_scan, axis=(0, 1)))[0][[0, -1]] # shrink the boundary x_start, x_end = max(0, x_start+1), min(mask_scan.shape[0], x_end-1) y_start, y_end = max(0, y_start+1), min(mask_scan.shape[1], y_end-1) z_start, z_end = max(0, z_start+1), min(mask_scan.shape[2], z_end-1) liver_mask = get_fixed_geo(mask_scan, tumor_type) mask_scan[x_start:x_end, y_start:y_end, z_start:z_end] = liver_mask return mask_scan if __name__ == 'main': geo_mask = get_fixed_geo(mask_scan, tumor_type)