Skip to content

ir_plane_tracker

pupil_labs.ir_plane_tracker package.

A tool for tracking planes marked with markers.

Modules:

  • tracker

Classes:

PlaneLocalization dataclass

PlaneLocalization(corners: NDArray[float64], img2plane: NDArray[float64], plane2img: NDArray[float64], reprojection_error: float)

Result of plane localization.

Attributes:

  • corners (NDArray[float64]) –

    Corners of the plane in image coordinates.

  • img2plane (NDArray[float64]) –

    Transformation matrix from image to plane coordinates.

  • plane2img (NDArray[float64]) –

    Transformation matrix from plane to image coordinates.

  • reprojection_error (float) –

    Reprojection error of the localization in pixels.

corners instance-attribute

corners: NDArray[float64]

Corners of the plane in image coordinates.

img2plane instance-attribute

img2plane: NDArray[float64]

Transformation matrix from image to plane coordinates.

plane2img instance-attribute

plane2img: NDArray[float64]

Transformation matrix from plane to image coordinates.

reprojection_error instance-attribute

reprojection_error: float

Reprojection error of the localization in pixels.

Tracker

Tracker(camera_matrix: NDArray[float64], dist_coeffs: NDArray[float64], params: TrackerParams | None = None)

A Tracker for tracking planes marked with markers.

Parameters:

  • camera_matrix (NDArray[float64]) –

    Camera intrinsic matrix.

  • dist_coeffs (NDArray[float64]) –

    Camera distortion coefficients.

  • params (TrackerParams | None, default: None ) –

    Tracker parameters. If None, default parameters are used.

Methods:

  • __call__

    Tracks the plane in the given image.

Source code in src/pupil_labs/ir_plane_tracker/tracker.py
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
def __init__(
    self,
    camera_matrix: npt.NDArray[np.float64],
    dist_coeffs: npt.NDArray[np.float64],
    params: TrackerParams | None = None,
):
    """Creates a Tracker instance for tracking planes marked with markers.

    Args:
        camera_matrix: Camera intrinsic matrix.
        dist_coeffs: Camera distortion coefficients.
        params: Tracker parameters. If None, default parameters are used.

    """
    self.camera_matrix = camera_matrix
    self.dist_coeffs = dist_coeffs
    if params is None:
        self.params = TrackerParams()
    else:
        self.params = params

    self.debug = DebugData(self.params)

__call__

__call__(image: NDArray[uint8]) -> PlaneLocalization | None

Tracks the plane in the given image.

Parameters:

  • image (NDArray[uint8]) –

    Input image.

Returns:

  • PlaneLocalization | None

    PlaneLocalization if the plane is found, None otherwise.

Source code in src/pupil_labs/ir_plane_tracker/tracker.py
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
def __call__(self, image: npt.NDArray[np.uint8]) -> PlaneLocalization | None:
    """Tracks the plane in the given image.

    Args:
        image: Input image.

    Returns:
        PlaneLocalization if the plane is found, None otherwise.

    """
    self.debug = DebugData(self.params)
    self.debug.img_raw = image.copy()
    # image = cv2.undistort(image, self.camera_matrix, self.dist_coeffs)

    if self.params.debug:
        self.vis = image.copy()

    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    self.debug.img_gray = image.copy()

    line_contours, ellipse_contours = self.get_contours(image)
    if len(line_contours) < self.params.min_line_contour_count:
        return None
    if len(ellipse_contours) < self.params.min_ellipse_contour_count:
        return None

    fragments = self.fit_line_fragments(line_contours)
    if len(fragments) < self.params.min_line_fragments_count:
        return None

    ellipses = self.fit_ellipses_to_contours(ellipse_contours, image.shape[:2])
    if len(ellipses) < self.params.min_ellipse_count:
        return None

    feature_lines = self.find_feature_lines(fragments, ellipses)
    if len(feature_lines) < self.params.min_feature_line_count:
        return None

    combinations = self.get_possible_combinations(feature_lines)

    rvec, tvec = self.fit_camera_pose(combinations)

    if rvec is None or tvec is None:
        return None

    screen_corners = self.calculate_localization(rvec, tvec)

    return screen_corners

TrackerParams dataclass

TrackerParams(plane_width: float = nan, plane_height: float = nan, top_pos: tuple[float, float] = (nan, nan), bottom_pos: tuple[float, float] = (nan, nan), right_pos: tuple[float, float] = (nan, nan), left_pos: tuple[float, float] = (nan, nan), feature_point_positions_mm: NDArray[float64] = lambda: array([0.0, 6.0, 8.0, 10.0])(), padding_mm: float = 5.0, circle_diameter_mm: float = 6.0, line_thickness_mm: float = 3.0, img_size_factor: float = 1.0, thresh_c: int = 45, thresh_half_kernel_size: int = 20, min_contour_area_line: int = 70, max_contour_area_line: int = 360, min_contour_area_ellipse: int = 12, max_contour_area_ellipse: int = 70, min_line_contour_count: int = 3, min_ellipse_contour_count: int = 6, min_contour_support: int = 6, fragments_min_length: float = 30.0, fragments_max_length: float = 70.0, fragments_max_projection_error: float = 5.0, min_line_fragments_count: int = 3, min_ellipse_size: int = 4, max_ellipse_aspect_ratio: float = 2.0, min_ellipse_count: int = 8, max_cr_error: float = 0.12, max_feature_line_length: float = 150.0, min_feature_line_count: int = 3, feature_line_max_projection_error: float = 2.0, optimization_error_threshold: float = 15.0, debug: bool = False)

Parameters for the IR plane tracker.

Attributes:

bottom_pos class-attribute instance-attribute

bottom_pos: tuple[float, float] = (nan, nan)

Position of the bottom marker in mm.

left_pos class-attribute instance-attribute

left_pos: tuple[float, float] = (nan, nan)

Position of the left marker in mm.

plane_height class-attribute instance-attribute

plane_height: float = nan

Height of the tracked plane in mm.

plane_width class-attribute instance-attribute

plane_width: float = nan

Width of the tracked plane in mm.

right_pos class-attribute instance-attribute

right_pos: tuple[float, float] = (nan, nan)

Position of the right marker in mm.

top_pos class-attribute instance-attribute

top_pos: tuple[float, float] = (nan, nan)

Position of the top marker in mm.