Source code for dipy.nn.utils

import numpy as np
from scipy.ndimage import affine_transform

from dipy.align.reslice import reslice
from dipy.testing.decorators import warning_for_keywords


[docs] @warning_for_keywords() def normalize(image, *, min_v=None, max_v=None, new_min=-1, new_max=1): """ normalization function Parameters ---------- image : np.ndarray Image to be normalized. min_v : int or float, optional minimum value range for normalization intensities below min_v will be clipped if None it is set to min value of image Default : None max_v : int or float, optional maximum value range for normalization intensities above max_v will be clipped if None it is set to max value of image Default : None new_min : int or float, optional new minimum value after normalization Default : 0 new_max : int or float, optional new maximum value after normalization Default : 1 Returns ------- np.ndarray Normalized image from range new_min to new_max """ if min_v is None: min_v = np.min(image) if max_v is None: max_v = np.max(image) return np.interp(image, (min_v, max_v), (new_min, new_max))
[docs] def unnormalize(image, norm_min, norm_max, min_v, max_v): """ unnormalization function Parameters ---------- image : np.ndarray norm_min : int or float minimum value of normalized image norm_max : int or float maximum value of normalized image min_v : int or float minimum value of unnormalized image max_v : int or float maximum value of unnormalized image Returns ------- np.ndarray unnormalized image from range min_v to max_v """ return (image - norm_min) / (norm_max - norm_min) * (max_v - min_v) + min_v
def set_logger_level(log_level, logger): """Change the logger to one of the following: DEBUG, INFO, WARNING, CRITICAL, ERROR Parameters ---------- log_level : str Log level for the logger """ logger.setLevel(level=log_level)
[docs] @warning_for_keywords() def transform_img( image, affine, *, voxsize=None, considered_points="corners", init_shape=(256, 256, 256), scale=2, ): """ Function to reshape image as an input to the model Parameters ---------- image : np.ndarray Image to transform to voxelspace affine : np.ndarray Affine matrix provided by the file voxsize : np.ndarray (3,), optional Voxel size of the image considered_points : str, optional which points to consider when calculating the boundary of the image. If there is shearing in the affine, 'all' might be more accurate init_shape : list, tuple or numpy array (3,), optional Initial shape to transform the image to scale : float, optional How much we want to scale the image Returns ------- tuple Tuple with variables for recover_img """ if voxsize is not None and np.any(voxsize != np.ones(3)): image2, affine2 = reslice(image, affine, voxsize, (1, 1, 1)) else: image2 = image.copy() affine2 = affine.copy() shape = image2.shape if considered_points == "corners": corners = np.array( [ [0, 0, 0, 1], [shape[0] - 1, 0, 0, 1], [0, shape[1] - 1, 0, 1], [0, 0, shape[2] - 1, 1], [shape[0] - 1, shape[1] - 1, shape[2] - 1, 1], [shape[0] - 1, 0, shape[2] - 1, 1], [0, shape[1] - 1, shape[2] - 1, 1], [shape[0] - 1, shape[1] - 1, 0, 1], ], dtype=np.float64, ) else: temp1 = np.arange(shape[0]) temp2 = np.arange(shape[1]) temp3 = np.arange(shape[2]) grid1, grid2, grid3 = np.meshgrid(temp1, temp2, temp3) corners = np.vstack([grid1.ravel(), grid2.ravel(), grid3.ravel()]).T corners = np.hstack([corners, np.full((corners.shape[0], 1), 1)]) corners = corners.astype(np.float64) transformed_corners = (affine2 @ corners.T).T min_bounds = transformed_corners.min(axis=0)[:3] max_bounds = transformed_corners.max(axis=0)[:3] # Calculate the required offset to ensure # all necessary coordinates are positive offset = np.floor(-min_bounds) new_shape = (np.ceil(max_bounds) + offset).astype(int) offset_array = np.array( [[1, 0, 0, offset[0]], [0, 1, 0, offset[1]], [0, 0, 1, offset[2]], [0, 0, 0, 1]] ) new_affine = affine2.copy() new_affine = np.matmul(offset_array, new_affine) inv_affine = np.linalg.inv(new_affine) new_image = np.zeros(tuple(new_shape)) affine_transform( image2, inv_affine, output_shape=tuple(new_shape), output=new_image ) new_image, pad_vs, crop_vs = pad_crop(new_image, init_shape) if scale != 1: new_image, _ = reslice(new_image, np.eye(4), (1, 1, 1), (scale, scale, scale)) return new_image, inv_affine, image2.shape, offset_array, scale, crop_vs, pad_vs
[docs] def recover_img( image, inv_affine, mid_shape, ori_shape, offset_array, voxsize, scale, crop_vs, pad_vs, ): """ Function to recover image from transform_img Parameters ---------- image : np.ndarray Image to recover inv_affine : np.ndarray Affine matrix returned from transform_img mid_shape : np.ndarray (3,) shape of image returned from transform_img ori_shape : tuple (3,) original shape of the image offset_array : np.ndarray Affine matrix that was used in transform_img to translate the center voxsize : np.ndarray (3,) Voxel size used in transform_img scale : float Scale used in transform_img crop_vs : np.ndarray (3,2) crop range used in transform_img pad_vs : np.ndarray (3,2) pad range used in transform_img Returns ------- image2 : np.ndarray Recovered image """ new_affine = np.linalg.inv(inv_affine) new_image, _ = reslice(image, np.eye(4), (scale, scale, scale), (1, 1, 1)) crop_vs = crop_vs.astype(int) pad_vs = pad_vs.astype(int) new_image = np.pad( new_image, ( (crop_vs[0, 0], crop_vs[0, 1]), (crop_vs[1, 0], crop_vs[1, 1]), (crop_vs[2, 0], crop_vs[2, 1]), ), ) new_image = new_image[ pad_vs[0, 0] : new_image.shape[0] - pad_vs[0, 1], pad_vs[1, 0] : new_image.shape[1] - pad_vs[1, 1], pad_vs[2, 0] : new_image.shape[2] - pad_vs[2, 1], ] new_image = affine_transform(new_image, new_affine, output_shape=mid_shape) affine = np.matmul(np.linalg.inv(offset_array), new_affine) if voxsize is not None and np.any(voxsize != np.ones(3)): image2, _ = reslice(new_image, affine, (1, 1, 1), voxsize) else: image2 = new_image # because of zoom rounding errors image2, _, _ = pad_crop(image2, ori_shape) return image2
[docs] def pad_crop(image, target_shape): """ Function to figure out pad and crop range to fit the target shape with the image Parameters ---------- image : np.ndarray Target image target_shape : (3,) Target shape Returns ------- image : np.ndarray Padded/cropped image pad_vs : np.ndarray (3,2) Pad range used crop_vs : np.ndarray (3,2) Crop range used """ crop_vs = np.zeros((3, 2)).astype(int) pad_vs = np.zeros((3, 2)).astype(int) if image.shape == target_shape: return image, pad_vs, crop_vs pad_crop_v = np.array(target_shape) - np.array(image.shape) for d in range(3): if pad_crop_v[d] < 0: crop_vs[d, 0] = -pad_crop_v[d] // 2 crop_vs[d, 1] = -pad_crop_v[d] - crop_vs[d, 0] elif pad_crop_v[d] > 0: pad_vs[d, 0] = pad_crop_v[d] // 2 pad_vs[d, 1] = pad_crop_v[d] - pad_vs[d, 0] image = np.pad( image, ( (pad_vs[0, 0], pad_vs[0, 1]), (pad_vs[1, 0], pad_vs[1, 1]), (pad_vs[2, 0], pad_vs[2, 1]), ), ) image = image[ crop_vs[0, 0] : image.shape[0] - crop_vs[0, 1], crop_vs[1, 0] : image.shape[1] - crop_vs[1, 1], crop_vs[2, 0] : image.shape[2] - crop_vs[2, 1], ] return image, pad_vs, crop_vs