def jacobian_determinant(disp): """ jacobian determinant of a displacement field. NB: to compute the spatial gradients, we use np.gradient. Parameters: disp: 3D displacement field of size [nb_dims, *vol_shape] Returns: jacobian determinant (matrix) """ # check inputs volshape = disp.shape[1:] nb_dims = len(volshape) assert len(volshape) in (2, 3), 'flow has to be 2D or 3D' # compute grid grid_lst = nd.volsize2ndgrid(volshape) grid = np.stack(grid_lst, 0) # compute gradients [xFX, xFY, xFZ] = np.gradient(grid[0] - disp[0]) [yFX, yFY, yFZ] = np.gradient(grid[1] - disp[1]) [zFX, zFY, zFZ] = np.gradient(grid[2] - disp[2]) jac_det = np.zeros(grid[0].shape) for i in range(grid.shape[1]): for j in range(grid.shape[2]): for k in range(grid.shape[3]): jac_mij = [[xFX[i, j, k], xFY[i, j, k], xFZ[i, j, k]], [yFX[i, j, k], yFY[i, j, k], yFZ[i, j, k]], [zFX[i, j, k], zFY[i, j, k], zFZ[i, j, k]]] jac_det[i, j, k] = np.linalg.det(jac_mij) return jac_det
def jacobian_determinant(disp): """ jacobian determinant of a displacement field. NB: to compute the spatial gradients, we use np.gradient. Parameters: disp: 2D or 3D displacement field of size [*vol_shape, nb_dims], where vol_shape is of len nb_dims Returns: jacobian determinant (scalar) """ # check inputs volshape = disp.shape[:-1] nb_dims = len(volshape) assert len(volshape) in (2, 3), 'flow has to be 2D or 3D' # compute grid grid_lst = nd.volsize2ndgrid(volshape) grid = np.stack(grid_lst, len(volshape)) # compute gradients J = np.gradient(disp + grid) # 3D glow if nb_dims == 3: dx = J[0] dy = J[1] dz = J[2] # compute jacobian components Jdet0 = dx[..., 0] * (dy[..., 1] * dz[..., 2] - dy[..., 2] * dz[..., 1]) Jdet1 = dx[..., 1] * (dy[..., 0] * dz[..., 2] - dy[..., 2] * dz[..., 0]) Jdet2 = dx[..., 2] * (dy[..., 0] * dz[..., 1] - dy[..., 1] * dz[..., 0]) return Jdet0 - Jdet1 + Jdet2 else: # must be 2 dfdx = J[0] dfdy = J[1] return dfdx[..., 0] * dfdy[..., 1] - dfdy[..., 0] * dfdx[..., 1]
def vol_prior_hack( *args, proc_vol_fn=None, proc_seg_fn=None, prior_type='location', # file-static, file-gen, location prior_file=None, # prior filename prior_feed='input', # input or output patch_stride=1, patch_size=None, batch_size=1, collapse_2d=None, extract_slice=None, force_binary=False, nb_input_feats=1, verbose=False, vol_rand_seed=None, **kwargs): """ """ # prepare the vol_seg gen = vol_seg_hack(*args, **kwargs, proc_vol_fn=None, proc_seg_fn=None, collapse_2d=collapse_2d, extract_slice=extract_slice, force_binary=force_binary, verbose=verbose, patch_size=patch_size, patch_stride=patch_stride, batch_size=batch_size, vol_rand_seed=vol_rand_seed, nb_input_feats=nb_input_feats) # get prior if prior_type == 'location': prior_vol = nd.volsize2ndgrid(vol_size) prior_vol = np.transpose(prior_vol, [1, 2, 3, 0]) prior_vol = np.expand_dims(prior_vol, axis=0) # reshape for model elif prior_type == 'file': # assumes a npz filename passed in prior_file with timer.Timer('loading prior', True): data = np.load(prior_file) prior_vol = data['prior'].astype('float16') else: # assumes a volume with timer.Timer('astyping prior', verbose): prior_vol = prior_file if not (prior_vol.dtype == 'float16'): prior_vol = prior_vol.astype('float16') if force_binary: nb_labels = prior_vol.shape[-1] prior_vol[:, :, :, 1] = np.sum(prior_vol[:, :, :, 1:nb_labels], 3) prior_vol = np.delete(prior_vol, range(2, nb_labels), 3) nb_channels = prior_vol.shape[-1] if extract_slice is not None: if isinstance(extract_slice, int): prior_vol = prior_vol[:, :, extract_slice, np.newaxis, :] else: # assume slices prior_vol = prior_vol[:, :, extract_slice, :] # get the prior to have the right volume [x, y, z, nb_channels] assert np.ndim(prior_vol) == 4 or np.ndim( prior_vol) == 3, "prior is the wrong size" # prior generator if patch_size is None: patch_size = prior_vol.shape[0:3] assert len(patch_size) == len(patch_stride) prior_gen = patch( prior_vol, [*patch_size, nb_channels], patch_stride=[*patch_stride, nb_channels], batch_size=batch_size, collapse_2d=collapse_2d, keep_vol_size=True, infinite=True, #variable_batch_size=True, # this nb_labels_reshape=0) # assert next(prior_gen) is None, "bad prior gen setup" # generator loop while 1: # generate input and output volumes input_vol = next(gen) if verbose and np.all(input_vol.flat == 0): print("all entries are 0") # generate prior batch # with timer.Timer("with send?"): # prior_batch = prior_gen.send(input_vol.shape[0]) prior_batch = next(prior_gen) if prior_feed == 'input': yield ([input_vol, prior_batch], input_vol) else: assert prior_feed == 'output' yield (input_vol, [input_vol, prior_batch])
def add_prior( gen, proc_vol_fn=None, proc_seg_fn=None, prior_type='location', # file-static, file-gen, location prior_file=None, # prior filename prior_feed='input', # input or output patch_stride=1, patch_size=None, batch_size=1, collapse_2d=None, extract_slice=None, force_binary=False, verbose=False, patch_rand=False, patch_rand_seed=None): """ # # add a prior generator to a given generator # with the number of patches in batch matching output of gen """ # get prior if prior_type == 'location': prior_vol = nd.volsize2ndgrid(vol_size) prior_vol = np.transpose(prior_vol, [1, 2, 3, 0]) prior_vol = np.expand_dims(prior_vol, axis=0) # reshape for model elif prior_type == 'file': # assumes a npz filename passed in prior_file with timer.Timer('loading prior', True): data = np.load(prior_file) prior_vol = data['prior'].astype('float16') else: # assumes a volume with timer.Timer('loading prior', True): prior_vol = prior_file.astype('float16') if force_binary: nb_labels = prior_vol.shape[-1] prior_vol[:, :, :, 1] = np.sum(prior_vol[:, :, :, 1:nb_labels], 3) prior_vol = np.delete(prior_vol, range(2, nb_labels), 3) nb_channels = prior_vol.shape[-1] if extract_slice is not None: if isinstance(extract_slice, int): prior_vol = prior_vol[:, :, extract_slice, np.newaxis, :] else: # assume slices prior_vol = prior_vol[:, :, extract_slice, :] # get the prior to have the right volume [x, y, z, nb_channels] assert np.ndim(prior_vol) == 4 or np.ndim( prior_vol) == 3, "prior is the wrong size" # prior generator if patch_size is None: patch_size = prior_vol.shape[0:3] assert len(patch_size) == len(patch_stride) prior_gen = patch(prior_vol, [*patch_size, nb_channels], patch_stride=[*patch_stride, nb_channels], batch_size=batch_size, collapse_2d=collapse_2d, keep_vol_size=True, infinite=True, patch_rand=patch_rand, patch_rand_seed=patch_rand_seed, variable_batch_size=True, nb_labels_reshape=0) assert next(prior_gen) is None, "bad prior gen setup" # generator loop while 1: # generate input and output volumes gen_sample = next(gen) # generate prior batch gs_sample = _get_shape(gen_sample) prior_batch = prior_gen.send(gs_sample) yield (gen_sample, prior_batch)