mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-06-21 03:41:55 +03:00
Merge d80d020c86 into 5003ab895c
This commit is contained in:
commit
b7c9255908
@ -1,6 +1,35 @@
|
||||
import random
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
|
||||
from frigate.track.tracked_object import TrackedObjectAttribute
|
||||
from frigate.util.object import average_boxes, interpolated_percentile
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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):
|
||||
|
||||
@ -27,7 +27,11 @@ from frigate.util.image import (
|
||||
get_histogram,
|
||||
intersection_over_union,
|
||||
)
|
||||
from frigate.util.object import average_boxes, median_of_boxes
|
||||
from frigate.util.object import (
|
||||
average_boxes,
|
||||
interpolated_percentile,
|
||||
median_of_boxes,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -428,10 +432,10 @@ class NorfairTracker(ObjectTracker):
|
||||
position["xmaxs"].append(xmax)
|
||||
position["ymaxs"].append(ymax)
|
||||
# by using percentiles here, we hopefully remove outliers
|
||||
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)
|
||||
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)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@ -339,18 +339,13 @@ def reduce_boxes(boxes, iou_threshold=0.0):
|
||||
|
||||
def average_boxes(boxes: list[list[int, int, int, int]]) -> list[int, int, int, int]:
|
||||
"""Return a box that is the average of a list of boxes."""
|
||||
x_mins = []
|
||||
y_mins = []
|
||||
x_max = []
|
||||
y_max = []
|
||||
|
||||
for box in boxes:
|
||||
x_mins.append(box[0])
|
||||
y_mins.append(box[1])
|
||||
x_max.append(box[2])
|
||||
y_max.append(box[3])
|
||||
|
||||
return [np.mean(x_mins), np.mean(y_mins), np.mean(x_max), np.mean(y_max)]
|
||||
n = len(boxes)
|
||||
return [
|
||||
sum(box[0] for box in boxes) / n,
|
||||
sum(box[1] for box in boxes) / n,
|
||||
sum(box[2] for box in boxes) / n,
|
||||
sum(box[3] for box in boxes) / n,
|
||||
]
|
||||
|
||||
|
||||
def median_of_boxes(boxes: list[list[int, int, int, int]]) -> list[int, int, int, int]:
|
||||
@ -359,6 +354,25 @@ 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):
|
||||
|
||||
Loading…
Reference in New Issue
Block a user