Drop interpolated_percentile, keep only average_boxes

Per review: reimplementing np.percentile hurts readability and risks
divergence from numpy (e.g. numpy 2.x). Revert update_position to
np.percentile and remove the helper; keep only the average_boxes change
(sum()/len() instead of np.mean), which stays bit-identical.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Daniel-dev22
2026-06-23 17:39:41 -04:00
co-authored by Claude Opus 4.8
parent d80d020c86
commit 4f18a9fdac
3 changed files with 6 additions and 42 deletions
+1 -14
View File
@@ -4,7 +4,7 @@ import unittest
import numpy as np
from frigate.track.tracked_object import TrackedObjectAttribute
from frigate.util.object import average_boxes, interpolated_percentile
from frigate.util.object import average_boxes
class TestBoxStatistics(unittest.TestCase):
@@ -18,19 +18,6 @@ class TestBoxStatistics(unittest.TestCase):
expected = [float(np.mean([b[i] for b in boxes])) for i in range(4)]
self.assertEqual(average_boxes(boxes), expected)
def test_interpolated_percentile_matches_numpy(self) -> None:
rng = random.Random(1)
for _ in range(5000):
values = [rng.randint(0, 5000) for _ in range(rng.randint(1, 10))]
for q in (15, 85, 50):
self.assertEqual(
interpolated_percentile(values, q),
float(np.percentile(values, q)),
)
def test_interpolated_percentile_single_value(self) -> None:
self.assertEqual(interpolated_percentile([42], 15), 42.0)
class TestAttribute(unittest.TestCase):
def test_overlapping_object_selection(self) -> None:
+5 -9
View File
@@ -27,11 +27,7 @@ from frigate.util.image import (
get_histogram,
intersection_over_union,
)
from frigate.util.object import (
average_boxes,
interpolated_percentile,
median_of_boxes,
)
from frigate.util.object import average_boxes, median_of_boxes
logger = logging.getLogger(__name__)
@@ -432,10 +428,10 @@ class NorfairTracker(ObjectTracker):
position["xmaxs"].append(xmax)
position["ymaxs"].append(ymax)
# by using percentiles here, we hopefully remove outliers
position["xmin"] = interpolated_percentile(position["xmins"], 15)
position["ymin"] = interpolated_percentile(position["ymins"], 15)
position["xmax"] = interpolated_percentile(position["xmaxs"], 85)
position["ymax"] = interpolated_percentile(position["ymaxs"], 85)
position["xmin"] = np.percentile(position["xmins"], 15)
position["ymin"] = np.percentile(position["ymins"], 15)
position["xmax"] = np.percentile(position["xmaxs"], 85)
position["ymax"] = np.percentile(position["ymaxs"], 85)
return True
-19
View File
@@ -354,25 +354,6 @@ def median_of_boxes(boxes: list[list[int, int, int, int]]) -> list[int, int, int
return sorted_boxes[int(len(sorted_boxes) / 2.0)]
def interpolated_percentile(values: list[int], q: float) -> float:
"""Linear-interpolated percentile, matching numpy.percentile for the small
lists used in position smoothing without the per-call numpy overhead."""
ordered = sorted(values)
n = len(ordered)
if n == 1:
return float(ordered[0])
rank = (q / 100.0) * (n - 1)
lo = int(rank)
frac = rank - lo
if frac == 0.0:
return float(ordered[lo])
diff = ordered[lo + 1] - ordered[lo]
# numpy's lerp switches sides at frac >= 0.5 to limit rounding error
if frac < 0.5:
return ordered[lo] + diff * frac
return ordered[lo + 1] - diff * (1.0 - frac)
def intersects_any(box_a, boxes):
for box in boxes:
if box_overlaps(box_a, box):