def register(self, img_obj: ImageClass, apply_to_self=True): """Register roi with image Do not apply threshold until after interpolation""" if apply_to_self is False: roi_copy = self.copy() roi_copy.register(img_obj=img_obj, apply_to_self=True) return roi_copy from mirp.imageProcess import interpolate_to_new_grid # Skip if image and/or is missing if img_obj is None or self.roi is None: return # Check whether registration is required registration_required = False # Mismatch in grid dimension if np.any( [np.abs(np.array(self.roi.size) - np.array(img_obj.size)) > 0.0]): registration_required = True # Mismatch in origin if np.any([np.abs(self.roi.origin - img_obj.origin) > 0.0]): registration_required = True # Mismatch in spacing if np.any([np.abs(self.roi.spacing - img_obj.spacing) > 0.0]): registration_required = True if not np.allclose(self.roi.orientation, img_obj.orientation): raise ValueError( "Cannot register segmentation and image object due to different alignments. " "Please use an external programme to transfer segmentation to the image." ) if registration_required: # Register roi to image; this transforms the roi grid into self.roi.size, sample_spacing, voxel_grid, grid_origin = \ interpolate_to_new_grid(orig_dim=self.roi.size, orig_spacing=self.roi.spacing, orig_vox=self.roi.get_voxel_grid(), sample_dim=img_obj.size, sample_spacing=img_obj.spacing, grid_origin=np.dot(self.roi.m_affine_inv, np.transpose(img_obj.origin - self.roi.origin)), order=1, mode="nearest", align_to_center=False) # Update origin before spacing, because computing the origin requires the original affine matrix. self.roi.origin = self.roi.origin + np.dot( self.roi.m_affine, np.transpose(grid_origin)) # Update spacing and affine matrix. self.roi.set_spacing(sample_spacing) # Update voxel grid self.roi.set_voxel_grid(voxel_grid=voxel_grid)
def register(self, img_obj, apply_to_self=True): """Register roi with image Do not apply threshold until after interpolation""" if apply_to_self is False: roi_copy = self.copy() roi_copy.register(img_obj=img_obj, apply_to_self=True) return roi_copy from mirp.imageProcess import interpolate_to_new_grid # Skip if image and/or is missing if img_obj is None or self.roi is None: return # Check whether registration is required registration_required = False # Mismatch in grid dimension if np.any( [np.abs(np.array(self.roi.size) - np.array(img_obj.size)) > 0.0]): registration_required = True # Mismatch in origin if np.any([np.abs(self.roi.origin - img_obj.origin) > 0.0]): registration_required = True # Mismatch in spacing if np.any([np.abs(self.roi.spacing - img_obj.spacing) > 0.0]): registration_required = True if registration_required: # Register roi to image; this transforms the roi grid into self.roi.size, self.roi.origin, self.roi.spacing, voxel_grid = \ interpolate_to_new_grid(orig_dim=self.roi.size, orig_origin=self.roi.origin, orig_spacing=self.roi.spacing, orig_vox=self.roi.get_voxel_grid(), sample_dim=img_obj.size, sample_origin=img_obj.origin, sample_spacing=img_obj.spacing, order=1, mode="nearest", align_to_center=False) # Update slice position self.roi.slice_z_pos = self.roi.origin[0] + np.arange( self.roi.size[0]) * self.roi.spacing[0] # Update voxel grid self.roi.set_voxel_grid(voxel_grid=voxel_grid)
def translate(self, t_x=0.0, t_y=0.0, t_z=0.0): """Translate image volume""" from mirp.imageProcess import interpolate_to_new_grid # Skip for missing images if self.is_missing: return # Calculate the new sample origin after translation sample_origin = np.array(self.origin) sample_origin[0] += t_z * self.spacing[0] sample_origin[1] += t_y * self.spacing[1] sample_origin[2] += t_x * self.spacing[2] # Interpolate at shift points self.size, self.origin, self.spacing, upd_voxel_grid = \ interpolate_to_new_grid(orig_dim=self.size, orig_origin=self.origin, orig_spacing=self.spacing, orig_vox=self.get_voxel_grid(), sample_dim=self.size, sample_origin=sample_origin, sample_spacing=self.spacing, order=1, mode="nearest") # Update voxel grid self.set_voxel_grid(voxel_grid=upd_voxel_grid)
def interpolate(self, by_slice, settings): """Performs interpolation of the image volume""" from mirp.imageProcess import interpolate_to_new_grid, gaussian_preprocess_filter # Skip for missing images if self.is_missing: return # Local interpolation constants if None not in settings.img_interpolate.new_spacing: iso_spacing = settings.img_interpolate.new_spacing[0] new_spacing = np.array([iso_spacing, iso_spacing, iso_spacing]) # Desired spacing in mm elif type(settings.img_interpolate.new_non_iso_spacing) in [list, tuple]: if None not in settings.img_interpolate.new_non_iso_spacing: non_iso_spacing = settings.img_interpolate.new_non_iso_spacing new_spacing = np.array(non_iso_spacing) else: new_spacing = self.spacing else: new_spacing = self.spacing # Read additional details order = settings.img_interpolate.spline_order # Order of multidimensional spline filter (0=nearest neighbours, 1=linear, 3=cubic) interpolate_flag = settings.img_interpolate.interpolate # Whether to interpolate or not # Set spacing for interpolation across slices to the original spacing in case interpolation is only conducted within the slice if by_slice: new_spacing[0] = self.spacing[0] # Image translation translate_z = settings.vol_adapt.translate_z[0] translate_y = settings.vol_adapt.translate_y[0] translate_x = settings.vol_adapt.translate_x[0] # Convert to [0.0, 1.0] range translate_x = translate_x - np.floor(translate_x) translate_y = translate_y - np.floor(translate_y) translate_z = translate_z - np.floor(translate_z) trans_vec = np.array([translate_z, translate_y, translate_x]) # Add translation fractions self.transl_fraction_x = translate_x self.transl_fraction_y = translate_y self.transl_fraction_z = translate_z # Skip if translation in both directions is 0.0 if translate_x == 0.0 and translate_y == 0.0 and translate_z == 0.0 and not interpolate_flag: return None # Check if pre-processing is required if settings.img_interpolate.anti_aliasing: self.set_voxel_grid(voxel_grid=gaussian_preprocess_filter(orig_vox=self.get_voxel_grid(), orig_spacing=self.spacing, sample_spacing=new_spacing, param_beta=settings.img_interpolate.smoothing_beta, mode="nearest", by_slice=by_slice)) # Interpolate image and positioning self.size, sample_spacing, upd_voxel_grid, grid_origin = \ interpolate_to_new_grid(orig_dim=self.size, orig_spacing=self.spacing, orig_vox=self.get_voxel_grid(), sample_spacing=new_spacing, translation=trans_vec, order=order, mode="nearest", align_to_center=True) # Update origin before spacing, because computing the origin requires the original affine matrix. self.origin = self.origin + np.dot(self.m_affine, np.transpose(grid_origin)) # Update spacing and affine matrix. self.set_spacing(sample_spacing) # Round intensities in case of modalities with inherently discretised intensities if (self.modality == "CT") and (self.spat_transform == "base"): upd_voxel_grid = np.round(upd_voxel_grid) elif (self.modality == "PT") and (self.spat_transform == "base"): upd_voxel_grid[upd_voxel_grid < 0.0] = 0.0 # Set interpolation self.interpolated = True # Set interpolation algorithm if order == 0: self.interpolation_algorithm = "nnb" elif order == 1: self.interpolation_algorithm = "lin" elif order > 1: self.interpolation_algorithm = "si" + str(order) # Set voxel grid self.set_voxel_grid(voxel_grid=upd_voxel_grid)