mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Make stationary detection more resilient to inaccurate boxes (#10597)
This commit is contained in:
parent
e5595ebb2f
commit
df6c3b14dd
@ -17,12 +17,13 @@ from frigate.ptz.autotrack import PtzMotionEstimator
|
|||||||
from frigate.track import ObjectTracker
|
from frigate.track import ObjectTracker
|
||||||
from frigate.types import PTZMetricsTypes
|
from frigate.types import PTZMetricsTypes
|
||||||
from frigate.util.image import intersection_over_union
|
from frigate.util.image import intersection_over_union
|
||||||
from frigate.util.object import average_boxes
|
from frigate.util.object import average_boxes, median_of_boxes
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
THRESHOLD_STATIONARY_IOU_AVERAGE = 0.6
|
THRESHOLD_ACTIVE_IOU = 0.2
|
||||||
|
THRESHOLD_STATIONARY_IOU = 0.6
|
||||||
MAX_STATIONARY_HISTORY = 10
|
MAX_STATIONARY_HISTORY = 10
|
||||||
|
|
||||||
|
|
||||||
@ -146,6 +147,7 @@ class NorfairTracker(ObjectTracker):
|
|||||||
# tracks the current position of the object based on the last N bounding boxes
|
# tracks the current position of the object based on the last N bounding boxes
|
||||||
# returns False if the object has moved outside its previous position
|
# returns False if the object has moved outside its previous position
|
||||||
def update_position(self, id: str, box: list[int, int, int, int]):
|
def update_position(self, id: str, box: list[int, int, int, int]):
|
||||||
|
xmin, ymin, xmax, ymax = box
|
||||||
position = self.positions[id]
|
position = self.positions[id]
|
||||||
self.stationary_box_history[id].append(box)
|
self.stationary_box_history[id].append(box)
|
||||||
|
|
||||||
@ -158,11 +160,9 @@ class NorfairTracker(ObjectTracker):
|
|||||||
box, average_boxes(self.stationary_box_history[id])
|
box, average_boxes(self.stationary_box_history[id])
|
||||||
)
|
)
|
||||||
|
|
||||||
xmin, ymin, xmax, ymax = box
|
# object has minimal or zero iou
|
||||||
|
# assume object is active
|
||||||
# if the iou drops below the threshold
|
if avg_iou < THRESHOLD_ACTIVE_IOU:
|
||||||
# assume the object has moved to a new position and reset the computed box
|
|
||||||
if avg_iou < THRESHOLD_STATIONARY_IOU_AVERAGE:
|
|
||||||
self.positions[id] = {
|
self.positions[id] = {
|
||||||
"xmins": [xmin],
|
"xmins": [xmin],
|
||||||
"ymins": [ymin],
|
"ymins": [ymin],
|
||||||
@ -175,6 +175,33 @@ class NorfairTracker(ObjectTracker):
|
|||||||
}
|
}
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# object has iou below threshold, check median to reduce outliers
|
||||||
|
if avg_iou < THRESHOLD_STATIONARY_IOU:
|
||||||
|
median_iou = intersection_over_union(
|
||||||
|
(
|
||||||
|
position["xmin"],
|
||||||
|
position["ymin"],
|
||||||
|
position["xmax"],
|
||||||
|
position["ymax"],
|
||||||
|
),
|
||||||
|
median_of_boxes(self.stationary_box_history[id]),
|
||||||
|
)
|
||||||
|
|
||||||
|
# if the median iou drops below the threshold
|
||||||
|
# assume object is no longer stationary
|
||||||
|
if median_iou < THRESHOLD_STATIONARY_IOU:
|
||||||
|
self.positions[id] = {
|
||||||
|
"xmins": [xmin],
|
||||||
|
"ymins": [ymin],
|
||||||
|
"xmaxs": [xmax],
|
||||||
|
"ymaxs": [ymax],
|
||||||
|
"xmin": xmin,
|
||||||
|
"ymin": ymin,
|
||||||
|
"xmax": xmax,
|
||||||
|
"ymax": ymax,
|
||||||
|
}
|
||||||
|
return False
|
||||||
|
|
||||||
# if there are less than 10 entries for the position, add the bounding box
|
# if there are less than 10 entries for the position, add the bounding box
|
||||||
# and recompute the position box
|
# and recompute the position box
|
||||||
if len(position["xmins"]) < 10:
|
if len(position["xmins"]) < 10:
|
||||||
|
@ -339,6 +339,12 @@ def average_boxes(boxes: list[list[int, int, int, int]]) -> list[int, int, int,
|
|||||||
return [np.mean(x_mins), np.mean(y_mins), np.mean(x_max), np.mean(y_max)]
|
return [np.mean(x_mins), np.mean(y_mins), np.mean(x_max), np.mean(y_max)]
|
||||||
|
|
||||||
|
|
||||||
|
def median_of_boxes(boxes: list[list[int, int, int, int]]) -> list[int, int, int, int]:
|
||||||
|
"""Return a box that is the median of a list of boxes."""
|
||||||
|
sorted_boxes = sorted(boxes, key=lambda x: area(x))
|
||||||
|
return sorted_boxes[int(len(sorted_boxes) / 2.0)]
|
||||||
|
|
||||||
|
|
||||||
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):
|
||||||
|
Loading…
Reference in New Issue
Block a user