mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-08-02 17:12:16 +03:00
CI / AMD64 Build (push) Has been cancelled
CI / ARM Build (push) Has been cancelled
CI / Jetson Jetpack 6 (push) Has been cancelled
CI / AMD64 Extra Build (push) Has been cancelled
CI / ARM Extra Build (push) Has been cancelled
CI / Synaptics Build (push) Has been cancelled
CI / Assemble and push default build (push) Has been cancelled
* perf(track): avoid numpy reductions on tiny box lists in position smoothing update_position runs per tracked object per frame. While a position has fewer than 10 samples it calls np.percentile four times, and average_boxes (per stationary object per frame) calls np.mean four times - all on lists of at most 10 ints, where numpy's per-call dispatch/validation overhead dominates the actual work. Replace them with pure-Python equivalents: - average_boxes: sum()/len() instead of np.mean (bit-identical output) - interpolated_percentile(): linear-interpolated percentile matching numpy.percentile (including its lerp branch at frac>=0.5) for the small lists used here, in place of np.percentile Measured in the release image (numpy 1.26.4) on a 10-element list: np.percentile 18735 ns -> 191 ns/call (98x); np.mean-based average_boxes 7480 ns -> 591 ns (12.7x); ~74 us saved per object-frame in update_position. A live py-spy --gil profile of a camera process_frames worker showed np.percentile (update_position) and np.mean (average_boxes) among the top Frigate-owned on-CPU frames. Output is unchanged: added tests assert both helpers are bit-identical to numpy over randomized small inputs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * 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> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
67 lines
2.3 KiB
Python
67 lines
2.3 KiB
Python
import random
|
|
import unittest
|
|
|
|
import numpy as np
|
|
|
|
from frigate.track.tracked_object import TrackedObjectAttribute
|
|
from frigate.util.object import average_boxes
|
|
|
|
|
|
class TestBoxStatistics(unittest.TestCase):
|
|
def test_average_boxes_matches_numpy(self) -> None:
|
|
rng = random.Random(0)
|
|
for _ in range(5000):
|
|
boxes = [
|
|
[rng.randint(0, 4000) for _ in range(4)]
|
|
for _ in range(rng.randint(1, 10))
|
|
]
|
|
expected = [float(np.mean([b[i] for b in boxes])) for i in range(4)]
|
|
self.assertEqual(average_boxes(boxes), expected)
|
|
|
|
|
|
class TestAttribute(unittest.TestCase):
|
|
def test_overlapping_object_selection(self) -> None:
|
|
attribute = TrackedObjectAttribute(
|
|
(
|
|
"amazon",
|
|
0.80078125,
|
|
(847, 242, 883, 255),
|
|
468,
|
|
2.769230769230769,
|
|
(702, 134, 1050, 482),
|
|
)
|
|
)
|
|
objects = [
|
|
{
|
|
"label": "car",
|
|
"score": 0.98828125,
|
|
"box": (728, 223, 1266, 719),
|
|
"area": 266848,
|
|
"ratio": 1.0846774193548387,
|
|
"region": (349, 0, 1397, 1048),
|
|
"frame_time": 1727785394.498972,
|
|
"centroid": (997, 471),
|
|
"id": "1727785349.150633-408hal",
|
|
"start_time": 1727785349.150633,
|
|
"motionless_count": 362,
|
|
"position_changes": 0,
|
|
"score_history": [0.98828125, 0.95703125, 0.98828125, 0.98828125],
|
|
},
|
|
{
|
|
"label": "person",
|
|
"score": 0.76953125,
|
|
"box": (826, 172, 939, 417),
|
|
"area": 27685,
|
|
"ratio": 0.46122448979591835,
|
|
"region": (702, 134, 1050, 482),
|
|
"frame_time": 1727785394.498972,
|
|
"centroid": (882, 294),
|
|
"id": "1727785390.499768-9fbhem",
|
|
"start_time": 1727785390.499768,
|
|
"motionless_count": 2,
|
|
"position_changes": 1,
|
|
"score_history": [0.8828125, 0.83984375, 0.91796875, 0.94140625],
|
|
},
|
|
]
|
|
assert attribute.find_best_object(objects) == "1727785390.499768-9fbhem"
|