def from_slice(cls, slice_to_copy): slice = cls() if not isinstance(slice_to_copy, Slice): raise ValueError("Input must be of type Slice. Given: %s" % type(slice_to_copy)) # Copy image slice and mask slice.sitk = sitk.Image(slice_to_copy.sitk) slice.itk = sitkh.get_itk_from_sitk_image(slice.sitk) slice.sitk_mask = sitk.Image(slice_to_copy.sitk_mask) slice.itk_mask = sitkh.get_itk_from_sitk_image(slice.sitk_mask) slice._filename = slice_to_copy.get_filename() slice._slice_number = slice_to_copy.get_slice_number() slice._dir_input = slice_to_copy.get_directory() # slice._history_affine_transforms, slice._history_motion_corrections = slice_to_copy.get_registration_history() # Store current affine transform of image slice._affine_transform_sitk = sitkh.get_sitk_affine_transform_from_sitk_image( slice.sitk) # Prepare history of affine transforms, i.e. encoded spatial # position+orientation of slice, and rigid motion estimates of slice # obtained in the course of the registration/reconstruction process slice._history_affine_transforms, slice._history_motion_corrections = slice_to_copy.get_registration_history( ) return slice
def test_computation_point_physical_space_via_affine_transform(self): # Get indices with intensities greater than 0 # indices \in \R^{dim, N_points} indices = np.array( np.where(sitk.GetArrayFromImage(self.image_sitk)[::-1] > 0)) N_points = indices.shape[1] # Get sitk affine transform from image first affine_transform_sitk = \ sitkh.get_sitk_affine_transform_from_sitk_image(self.image_sitk) dim = self.image_sitk.GetDimension() A = np.array(affine_transform_sitk.GetMatrix()).reshape(dim, dim) t = np.array(affine_transform_sitk.GetTranslation()).reshape(3, 1) for i in range(0, N_points): index = indices[:, i].reshape(dim, 1) # Check Alignment self.assertEqual( np.around(np.linalg.norm( (A.dot(index) + t).flatten() - self.image_sitk.TransformIndexToPhysicalPoint( index.flatten())), decimals=self.accuracy), 0)
def from_sitk_image(cls, slice_sitk, slice_number, filename="unknown", slice_sitk_mask=None): slice = cls() # Directory # dir_input = "/".join(filename.split("/")[0:-1]) + "/" # Filename without extension # filename = filename.split("/")[-1:][0].split(".")[0] slice._dir_input = None slice._filename = filename slice._slice_number = slice_number # Append stacks as SimpleITK and ITK Image objects slice.sitk = slice_sitk slice.itk = sitkh.get_itk_from_sitk_image(slice_sitk) # Append masks (if provided) if slice_sitk_mask is not None: slice.sitk_mask = slice_sitk_mask slice.itk_mask = sitkh.get_itk_from_sitk_image(slice_sitk_mask) else: slice.sitk_mask = slice._generate_identity_mask() slice.itk_mask = sitkh.get_itk_from_sitk_image(slice.sitk_mask) # slice._sitk_upsampled = None # HACK (for current Slice-to-Volume Registration) # See class SliceToVolumeRegistration # slice._sitk_upsampled = slice._get_upsampled_isotropic_resolution_slice(slice_sitk) # slice._itk_upsampled = sitkh.get_itk_from_sitk_image(slice._sitk_upsampled) # if slice_sitk_mask is not None: # slice._sitk_mask_upsampled = slice._get_upsampled_isotropic_resolution_slice(slice_sitk_mask) # slice._itk_mask_upsampled = sitkh.get_itk_from_sitk_image(slice._sitk_mask_upsampled) # else: # slice._sitk_mask_upsampled = None # slice._itk_mask_upsampled = None # Store current affine transform of image slice._affine_transform_sitk = sitkh.get_sitk_affine_transform_from_sitk_image( slice.sitk) # Prepare history of affine transforms, i.e. encoded spatial # position+orientation of slice, and rigid motion estimates of slice # obtained in the course of the registration/reconstruction process slice._history_affine_transforms = [] slice._history_affine_transforms.append(slice._affine_transform_sitk) slice._history_motion_corrections = [] slice._history_motion_corrections.append(sitk.Euler3DTransform()) return slice
def from_filename(cls, file_path, slice_number, slice_thickness, file_path_mask=None, verbose=False, ): slice = cls() if not ph.file_exists(file_path): raise exceptions.FileNotExistent(file_path) slice._dir_input = os.path.dirname(file_path) slice._filename = os.path.basename(file_path).split(".")[0] slice._slice_number = slice_number slice._slice_thickness = slice_thickness # Append stacks as SimpleITK and ITK Image objects slice.sitk = sitkh.read_nifti_image_sitk(file_path, sitk.sitkFloat64) slice.itk = sitkh.get_itk_from_sitk_image(slice.sitk) # Append masks (if provided) if file_path_mask is None: slice.sitk_mask = slice._generate_identity_mask() if verbose: ph.print_info( "Identity mask created for '%s'." % (file_path)) else: if not ph.file_exists(file_path_mask): raise exceptions.FileNotExistent(file_path_mask) slice.sitk_mask = sitkh.read_nifti_image_sitk( file_path_mask, sitk.sitkUInt8) try: # ensure mask occupies the same physical space slice.sitk_mask.CopyInformation(slice.sitk) except RuntimeError as e: raise IOError( "Given image and its mask do not occupy the same space: %s" % e.message) slice.itk_mask = sitkh.get_itk_from_sitk_image(slice.sitk_mask) # Store current affine transform of image slice._affine_transform_sitk = sitkh.get_sitk_affine_transform_from_sitk_image( slice.sitk) # Prepare history of affine transforms, i.e. encoded spatial # position+orientation of slice, and motion estimates of slice # obtained in the course of the registration/reconstruction process slice._history_affine_transforms = [] slice._history_affine_transforms.append(slice._affine_transform_sitk) slice._history_motion_corrections = [] slice._history_motion_corrections.append(sitk.Euler3DTransform()) return slice
def from_filename(cls, file_path, slice_number, file_path_mask=None, verbose=False): slice = cls() if not ph.file_exists(file_path): raise exceptions.FileNotExistent(file_path) slice._dir_input = os.path.dirname(file_path) slice._filename = os.path.basename(file_path).split(".")[0] slice._slice_number = slice_number # Append stacks as SimpleITK and ITK Image objects slice.sitk = sitk.ReadImage(file_path, sitk.sitkFloat64) slice.itk = sitkh.get_itk_from_sitk_image(slice.sitk) # Append masks (if provided) if file_path_mask is None: slice.sitk_mask = slice._generate_identity_mask() if verbose: ph.print_info("Identity mask created for '%s'." % (file_path)) else: if not ph.file_exists(file_path_mask): raise exceptions.FileNotExistent(file_path_mask) slice.sitk_mask = sitk.ReadImage(file_path_mask, sitk.sitkUInt8) slice.itk_mask = sitkh.get_itk_from_sitk_image(slice.sitk_mask) # Store current affine transform of image slice._affine_transform_sitk = sitkh.get_sitk_affine_transform_from_sitk_image( slice.sitk) # Prepare history of affine transforms, i.e. encoded spatial # position+orientation of slice, and motion estimates of slice # obtained in the course of the registration/reconstruction process slice._history_affine_transforms = [] slice._history_affine_transforms.append(slice._affine_transform_sitk) slice._history_motion_corrections = [] slice._history_motion_corrections.append(sitk.Euler3DTransform()) return slice
def test_get_sitk_affine_transform_from_sitk_direction_and_origin(self): origin = self.image_sitk.GetOrigin() direction = self.image_sitk.GetDirection() affine_transform_ref = sitkh.get_sitk_affine_transform_from_sitk_image( self.image_sitk) affine_transform = \ sitkh.get_sitk_affine_transform_from_sitk_direction_and_origin( direction, origin, self.image_sitk) # Check Fixed Parameters self.assertEqual(np.around(np.linalg.norm( np.array(affine_transform_ref.GetFixedParameters()) - affine_transform.GetFixedParameters()), decimals=self.accuracy), 0) # Check Parameters self.assertEqual(np.around(np.linalg.norm( np.array(affine_transform_ref.GetParameters()) - affine_transform.GetParameters()), decimals=self.accuracy), 0)
def test_get_sitk_affine_transform_from_sitk_image(self): # Get indices with intensities greater than 0 # indices \in \R^{dim, N_points} indices = np.array( np.where(sitk.GetArrayFromImage(self.image_sitk)[::-1] > 0)) N_points = indices.shape[1] # Get sitk affine transform from image first (the way it is used in # slice.py) affine_transform_sitk = \ sitkh.get_sitk_affine_transform_from_sitk_image(self.image_sitk) for i in range(0, N_points): index = [int(j) for j in indices[:, i]] # Check Alignment self.assertEqual(np.around(np.linalg.norm(np.array( affine_transform_sitk.TransformPoint(index)) - self.image_sitk.TransformIndexToPhysicalPoint(index)), decimals=self.accuracy), 0)
def from_filename( cls, file_path, file_path_mask=None, extract_slices=True, verbose=False, slice_thickness=None, ): stack = cls() if not ph.file_exists(file_path): raise exceptions.FileNotExistent(file_path) path_to_directory = os.path.dirname(file_path) # Strip extension from filename and remove potentially included "." filename = [ re.sub("." + ext, "", os.path.basename(file_path)) for ext in ALLOWED_EXTENSIONS if file_path.endswith(ext) ][0] # filename = filename.replace(".", "p") stack._dir = os.path.dirname(file_path) stack._filename = filename # Append stacks as SimpleITK and ITK Image objects stack.sitk = sitkh.read_nifti_image_sitk(file_path, sitk.sitkFloat64) stack.itk = sitkh.get_itk_from_sitk_image(stack.sitk) # Set slice thickness of acquisition if slice_thickness is None: stack._slice_thickness = stack.sitk.GetSpacing()[-1] else: stack._slice_thickness = slice_thickness # Append masks (either provided or binary mask) if file_path_mask is None: stack.sitk_mask = stack._generate_identity_mask() if verbose: ph.print_info("Identity mask created for '%s'." % (file_path)) else: if not ph.file_exists(file_path_mask): raise exceptions.FileNotExistent(file_path_mask) stack.sitk_mask = sitkh.read_nifti_image_sitk( file_path_mask, sitk.sitkUInt8) try: # ensure masks occupy same physical space stack.sitk_mask.CopyInformation(stack.sitk) except RuntimeError as e: raise IOError( "Given image and its mask do not occupy the same space: %s" % e.message) stack._is_unity_mask = False # Append itk object stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) # Store current affine transform of image stack._affine_transform_sitk = sitkh.get_sitk_affine_transform_from_sitk_image( stack.sitk) # Prepare history of affine transforms, i.e. encoded spatial # position+orientation of stack, and motion estimates of stack # obtained in the course of the registration/reconstruction process stack._history_affine_transforms = [] stack._history_affine_transforms.append(stack._affine_transform_sitk) stack._history_motion_corrections = [] stack._history_motion_corrections.append(sitk.Euler3DTransform()) # Extract all slices and their masks from the stack and store them if extract_slices: dimenson = stack.sitk.GetDimension() if dimenson == 3: stack._N_slices = stack.sitk.GetSize()[-1] stack._slices = stack._extract_slices( slice_thickness=stack.get_slice_thickness()) elif dimenson == 2: stack._N_slices = 1 stack._slices = [stack.sitk[:, :]] else: stack._N_slices = 0 stack._slices = None if verbose: ph.print_info( "Stack (image + mask) associated to '%s' successfully read." % (file_path)) return stack
def from_sitk_image( cls, image_sitk, slice_thickness, filename="unknown", image_sitk_mask=None, extract_slices=True, slice_numbers=None, ): stack = cls() # Explicit cast (+ creation of other image instance) stack.sitk = sitk.Cast(image_sitk, sitk.sitkFloat64) stack.itk = sitkh.get_itk_from_sitk_image(stack.sitk) # Set slice thickness of acquisition if not ph.is_float(slice_thickness): raise ValueError("Slice thickness must be of type float") stack._slice_thickness = float(slice_thickness) stack._filename = filename stack._dir = None # Append masks (if provided) if image_sitk_mask is not None: stack.sitk_mask = sitk.Cast(image_sitk_mask, sitk.sitkUInt8) try: # ensure mask occupies the same physical space stack.sitk_mask.CopyInformation(stack.sitk) except RuntimeError as e: raise IOError( "Given image and its mask do not occupy the same space: %s" % e.message) stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) if sitk.GetArrayFromImage(stack.sitk_mask).prod() == 1: stack._is_unity_mask = True else: stack._is_unity_mask = False else: stack.sitk_mask = stack._generate_identity_mask() stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) stack._is_unity_mask = True # Extract all slices and their masks from the stack and store them if extract_slices: stack._N_slices = stack.sitk.GetSize()[-1] stack._slices = stack._extract_slices( slice_numbers=slice_numbers, slice_thickness=slice_thickness, ) else: stack._N_slices = 0 stack._slices = None # Store current affine transform of image stack._affine_transform_sitk = sitkh.get_sitk_affine_transform_from_sitk_image( stack.sitk) stack._history_affine_transforms = [] stack._history_affine_transforms.append(stack._affine_transform_sitk) stack._history_motion_corrections = [] stack._history_motion_corrections.append(sitk.Euler3DTransform()) return stack
def from_slice_filenames( cls, dir_input, prefix_stack, suffix_mask=None, dic_slice_filenames=None, prefix_slice="_slice", slice_thickness=None, ): stack = cls() if dir_input[-1] is not "/": dir_input += "/" stack._dir = dir_input stack._filename = prefix_stack # Get 3D images stack.sitk = sitkh.read_nifti_image_sitk( dir_input + prefix_stack + ".nii.gz", sitk.sitkFloat64) stack.itk = sitkh.get_itk_from_sitk_image(stack.sitk) # Store current affine transform of image stack._affine_transform_sitk = sitkh.get_sitk_affine_transform_from_sitk_image( stack.sitk) # Prepare history of affine transforms, i.e. encoded spatial # position+orientation of stack, and motion estimates of stack # obtained in the course of the registration/reconstruction process stack._history_affine_transforms = [] stack._history_affine_transforms.append(stack._affine_transform_sitk) stack._history_motion_corrections = [] stack._history_motion_corrections.append(sitk.Euler3DTransform()) # Set slice thickness of acquisition if slice_thickness is None: stack._slice_thickness = float(stack.sitk.GetSpacing()[-1]) else: stack._slice_thickness = float(slice_thickness) # Append masks (either provided or binary mask) if suffix_mask is not None and \ os.path.isfile(dir_input + prefix_stack + suffix_mask + ".nii.gz"): stack.sitk_mask = sitkh.read_nifti_image_sitk( dir_input + prefix_stack + suffix_mask + ".nii.gz", sitk.sitkUInt8) stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) stack._is_unity_mask = False else: stack.sitk_mask = stack._generate_identity_mask() stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) stack._is_unity_mask = True # Get slices if dic_slice_filenames is None: stack._N_slices = stack.sitk.GetDepth() stack._slices = [None] * stack._N_slices # Append slices as Slice objects for i in range(0, stack._N_slices): path_to_slice = os.path.join( dir_input, prefix_stack + prefix_slice + str(i) + ".nii.gz") path_to_slice_mask = os.path.join( dir_input, prefix_stack + prefix_slice + str(i) + suffix_mask + ".nii.gz") if ph.file_exists(path_to_slice_mask): stack._slices[i] = sl.Slice.from_filename( file_path=path_to_slice, slice_number=i, file_path_mask=path_to_slice_mask) else: stack._slices[i] = sl.Slice.from_filename( file_path=path_to_slice, slice_number=i) else: slice_numbers = sorted(dic_slice_filenames.keys()) stack._N_slices = len(slice_numbers) stack._slices = [None] * stack._N_slices for i, slice_number in enumerate(slice_numbers): path_to_slice = os.path.join( dir_input, dic_slice_filenames[slice_number] + ".nii.gz") path_to_slice_mask = os.path.join( dir_input, dic_slice_filenames[slice_number] + suffix_mask + ".nii.gz") if ph.file_exists(path_to_slice_mask): stack._slices[i] = sl.Slice.from_filename( file_path=path_to_slice, slice_number=slice_number, file_path_mask=path_to_slice_mask, slice_thickness=stack.get_slice_thickness(), ) else: stack._slices[i] = sl.Slice.from_filename( file_path=path_to_slice, slice_number=slice_number, slice_thickness=stack.get_slice_thickness(), ) return stack
def from_sitk_image( cls, slice_sitk, slice_number, slice_thickness, filename="unknown", slice_sitk_mask=None, ): slice = cls() # Directory # dir_input = "/".join(filename.split("/")[0:-1]) + "/" # Filename without extension # filename = filename.split("/")[-1:][0].split(".")[0] slice._dir_input = None slice._filename = filename slice._slice_number = slice_number slice._slice_thickness = slice_thickness # Explicit cast (+ creation of other image instance) slice.sitk = sitk.Cast(slice_sitk, sitk.sitkFloat64) slice.itk = sitkh.get_itk_from_sitk_image(slice.sitk) # Append masks (if provided) if slice_sitk_mask is not None: slice.sitk_mask = sitk.Cast(slice_sitk_mask, sitk.sitkUInt8) try: # ensure mask occupies the same physical space slice.sitk_mask.CopyInformation(slice.sitk) except RuntimeError as e: raise IOError( "Given image and its mask do not occupy the same space: %s" % e.message) slice.itk_mask = sitkh.get_itk_from_sitk_image(slice.sitk_mask) else: slice.sitk_mask = slice._generate_identity_mask() slice.itk_mask = sitkh.get_itk_from_sitk_image(slice.sitk_mask) # slice._sitk_upsampled = None # HACK (for current Slice-to-Volume Registration) # See class SliceToVolumeRegistration # slice._sitk_upsampled = slice._get_upsampled_isotropic_resolution_slice(slice_sitk) # slice._itk_upsampled = # sitkh.get_itk_from_sitk_image(slice._sitk_upsampled) # if slice_sitk_mask is not None: # slice._sitk_mask_upsampled = slice._get_upsampled_isotropic_resolution_slice(slice_sitk_mask) # slice._itk_mask_upsampled = sitkh.get_itk_from_sitk_image(slice._sitk_mask_upsampled) # else: # slice._sitk_mask_upsampled = None # slice._itk_mask_upsampled = None # Store current affine transform of image slice._affine_transform_sitk = sitkh.get_sitk_affine_transform_from_sitk_image( slice.sitk) # Prepare history of affine transforms, i.e. encoded spatial # position+orientation of slice, and rigid motion estimates of slice # obtained in the course of the registration/reconstruction process slice._history_affine_transforms = [] slice._history_affine_transforms.append(slice._affine_transform_sitk) slice._history_motion_corrections = [] slice._history_motion_corrections.append(sitk.Euler3DTransform()) return slice