def field_conversion_method(field_image, image=None, get_position_field=True): data = np.zeros_like(field_image.data, dtype=np.float32) # Matrix to go from voxel to world space if image is not None: voxel_2_xyz = image.voxel_2_mm vol_ext = image.vol_ext field = Image.from_data(data, image.get_header()) else: voxel_2_xyz = field_image.voxel_2_mm vol_ext = field_image.vol_ext field = Image.from_data(data, field_image.get_header()) voxels = np.mgrid[[slice(i) for i in vol_ext]] voxels = [d.reshape(vol_ext, order='F') for d in voxels] mms = [voxel_2_xyz[i][3] + sum(voxel_2_xyz[i][k] * voxels[k] for k in range(len(voxels))) for i in range(len(voxel_2_xyz) - (4 - len(vol_ext)))] input_data = np.squeeze(field_image.data) field_data = np.squeeze(data) mms = np.squeeze(mms) if get_position_field: for i in range(data.shape[-1]): # Output is the deformation/position field field_data[..., i] = input_data[..., i] + mms[i] else: for i in range(data.shape[-1]): # Output is the displacement field field_data[..., i] = input_data[..., i] - mms[i] return field
def initialise_field(im, affine=None): """ Create a field image from the specified target image. Sets the data to 0. Parameters: ----------- :param im: The target image. Mandatory. :param affine: The initial affine transformation :return: Return the created field object """ vol_ext = im.vol_ext dims = list() dims.extend(vol_ext) while len(dims) < 4: dims.extend([1]) dims.extend([len(vol_ext)]) # Inititalise with zero data = np.zeros(dims, dtype=np.float32) field = Image.from_data(data, im.get_header()) # We have supplied an affine transformation if affine is not None: if affine.shape != (4, 4): raise RegError('Input affine transformation ' 'should be a 4x4 matrix.') # The updated transformation transform = affine * im.voxel_2_mm field.update_transformation(transform) return field
def initialise_jacobian_field(im, affine=None): """ Create a jacobian field image from the specified target image/field. Sets the data to 0. Parameters: ----------- :param im: The target image/field. Mandatory. :param affine: The initial affine transformation :return: Return the created jacobian field object. Each jacobian is stored in a vector of size 9 in row major order """ vol_ext = np.array(im.vol_ext) dims = list() dims.extend(vol_ext) while len(dims) < 4: dims.extend([1]) num_dims = len(vol_ext[vol_ext>1]) dims.extend([num_dims**2]) # Inititalise with zero data = np.zeros(dims, dtype=np.float32) jacfield = Image.from_data(data, im.get_header()) jacfield.set_matrix_data_attributes(num_dims, num_dims) # We have supplied an affine transformation if affine is not None: if affine.shape != (4, 4): raise RegError('Input affine transformation ' 'should be a 4x4 matrix.') # The updated transformation transform = affine * im.voxel_2_mm jacfield.update_transformation(transform) return jacfield
def exponentiate(self): """ Compute the exponential of this velocity field using the scaling and squaring approach. The velocity field is in the tangent space of the manifold and the displacement field is the actual manifold and the transformation between the velocity field and the displacement field is given by the exponential chart. :param disp_image: Displacement field image that will be updated with the exponentiated velocity field. """ self.__do_init_check() data = self.field.data result_data = np.zeros(self.field.data.shape) result = Image.from_data(result_data, self.field.get_header()) # Important: Need to specify which axes to use norm = np.linalg.norm(data, axis=data.ndim-1) max_norm = np.max(norm[:]) if max_norm < 0: raise ValueError('Maximum norm is invalid.') if max_norm == 0: return result pix_dims = np.asarray(self.field.zooms) # ignore NULL dimensions min_size = np.min(pix_dims[pix_dims > 0]) num_steps = max(0,np.ceil(np.log2(max_norm / (min_size / 2))).astype('int')) # Approximate the initial exponential init = 1 << num_steps result.data = data / init dfc = DisplacementFieldComposer() # Do the squaring step to perform the integration # The exponential is num_steps times recursive composition of # the field with itself, which is equivalant to integration over # the unit interval. for _ in range(0, num_steps): result = dfc.compose(result, result) return result