Skip to content

Utils#

A small grab-bag of helpers that don't fit anywhere else. Only two are part of the public API:

  • get_cutout — crops the axis-aligned bounding rectangle around a set of points out of an image. Handy for feeding a patch into a ReID / appearance model to build your own distance function.
  • print_objects_as_table — pretty-prints the current TrackedObjects as a Rich table (id, age, hit counter, last distance, init id). Useful for quickly debugging why the tracker is — or isn't — matching things.

Example#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from norfair import Detection, Tracker, Video, get_cutout, print_objects_as_table

tracker = Tracker(distance_function="euclidean", distance_threshold=50)

with Video(input_path="video.mp4") as video:
    for frame in video:
        detections = [Detection(points=p) for p in my_detector(frame)]
        tracked_objects = tracker.update(detections=detections)

        # Debug: dump the current track table.
        print_objects_as_table(tracked_objects)

        # Grab an appearance patch for the first tracked object.
        if tracked_objects:
            patch = get_cutout(tracked_objects[0].estimate, frame)

API#

Miscellaneous helpers: point validation, terminal sizing, warnings.

get_cutout(points, image) #

Return the axis-aligned bounding-box cutout of points in image.

Parameters:

Name Type Description Default
points ndarray

Array of shape (N, 2) with x/y coordinates.

required
image ndarray

Image array with at least two spatial dimensions (height, width, ...).

required

Returns:

Type Description
ndarray

The cropped region. Returns an empty slice (with a warning) when the bounding box is degenerate (zero width or height after clipping).

Raises:

Type Description
ValueError

If points is empty or does not have shape (N, 2).

Source code in norfair/utils.py
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
def get_cutout(points, image):
    """Return the axis-aligned bounding-box cutout of ``points`` in ``image``.

    Parameters
    ----------
    points : np.ndarray
        Array of shape ``(N, 2)`` with x/y coordinates.
    image : np.ndarray
        Image array with at least two spatial dimensions (height, width, ...).

    Returns
    -------
    np.ndarray
        The cropped region.  Returns an empty slice (with a warning) when the
        bounding box is degenerate (zero width or height after clipping).

    Raises
    ------
    ValueError
        If *points* is empty or does not have shape ``(N, 2)``.
    """
    points = np.asarray(points)
    if points.ndim != 2 or points.shape[1] != 2:
        raise ValueError(f"points must have shape (N, 2), got {points.shape}")
    if points.shape[0] == 0:
        raise ValueError("points array is empty")

    image = np.asarray(image)
    if image.ndim < 2:
        raise ValueError(f"image must have at least 2 dimensions, got {image.ndim}")
    img_h, img_w = image.shape[:2]

    min_x = int(np.clip(np.min(points[:, 0]), 0, img_w))
    max_x = int(np.clip(np.max(points[:, 0]), 0, img_w))
    min_y = int(np.clip(np.min(points[:, 1]), 0, img_h))
    max_y = int(np.clip(np.max(points[:, 1]), 0, img_h))

    if min_x == max_x or min_y == max_y:
        warning(
            "get_cutout: degenerate bounding box "
            f"(x={min_x}..{max_x}, y={min_y}..{max_y}); "
            "returning empty cutout"
        )

    return image[min_y:max_y, min_x:max_x]

print_objects_as_table(tracked_objects) #

Pretty-print a table summarizing tracked_objects for debugging.

Parameters:

Name Type Description Default
tracked_objects Sequence

Sequence of tracked objects. Each element is expected to have id, age, hit_counter, last_distance, and initializing_id attributes (missing attributes are shown as "?").

required
Source code in norfair/utils.py
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
def print_objects_as_table(tracked_objects: Sequence):
    """Pretty-print a table summarizing ``tracked_objects`` for debugging.

    Parameters
    ----------
    tracked_objects : Sequence
        Sequence of tracked objects. Each element is expected to have
        ``id``, ``age``, ``hit_counter``, ``last_distance``, and
        ``initializing_id`` attributes (missing attributes are shown
        as ``"?"``).
    """
    print()
    console = Console()
    table = Table(show_header=True, header_style="bold magenta")
    table.add_column("Id", style="yellow", justify="center")
    table.add_column("Age", justify="right")
    table.add_column("Hit Counter", justify="right")
    table.add_column("Last distance", justify="right")
    table.add_column("Init Id", justify="center")
    for obj in tracked_objects:
        last_dist = getattr(obj, "last_distance", None)
        last_dist_str = f"{last_dist:.4f}" if last_dist is not None else "?"
        table.add_row(
            str(getattr(obj, "id", "?")),
            str(getattr(obj, "age", "?")),
            str(getattr(obj, "hit_counter", "?")),
            last_dist_str,
            str(getattr(obj, "initializing_id", "?")),
        )
    console.print(table)

See also#

  • Tracker — source of the TrackedObjects inspected here.
  • Distancesget_cutout pairs well with a custom appearance distance.