msbackup / GenCT-ageencoder /mask_generation.py
qic999's picture
Upload folder using huggingface_hub
3bc8d9b verified
### 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)