|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import numpy as np
|
|
|
import torch
|
|
|
import torch.nn.functional as F
|
|
|
from monai.transforms import Rand3DElastic, RandAffine, RandZoom
|
|
|
from monai.utils import ensure_tuple_rep
|
|
|
|
|
|
|
|
|
def erode3d(input_tensor, erosion=3):
|
|
|
|
|
|
erosion = ensure_tuple_rep(erosion, 3)
|
|
|
structuring_element = torch.ones(1, 1, erosion[0], erosion[1], erosion[2]).to(input_tensor.device)
|
|
|
|
|
|
|
|
|
input_padded = F.pad(
|
|
|
input_tensor.float().unsqueeze(0).unsqueeze(0),
|
|
|
(erosion[0] // 2, erosion[0] // 2, erosion[1] // 2, erosion[1] // 2, erosion[2] // 2, erosion[2] // 2),
|
|
|
mode="constant",
|
|
|
value=1.0,
|
|
|
)
|
|
|
|
|
|
|
|
|
output = F.conv3d(input_padded, structuring_element, padding=0)
|
|
|
|
|
|
|
|
|
output = torch.where(output == torch.sum(structuring_element), 1.0, 0.0)
|
|
|
|
|
|
return output.squeeze(0).squeeze(0)
|
|
|
|
|
|
|
|
|
def dilate3d(input_tensor, erosion=3):
|
|
|
|
|
|
erosion = ensure_tuple_rep(erosion, 3)
|
|
|
structuring_element = torch.ones(1, 1, erosion[0], erosion[1], erosion[2]).to(input_tensor.device)
|
|
|
|
|
|
|
|
|
input_padded = F.pad(
|
|
|
input_tensor.float().unsqueeze(0).unsqueeze(0),
|
|
|
(erosion[0] // 2, erosion[0] // 2, erosion[1] // 2, erosion[1] // 2, erosion[2] // 2, erosion[2] // 2),
|
|
|
mode="constant",
|
|
|
value=1.0,
|
|
|
)
|
|
|
|
|
|
|
|
|
output = F.conv3d(input_padded, structuring_element, padding=0)
|
|
|
|
|
|
|
|
|
output = torch.where(output > 0, 1.0, 0.0)
|
|
|
|
|
|
return output.squeeze(0).squeeze(0)
|
|
|
|
|
|
|
|
|
def augmentation_tumor_bone(pt_nda, output_size, random_seed=None):
|
|
|
volume = pt_nda.squeeze(0)
|
|
|
real_l_volume_ = torch.zeros_like(volume)
|
|
|
real_l_volume_[volume == 128] = 1
|
|
|
real_l_volume_ = real_l_volume_.to(torch.uint8)
|
|
|
|
|
|
elastic = RandAffine(
|
|
|
mode="nearest",
|
|
|
prob=1.0,
|
|
|
translate_range=(5, 5, 0),
|
|
|
rotate_range=(0, 0, 0.1),
|
|
|
scale_range=(0.15, 0.15, 0),
|
|
|
padding_mode="zeros",
|
|
|
)
|
|
|
elastic.set_random_state(seed=random_seed)
|
|
|
|
|
|
tumor_szie = torch.sum((real_l_volume_ > 0).float())
|
|
|
|
|
|
|
|
|
volume[real_l_volume_ > 0] = 200
|
|
|
|
|
|
if tumor_szie > 0:
|
|
|
|
|
|
organ_mask = (
|
|
|
torch.logical_and(33 <= volume, volume <= 56).float()
|
|
|
+ torch.logical_and(63 <= volume, volume <= 97).float()
|
|
|
+ (volume == 127).float()
|
|
|
+ (volume == 114).float()
|
|
|
+ real_l_volume_
|
|
|
)
|
|
|
organ_mask = (organ_mask > 0).float()
|
|
|
cnt = 0
|
|
|
while True:
|
|
|
threshold = 0.8 if cnt < 40 else 0.75
|
|
|
real_l_volume = real_l_volume_
|
|
|
|
|
|
distored_mask = elastic((real_l_volume > 0).cuda(), spatial_size=tuple(output_size)).as_tensor()
|
|
|
real_l_volume = distored_mask * organ_mask
|
|
|
cnt += 1
|
|
|
print(torch.sum(real_l_volume), "|", tumor_szie * threshold)
|
|
|
if torch.sum(real_l_volume) >= tumor_szie * threshold:
|
|
|
real_l_volume = dilate3d(real_l_volume.squeeze(0), erosion=5)
|
|
|
real_l_volume = erode3d(real_l_volume, erosion=5).unsqueeze(0).to(torch.uint8)
|
|
|
break
|
|
|
else:
|
|
|
real_l_volume = real_l_volume_
|
|
|
|
|
|
volume[real_l_volume == 1] = 128
|
|
|
|
|
|
pt_nda = volume.unsqueeze(0)
|
|
|
return pt_nda
|
|
|
|
|
|
|
|
|
def augmentation_tumor_liver(pt_nda, output_size, random_seed=None):
|
|
|
volume = pt_nda.squeeze(0)
|
|
|
real_l_volume_ = torch.zeros_like(volume)
|
|
|
real_l_volume_[volume == 1] = 1
|
|
|
real_l_volume_[volume == 26] = 2
|
|
|
real_l_volume_ = real_l_volume_.to(torch.uint8)
|
|
|
|
|
|
elastic = Rand3DElastic(
|
|
|
mode="nearest",
|
|
|
prob=1.0,
|
|
|
sigma_range=(5, 8),
|
|
|
magnitude_range=(100, 200),
|
|
|
translate_range=(10, 10, 10),
|
|
|
rotate_range=(np.pi / 36, np.pi / 36, np.pi / 36),
|
|
|
scale_range=(0.2, 0.2, 0.2),
|
|
|
padding_mode="zeros",
|
|
|
)
|
|
|
elastic.set_random_state(seed=random_seed)
|
|
|
|
|
|
tumor_szie = torch.sum(real_l_volume_ == 2)
|
|
|
|
|
|
|
|
|
volume[volume == 1] = 0
|
|
|
volume[volume == 26] = 0
|
|
|
|
|
|
volume[real_l_volume_ == 1] = 1
|
|
|
volume[real_l_volume_ == 2] = 1
|
|
|
|
|
|
while True:
|
|
|
real_l_volume = real_l_volume_
|
|
|
|
|
|
real_l_volume = elastic((real_l_volume == 2).cuda(), spatial_size=tuple(output_size)).as_tensor()
|
|
|
|
|
|
organ_mask = (real_l_volume_ == 1).float() + (real_l_volume_ == 2).float()
|
|
|
|
|
|
organ_mask = dilate3d(organ_mask.squeeze(0), erosion=5)
|
|
|
organ_mask = erode3d(organ_mask, erosion=5).unsqueeze(0)
|
|
|
real_l_volume = real_l_volume * organ_mask
|
|
|
print(torch.sum(real_l_volume), "|", tumor_szie * 0.80)
|
|
|
if torch.sum(real_l_volume) >= tumor_szie * 0.80:
|
|
|
real_l_volume = dilate3d(real_l_volume.squeeze(0), erosion=5)
|
|
|
real_l_volume = erode3d(real_l_volume, erosion=5).unsqueeze(0)
|
|
|
break
|
|
|
|
|
|
volume[real_l_volume == 1] = 26
|
|
|
|
|
|
pt_nda = volume.unsqueeze(0)
|
|
|
return pt_nda
|
|
|
|
|
|
|
|
|
def augmentation_tumor_lung(pt_nda, output_size, random_seed=None):
|
|
|
volume = pt_nda.squeeze(0)
|
|
|
real_l_volume_ = torch.zeros_like(volume)
|
|
|
real_l_volume_[volume == 23] = 1
|
|
|
real_l_volume_ = real_l_volume_.to(torch.uint8)
|
|
|
|
|
|
elastic = Rand3DElastic(
|
|
|
mode="nearest",
|
|
|
prob=1.0,
|
|
|
sigma_range=(5, 8),
|
|
|
magnitude_range=(100, 200),
|
|
|
translate_range=(20, 20, 20),
|
|
|
rotate_range=(np.pi / 36, np.pi / 36, np.pi),
|
|
|
scale_range=(0.15, 0.15, 0.15),
|
|
|
padding_mode="zeros",
|
|
|
)
|
|
|
elastic.set_random_state(seed=random_seed)
|
|
|
|
|
|
tumor_szie = torch.sum(real_l_volume_)
|
|
|
|
|
|
new_real_l_volume_ = dilate3d(real_l_volume_.squeeze(0), erosion=3)
|
|
|
new_real_l_volume_ = new_real_l_volume_.unsqueeze(0)
|
|
|
new_real_l_volume_[real_l_volume_ > 0] = 0
|
|
|
new_real_l_volume_[volume < 28] = 0
|
|
|
new_real_l_volume_[volume > 32] = 0
|
|
|
tmp = volume[(volume * new_real_l_volume_).nonzero(as_tuple=True)].view(-1)
|
|
|
|
|
|
mode = torch.mode(tmp, 0)[0].item()
|
|
|
print(mode)
|
|
|
assert 28 <= mode <= 32
|
|
|
volume[real_l_volume_.bool()] = mode
|
|
|
|
|
|
if tumor_szie > 0:
|
|
|
|
|
|
while True:
|
|
|
real_l_volume = real_l_volume_
|
|
|
|
|
|
real_l_volume = elastic(real_l_volume, spatial_size=tuple(output_size)).as_tensor()
|
|
|
|
|
|
lung_mask = (
|
|
|
(volume == 28).float()
|
|
|
+ (volume == 29).float()
|
|
|
+ (volume == 30).float()
|
|
|
+ (volume == 31).float()
|
|
|
+ (volume == 32).float()
|
|
|
)
|
|
|
|
|
|
lung_mask = dilate3d(lung_mask.squeeze(0), erosion=5)
|
|
|
lung_mask = erode3d(lung_mask, erosion=5).unsqueeze(0)
|
|
|
real_l_volume = real_l_volume * lung_mask
|
|
|
print(torch.sum(real_l_volume), "|", tumor_szie * 0.85)
|
|
|
if torch.sum(real_l_volume) >= tumor_szie * 0.85:
|
|
|
real_l_volume = dilate3d(real_l_volume.squeeze(0), erosion=5)
|
|
|
real_l_volume = erode3d(real_l_volume, erosion=5).unsqueeze(0).to(torch.uint8)
|
|
|
break
|
|
|
else:
|
|
|
real_l_volume = real_l_volume_
|
|
|
|
|
|
volume[real_l_volume == 1] = 23
|
|
|
|
|
|
pt_nda = volume.unsqueeze(0)
|
|
|
return pt_nda
|
|
|
|
|
|
|
|
|
def augmentation_tumor_pancreas(pt_nda, output_size, random_seed=None):
|
|
|
volume = pt_nda.squeeze(0)
|
|
|
real_l_volume_ = torch.zeros_like(volume)
|
|
|
real_l_volume_[volume == 4] = 1
|
|
|
real_l_volume_[volume == 24] = 2
|
|
|
real_l_volume_ = real_l_volume_.to(torch.uint8)
|
|
|
|
|
|
elastic = Rand3DElastic(
|
|
|
mode="nearest",
|
|
|
prob=1.0,
|
|
|
sigma_range=(5, 8),
|
|
|
magnitude_range=(100, 200),
|
|
|
translate_range=(15, 15, 15),
|
|
|
rotate_range=(np.pi / 36, np.pi / 36, np.pi / 36),
|
|
|
scale_range=(0.1, 0.1, 0.1),
|
|
|
padding_mode="zeros",
|
|
|
)
|
|
|
elastic.set_random_state(seed=random_seed)
|
|
|
|
|
|
tumor_szie = torch.sum(real_l_volume_ == 2)
|
|
|
|
|
|
|
|
|
volume[volume == 24] = 0
|
|
|
volume[volume == 4] = 0
|
|
|
|
|
|
volume[real_l_volume_ == 1] = 4
|
|
|
volume[real_l_volume_ == 2] = 4
|
|
|
|
|
|
while True:
|
|
|
real_l_volume = real_l_volume_
|
|
|
|
|
|
real_l_volume = elastic((real_l_volume == 2).cuda(), spatial_size=tuple(output_size)).as_tensor()
|
|
|
|
|
|
organ_mask = (real_l_volume_ == 1).float() + (real_l_volume_ == 2).float()
|
|
|
|
|
|
organ_mask = dilate3d(organ_mask.squeeze(0), erosion=5)
|
|
|
organ_mask = erode3d(organ_mask, erosion=5).unsqueeze(0)
|
|
|
real_l_volume = real_l_volume * organ_mask
|
|
|
print(torch.sum(real_l_volume), "|", tumor_szie * 0.80)
|
|
|
if torch.sum(real_l_volume) >= tumor_szie * 0.80:
|
|
|
real_l_volume = dilate3d(real_l_volume.squeeze(0), erosion=5)
|
|
|
real_l_volume = erode3d(real_l_volume, erosion=5).unsqueeze(0)
|
|
|
break
|
|
|
|
|
|
volume[real_l_volume == 1] = 24
|
|
|
|
|
|
pt_nda = volume.unsqueeze(0)
|
|
|
return pt_nda
|
|
|
|
|
|
|
|
|
def augmentation_tumor_colon(pt_nda, output_size, random_seed=None):
|
|
|
volume = pt_nda.squeeze(0)
|
|
|
real_l_volume_ = torch.zeros_like(volume)
|
|
|
real_l_volume_[volume == 27] = 1
|
|
|
real_l_volume_ = real_l_volume_.to(torch.uint8)
|
|
|
|
|
|
elastic = Rand3DElastic(
|
|
|
mode="nearest",
|
|
|
prob=1.0,
|
|
|
sigma_range=(5, 8),
|
|
|
magnitude_range=(100, 200),
|
|
|
translate_range=(5, 5, 5),
|
|
|
rotate_range=(np.pi / 36, np.pi / 36, np.pi / 36),
|
|
|
scale_range=(0.1, 0.1, 0.1),
|
|
|
padding_mode="zeros",
|
|
|
)
|
|
|
elastic.set_random_state(seed=random_seed)
|
|
|
|
|
|
tumor_szie = torch.sum(real_l_volume_)
|
|
|
|
|
|
|
|
|
volume[real_l_volume_.bool()] = 62
|
|
|
|
|
|
if tumor_szie > 0:
|
|
|
|
|
|
organ_mask = (volume == 62).float()
|
|
|
organ_mask = dilate3d(organ_mask.squeeze(0), erosion=5)
|
|
|
organ_mask = erode3d(organ_mask, erosion=5).unsqueeze(0)
|
|
|
|
|
|
cnt = 0
|
|
|
while True:
|
|
|
threshold = 0.8
|
|
|
real_l_volume = real_l_volume_
|
|
|
if cnt < 20:
|
|
|
|
|
|
distored_mask = elastic((real_l_volume == 1).cuda(), spatial_size=tuple(output_size)).as_tensor()
|
|
|
real_l_volume = distored_mask * organ_mask
|
|
|
elif 20 <= cnt < 40:
|
|
|
threshold = 0.75
|
|
|
else:
|
|
|
break
|
|
|
|
|
|
real_l_volume = real_l_volume * organ_mask
|
|
|
print(torch.sum(real_l_volume), "|", tumor_szie * threshold)
|
|
|
cnt += 1
|
|
|
if torch.sum(real_l_volume) >= tumor_szie * threshold:
|
|
|
real_l_volume = dilate3d(real_l_volume.squeeze(0), erosion=5)
|
|
|
real_l_volume = erode3d(real_l_volume, erosion=5).unsqueeze(0).to(torch.uint8)
|
|
|
break
|
|
|
else:
|
|
|
real_l_volume = real_l_volume_
|
|
|
|
|
|
volume[real_l_volume == 1] = 27
|
|
|
|
|
|
pt_nda = volume.unsqueeze(0)
|
|
|
return pt_nda
|
|
|
|
|
|
|
|
|
def augmentation_body(pt_nda, random_seed=None):
|
|
|
volume = pt_nda.squeeze(0)
|
|
|
|
|
|
zoom = RandZoom(min_zoom=0.99, max_zoom=1.01, mode="nearest", align_corners=None, prob=1.0)
|
|
|
zoom.set_random_state(seed=random_seed)
|
|
|
|
|
|
volume = zoom(volume)
|
|
|
|
|
|
pt_nda = volume.unsqueeze(0)
|
|
|
return pt_nda
|
|
|
|
|
|
|
|
|
def augmentation(pt_nda, output_size, random_seed=None):
|
|
|
label_list = torch.unique(pt_nda)
|
|
|
label_list = list(label_list.cpu().numpy())
|
|
|
|
|
|
if 128 in label_list:
|
|
|
print("augmenting bone lesion/tumor")
|
|
|
pt_nda = augmentation_tumor_bone(pt_nda, output_size, random_seed)
|
|
|
elif 26 in label_list:
|
|
|
print("augmenting liver tumor")
|
|
|
pt_nda = augmentation_tumor_liver(pt_nda, output_size, random_seed)
|
|
|
elif 23 in label_list:
|
|
|
print("augmenting lung tumor")
|
|
|
pt_nda = augmentation_tumor_lung(pt_nda, output_size, random_seed)
|
|
|
elif 24 in label_list:
|
|
|
print("augmenting pancreas tumor")
|
|
|
pt_nda = augmentation_tumor_pancreas(pt_nda, output_size, random_seed)
|
|
|
elif 27 in label_list:
|
|
|
print("augmenting colon tumor")
|
|
|
pt_nda = augmentation_tumor_colon(pt_nda, output_size, random_seed)
|
|
|
else:
|
|
|
print("augmenting body")
|
|
|
pt_nda = augmentation_body(pt_nda, random_seed)
|
|
|
|
|
|
return pt_nda
|
|
|
|