def preprocess(self, data_group): input_data = data_group.preprocessed_case if self.mask is not None: mask_numpy = read_image_files(self.mask)[..., 0] elif self.mask_preprocessor is not None: mask_numpy = read_image_files(self.mask_preprocessor.mask_numpy)[..., 0] else: mask_numpy = None if self.channels is not None: return_data = np.copy(input_data).astype(float) input_data = np.take(input_data, indices=self.channels, axis=-1) if self.normalize_by_channel: # Make this an optional parameter. data_group.preprocessed_case = data_group.preprocessed_case.astype(float) for channel in range(data_group.preprocessed_case.shape[-1]): data_group.preprocessed_case[..., channel] = self.normalize(input_data[..., channel], mask_numpy) else: data_group.preprocessed_case = self.normalize(input_data, mask_numpy) if self.channels is not None: for channel_idx, channel in enumerate(self.channels): return_data[..., channel] = data_group.preprocessed_case[..., channel_idx] data_group.preprocessed_case = return_data # TODO: Reduce redundancy in naming self.output_data = data_group.preprocessed_case
def preprocess(self, data_group): normalize_numpy = data_group.preprocessed_case if self.mask is not None: mask_numpy = read_image_files(self.mask)[..., 0] elif self.mask_preprocessor is not None: data_group_label = data_group.label mask_numpy = read_image_files( self.mask_preprocessor.data_dictionary[data_group.label][ self.mask_name])[..., 0] else: mask_numpy = None if mask_numpy is not None: vol_mean = np.mean(normalize_numpy[mask_numpy > 0]) vol_std = np.std(normalize_numpy[mask_numpy > 0]) normalize_numpy = (normalize_numpy - vol_mean) / vol_std normalize_numpy[mask_numpy == 0] = 0 elif self.mask_zeros: idx_nonzeros = np.nonzero(normalize_numpy) vol_mean = np.mean(normalize_numpy[idx_nonzeros]) vol_std = np.mean(normalize_numpy[idx_nonzeros]) normalize_numpy[idx_nonzeros] = (normalize_numpy[idx_nonzeros] - vol_mean) / vol_std else: vol_mean = np.mean(normalize_numpy) vol_std = np.std(normalize_numpy) normalize_numpy = (normalize_numpy - vol_mean) / vol_std # TODO: Reduce redundancy in naming self.output_data = normalize_numpy data_group.preprocessed_case = normalize_numpy
def calc_volume(input_data, pixdim=None, affine=None, mask_value=0): input_data, input_affine = read_image_files(input_data, return_affine=True) pixdim = _get_pixdim(pixdim, affine, input_affine) return pixdim[0] * pixdim[1] * pixdim[2] * calc_voxel_count(input_data, mask_value)
def execute(self, data_collection, return_array=False): """ There is a lot of repeated code in the preprocessors. Think about preprocessor structures and work on this class. """ if self.verbose: docker_print('Working on Preprocessor:', self.name) for label, data_group in list(self.data_groups.items()): self.generate_output_filenames(data_collection, data_group) if type(data_group.preprocessed_case) is not list: self.output_data = data_group.preprocessed_case else: for file_idx, output_filename in enumerate(self.output_filenames): if os.path.isdir(data_group.preprocessed_case[file_idx]): if self.overwrite or not os.path.exists(output_filename): array_data, affine = read_image_files(data_group.preprocessed_case[file_idx], return_affine=True) # TO-DO: Check if subsetting language behaviour below has edge cases. save_data(array_data[..., 0], output_filename, reference_data=affine) else: self.output_filenames[file_idx] = data_group.preprocessed_case[file_idx] data_group.preprocessed_case = self.output_filenames self.output_data = data_group.preprocessed_case if return_array: self.convert_to_array_data(data_group)
def initialize(self, data_collection): super(SkullStrip_Model, self).initialize(data_collection) for label, data_group in data_collection.data_groups.iteritems(): reference_filename = data_group.data[data_collection.current_case][ self.reference_channel[0]] self.mask_filename = self.generate_output_filename( reference_filename, self.mask_string) input_data = np.take(data_group.preprocessed_case, self.reference_channel, axis=-1)[np.newaxis, ...] # Also Hacky self.model.outputs[-1].model = self.model self.model.outputs[-1].input_patch_shape = self.model.outputs[ -1].model.model.layers[0].input_shape self.model.outputs[-1].process_case([input_data]) self.model.outputs[-1].postprocess() save_numpy_2_nifti( np.squeeze(self.model.outputs[-1].return_objects[-1]), data_group.preprocessed_affine, self.mask_filename) # Hacky self.mask_numpy = read_image_files(self.mask_filename, return_affine=False)
def initialize(self, data_collection): super(SkullStrip, self).initialize(data_collection) for label, data_group in data_collection.data_groups.iteritems(): reference_filename = data_group.data[data_collection.current_case][ self.reference_channel] self.mask_filename = self.generate_output_filename( reference_filename, self.mask_string) if type(data_group.preprocessed_case) is list: input_file = data_group.preprocessed_case[ self.reference_channel] else: # What to do about affines here... Also, reroute this file to a temporary directory. input_file = save_numpy_2_nifti( data_group.preprocessed_case[..., self.reference_channel], data_group.preprocessed_affine, self.generate_output_filename(reference_filename)) specific_command = self.command + [ quotes(input_file), quotes(self.mask_filename), '-f', str(self.bet2_f), '-g', str(self.bet2_g), '-m' ] subprocess.call(' '.join(specific_command), shell=True) os.rename(self.mask_filename + '_mask.nii.gz', self.mask_filename) self.mask_numpy = read_image_files(self.mask_filename, return_affine=False)
def convert_to_array_data(self, data_group): data_group.preprocessed_case, affine = read_image_files( self.output_data, return_affine=True) if affine is not None: data_group.preprocessed_affine = affine
def execute(self, data_collection): if self.mask_numpy is None: for label, data_group in list(data_collection.data_groups.items()): input_data = np.take(data_group.preprocessed_case, self.reference_channel, axis=-1)[np.newaxis, ...] # Hacky -- TODO: Revise. self.model.outputs[-1].model = self.model self.model.outputs[-1].input_patch_shape = self.model.outputs[ -1].model.model.layers[0].input_shape self.model.outputs[-1].process_case(input_data) self.model.outputs[-1].postprocess(input_data) reference_filename = data_group.data[ data_collection.current_case][self.reference_channel[0]] self.mask_filename = self.generate_output_filename( reference_filename, self.mask_string) save_numpy_2_nifti( np.squeeze(self.model.outputs[-1].return_objects[-1]), self.mask_filename, data_group.preprocessed_affine) # Hacky self.mask_numpy = read_image_files(self.mask_filename, return_affine=False) super(SkullStrip_Model, self).execute(data_collection)
def convert_to_array_data(self): self.preprocessed_case, affine = read_image_files( self.preprocessed_case, return_affine=True) if affine is not None: self.preprocessed_affine = affine
def get_data(self, index=None, return_affine=False): """ Wonky behavior reading from hdf5 here. """ if self.source == 'hdf5': preprocessed_case = self.data[index][:][np.newaxis][0] # Storing affines needs work. How not to duplicate affines in case # of augmentation, for example? if self.data_affines is not None: if self.data_affines.shape[0] == 0: preprocessed_affine = None else: preprocessed_affine = self.data_affines[index] else: preprocessed_affine = None else: if type(self.preprocessed_case) is np.ndarray: preprocessed_case, preprocessed_affine = self.preprocessed_case, self.preprocessed_affine else: preprocessed_case, preprocessed_affine = read_image_files(self.preprocessed_case, return_affine=True) if return_affine: return preprocessed_case, preprocessed_affine else: return preprocessed_case return None
def calc_max_2D_diameter_ellipse(input_data, pixdim=None, affine=None, mask_value=0, axis=2, calc_multiple=False): input_data, input_affine = read_image_files(input_data, return_affine=True) pixdim = _get_pixdim(pixdim, affine, input_affine) input_data = input_data[..., -1] connected_components = label(input_data, connectivity=2) component_labels = np.unique(connected_components) max_2ds = [] major_diameter = None for label_idx in component_labels: component = connected_components.astype(int) component[connected_components != label_idx] = 0 major_diameter = None for z_slice in xrange(component.shape[2]): label_slice = component[..., z_slice] if np.sum(label_slice) == 0: continue label_properties = regionprops(label_slice) current_major = label_properties[0].major_axis_length current_orientation = label_properties[0].orientation x_dim = abs(np.cos(current_orientation) * current_major) y_dim = abs(np.sin(current_orientation) * current_major) current_major = ((x_dim * pixdim[0])**2 + (y_dim * pixdim[1])**2)**.5 if major_diameter is None: major_diameter = current_major elif current_major > major_diameter: major_diameter = current_major if major_diameter is not None: max_2ds += [major_diameter] if calc_multiple: return max_2ds else: return max(max_2ds)
def get_affine(self, index): if self.source == 'directory': if self.preprocessed_affine is None: self.preprocessed_case, self.preprocessed_affine = read_image_files(self.preprocessed_case, return_affine=True) return self.preprocessed_affine # A little unsure of the practical implication of the storage code below. elif self.source == 'storage': return self.data[index][:][np.newaxis], self.data_affines[index] return None
def preprocess(self, data_group): if self.mask is not None: mask_numpy = read_image_files(self.mask)[..., 0] elif self.mask_preprocessor is not None: mask_numpy = read_image_files( self.mask_preprocessor.data_dictionary[data_group.label][ self.mask_name])[..., 0] else: mask_numpy = None if self.normalize_by_channel: for channel in xrange(data_group.preprocessed_case.shape[-1]): data_group.preprocessed_case[..., channel] = self.normalize( data_group.preprocessed_case[..., channel], mask_numpy) else: data_group.preprocessed_case = self.normalize( data_group.preprocessed_case, mask_numpy) # TODO: Reduce redundancy in naming self.output_data = data_group.preprocessed_case
def calc_max_3D_diameter(input_data, pixdim=None, affine=None, mask_value=0, axis=2, calc_multiple=False): """ Combine repeated code with 2D max diameter? """ input_data, input_affine = read_image_files(input_data, return_affine=True) pixdim = _get_pixdim(pixdim, affine, input_affine) input_data = input_data[..., -1] connected_components = label(input_data, connectivity=2) component_labels = np.unique(connected_components) max_3ds = [] major_diameter = None for label_idx in component_labels: component = connected_components.astype(int) component[connected_components != label_idx] = 0 major_diameter = [None] if np.sum(component) == 0: continue label_properties = regionprops(component) current_major = label_properties[0].major_axis_length current_orientation = label_properties[0].orientation print current_orientation if major_diameter is None: major_diameter = current_major elif current_major > major_diameter: major_diameter = current_major if major_diameter is not None: max_3ds += [major_diameter * pixdim[0] * pixdim[1]] if calc_multiple: return max_3ds else: return max(max_3ds)
def calc_surface_area(input_data, pixdim=None, affine=None, mask_value=0, mode='edges'): """ Reminder: Verify on real-world data. Also, some of the binarization feels clumsy/ineffecient. Also, this will over-estimate surface area, because it is counting cubes instead of, say, triangular surfaces """ input_data, input_affine = read_image_files(input_data, return_affine=True) input_data = input_data[..., -1] pixdim = _get_pixdim(pixdim, affine, input_affine) if mode == 'mesh': verts, faces = marching_cubes(input_data, 0, pixdim) surface_area = mesh_surface_area(verts, faces) elif mode == 'edges': edges_kernel = np.zeros((3, 3, 3), dtype=float) edges_kernel[1, 1, 0] = -1 * pixdim[0] * pixdim[1] edges_kernel[0, 1, 1] = -1 * pixdim[1] * pixdim[2] edges_kernel[1, 0, 1] = -1 * pixdim[0] * pixdim[2] edges_kernel[1, 2, 1] = -1 * pixdim[0] * pixdim[2] edges_kernel[2, 1, 1] = -1 * pixdim[1] * pixdim[2] edges_kernel[1, 1, 2] = -1 * pixdim[0] * pixdim[1] edges_kernel[1, 1, 1] = 1 * (2 * pixdim[0] * pixdim[1] + 2 * pixdim[0] * pixdim[2] + 2 * pixdim[1] * pixdim[2]) label_numpy = np.copy(input_data) label_numpy[label_numpy != mask_value] = 1 label_numpy[label_numpy == mask_value] = 0 edge_image = signal.convolve(label_numpy, edges_kernel, mode='same') edge_image[edge_image < 0] = 0 surface_area = np.sum(edge_image) else: print 'Warning, mode parameter', mode, 'not available. Returning None.' surface_area = None return surface_area
def get_affine(self, index): if self.source == 'directories': if self.preprocessed_affine is None: self.preprocessed_case, self.preprocessed_affine = read_image_files( self.preprocessed_case, return_affine=True) return self.preprocessed_affine # A little unsure of the practical implication of the storage code below. elif self.source == 'hdf5': if self.data_affines.shape[0] == 0: affine = None else: affine = self.data_affines[index] return affine return None
def load_case_data(self, case): data_groups = self.get_data_groups() # This is weird. self.current_case = case for data_group in data_groups: if self.preprocessors != []: data_group.preprocessed_case = copy.copy( data_group.data[self.current_case]) else: data_group.preprocessed_case = data_group.data[ self.current_case] self.preprocess() for data_group in data_groups: if type(data_group.preprocessed_case) is np.ndarray: data_group.preprocessed_case, data_group.preprocessed_affine = data_group.preprocessed_case, data_group.preprocessed_affine else: data_group.preprocessed_case, data_group.preprocessed_affine = read_image_files( data_group.preprocessed_case, return_affine=True) data_group.base_case, data_group.base_affine = data_group.get_data( index=case, return_affine=True) if self.preprocessors == []: data_group.preprocessed_case, data_group.preprocessed_affine = data_group.base_case, data_group.base_affine if data_group.source == 'hdf5': data_group.base_casename = data_group.data_casenames[case][ 0].decode("utf-8") else: data_group.base_case = data_group.base_case[np.newaxis, ...] data_group.base_casename = case for data_group in data_groups: # Inconsistencies in batch size during preprocessing, TODO! Important. data_group.preprocessed_case = data_group.preprocessed_case[ np.newaxis, ...] if len(self.augmentations) != 0: data_group.augmentation_cases[0] = data_group.preprocessed_case
def get_data(self, index, return_affine=False): if self.source == 'directory': self.preprocessed_case, affine = read_image_files(self.preprocessed_case, return_affine=True) if affine is not None: self.preprocessed_affine = affine if return_affine: return self.preprocessed_case, self.preprocessed_affine else: return self.preprocessed_case elif self.source == 'storage': if return_affine: return self.data[index][:][np.newaxis], self.data_affines[index] else: return self.data[index][:][np.newaxis] return None
def data_generator(self, data_group_labels, cases=None, yield_data=True): # Referencing to data groups is a little wonky here, TODO: clean up if data_group_labels is None: data_group_labels = self.data_groups.keys() data_groups = [self.data_groups[label] for label in data_group_labels] for data_group in data_groups: if len(self.augmentations) != 0: data_group.augmentation_cases = [None] * ( 1 + len(self.augmentations)) if cases is None: cases = self.cases for case_idx, case_name in enumerate(cases): if self.verbose: print 'Working on image.. ', case_idx, 'at', case_name for data_group in data_groups: # This is messy code. TODO: return to conditional below. Suspicious data has been laoded twice. if case_name != data_group.base_casename: data_group.base_case, data_group.base_affine = read_image_files( data_group.data[data_group.cases.index(case_name)], return_affine=True) data_group.base_case = data_group.base_case[:][np.newaxis] data_group.base_casename = case_name if len(self.augmentations) != 0: data_group.augmentation_cases[0] = data_group.base_case recursive_augmentation_generator = self.recursive_augmentation( data_groups, augmentation_num=0) for i in xrange(self.multiplier): generate_data = next(recursive_augmentation_generator) if yield_data: yield tuple([ data_group.augmentation_cases[-1] for data_group in data_groups ]) else: yield True
def get_shape(self): # TODO: Add support for non-nifti files. # Also this is not good. Perhaps specify shape in input? if self.output_shape is None: if self.data == {}: print('No Data!') return (0,) elif self.base_shape is None: if self.source == 'hdf5': self.base_shape = self.data[0].shape else: self.base_shape = read_image_files(list(self.data.values())[0]).shape self.output_shape = self.base_shape else: return None return self.output_shape
def get_data(self, index=None, return_affine=False): """ Wonky behavior reading from hdf5 here. """ if self.source == 'hdf5': if return_affine: return self.data[index][:][ np.newaxis], self.data_affines[index] else: return self.data[index][:][np.newaxis] else: self.preprocessed_case, affine = read_image_files( self.preprocessed_case, return_affine=True) if affine is not None: self.preprocessed_affine = affine if return_affine: return self.preprocessed_case, self.preprocessed_affine else: return self.preprocessed_case return None
def initialize(self, data_collection): super(SkullStrip, self).initialize(data_collection) for label, data_group in data_collection.data_groups.iteritems(): if type(data_group.preprocessed_case) is list: input_file = data_group.preprocessed_case[ self.reference_channel] else: # What to do about affines here... input_file = save_numpy_2_nifti( data_group.preprocessed_case[..., self.reference_channel], data_group.preprocessed_affine, 'DEEPNEURO_TEMP_FILE.nii.gz') base_filename = data_group.data[data_collection.current_case][ self.reference_channel] self.mask_filename = self.generate_output_filename( base_filename, self.mask_string) specific_command = self.command + [ input_file, self.mask_filename, '-f', str(self.bet2_f), '-g', str(self.bet2_g), '-m' ] subprocess.call(' '.join(specific_command), shell=True, stdout=FNULL, stderr=subprocess.STDOUT) os.rename(self.mask_filename + '_mask.nii.gz', self.mask_filename) self.mask_numpy = read_image_files(self.mask_filename, return_affine=False)
self.data_groups[data_group_label].write_to_storage() return def add_channel(self, case, input_data, data_group_labels=None, channel_dim=-1): """ This function and remove_channel are edge cases that should be dealt with outside of data_collection. """ # TODO: Add functionality for inserting channel at specific index, multiple channels if isinstance(input_data, str): input_data = read_image_files([input_data]) if data_group_labels is None: data_groups = list(self.data_groups.values()) else: data_groups = [ self.data_groups[label] for label in data_group_labels ] for data_group in data_groups: if case != self.current_case: self.load_case_data(case) data_group.preprocessed_case = np.concatenate( (data_group.preprocessed_case, input_data[np.newaxis, ...]),
def create_mosaic(input_volume, output_filepath=None, label_volume=None, generate_outline=True, mask_value=0, step=1, dim=2, cols=8, label_buffer=5, rotate_90=3, flip=True): """This creates a mosaic of 2D images from a 3D Volume. Parameters ---------- input_volume : TYPE Any neuroimaging file with a filetype supported by qtim_tools, or existing numpy array. output_filepath : None, optional Where to save your output, in a filetype supported by matplotlib (e.g. .png). If label_volume : None, optional Whether to create your mosaic with an attached label filepath / numpy array. Will not perform volume transforms from header (yet) generate_outline : bool, optional If True, will generate outlines for label_volumes, instead of filled-in areas. Default is True. mask_value : int, optional Background value for label volumes. Default is 0. step : int, optional Will generate an image for every [step] slice. Default is 1. dim : int, optional Mosaic images will be sliced along this dimension. Default is 2, which often corresponds to axial. cols : int, optional How many columns in your output mosaic. Rows will be determined automatically. Default is 8. label_buffer : int, optional Images more than [label_buffer] slices away from a slice containing a label pixel will note be included. Default is 5. rotate_90 : int, optional If the output mosaic is incorrectly rotated, you may rotate clockwise [rotate_90] times. Default is 3. flip : bool, optional If the output is incorrectly flipped, you may set to True to flip the data. Default is True. No Longer Returned ------------------ Returns ------- output_array: N+1 or N-dimensional array The generated mosaic array. """ image_numpy = read_image_files(input_volume) if step is None: step = 1 if label_volume is not None: label_numpy = read_image_files(label_volume) if generate_outline: label_numpy = generate_label_outlines(label_numpy, dim, mask_value) # This is fun in a wacky way, but could probably be done more concisely and effeciently. mosaic_selections = [] for i in range(label_numpy.shape[dim]): label_slice = np.squeeze(label_numpy[[slice(None) if k != dim else slice(i, i + 1) for k in range(3)]]) if np.sum(label_slice) != 0: mosaic_selections += list(range(i - label_buffer, i + label_buffer)) mosaic_selections = np.unique(mosaic_selections) mosaic_selections = mosaic_selections[mosaic_selections >= 0] mosaic_selections = mosaic_selections[mosaic_selections <= image_numpy.shape[dim]] mosaic_selections = mosaic_selections[::step] color_range_image = [np.min(image_numpy), np.max(image_numpy)] color_range_label = [np.min(label_numpy), np.max(label_numpy)] # One day, specify rotations by affine matrix. # Is test slice necessary? Operate directly on shape if possible. test_slice = np.rot90(np.squeeze(image_numpy[[slice(None) if k != dim else slice(0, 1) for k in range(3)]]), rotate_90) slice_width = test_slice.shape[1] slice_height = test_slice.shape[0] mosaic_image_numpy = np.zeros((int(slice_height * np.ceil(float(len(mosaic_selections)) / float(cols))), int(test_slice.shape[1] * cols)), dtype=float) mosaic_label_numpy = np.zeros_like(mosaic_image_numpy) row_index = 0 col_index = 0 for i in mosaic_selections: image_slice = np.rot90(np.squeeze(image_numpy[[slice(None) if k != dim else slice(i, i + 1) for k in range(3)]]), rotate_90) label_slice = np.rot90(np.squeeze(label_numpy[[slice(None) if k != dim else slice(i, i + 1) for k in range(3)]]), rotate_90) # Again, specify from affine matrix if possible. if flip: image_slice = np.fliplr(image_slice) label_slice = np.fliplr(label_slice) if image_slice.size > 0: mosaic_image_numpy[int(row_index):int(row_index + slice_height), int(col_index):int(col_index + slice_width)] = image_slice mosaic_label_numpy[int(row_index):int(row_index + slice_height), int(col_index):int(col_index + slice_width)] = label_slice if col_index == mosaic_image_numpy.shape[1] - slice_width: col_index = 0 row_index += slice_height else: col_index += slice_width mosaic_label_numpy = np.ma.masked_where(mosaic_label_numpy == 0, mosaic_label_numpy) if output_filepath is not None: plt.figure(figsize=(mosaic_image_numpy.shape[0] / 100, mosaic_image_numpy.shape[1] / 100), dpi=100, frameon=False) plt.margins(0, 0) plt.gca().set_axis_off() plt.gca().xaxis.set_major_locator(plt.NullLocator()) plt.gca().yaxis.set_major_locator(plt.NullLocator()) plt.imshow(mosaic_image_numpy, 'gray', vmin=color_range_image[0], vmax=color_range_image[1], interpolation='none') plt.imshow(mosaic_label_numpy, 'jet', vmin=color_range_label[0], vmax=color_range_label[1], interpolation='none') plt.savefig(output_filepath, bbox_inches='tight', pad_inches=0.0, dpi=1000) plt.clf() plt.close() return mosaic_image_numpy else: color_range_image = [np.min(image_numpy), np.max(image_numpy)] test_slice = np.rot90(np.squeeze(image_numpy[[slice(None) if k != dim else slice(0, 1) for k in range(3)]]), rotate_90) slice_width = test_slice.shape[1] slice_height = test_slice.shape[0] mosaic_selections = np.arange(image_numpy.shape[dim])[::step] mosaic_image_numpy = np.zeros((int(slice_height * np.ceil(float(len(mosaic_selections)) / float(cols))), int(test_slice.shape[1] * cols)), dtype=float) row_index = 0 col_index = 0 for i in mosaic_selections: image_slice = np.squeeze(image_numpy[[slice(None) if k != dim else slice(i, i + 1) for k in range(3)]]) image_slice = np.rot90(image_slice, rotate_90) if flip: image_slice = np.fliplr(image_slice) mosaic_image_numpy[int(row_index):int(row_index + slice_height), int(col_index):int(col_index + slice_width)] = image_slice if col_index == mosaic_image_numpy.shape[1] - slice_width: col_index = 0 row_index += slice_height else: col_index += slice_width if output_filepath is not None: plt.figure(figsize=(mosaic_image_numpy.shape[0] / 100, mosaic_image_numpy.shape[1] / 100), dpi=100, frameon=False) plt.margins(0, 0) plt.gca().set_axis_off() plt.gca().xaxis.set_major_locator(plt.NullLocator()) plt.gca().yaxis.set_major_locator(plt.NullLocator()) plt.imshow(mosaic_image_numpy, 'gray', vmin=color_range_image[0], vmax=color_range_image[1], interpolation='none') plt.savefig(output_filepath, bbox_inches='tight', pad_inches=0.0, dpi=500) plt.clf() plt.close() return mosaic_image_numpy
def calc_voxel_count(input_data, mask_value=0): input_data = read_image_files(input_data) return input_data[input_data != mask_value].size
def check_data(output_data=None, data_collection=None, batch_size=4, merge_batch=True, show_output=True, output_filepath=None, viz_rows=None, viz_mode_2d=None, viz_mode_3d='2d_slice', color_range=None, output_groups=None, combine_outputs=False, rgb_output=True, colorbar=True, subplot_rows=None, title=None, subplot_titles=None, output_directory=None, case_name=None, **kwargs): if data_collection is not None: if batch_size > data_collection.total_cases * data_collection.multiplier: batch_size = data_collection.total_cases * data_collection.multiplier generator = data_collection.data_generator(perpetual=True, verbose=False, batch_size=batch_size) case_name = data_collection.current_case output_data = next(generator) if type(output_data) is not dict: output_data = {'output_data': output_data} # Very bad, reformat. output_data = { label: data for label, data in list(output_data.items()) if '_affine' not in label and '_augmentation_string' not in label and 'casename' not in label } for label, data in list(output_data.items()): if type(data) is str: output_data[label] = read_image_files(data)[np.newaxis, ...] if color_range is None: color_range = { label: [np.min(data), np.max(data)] for label, data in list(output_data.items()) } if output_groups is not None: output_data = { label: data for label, data in list(output_data.items()) if label in output_groups } if not show_output: subplot_titles = None output_images = OrderedDict() if data_collection is None: reference_key = list(output_data)[0] batch_size = output_data[reference_key].shape[0] if viz_rows is None: viz_rows = int(np.ceil(np.sqrt(batch_size))) else: viz_rows = min(viz_rows, batch_size) viz_columns = int(np.ceil(batch_size / float(viz_rows))) for label, data in list(output_data.items()): if '_affine' in label or '_augmentation_string' in label or 'casename' in label: continue if data.ndim == 5: output_images, color_range = display_3d_data( data, color_range, viz_mode_3d, label, output_images, viz_rows, viz_columns, subplot_titles=subplot_titles, **kwargs) elif data.ndim == 4: if data.shape[-1] == 2: for i in range(data.shape[-1]): if subplot_titles is None: subplot_title = label + '_' + str(i) else: subplot_title = subplot_titles[label][i] output_images[subplot_title] = merge_data( data[..., i][..., np.newaxis], [viz_rows, viz_columns], 1) color_range[subplot_title] = color_range[label] if data.shape[-1] not in [1, 3]: output_images[label + '_RGB'] = merge_data( data[..., 0:3], [viz_rows, viz_columns], 3) color_range[label + '_RGB'] = color_range[label] for i in range(3, data.shape[-1]): output_images[label + '_' + str(i)] = merge_data( data[..., i][..., np.newaxis], [viz_rows, viz_columns], 1) color_range[label + '_' + str(i)] = color_range[label] else: output_images[label] = merge_data(data, [viz_rows, viz_columns], data.shape[-1]) elif data.ndim == 3: output_images[label] = merge_data(data, [viz_rows, viz_columns], data.shape[-1]) # elif data.ndim == 2: # output_images[label] = display_1d_data(data, [viz_rows, viz_columns]) if show_output: plots = len(list(output_images.keys())) if subplot_rows is None: subplot_rows = int(np.ceil(np.sqrt(plots))) plot_columns = int(np.ceil(plots / float(subplot_rows))) fig, axarr = plt.subplots(plot_columns, subplot_rows) # matplotlib is so annoying if subplot_rows == 1 and plot_columns == 1: axarr = np.array([axarr]).reshape(1, 1) elif subplot_rows == 1 or plot_columns == 1: axarr = axarr.reshape(plot_columns, subplot_rows) for plot_idx, (label, data) in enumerate(output_images.items()): image_row = plot_idx % plot_columns image_column = plot_idx // plot_columns if data.shape[-1] == 3: # Weird matplotlib bug/feature: if np.min(data) < 0: data = (data - np.min(data)) / (np.max(data) - np.min(data)) plt_image = axarr[image_row, image_column].imshow( np.squeeze(data), cmap=plt.get_cmap('hot'), vmin=color_range[label][0], vmax=color_range[label][1], interpolation='none') if colorbar: fig.colorbar(plt_image, ax=axarr[image_row, image_column]) elif data.shape[-1] == 1: plt_image = axarr[image_row, image_column].imshow( np.squeeze(data), cmap='gray', vmin=color_range[label][0], vmax=color_range[label][1], interpolation='none') if colorbar: fig.colorbar(plt_image, ax=axarr[image_row, image_column], cmap='gray') axarr[image_row, image_column].set_title(label) for plot_idx in range(len(output_images), subplot_rows * plot_columns): image_row = plot_idx % plot_columns image_column = plot_idx // plot_columns fig.delaxes(axarr[image_row, image_column]) if title is not None: fig.suptitle(title, fontsize=28) plt.show() output_filepaths = {} if (output_directory is not None or output_filepath is not None): for label, data in list(output_images.items()): output_images[label] = image_preprocess(data) if output_filepath is not None: output_filepaths[label] = save_data( output_images[label], replace_suffix(output_filepath, '', '_' + label)) continue if output_directory is not None and case_name is not None: output_filepaths[label] = save_data( output_images[label], os.path.join( output_directory, nifti_splitext( replace_suffix(os.path.basename(case_name), '', '_' + label))[0]) + '.png') return output_filepaths, output_images