def gif_slices(img_paths, save_path="", interval=50): """ Generates and saves gif of slices of image supports multiple images to generate multiple gif files. :param img_paths: list or comma separated string of image paths :param save_path: path to directory where visualisation/s is/are to be saved :param interval: time in miliseconds between frames of gif """ if type(img_paths) is str: img_paths = string_to_list(img_paths) img = load_nifti_file(img_paths[0]) img_shape = np.shape(img) for img_path in img_paths: fig = plt.figure() ax = plt.Axes(fig, [0.0, 0.0, 1.0, 1.0]) ax.set_axis_off() fig.add_axes(ax) img = load_nifti_file(img_path) frames = [] for index in range(img_shape[-1]): frame = plt.imshow(img[:, :, index], aspect="auto", animated=True) # plt.axis('off') frames.append([frame]) anim = animation.ArtistAnimation(fig, frames, interval=interval) path_to_anim_save = os.path.join( save_path, os.path.split(img_path)[-1].split(".")[0] + ".gif") anim.save(path_to_anim_save) logger.info("Animation saved to: %s.", path_to_anim_save)
def gif_warp( img_paths, ddf_path, slice_inds=None, num_interval=100, interval=50, save_path="" ): """ Apply ddf to image slice/s to generate gif :param img_paths: list or comma separated string of image paths :param ddf_path: path to ddf to use for warping :param slice_inds: list of slice indices to use for each image :param num_interval: number of intervals in which to apply ddf :param interval: time in miliseconds between frames of gif :param save_path: path to directory where visualisation/s is/are to be saved """ if type(img_paths) is str: img_paths = string_to_list(img_paths) image = load_nifti_file(img_paths[0]) img_shape = np.shape(image) if slice_inds is None: slice_inds = [round(np.random.rand() * (img_shape[-1]) - 1)] for img_path in img_paths: for slice_ind in slice_inds: fig = plt.figure() ax = plt.Axes(fig, [0.0, 0.0, 1.0, 1.0]) ax.set_axis_off() fig.add_axes(ax) ddf_scalers = np.linspace(0, 1, num=num_interval) frames = [] for ddf_scaler in ddf_scalers: image = load_nifti_file(img_path) ddf = load_nifti_file(ddf_path) image = np.expand_dims(image, axis=0) ddf = np.expand_dims(ddf, axis=0) * ddf_scaler warped_image = warp_image_ddf(image=image, ddf=ddf, grid_ref=None) warped_image = np.squeeze(warped_image.numpy()) frame = plt.imshow( warped_image[:, :, slice_ind], aspect="auto", animated=True ) frames.append([frame]) anim = animation.ArtistAnimation(fig, frames, interval=interval) path_to_anim_save = os.path.join( save_path, os.path.split(img_path)[-1].split(".")[0] + "_slice_" + str(slice_ind) + ".gif", ) anim.save(path_to_anim_save) print("Animation saved to:", path_to_anim_save)
def tile_slices(img_paths, save_path="", fname=None, slice_inds=None, col_titles=None): """ Generate a tiled plot of muliple images for multiple slices in the image. Rows are different slices, columns are different images. :param img_paths: list or comma separated string of image paths :param save_path: path to directory where visualisation/s is/are to be saved :param fname: file name with extension to save visualisation to :param slice_inds: list of slice indices to plot for each image :param col_titles: titles for each column, if None then inferred from file names """ if type(img_paths) is str: img_paths = string_to_list(img_paths) img = load_nifti_file(img_paths[0]) img_shape = np.shape(img) if slice_inds is None: slice_inds = [round(np.random.rand() * (img_shape[-1]) - 1)] if col_titles is None: col_titles = [ os.path.split(img_path)[-1].split(".")[0] for img_path in img_paths ] num_inds = len(slice_inds) num_imgs = len(img_paths) subplot_mat = np.array(np.arange(num_inds * num_imgs) + 1).reshape( num_inds, num_imgs) plt.figure(figsize=(num_imgs * 2, num_inds * 2)) imgs = [] for img_path in img_paths: img = load_nifti_file(img_path) imgs.append(img) for img, col_num in zip(imgs, range(num_imgs)): for index, row_num in zip(slice_inds, range(num_inds)): plt.subplot(num_inds, num_imgs, subplot_mat[row_num, col_num]) plt.imshow(img[:, :, index]) plt.axis("off") if row_num - 0 < 1e-3: plt.title(col_titles[col_num]) if fname is None: fname = "visualisation.png" save_fig_to = os.path.join(save_path, fname) plt.savefig(save_fig_to) print("Plot saved to:", save_fig_to)
def warp(image_path: str, ddf_path: str, out_path: str): """ :param image_path: file path of the image file :param ddf_path: file path of the ddf file :param out_path: file path of the output """ if out_path == "": out_path = "warped.nii.gz" logging.warning( f"Output file path is not provided, will save output in {out_path}." ) else: if not (out_path.endswith(".nii") or out_path.endswith(".nii.gz")): out_path = os.path.join(os.path.dirname(out_path), "warped.nii.gz") logging.warning( f"Output file path should end with .nii or .nii.gz, " f"will save output in {out_path}.") os.makedirs(os.path.dirname(out_path), exist_ok=True) # load image and ddf image = load_nifti_file(image_path) ddf = load_nifti_file(ddf_path) if len(image.shape) not in [3, 4]: raise ValueError(f"image shape must be (m_dim1, m_dim2, m_dim3) " f"or (m_dim1, m_dim2, m_dim3, ch)," f" got {image.shape}") if not (len(ddf.shape) == 4 and ddf.shape[-1] == 3): raise ValueError( f"ddf shape must be (f_dim1, f_dim2, f_dim3, 3), got {ddf.shape}") # add batch dimension manually image = tf.expand_dims(image, axis=0) ddf = tf.expand_dims(ddf, axis=0) # warp warped_image = warp_image_ddf(image=image, ddf=ddf, grid_ref=None) warped_image = warped_image.numpy() warped_image = warped_image[0, ...] # removed added batch dimension # save output nib.save(img=nib.Nifti2Image(warped_image, affine=np.eye(4)), filename=out_path)
def warp(image_path: str, ddf_path: str, out_path: str): """ :param image_path: file path of the image file :param ddf_path: file path of the ddf file :param out_path: file path of the output """ if out_path == "": out_path = "warped.nii.gz" logger.warning( "Output file path is not provided, will save output in %s.", out_path) else: if not (out_path.endswith(".nii") or out_path.endswith(".nii.gz")): out_path = os.path.join(os.path.dirname(out_path), "warped.nii.gz") logger.warning( "Output file path should end with .nii or .nii.gz, " "will save output in %s.", out_path, ) os.makedirs(os.path.dirname(out_path), exist_ok=True) # load image and ddf image = load_nifti_file(image_path) ddf = load_nifti_file(ddf_path) fixed_image_shape = ddf.shape[:3] shape_sanity_check(image=image, ddf=ddf) # add batch dimension manually image = tf.expand_dims(image, axis=0) ddf = tf.expand_dims(ddf, axis=0) # warp warped_image = Warping(fixed_image_size=fixed_image_shape)([ddf, image]) warped_image = warped_image.numpy() warped_image = warped_image[0, ...] # removed added batch dimension # save output nib.save(img=nib.Nifti1Image(warped_image, affine=np.eye(4)), filename=out_path) logger.info("Warped image has been saved at %s.", out_path)
def warp(image_path: str, ddf_path: str, out_path: str): """ :param image_path: file path of the image file :param ddf_path: file path of the ddf file :param out_path: file path of the output """ if out_path == "": out_path = "warped.nii.gz" logging.warning( f"Output file path is not provided, will save output in {out_path}." ) else: if not (out_path.endswith(".nii") or out_path.endswith(".nii.gz")): out_path = os.path.join(os.path.dirname(out_path), "warped.nii.gz") logging.warning( f"Output file path should end with .nii or .nii.gz, " f"will save output in {out_path}." ) os.makedirs(os.path.dirname(out_path), exist_ok=True) # load image and ddf image = load_nifti_file(image_path) ddf = load_nifti_file(ddf_path) shape_sanity_check(image=image, ddf=ddf) # add batch dimension manually image = tf.expand_dims(image, axis=0) ddf = tf.expand_dims(ddf, axis=0) # warp warped_image = warp_image_ddf(image=image, ddf=ddf, grid_ref=None) warped_image = warped_image.numpy() warped_image = warped_image[0, ...] # removed added batch dimension # save output nib.save(img=nib.Nifti1Image(warped_image, affine=np.eye(4)), filename=out_path)
def test_overwrite(self, overwrite: bool): arr1 = np.random.rand(2, 3, 4, 3) arr2 = arr1 + 1 nifti_file_path = os.path.join(self.save_dir, self.arr_name + ".nii.gz") # save arr1 os.makedirs(self.save_dir, exist_ok=True) nib.save(img=nib.Nifti1Image(arr1, affine=np.eye(4)), filename=nifti_file_path) # save arr2 w/o overwrite save_array( save_dir=self.save_dir, arr=arr2, name=self.arr_name, normalize=True, overwrite=overwrite, ) arr_read = load_nifti_file(file_path=nifti_file_path) assert is_equal_np(arr2 if overwrite else arr1, arr_read)
def test_load_nifti_file(): """ check if the nifti files can be correctly loaded """ # nii.gz nii_gz_filepath = "./data/test/nifti/paired/test/fixed_images/case000026.nii.gz" load_nifti_file(file_path=nii_gz_filepath) # nii nii_filepath = "./data/test/nifti/unit_test/case000026.nii" load_nifti_file(file_path=nii_filepath) # wrong file type h5_filepath = "./data/test/h5/paired/test/fixed_images.h5" with pytest.raises(ValueError) as err_info: load_nifti_file(file_path=h5_filepath) assert "Nifti file path must end with .nii or .nii.gz" in str( err_info.value)
def test_load_nifti_file_err(): h5_filepath = "./data/test/h5/paired/test/fixed_images.h5" with pytest.raises(ValueError) as err_info: load_nifti_file(file_path=h5_filepath) assert "Nifti file path must end with .nii or .nii.gz" in str( err_info.value)
def test_load_nifti_file(path, shape): arr = load_nifti_file(file_path=path) assert arr.shape == shape
def gif_tile_slices(img_paths, save_path=None, size=(2, 2), fname=None, interval=50): """ Creates tiled gif over slices of multiple images. :param img_paths: list or comma separated string of image paths :param save_path: path to directory where visualisation/s is/are to be saved :param interval: time in miliseconds between frames of gif :param size: number of columns and rows of images for the tiled gif (tuple e.g. (2,2)) :param fname: filename to save visualisation to """ if type(img_paths) is str: img_paths = string_to_list(img_paths) num_images = np.prod(size) if int(len(img_paths)) != int(num_images): raise ValueError("The number of images supplied is " + str(len(img_paths)) + " whereas the number required is " + str(np.prod(size)) + " as size specified is " + str(size)) img = load_nifti_file(img_paths[0]) img_shape = np.shape(img) imgs = [] for img_path in img_paths: img = load_nifti_file(img_path) shape = np.shape(img) if shape != img_shape: raise ValueError("all images do not have equal shapes") imgs.append(img) frames = [] fig = plt.figure() ax = plt.Axes(fig, [0.0, 0.0, 1.0, 1.0]) ax.set_axis_off() fig.add_axes(ax) for index in range(img_shape[-1]): temp_tiles = [] frame = np.matlib.repmat(np.ones((img_shape[0], img_shape[1])), size[0], size[1]) for img in imgs: temp_tile = img[:, :, index] temp_tiles.append(temp_tile) tile_count = 0 for i in range(size[0]): for j in range(size[1]): tile = temp_tiles[tile_count] tile_count += 1 frame[i * img_shape[0]:(i + 1) * img_shape[0], j * img_shape[0]:(j + 1) * img_shape[0], ] = tile frame = plt.imshow(frame, aspect="auto", animated=True) frames.append([frame]) if fname is None: fname = "visualisation.gif" anim = animation.ArtistAnimation(fig, frames, interval=interval) path_to_anim_save = os.path.join(save_path, fname) anim.save(path_to_anim_save) logger.info("Animation saved to: %s", path_to_anim_save)
def test_save_array(): """ Test save_array by testing different shapes and count output files """ def get_num_pngs_in_dir(dir_paths): return len([x for x in os.listdir(dir_paths) if x.endswith(".png")]) def get_num_niftis_in_dir(dir_paths): return len([x for x in os.listdir(dir_paths) if x.endswith(".nii.gz")]) save_dir = "logs/test_util_save_array" if os.path.exists(save_dir): shutil.rmtree(save_dir) # test 3D tf tensor name = "3d_tf" out_dir = os.path.join(save_dir, name) arr = tf.random.uniform(shape=(2, 3, 4)) save_array(save_dir=save_dir, arr=arr, name=name, gray=True) assert get_num_pngs_in_dir(out_dir) == 4 assert get_num_niftis_in_dir(save_dir) == 1 shutil.rmtree(out_dir) os.remove(os.path.join(save_dir, name + ".nii.gz")) # test 4D tf tensor name = "4d_tf" out_dir = os.path.join(save_dir, name) arr = tf.random.uniform(shape=(2, 3, 4, 3)) save_array(save_dir=save_dir, arr=arr, name=name, gray=True) assert get_num_pngs_in_dir(out_dir) == 4 assert get_num_niftis_in_dir(save_dir) == 1 shutil.rmtree(out_dir) os.remove(os.path.join(save_dir, name + ".nii.gz")) # test 3D np tensor name = "3d_np" out_dir = os.path.join(save_dir, name) arr = np.random.rand(2, 3, 4) save_array(save_dir=save_dir, arr=arr, name=name, gray=True) assert get_num_pngs_in_dir(out_dir) == 4 assert get_num_niftis_in_dir(save_dir) == 1 shutil.rmtree(out_dir) os.remove(os.path.join(save_dir, name + ".nii.gz")) # test 4D np tensor name = "4d_np" out_dir = os.path.join(save_dir, name) arr = np.random.rand(2, 3, 4, 3) save_array(save_dir=save_dir, arr=arr, name=name, gray=True) assert get_num_pngs_in_dir(out_dir) == 4 assert get_num_niftis_in_dir(save_dir) == 1 shutil.rmtree(out_dir) os.remove(os.path.join(save_dir, name + ".nii.gz")) # test 4D np tensor without nifti name = "4d_np" out_dir = os.path.join(save_dir, name) arr = np.random.rand(2, 3, 4, 3) save_array(save_dir=save_dir, arr=arr, name=name, gray=True, save_nifti=False) assert get_num_pngs_in_dir(out_dir) == 4 assert get_num_niftis_in_dir(save_dir) == 0 shutil.rmtree(out_dir) # test 4D np tensor without png name = "4d_np" out_dir = os.path.join(save_dir, name) arr = np.random.rand(2, 3, 4, 3) assert not os.path.exists(out_dir) save_array(save_dir=save_dir, arr=arr, name=name, gray=True, save_png=False) assert not os.path.exists(out_dir) assert get_num_niftis_in_dir(save_dir) == 1 os.remove(os.path.join(save_dir, name + ".nii.gz")) # test 4D np tensor with overwrite name = "4d_np" out_dir = os.path.join(save_dir, name) arr1 = np.random.rand(2, 3, 4, 3) arr2 = np.random.rand(2, 3, 4, 3) assert not is_equal_np(arr1, arr2) nifti_file_path = os.path.join(save_dir, name + ".nii.gz") # save arr1 os.makedirs(save_dir, exist_ok=True) nib.save(img=nib.Nifti2Image(arr1, affine=np.eye(4)), filename=nifti_file_path) # save arr2 without overwrite save_array(save_dir=save_dir, arr=arr1, name=name, gray=True, overwrite=False) arr_read = load_nifti_file(file_path=nifti_file_path) assert is_equal_np(arr1, arr_read) # save arr2 with overwrite save_array(save_dir=save_dir, arr=arr2, name=name, gray=True, overwrite=True) arr_read = load_nifti_file(file_path=nifti_file_path) assert is_equal_np(arr2, arr_read) shutil.rmtree(out_dir) os.remove(os.path.join(save_dir, name + ".nii.gz")) # test 5D np tensor name = "5d_np" arr = np.random.rand(2, 3, 4, 1, 3) with pytest.raises(ValueError) as err_info: save_array(save_dir=save_dir, arr=arr, name=name, gray=True) assert "arr must be 3d or 4d numpy array or tf tensor" in str( err_info.value) # test 4D np tensor with wrong shape name = "5d_np" arr = np.random.rand(2, 3, 4, 1) with pytest.raises(ValueError) as err_info: save_array(save_dir=save_dir, arr=arr, name=name, gray=True) assert "4d arr must have 3 channels as last dimension" in str( err_info.value)
def test_load_nifti_file(path, shape): """ check if the nifti files can be correctly loaded """ arr = load_nifti_file(file_path=path) assert arr.shape == shape