def _map_source_images_to_segmentation( self, segmentation: sitk.Image, source_images: List[pydicom.Dataset] ) -> List[List[pydicom.Dataset]]: """Maps an list of source image datasets to the slices of a SimpleITK image. Args: segmentation: A `SimpleITK.Image` with integer labels and a single component per spatial location. source_images: A list of `pydicom.Dataset` which are the source images for the segmentation image. Returns: A `list` with a `list` for each slice, which contains the mapped `pydicom.Dataset` instances for that slice location. Slices can have zero or more matched datasets. """ result: List[List[pydicom.Dataset]] = [ list() for _ in range(segmentation.GetDepth()) ] for source_image in source_images: position = [float(x) for x in source_image.ImagePositionPatient] index = segmentation.TransformPhysicalPointToIndex(position) if index[2] < 0 or index[2] >= segmentation.GetDepth(): continue # TODO Add reverse check if segmentation is contained in image result[index[2]].append(source_image) slices_mapped = sum(len(x) > 0 for x in result) logger.info(f"{slices_mapped} of {segmentation.GetDepth()} slices" "mapped to source DICOM images") return result
def __init__(self, data: sitk.Image, segmentation: sitk.Image, bb_size): self.segmentation = segmentation # place bb so that the segmentation is centered self.offset = ( (np.array(bb_size) - np.array(self.segmentation.GetSize())) / 2).astype(int) # adjust offset if resulting bb is out of bounds segmentation_origin_in_data = data.TransformPhysicalPointToIndex( segmentation.GetOrigin()) self.offset = [ seg_or if seg_or - off < 0 else off for seg_or, off in zip(segmentation_origin_in_data, self.offset) ] self.offset = [ off + ((seg_or - off + bb_sz) - data_sz) if seg_or - off + bb_sz > data_sz else off for seg_or, off, bb_sz, data_sz in zip(segmentation_origin_in_data, self.offset, bb_size, data.GetSize()) ] cropped_origin = np.array(segmentation_origin_in_data) - self.offset assert all(cr_or >= 0 for cr_or in cropped_origin), \ f"Data size: {data.GetSize()}, BB size: {bb_size}, BB origin: {cropped_origin}" assert all(cr_or + bb_s <= data_s for cr_or, bb_s, data_s in zip(cropped_origin, bb_size, data.GetSize())), \ f"Data size: {data.GetSize()}, BB size: {bb_size}, BB origin: {cropped_origin}" self.data = data[cropped_origin[0]:cropped_origin[0] + bb_size[0], cropped_origin[1]:cropped_origin[1] + bb_size[1], cropped_origin[2]:cropped_origin[2] + bb_size[2]]
def centroid(mask: sitk.Image, label: int = 1, world_coordinates: bool = False) -> tuple: """Find the centroid of a labelled region specified by a segmentation mask. Parameters ---------- mask Segmentation mask describing the region of interest. Can be an image of type unsigned int representing a label map or `segmentation.Segmentation`. label, optional Label to use when computing the centroid if segmentation mask contains more than 1 labelled region. world_coordinates, optional If True, return centroid in world coordinates, otherwise in image (voxel) coordinates (default). Returns ------- tuple The centroid coordinates. """ if isinstance(mask, Segmentation): seg = Segmentation(mask) mask = seg.get_label(label=label, relabel=True) filter_ = sitk.LabelShapeStatisticsImageFilter() filter_.Execute(mask) centroid_coords = filter_.GetCentroid(label) if not world_coordinates: centroid_coords = mask.TransformPhysicalPointToIndex(centroid_coords) return centroid_coords
def get_cuboid_image(radii_world, reference: sitk.Image, center_ras): r, a, s = center_ras center_lps = -r, -a, s center_voxel = reference.TransformPhysicalPointToIndex(center_lps) spacing = np.array(reference.GetSpacing()) radii_voxel = np.array(radii_world) / spacing radii_voxel = radii_voxel.round().astype(np.uint16) axes_voxel = 2 * radii_voxel cuboid = sitk.Image(*axes_voxel.tolist(), sitk.sitkUInt8) + 1 result = reference * 0 destination = (center_voxel - radii_voxel).tolist() paste = sitk.PasteImageFilter() paste.SetDestinationIndex(destination) paste.SetSourceSize(cuboid.GetSize()) result = paste.Execute(result, cuboid) return result
def find_centroid(mask: sitk.Image) -> np.ndarray: """Find the centroid of a binary image in image coordinates. Parameters ---------- mask The binary mask image. Returns ------- np.ndarray The (x, y, z) coordinates of the centroid in image space. """ stats = sitk.LabelShapeStatisticsImageFilter() stats.Execute(mask) centroid_coords = stats.GetCentroid(1) centroid_idx = mask.TransformPhysicalPointToIndex(centroid_coords) return np.asarray(centroid_idx, dtype=np.float64)