mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-11-05 21:30:30 +03:00
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:
co-authored by
Claude Opus 4.8
parent
d80d020c86
commit
4f18a9fdac
@@ -4,7 +4,7 @@ import unittest
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from frigate.track.tracked_object import TrackedObjectAttribute
|
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):
|
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)]
|
expected = [float(np.mean([b[i] for b in boxes])) for i in range(4)]
|
||||||
self.assertEqual(average_boxes(boxes), expected)
|
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):
|
class TestAttribute(unittest.TestCase):
|
||||||
def test_overlapping_object_selection(self) -> None:
|
def test_overlapping_object_selection(self) -> None:
|
||||||
|
|||||||
@@ -27,11 +27,7 @@ from frigate.util.image import (
|
|||||||
get_histogram,
|
get_histogram,
|
||||||
intersection_over_union,
|
intersection_over_union,
|
||||||
)
|
)
|
||||||
from frigate.util.object import (
|
from frigate.util.object import average_boxes, median_of_boxes
|
||||||
average_boxes,
|
|
||||||
interpolated_percentile,
|
|
||||||
median_of_boxes,
|
|
||||||
)
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -432,10 +428,10 @@ class NorfairTracker(ObjectTracker):
|
|||||||
position["xmaxs"].append(xmax)
|
position["xmaxs"].append(xmax)
|
||||||
position["ymaxs"].append(ymax)
|
position["ymaxs"].append(ymax)
|
||||||
# by using percentiles here, we hopefully remove outliers
|
# by using percentiles here, we hopefully remove outliers
|
||||||
position["xmin"] = interpolated_percentile(position["xmins"], 15)
|
position["xmin"] = np.percentile(position["xmins"], 15)
|
||||||
position["ymin"] = interpolated_percentile(position["ymins"], 15)
|
position["ymin"] = np.percentile(position["ymins"], 15)
|
||||||
position["xmax"] = interpolated_percentile(position["xmaxs"], 85)
|
position["xmax"] = np.percentile(position["xmaxs"], 85)
|
||||||
position["ymax"] = interpolated_percentile(position["ymaxs"], 85)
|
position["ymax"] = np.percentile(position["ymaxs"], 85)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -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)]
|
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):
|
def intersects_any(box_a, boxes):
|
||||||
for box in boxes:
|
for box in boxes:
|
||||||
if box_overlaps(box_a, box):
|
if box_overlaps(box_a, box):
|
||||||
|
|||||||
Reference in New Issue
Block a user