import numpy as np import os import random import torch from scipy.ndimage.interpolation import zoom from torch.utils.data import Dataset from scipy import ndimage from PIL import Image from scipy.ndimage import map_coordinates, gaussian_filter import cv2 def random_rot_flip(image, label): k = np.random.randint(0, 4) image = np.rot90(image, k, axes=(0,1)) label = np.rot90(label, k, axes=(0,1)) axis = np.random.randint(0, 2) image = np.flip(image, axis=axis) label = np.flip(label, axis=axis) return image.copy(), label.copy() def random_rotate(image, label): angle = np.random.uniform(-25, 25) rotated_channels = [] for c in range(image.shape[-1]): rotated_c = ndimage.rotate( image[..., c], angle, order=1, reshape=False, mode='nearest' ) rotated_channels.append(rotated_c) image_rot = np.stack(rotated_channels, axis=-1) label_rot = ndimage.rotate( label, angle, order=0, reshape=False, mode='nearest' ) return image_rot, label_rot def elastic_transform(image, label, alpha=1000, sigma=30): shape = image.shape[:2] random_state = np.random.RandomState(None) dx = gaussian_filter( (random_state.rand(*shape) * 2 - 1), sigma, mode="constant" ) * alpha dy = gaussian_filter( (random_state.rand(*shape) * 2 - 1), sigma, mode="constant" ) * alpha x, y = np.meshgrid(np.arange(shape[0]), np.arange(shape[1]), indexing='ij') indices = np.reshape(x + dx, (-1, 1)), np.reshape(y + dy, (-1, 1)) dist_image = [] for c in range(image.shape[-1]): channel = map_coordinates( image[..., c], indices, order=3, mode='reflect' ).reshape(shape) dist_image.append(channel) dist_image = np.stack(dist_image, axis=-1) dist_label = map_coordinates( label, indices, order=0, mode='reflect' ).reshape(shape) return dist_image, dist_label class AdvancedMedicalAug(torch.nn.Module): def __init__(self, aug_prob=0.8): super().__init__() self.aug_prob = aug_prob def forward(self, image, label): if isinstance(image, torch.Tensor): image = image.numpy() if isinstance(label, torch.Tensor): label = label.numpy() if random.random() < self.aug_prob: if random.random() > 0.5: image, label = random_rot_flip(image, label) else: image, label = random_rotate(image, label) if random.random() < 0.3: image, label = elastic_transform(image, label) image = self.intensity_augment(image) return image, label def intensity_augment(self, image): for c in range(image.shape[-1]): image[..., c] = np.clip( image[..., c] * random.uniform(0.7, 1.3), 0, 1 ) if random.random() < 0.2: noise = np.random.normal(0, 0.05, image[..., c].shape) image[..., c] = np.clip(image[..., c] + noise, 0, 1) return image class Synapse_dataset(Dataset): def __init__(self, base_dir, list_dir, split, img_size, transform=None): self.transform = transform self.split = split self.sample_list = open(os.path.join(list_dir, self.split+'.txt')).readlines() self.data_dir = base_dir self.img_size = img_size def __len__(self): return len(self.sample_list) def __getitem__(self, idx): slice_name = self.sample_list[idx].strip('\n') data_path = os.path.join(self.data_dir, slice_name) data = np.load(data_path) image = data['image'].astype(np.float32) if len(image.shape) == 2: image = np.expand_dims(image, axis=-1) if 'label' in data.files: label = data['label'].astype(np.int32) else: label = np.zeros_like(image, dtype=np.int32) if image.shape != self.img_size: x, y, z = image.shape image = zoom(image, (self.img_size[0] / x, self.img_size[1] / y, z), order=3) label = zoom(label, (self.img_size[0] / x, self.img_size[1] / y), order=0) if self.transform: image, label = self.transform(image, label) if self.split == 'train': image, label = torch.from_numpy(image), torch.from_numpy(label) sample = {'image': image, 'label': label, 'case_name': slice_name} return sample