def test_center_crop_odd(self): """ This test will check if center crop really crops the center :return: """ data = np.zeros((8, 4, 30, 30, 30)) seg = np.zeros(data.shape) # we set the center that we expect to be cropped to 1 and then check if we only get 1's in the result # crop_size is [10, 20, 16] and data_shape is [30, 30, 30] crop_size = np.array([9, 19, 13]) shp = np.array(data.shape[2:]) border = (shp - crop_size) // 2 data[:, :, border[0]:(shp[0] + crop_size[0]), border[1]:(shp[1] + crop_size[0]), border[2]:(shp[2] + crop_size[0])] = 1 # same with seg seg[:, :, border[0]:(shp[0] + crop_size[0]), border[1]:(shp[1] + crop_size[0]), border[2]:(shp[2] + crop_size[0])] = 1 data_cropped, seg_cropped = crop(data, seg, crop_size, margins=(0, 0, 0), crop_type="center") assert np.sum(data_cropped == 0) == 0, "Center crop did not crop the center of data (even data " \ "and odd crop size)" assert np.sum( seg_cropped == 0 ) == 0, "Center crop did not crop the center of seg (even data and odd crop size)"
def generate_train_batch(self): # DataLoader has its own methods for selecting what patients to use next, see its Documentation idx = self.get_indices() patients_for_batch = [self._data[i] for i in idx] # initialize empty array for data and seg data = np.zeros((self.batch_size, self.num_modalities, *self.patch_size), dtype=np.float32) seg = np.zeros((self.batch_size, 1, *self.patch_size), dtype=np.float32) metadata = [] patient_names = [] # iterate over patients_for_batch and include them in the batch for i, j in enumerate(patients_for_batch): patient_data, patient_metadata = self.load_patient(j) # this will only pad patient_data if its shape is smaller than self.patch_size patient_data = pad_nd_image(patient_data, self.patch_size) # now random crop to self.patch_size # crop expects the data to be (b, c, x, y, z) but patient_data is (c, x, y, z) so we need to add one # dummy dimension in order for it to work (@Todo, could be improved) patient_data, patient_seg = crop( patient_data[:-1][None], patient_data[-1:][None], self.patch_size, crop_type="random") data[i] = patient_data[0] seg[i] = patient_seg[0] metadata.append(patient_metadata) patient_names.append(j) return {'data': data, 'seg': seg, 'metadata': metadata, 'names': patient_names}
def generate_train_batch(self): subjects = self._data[0] subject_idx = int(random.uniform(0, len(subjects))) data, seg = load_training_data(self.Config, subjects[subject_idx]) # Convert peaks to tensors if tensor model if self.Config.NR_OF_GRADIENTS == 18*self.Config.NR_SLICES: data = peak_utils.peaks_to_tensors(data) slice_direction = data_utils.slice_dir_to_int(self.Config.TRAINING_SLICE_DIRECTION) if data.shape[slice_direction] <= self.batch_size: print("INFO: Batch size bigger than nr of slices. Therefore sampling with replacement.") slice_idxs = np.random.choice(data.shape[slice_direction], self.batch_size, True, None) else: slice_idxs = np.random.choice(data.shape[slice_direction], self.batch_size, False, None) if self.Config.NR_SLICES > 1: x, y = data_utils.sample_Xslices(data, seg, slice_idxs, slice_direction=slice_direction, labels_type=self.Config.LABELS_TYPE, slice_window=self.Config.NR_SLICES) else: x, y = data_utils.sample_slices(data, seg, slice_idxs, slice_direction=slice_direction, labels_type=self.Config.LABELS_TYPE) # Can be replaced by crop # x = pad_nd_image(x, self.Config.INPUT_DIM, mode='constant', kwargs={'constant_values': 0}) # y = pad_nd_image(y, self.Config.INPUT_DIM, mode='constant', kwargs={'constant_values': 0}) # x = center_crop_2D_image_batched(x, self.Config.INPUT_DIM) # y = center_crop_2D_image_batched(y, self.Config.INPUT_DIM) # If want to convert e.g. 1.25mm (HCP) image to 2mm image (bb) # x, y = self._zoom_x_and_y(x, y, 0.67) # very slow -> try spatial_transform, should be fast if self.Config.PAD_TO_SQUARE: #Crop and pad to input size x, y = crop(x, y, crop_size=self.Config.INPUT_DIM) # does not work with img with batches and channels else: # Works -> results as good? # Will pad each axis to be multiple of 16. (Each sample can end up having different dimensions. Also x and y # can be different) # This is needed for Schizo dataset x = pad_nd_image(x, shape_must_be_divisible_by=(16, 16), mode='constant', kwargs={'constant_values': 0}) y = pad_nd_image(y, shape_must_be_divisible_by=(16, 16), mode='constant', kwargs={'constant_values': 0}) # Does not make it slower x = x.astype(np.float32) y = y.astype(np.float32) # possible optimization: sample slices from different patients and pad all to same size (size of biggest) data_dict = {"data": x, # (batch_size, channels, x, y, [z]) "seg": y, "slice_dir": slice_direction} # (batch_size, channels, x, y, [z]) return data_dict
def generate_train_batch(self): # np.random.seed(1234) subjects = self._data[0] subject_idx = int(random.uniform(0, len(subjects))) # len(subjects)-1 not needed because int always rounds to floor data, seg = load_training_data(self.Config, subjects[subject_idx]) #Convert peaks to tensors if tensor model if self.Config.NR_OF_GRADIENTS == 18*self.Config.NR_SLICES: data = peak_utils.peaks_to_tensors(data) slice_direction = data_utils.slice_dir_to_int(self.Config.TRAINING_SLICE_DIRECTION) slice_idxs = np.random.choice(data.shape[slice_direction], self.batch_size, False, None) if self.Config.NR_SLICES > 1: x, y = data_utils.sample_Xslices(data, seg, slice_idxs, slice_direction=slice_direction, labels_type=self.Config.LABELS_TYPE, slice_window=self.Config.NR_SLICES) else: x, y = data_utils.sample_slices(data, seg, slice_idxs, slice_direction=slice_direction, labels_type=self.Config.LABELS_TYPE) # Can be replaced by crop # x = pad_nd_image(x, self.Config.INPUT_DIM, mode='constant', kwargs={'constant_values': 0}) # y = pad_nd_image(y, self.Config.INPUT_DIM, mode='constant', kwargs={'constant_values': 0}) # x = center_crop_2D_image_batched(x, self.Config.INPUT_DIM) # y = center_crop_2D_image_batched(y, self.Config.INPUT_DIM) #Crop and pad to input size x, y = crop(x, y, crop_size=self.Config.INPUT_DIM) # does not work with img with batches and channels # Works -> results as good? -> todo: make the same way for inference! # This is needed for Schizo dataset # x = pad_nd_image(x, shape_must_be_divisible_by=(16, 16), mode='constant', kwargs={'constant_values': 0}) # y = pad_nd_image(y, shape_must_be_divisible_by=(16, 16), mode='constant', kwargs={'constant_values': 0}) # Does not make it slower x = x.astype(np.float32) y = y.astype(np.float32) # if not doing this: during validation: ConnectionResetError: [Errno 104] Connection # reset by peer #possible optimization: sample slices from different patients and pad all to same size (size of biggest) data_dict = {"data": x, # (batch_size, channels, x, y, [z]) "seg": y, "slice_dir": slice_direction} # (batch_size, channels, x, y, [z]) return data_dict
def generate_train_batch(self): idx = self.get_indices( ) # get batch_size subjects randomly, return a list data = np.zeros( (self.batch_size, self.nb_modalities, *self.patch_size), dtype=np.float32) for i, j in enumerate(idx): tmp_data = pad_nd_image(self._data[j]['img'], self.patch_size) cropped_data, cropped_seg = crop(tmp_data, None, self.patch_size, crop_type='random') data[i] = cropped_data[0] return {'data': data} # (b, 2, d, h, w), (b, 1, d, h, w)
def generate_train_batch(self): subjects = self._data[0] # subject_idx = int(random.uniform(0, len(subjects))) # len(subjects)-1 not needed because int always rounds to floor subject_idxs = np.random.choice(len(subjects), self.batch_size, False, None) x = [] y = [] for subject_idx in subject_idxs: data, seg = load_training_data( self.Config, subjects[subject_idx]) # (x, y, z, channels) data = data.transpose(3, 0, 1, 2) # channels have to be first seg = seg.transpose(3, 0, 1, 2) # Crop here instead of cropping entire batch at once to make each element in batch have same dimensions data, seg = crop(data[None, ...], seg[None, ...], crop_size=self.Config.INPUT_DIM) data = data.squeeze(axis=0) seg = seg.squeeze(axis=0) x.append(data) y.append(seg) x = np.array(x) y = np.array(y) # Can be replaced by crop -> shorter # x = pad_nd_image(x, self.Config.INPUT_DIM, mode='constant', kwargs={'constant_values': 0}) # y = pad_nd_image(y, self.Config.INPUT_DIM, mode='constant', kwargs={'constant_values': 0}) # x = center_crop_3D_image_batched(x, self.Config.INPUT_DIM) # y = center_crop_3D_image_batched(y, self.Config.INPUT_DIM) # Crop and pad to input size # x, y = crop(x, y, crop_size=self.Config.INPUT_DIM) # This is needed for Schizo dataset, but only works with DAug=True # x = pad_nd_image(x, shape_must_be_divisible_by=(8, 8), mode='constant', kwargs={'constant_values': 0}) # y = pad_nd_image(y, shape_must_be_divisible_by=(8, 8), mode='constant', kwargs={'constant_values': 0}) x = x.astype(np.float32) y = y.astype(np.float32) data_dict = { "data": x, # (batch_size, channels, x, y, [z]) "seg": y } # (batch_size, channels, x, y, [z]) return data_dict
def test_crop_roi(self): img = np.zeros((1, 3, 10, 10, 10)) img[:, :, 2:4, 2:4, 2:4] = 1 lbl = np.zeros((10, 10, 10)) lbl[2:4, 2:4, 2:4] = 1 crop_size = (5, 5, 5) lbl = np.expand_dims(np.expand_dims(lbl, axis=0), axis=0) for i in range(10): img_ret, lbl_ret = crop(img, lbl, crop_size, crop_type='roi') img_sum = np.sum(img) lbl_sum = np.sum(lbl) assert (img_sum == 3 * lbl_sum) assert (img_sum == np.sum(img_ret)) assert (lbl_sum == np.sum(lbl_ret))
def get_data_from_array(self, open_array): data = [] fnames = [] slice_idxs = [] labels = [] for slice in open_array: fn_name = self.files[slice[0]] numpy_array = np.load(fn_name, mmap_mode="r") numpy_slice = numpy_array[:, slice[1]] print("numpy_array shape :", numpy_array.shape, "numpy_slice shape :", numpy_slice.shape) # this will only pad patient_data if its shape is smaller than self.patch_size patient_data = pad_nd_image(numpy_slice, self.patch_size) # now random crop to self.patch_size # crop expects the data to be (b, c, x, y, z) but patient_data is (c, x, y, z) so we need to add one # dummy dimension in order for it to work (@Todo, could be improved) patient_data, patient_seg = crop(patient_data[:-1][None], patient_data[-1:][None], self.patch_size, crop_type="random") dataslice = patient_data[0][0][None] dataslice = dataslice[0][None] segGt = patient_seg[0] #print("Before data shape :",dataslice.shape ,"sdpegGt :",segGt.shape) #dataslice = dataslice[0] print("After data shape :", dataslice.shape, "segGt :", segGt.shape) data.append(dataslice) # 'None' keeps the dimension if self.label_slice is not None: labels.append(segGt) # 'None' keeps the dimension fnames.append(self.files[slice[0]]) slice_idxs.append(slice[1]) ret_dict = {'data': data, 'fnames': fnames, 'slice_idxs': slice_idxs} if self.label_slice is not None: ret_dict['seg'] = labels print("data shape :", len(data), "labels :", len(labels)) return ret_dict
def __call__(self, **data_dict): data = data_dict["data"] dimensionality = len(data.shape) - 2 size = np.array(data.shape[-dimensionality:], dtype=int) zoom = 1 + (np.random.random() * (self.max_zoom - 1)) samples = [] for sample in np.split(data, data.shape[0], 0): if np.random.random() < self.p_per_sample: sample = crop(sample, crop_size=(size / zoom).astype(int), crop_type="random")[0] sample = augment_resize(sample.squeeze(0), sample_seg=None, target_size=size.tolist())[0] else: sample = sample.squeeze(0) samples.append(sample) data = np.stack(samples) data_dict["data"] = data return data_dict
def generate_train_batch(self): idx = self.get_indices() patients_for_batch = [self._data[i] for i in idx] data = np.zeros((self.batch_size, self.num_modalities, *self.patch_size), dtype=np.float32) for i, _ in enumerate(patients_for_batch): patient_data = patients_for_batch[i] if not self.crop: patient_data = resize(patient_data, (patient_data.shape[0],)+self.patch_size, anti_aliasing=True) data[i] = patient_data else: # this will only pad patient_data if its shape is smaller than self.patch_size patient_data = pad_nd_image(patient_data, self.patch_size) # now random crop to self.patch_size patient_data = crop(patient_data[None], crop_size=self.patch_size, crop_type="center") data[i] = patient_data[0] return {'data': data}
def generate_train_batch(self): # DataLoader has its own methods for selecting what patients to use next, see its Documentation idx = self.get_indices() patients_for_batch = [self._data[i] for i in idx] print(idx) patch_size = None if self.patch_size == None: shapes = [] for i in patients_for_batch: patient_data, _ = self.load_patient(i) shapes.append(patient_data[0].shape) patch_size = np.max(shapes, 0) patch_size = (patch_size[0] + 16 - patch_size[0] % 16, patch_size[1] + 16 - patch_size[1] % 16, patch_size[2] + 16 - patch_size[2] % 16) else: patch_size = self.patch_size # initialize empty array for data and seg data = np.zeros((self.batch_size, self.num_modalities, *patch_size), dtype=np.float32) seg = np.zeros((self.batch_size, 1, *patch_size), dtype=np.float32) metadata = [] patient_names = [] # iterate over patients_for_batch and include them in the batch for i, j in enumerate(patients_for_batch): patient_data, patient_metadata = self.load_patient(j) if self.patch_size is not None: # this will only pad patient_data if its shape is smaller than self.patch_size patient_data = pad_nd_image(patient_data, patch_size) # now random crop to self.patch_size # crop expects the data to be (b, c, x, y, z) but patient_data is (c, x, y, z) so we need to add one # dummy dimension in order for it to work (@Todo, could be improved) patient_data, patient_seg = crop(patient_data[:-1][None], patient_data[-1:][None], patch_size, crop_type="random") data[i] = patient_data[0] seg[i] = patient_seg[0] else: for j in range(len(patient_data)): if j != len(patient_data) - 1: data[i][j] = resize_image_by_padding( patient_data[j], patch_size) else: seg[i][0] = resize_image_by_padding( patient_data[j], patch_size) metadata.append(patient_metadata) patient_names.append(j) return { 'data': data, 'seg': seg, 'metadata': metadata, 'names': patient_names }
def augment_spatial(data, seg, patch_size, patch_center_dist_from_border=30, do_elastic_deform=True, alpha=(0., 1000.), sigma=(10., 13.), do_rotation=True, angle_x=(0, 2 * np.pi), angle_y=(0, 2 * np.pi), angle_z=(0, 2 * np.pi), do_scale=True, scale=(0.75, 1.25), border_mode_data='nearest', border_cval_data=0, order_data=3, border_mode_seg='constant', border_cval_seg=0, order_seg=0, crop_mode='random', p_el_per_sample=1, p_scale_per_sample=1, p_rot_per_sample=1): dim = len(patch_size) seg_result = None if seg is not None: if dim == 2: seg_result = np.zeros( (seg.shape[0], seg.shape[1], patch_size[0], patch_size[1]), dtype=np.float32) else: seg_result = np.zeros((seg.shape[0], seg.shape[1], patch_size[0], patch_size[1], patch_size[2]), dtype=np.float32) if dim == 2: data_result = np.zeros( (data.shape[0], data.shape[1], patch_size[0], patch_size[1]), dtype=np.float32) else: data_result = np.zeros((data.shape[0], data.shape[1], patch_size[0], patch_size[1], patch_size[2]), dtype=np.float32) if not isinstance(patch_center_dist_from_border, (list, tuple, np.ndarray)): patch_center_dist_from_border = dim * [patch_center_dist_from_border] for sample_id in range(data.shape[0]): coords = create_zero_centered_coordinate_mesh(patch_size) modified_coords = False if np.random.uniform() < p_el_per_sample and do_elastic_deform: a = np.random.uniform(alpha[0], alpha[1]) s = np.random.uniform(sigma[0], sigma[1]) coords = elastic_deform_coordinates(coords, a, s) modified_coords = True if np.random.uniform() < p_rot_per_sample and do_rotation: if angle_x[0] == angle_x[1]: a_x = angle_x[0] else: a_x = np.random.uniform(angle_x[0], angle_x[1]) if dim == 3: if angle_y[0] == angle_y[1]: a_y = angle_y[0] else: a_y = np.random.uniform(angle_y[0], angle_y[1]) if angle_z[0] == angle_z[1]: a_z = angle_z[0] else: a_z = np.random.uniform(angle_z[0], angle_z[1]) coords = rotate_coords_3d(coords, a_x, a_y, a_z) else: coords = rotate_coords_2d(coords, a_x) modified_coords = True if np.random.uniform() < p_scale_per_sample and do_scale: if np.random.random() < 0.5 and scale[0] < 1: sc = np.random.uniform(scale[0], 1) else: sc = np.random.uniform(max(scale[0], 1), scale[1]) coords = scale_coords(coords, sc) modified_coords = True # now find a nice center location if modified_coords: if crop_mode == 'roi': lbs = get_lbls_for_roi_crop(patch_size, data.shape, seg[sample_id, 0]) for d in range(dim): if crop_mode == 'roi': ctr = int(lbs[d] + np.round(patch_size[d] / 2.)) elif crop_mode == 'center': ctr = int(np.round(data.shape[d + 2] / 2.)) else: ctr = np.random.uniform( patch_center_dist_from_border[d], data.shape[d + 2] - patch_center_dist_from_border[d]) coords[d] += ctr for channel_id in range(data.shape[1]): data_result[sample_id, channel_id] = interpolate_img( data[sample_id, channel_id], coords, order_data, border_mode_data, cval=border_cval_data) if seg is not None: for channel_id in range(seg.shape[1]): seg_result[sample_id, channel_id] = interpolate_img( seg[sample_id, channel_id], coords, order_seg, border_mode_seg, cval=border_cval_seg, is_seg=True) else: if seg is None: s = None else: s = seg[sample_id:sample_id + 1] if crop_mode == 'roi': d, s = crop(data[sample_id:sample_id + 1], s, patch_size, crop_type='roi') elif crop_mode == 'center': d, s = center_crop_aug(data[sample_id:sample_id + 1], patch_size, s) else: #crop_mode == 'random' margin = [ patch_center_dist_from_border[d] - patch_size[d] // 2 for d in range(dim) ] d, s = random_crop_aug(data[sample_id:sample_id + 1], s, patch_size, margin) data_result[sample_id] = d[0] if seg is not None: seg_result[sample_id] = s[0] return data_result, seg_result