Source code for iris.nodes.geometry_refinement.contour_interpolation
from typing import List
import numpy as np
from pydantic import Field
from iris.io.class_configs import Algorithm
from iris.io.dataclasses import GeometryPolygons
[docs]
class ContourInterpolation(Algorithm):
"""Implementation of contour interpolation algorithm conditioned by given NoiseMask.
Algorithm performs linar interpolation of points between vectorized, predicted points such that maximum distance between two consecutive points in a polygon isn't greater than
a fraction of an iris diameter length specified as `max_distance_between_boundary_points` parameter.
"""
[docs]
class Parameters(Algorithm.Parameters):
"""Parameters class for ContourInterpolation objects."""
max_distance_between_boundary_points: float = Field(..., gt=0.0, lt=1.0)
__parameters_type__ = Parameters
def __init__(self, max_distance_between_boundary_points: float = 0.01) -> None:
"""Assign parameters.
Args:
max_distance_between_boundary_points (float, optional): Maximum distance between boundary contour points expressed as a fraction of a iris diameter length. Defaults to 0.01.
"""
super().__init__(max_distance_between_boundary_points=max_distance_between_boundary_points)
[docs]
def run(self, polygons: GeometryPolygons) -> GeometryPolygons:
"""Refine polygons by interpolating contour points.
Args:
polygons (GeometryPolygons): Polygons to refine.
Returns:
GeometryPolygons: Refined polygons.
"""
max_boundary_dist_in_px = self.params.max_distance_between_boundary_points * polygons.iris_diameter
refined_pupil_array = self._interpolate_polygon_points(polygons.pupil_array, max_boundary_dist_in_px)
refined_iris_array = self._interpolate_polygon_points(polygons.iris_array, max_boundary_dist_in_px)
refined_eyeball_array = self._interpolate_polygon_points(polygons.eyeball_array, max_boundary_dist_in_px)
return GeometryPolygons(
pupil_array=refined_pupil_array,
iris_array=refined_iris_array,
eyeball_array=refined_eyeball_array,
)
def _interpolate_polygon_points(self, polygon: np.ndarray, max_distance_between_points_px: float) -> np.ndarray:
"""Interpolate contours points, so that the distance between two is no greater than `self.params.max_distance_between_boundary_points` in pixel space.
Args:
polygon (np.ndarray): Contour polygons.
max_distance_between_points_px (float): `self.params.max_distance_between_boundary_points` expressed in pixel length relative to iris diameter.
Returns:
np.ndarray: Interpolated polygon points.
"""
previous_boundary = np.roll(polygon, shift=1, axis=0)
distances = np.linalg.norm(polygon - previous_boundary, axis=1)
num_points = np.ceil(distances / max_distance_between_points_px).astype(int)
x: List[np.ndarray] = []
y: List[np.ndarray] = []
for (x1, y1), (x2, y2), num_point in zip(previous_boundary, polygon, num_points):
x.append(np.linspace(x1, x2, num=num_point, endpoint=False))
y.append(np.linspace(y1, y2, num=num_point, endpoint=False))
new_boundary = np.stack([np.concatenate(x), np.concatenate(y)], axis=1)
_, indices = np.unique(new_boundary, axis=0, return_index=True)
new_boundary = new_boundary[np.sort(indices)]
return new_boundary