mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-08 20:25:26 +03:00
Update logic for adding new segments
This commit is contained in:
parent
d8ef721c94
commit
a3b43471a9
@ -84,9 +84,7 @@ class ReviewSegment(Model): # type: ignore[misc]
|
|||||||
has_been_reviewed = BooleanField(default=False)
|
has_been_reviewed = BooleanField(default=False)
|
||||||
severity = CharField(max_length=30) # alert, detection, significant_motion
|
severity = CharField(max_length=30) # alert, detection, significant_motion
|
||||||
thumb_path = CharField(unique=True)
|
thumb_path = CharField(unique=True)
|
||||||
data = (
|
data = JSONField() # additional data about detection like list of labels, zone, areas of significant motion
|
||||||
JSONField()
|
|
||||||
) # additional data about detection like list of labels, zone, areas of significant motion
|
|
||||||
|
|
||||||
|
|
||||||
class Previews(Model): # type: ignore[misc]
|
class Previews(Model): # type: ignore[misc]
|
||||||
|
|||||||
@ -26,19 +26,27 @@ class SeverityEnum(str, Enum):
|
|||||||
|
|
||||||
|
|
||||||
class PendingReviewSegment:
|
class PendingReviewSegment:
|
||||||
|
def __init__(
|
||||||
def __init__(self, camera: str, frame_time: float, severity: SeverityEnum):
|
self,
|
||||||
|
camera: str,
|
||||||
|
frame_time: float,
|
||||||
|
severity: SeverityEnum,
|
||||||
|
detections: set[str] = set(),
|
||||||
|
objects: set[str] = set(),
|
||||||
|
zones: set[str] = set(),
|
||||||
|
audio: set[str] = set(),
|
||||||
|
motion: list[int] = [],
|
||||||
|
):
|
||||||
rand_id = "".join(random.choices(string.ascii_lowercase + string.digits, k=6))
|
rand_id = "".join(random.choices(string.ascii_lowercase + string.digits, k=6))
|
||||||
self.id = f"{frame_time}-{rand_id}"
|
self.id = f"{frame_time}-{rand_id}"
|
||||||
self.camera = camera
|
self.camera = camera
|
||||||
self.start_time = frame_time
|
self.start_time = frame_time
|
||||||
self.severity = severity
|
self.severity = severity
|
||||||
self.data: dict[str, set] = {
|
self.detections = detections
|
||||||
"objects": set(),
|
self.objects = objects
|
||||||
"zones": set(),
|
self.zones = zones
|
||||||
"audio": set(),
|
self.audio = audio
|
||||||
"significant_motion_areas": [],
|
self.sig_motion_areas = motion
|
||||||
}
|
|
||||||
self.last_update = frame_time
|
self.last_update = frame_time
|
||||||
|
|
||||||
def end(self) -> dict:
|
def end(self) -> dict:
|
||||||
@ -49,7 +57,13 @@ class PendingReviewSegment:
|
|||||||
ReviewSegment.end_time: self.last_update,
|
ReviewSegment.end_time: self.last_update,
|
||||||
ReviewSegment.severity: self.severity.value,
|
ReviewSegment.severity: self.severity.value,
|
||||||
ReviewSegment.thumb_path: "somewhere",
|
ReviewSegment.thumb_path: "somewhere",
|
||||||
ReviewSegment.data: self.data,
|
ReviewSegment.data: {
|
||||||
|
"detections": list(self.detections),
|
||||||
|
"objects": list(self.objects),
|
||||||
|
"zones": list(self.zones),
|
||||||
|
"audio": list(self.audio),
|
||||||
|
"significant_motion_areas": self.sig_motion_areas,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -86,26 +100,72 @@ class ReviewSegmentMaintainer(threading.Thread):
|
|||||||
active_objects = [
|
active_objects = [
|
||||||
o
|
o
|
||||||
for o in objects
|
for o in objects
|
||||||
if o.obj_data["motionless_count"]
|
if o["motionless_count"] > camera_config.detect.stationary.threshold
|
||||||
> camera_config.detect.stationary.threshold
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if len(active_objects) > 0:
|
if len(active_objects) > 0:
|
||||||
|
segment.last_update = frame_time
|
||||||
|
|
||||||
if segment.severity == SeverityEnum.signification_motion:
|
if segment.severity == SeverityEnum.signification_motion:
|
||||||
segment.severity = SeverityEnum.detection
|
segment.severity = SeverityEnum.detection
|
||||||
|
|
||||||
for object in active_objects:
|
for object in active_objects:
|
||||||
segment.data["objects"].add(object.obj_data["label"])
|
segment.detections.add(object["id"])
|
||||||
|
segment.objects.add(object["label"])
|
||||||
|
|
||||||
if segment.severity == SeverityEnum.detection and object.has_clip:
|
if segment.severity == SeverityEnum.detection and object["has_clip"]:
|
||||||
segment.severity = SeverityEnum.alert
|
segment.severity = SeverityEnum.alert
|
||||||
|
|
||||||
if object.current_zones:
|
if object["current_zones"]:
|
||||||
segment.data["zones"].update(object.current_zones)
|
segment.zones.update(object)
|
||||||
elif frame_time > (segment.last_update + camera_config.detect.max_disappeared):
|
elif frame_time > (
|
||||||
|
segment.last_update
|
||||||
|
+ (camera_config.detect.max_disappeared / camera_config.detect.fps)
|
||||||
|
):
|
||||||
self.end_segment(segment)
|
self.end_segment(segment)
|
||||||
|
|
||||||
|
def check_if_new_segment(
|
||||||
|
self,
|
||||||
|
camera: str,
|
||||||
|
frame_time: float,
|
||||||
|
objects: list[TrackedObject],
|
||||||
|
motion: list,
|
||||||
|
) -> None:
|
||||||
|
"""Check if a new review segment should be created."""
|
||||||
|
camera_config = self.config.cameras[camera]
|
||||||
|
active_objects = [
|
||||||
|
o
|
||||||
|
for o in objects
|
||||||
|
if o["motionless_count"] > camera_config.detect.stationary.threshold
|
||||||
|
]
|
||||||
|
|
||||||
|
if len(active_objects) > 0:
|
||||||
|
has_sig_object = False
|
||||||
|
detections: set = set()
|
||||||
|
objects: set = set()
|
||||||
|
zones: set = set()
|
||||||
|
|
||||||
|
for object in active_objects:
|
||||||
|
if not has_sig_object and object["has_clip"]:
|
||||||
|
has_sig_object = True
|
||||||
|
|
||||||
|
detections.add(object["id"])
|
||||||
|
objects.add(object["label"])
|
||||||
|
zones.update(object["current_zones"])
|
||||||
|
|
||||||
|
self.active_review_segments[camera] = PendingReviewSegment(
|
||||||
|
camera,
|
||||||
|
frame_time,
|
||||||
|
SeverityEnum.alert if has_sig_object else SeverityEnum.detection,
|
||||||
|
detections,
|
||||||
|
objects,
|
||||||
|
zones,
|
||||||
|
)
|
||||||
|
elif len(motion) >= 20:
|
||||||
|
self.active_review_segments[camera] = PendingReviewSegment(
|
||||||
|
camera, frame_time, SeverityEnum.signification_motion, motion=motion
|
||||||
|
)
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
while not self.stop_event.is_set():
|
while not self.stop_event.is_set():
|
||||||
# check if there is an updated config
|
# check if there is an updated config
|
||||||
@ -150,13 +210,25 @@ class ReviewSegmentMaintainer(threading.Thread):
|
|||||||
if current_segment is not None:
|
if current_segment is not None:
|
||||||
if topic == DetectionTypeEnum.video:
|
if topic == DetectionTypeEnum.video:
|
||||||
self.update_existing_segment(
|
self.update_existing_segment(
|
||||||
topic,
|
|
||||||
current_segment,
|
current_segment,
|
||||||
frame_time,
|
frame_time,
|
||||||
current_tracked_objects,
|
current_tracked_objects,
|
||||||
motion_boxes,
|
motion_boxes,
|
||||||
)
|
)
|
||||||
elif topic == DetectionTypeEnum.audio:
|
elif topic == DetectionTypeEnum.audio:
|
||||||
pass
|
current_segment.audio.update(audio_detections)
|
||||||
else:
|
else:
|
||||||
pass
|
if topic == DetectionTypeEnum.video:
|
||||||
|
self.check_if_new_segment(
|
||||||
|
camera,
|
||||||
|
frame_time,
|
||||||
|
current_tracked_objects,
|
||||||
|
motion_boxes,
|
||||||
|
)
|
||||||
|
elif topic == DetectionTypeEnum.audio and len(audio_detections) > 0:
|
||||||
|
self.active_review_segments[camera] = PendingReviewSegment(
|
||||||
|
camera,
|
||||||
|
frame_time,
|
||||||
|
SeverityEnum.detection,
|
||||||
|
audio=set(audio_detections),
|
||||||
|
)
|
||||||
|
|||||||
@ -28,13 +28,13 @@ SQL = pw.SQL
|
|||||||
|
|
||||||
def migrate(migrator, database, fake=False, **kwargs):
|
def migrate(migrator, database, fake=False, **kwargs):
|
||||||
migrator.sql(
|
migrator.sql(
|
||||||
'CREATE TABLE IF NOT EXISTS "review_segment" ("id" VARCHAR(30) NOT NULL PRIMARY KEY, "camera" VARCHAR(20) NOT NULL, "start_time" DATETIME NOT NULL, "end_time" DATETIME, "has_been_reviewed" INTEGER NOT NULL, "severity" VARCHAR(30) NOT NULL, "thumb_path" VARCHAR(255) NOT NULL, "data" JSON NOT NULL)'
|
'CREATE TABLE IF NOT EXISTS "reviewsegment" ("id" VARCHAR(30) NOT NULL PRIMARY KEY, "camera" VARCHAR(20) NOT NULL, "start_time" DATETIME NOT NULL, "end_time" DATETIME, "has_been_reviewed" INTEGER NOT NULL, "severity" VARCHAR(30) NOT NULL, "thumb_path" VARCHAR(255) NOT NULL, "data" JSON NOT NULL)'
|
||||||
)
|
)
|
||||||
migrator.sql(
|
migrator.sql(
|
||||||
'CREATE INDEX IF NOT EXISTS "review_segment_camera" ON "review_segment" ("camera")'
|
'CREATE INDEX IF NOT EXISTS "review_segment_camera" ON "reviewsegment" ("camera")'
|
||||||
)
|
)
|
||||||
migrator.sql(
|
migrator.sql(
|
||||||
'CREATE INDEX "review_segment_start_time_end_time" ON "review_segment" ("start_time" DESC, "end_time" DESC)'
|
'CREATE INDEX "review_segment_start_time_end_time" ON "reviewsegment" ("start_time" DESC, "end_time" DESC)'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user