Module i2pp.core.interpolators.interpolator_label_map
Interpolates pixel values within the regions of a label map.
Functions
def element_labels(dis: Discretization,
label_field: str) ‑> numpy.ndarray-
Expand source code
def element_labels(dis: Discretization, label_field: str) -> np.ndarray: """Reads the label of each element from its data field. Arguments: dis (Discretization): The discretization. label_field (str): Name of the element field holding the label. Returns: np.ndarray: The label of each element. Raises: ValueError: If an element does not have the label field. """ labels = [] for ele in dis.elements: if label_field not in ele.fields: available = ", ".join(ele.fields) or "none" raise ValueError( f"Element {ele.id} has no field '{label_field}' holding its " f"label. Available fields: {available}." ) labels.append(int(ele.fields[label_field])) return np.array(labels, dtype=np.int64)Reads the label of each element from its data field.
Arguments
dis (Discretization): The discretization. label_field (str): Name of the element field holding the label.
Returns
np.ndarray- The label of each element.
Raises
ValueError- If an element does not have the label field.
def enlarge_bounding_box_to_labels(dis: Discretization,
label_map_path: pathlib.Path,
label_field: str) ‑> None-
Expand source code
def enlarge_bounding_box_to_labels( dis: Discretization, label_map_path: Path, label_field: str ) -> None: """Enlarges the bounding box of the discretization to cover all labelled regions of its elements, so that the loaded image data covers them. Arguments: dis (Discretization): The discretization with a bounding box. label_map_path (Path): Path to the NIfTI label map. label_field (str): Name of the element field holding the label. """ labels = element_labels(dis, label_field) box = load_label_map(label_map_path).bounding_box(labels[labels != 0]) if box is None or dis.bounding_box is None: return dis.bounding_box = BoundingBox( min=np.minimum(dis.bounding_box.min, box.min), max=np.maximum(dis.bounding_box.max, box.max), )Enlarges the bounding box of the discretization to cover all labelled regions of its elements, so that the loaded image data covers them.
Arguments
dis (Discretization): The discretization with a bounding box. label_map_path (Path): Path to the NIfTI label map. label_field (str): Name of the element field holding the label.
Classes
class InterpolatorLabelMap (label_map_path: pathlib.Path, label_field: str, filter_outliers: bool = False)-
Expand source code
class InterpolatorLabelMap(Interpolator): """Interpolator assigning each element the mean of all image voxels within its region of a label map. The label of each element is read from an element data field (e.g. the VTU cell data `tu_label` of the terminal units of a lung tree). Each image voxel gets the label of the nearest voxel of the label map, so the label map may have a different resolution than the image. This functionality is used when the `interpolation_method` is set to "labelmap". """ def __init__( self, label_map_path: Path, label_field: str, filter_outliers: bool = False, ): """Initialize the InterpolatorLabelMap. Arguments: label_map_path (Path): Path to the NIfTI label map. label_field (str): Name of the element field holding the label. filter_outliers (bool): If True, outliers are removed using the modified Z-score before averaging. """ super().__init__() self._label_map_path = label_map_path self._label_field = label_field self._filter_outliers_enabled = filter_outliers def _collect_voxels( self, image_data: ImageData, labels: np.ndarray ) -> tuple[np.ndarray, np.ndarray]: """Collects the labels and values of all image voxels carrying one of the given labels. The image is processed slice by slice to limit the memory usage. Arguments: image_data (ImageData): The image data. labels (np.ndarray): The labels of interest. Returns: tuple[np.ndarray, np.ndarray]: The labels (N_voxels,) and values (N_voxels, N_channels) of the voxels. """ label_map = load_label_map(self._label_map_path) grid = image_data.grid_coords position = np.asarray(image_data.position, dtype=float) rows, cols = np.meshgrid(grid.row, grid.col, indexing="ij") slice_points = np.column_stack( (np.zeros(rows.size), rows.ravel(), cols.ravel()) ) voxel_labels = [] voxel_values = [] for k, slice_coord in enumerate(grid.slice): slice_points[:, 0] = slice_coord world = position + slice_points @ image_data.orientation.T slice_labels = label_map.labels_at(world) keep = np.isin(slice_labels, labels) voxel_labels.append(slice_labels[keep]) voxel_values.append( image_data.pixel_data[k].reshape(rows.size, -1)[keep] ) return np.concatenate(voxel_labels), np.concatenate(voxel_values) def _mean(self, values: np.ndarray) -> np.ndarray: """Computes the mean of voxel values with optional outlier filtering.""" if self._filter_outliers_enabled and len(values) > 5: keep = self._filter_outliers_modified_zscore(values) if np.any(keep): values = values[keep] return np.mean(values, axis=0) def _value_at_element_center( self, ele: Element, dis: Discretization, image_data: ImageData ) -> np.ndarray: """Interpolates the image at the center of an element.""" center = dis.nodes.coords[ get_node_position_of_element(ele.node_ids, dis.nodes.ids) ].mean(axis=0) center_grid = self.world_to_grid_coords( center[np.newaxis], image_data.orientation, np.asarray(image_data.position, dtype=float), ) return np.atleast_1d( self.interpolate_image_values_to_points(center_grid, image_data)[0] ) def compute_element_data( self, dis: Discretization, image_data: ImageData ) -> list[Element]: """Computes the mean pixel value within the labelled region of each element. Label 0 is background and marks elements without a region. If no image voxel carries the label of an element, the image is interpolated at the element center instead. Arguments: dis (Discretization): The discretization whose elements have the label field. image_data (ImageData): A structured representation containing 3D pixel data, grid coordinates, orientation, and metadata. Returns: list[Element]: A list of elements with their pixel values assigned. """ labels = element_labels(dis, self._label_field) voxel_labels, voxel_values = self._collect_voxels( image_data, labels[labels != 0] ) order = np.argsort(voxel_labels, kind="stable") voxel_labels = voxel_labels[order] voxel_values = voxel_values[order] starts = np.searchsorted(voxel_labels, labels, side="left") ends = np.searchsorted(voxel_labels, labels, side="right") for ele, start, end in zip(dis.elements, starts, ends): if start == end: self.backup_interpolation += 1 ele.data = self._value_at_element_center(ele, dis, image_data) else: ele.data = self._mean(voxel_values[start:end]) if np.all(np.isnan(ele.data)): self.nan_elements += 1 self._log_interpolation_warnings() return dis.elementsInterpolator assigning each element the mean of all image voxels within its region of a label map.
The label of each element is read from an element data field (e.g. the VTU cell data
tu_labelof the terminal units of a lung tree). Each image voxel gets the label of the nearest voxel of the label map, so the label map may have a different resolution than the image. This functionality is used when theinterpolation_methodis set to "labelmap".Initialize the InterpolatorLabelMap.
Arguments
label_map_path (Path): Path to the NIfTI label map. label_field (str): Name of the element field holding the label. filter_outliers (bool): If True, outliers are removed using the modified Z-score before averaging.
Ancestors
Methods
def compute_element_data(self,
dis: Discretization,
image_data: ImageData) ‑> list[Element]-
Expand source code
def compute_element_data( self, dis: Discretization, image_data: ImageData ) -> list[Element]: """Computes the mean pixel value within the labelled region of each element. Label 0 is background and marks elements without a region. If no image voxel carries the label of an element, the image is interpolated at the element center instead. Arguments: dis (Discretization): The discretization whose elements have the label field. image_data (ImageData): A structured representation containing 3D pixel data, grid coordinates, orientation, and metadata. Returns: list[Element]: A list of elements with their pixel values assigned. """ labels = element_labels(dis, self._label_field) voxel_labels, voxel_values = self._collect_voxels( image_data, labels[labels != 0] ) order = np.argsort(voxel_labels, kind="stable") voxel_labels = voxel_labels[order] voxel_values = voxel_values[order] starts = np.searchsorted(voxel_labels, labels, side="left") ends = np.searchsorted(voxel_labels, labels, side="right") for ele, start, end in zip(dis.elements, starts, ends): if start == end: self.backup_interpolation += 1 ele.data = self._value_at_element_center(ele, dis, image_data) else: ele.data = self._mean(voxel_values[start:end]) if np.all(np.isnan(ele.data)): self.nan_elements += 1 self._log_interpolation_warnings() return dis.elementsComputes the mean pixel value within the labelled region of each element.
Label 0 is background and marks elements without a region. If no image voxel carries the label of an element, the image is interpolated at the element center instead.
Arguments
dis (Discretization): The discretization whose elements have the label field. image_data (ImageData): A structured representation containing 3D pixel data, grid coordinates, orientation, and metadata.
Returns
list[Element]- A list of elements with their pixel values assigned.
Inherited members