From 657fab27873ccc0fa318f01106fe2dacacce2faa Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Fri, 15 Mar 2024 13:13:40 -0600 Subject: [PATCH] Save motion as motion box count (#10484) --- frigate/api/review.py | 5 ++-- frigate/record/maintainer.py | 36 ++++++--------------------- frigate/test/test_record_retention.py | 8 +++--- 3 files changed, 13 insertions(+), 36 deletions(-) diff --git a/frigate/api/review.py b/frigate/api/review.py index 6d3ba1c3f..008bcdb0b 100644 --- a/frigate/api/review.py +++ b/frigate/api/review.py @@ -366,7 +366,7 @@ def motion_activity(): data: list[Recordings] = ( Recordings.select( Recordings.start_time, - Recordings.regions, + Recordings.motion, ) .where(reduce(operator.and_, clauses)) .order_by(Recordings.start_time.asc()) @@ -378,8 +378,7 @@ def motion_activity(): scale = request.args.get("scale", type=int, default=30) # resample data using pandas to get activity on scaled basis - df = pd.DataFrame(data, columns=["start_time", "regions"]) - df = df.rename(columns={"regions": "motion"}) + df = pd.DataFrame(data, columns=["start_time", "motion"]) # set date as datetime index df["start_time"] = pd.to_datetime(df["start_time"], unit="s") diff --git a/frigate/record/maintainer.py b/frigate/record/maintainer.py index 89395db12..98030814f 100644 --- a/frigate/record/maintainer.py +++ b/frigate/record/maintainer.py @@ -28,7 +28,6 @@ from frigate.const import ( RECORD_DIR, ) from frigate.models import Event, Recordings -from frigate.util.image import area from frigate.util.services import get_video_properties logger = logging.getLogger(__name__) @@ -39,12 +38,12 @@ QUEUE_READ_TIMEOUT = 0.00001 # seconds class SegmentInfo: def __init__( self, - motion_area: int, + motion_count: int, active_object_count: int, region_count: int, average_dBFS: int, ) -> None: - self.motion_area = motion_area + self.motion_count = motion_count self.active_object_count = active_object_count self.region_count = region_count self.average_dBFS = average_dBFS @@ -52,7 +51,7 @@ class SegmentInfo: def should_discard_segment(self, retain_mode: RetainModeEnum) -> bool: return ( retain_mode == RetainModeEnum.motion - and self.motion_area == 0 + and self.motion_count == 0 and self.average_dBFS == 0 ) or ( retain_mode == RetainModeEnum.active_objects @@ -76,13 +75,6 @@ class RecordingMaintainer(threading.Thread): self.audio_recordings_info: dict[str, list] = defaultdict(list) self.end_time_cache: dict[str, Tuple[datetime.datetime, float]] = {} - self.camera_frame_area: dict[str, int] = {} - - for camera in self.config.cameras.values(): - self.camera_frame_area[camera.name] = ( - camera.detect.width * camera.detect.height * 0.1 - ) - async def move_files(self) -> None: cache_files = [ d @@ -304,7 +296,7 @@ class RecordingMaintainer(threading.Thread): video_frame_count = 0 active_count = 0 region_count = 0 - total_motion_area = 0 + motion_count = 0 for frame in self.object_recordings_info[camera]: # frame is after end time of segment if frame[0] > end_time.timestamp(): @@ -321,23 +313,9 @@ class RecordingMaintainer(threading.Thread): if not o["false_positive"] and o["motionless_count"] == 0 ] ) - total_motion_area += sum([area(box) for box in frame[2]]) + motion_count += len(frame[2]) region_count += len(frame[3]) - if video_frame_count > 0: - normalized_motion_area = min( - int( - ( - total_motion_area - / (self.camera_frame_area[camera] * video_frame_count) - ) - * 100 - ), - 100, - ) - else: - normalized_motion_area = 0 - audio_values = [] for frame in self.audio_recordings_info[camera]: # frame is after end time of segment @@ -357,7 +335,7 @@ class RecordingMaintainer(threading.Thread): average_dBFS = 0 if not audio_values else np.average(audio_values) return SegmentInfo( - normalized_motion_area, active_count, region_count, round(average_dBFS) + motion_count, active_count, region_count, round(average_dBFS) ) async def move_segment( @@ -443,7 +421,7 @@ class RecordingMaintainer(threading.Thread): Recordings.start_time: start_time.timestamp(), Recordings.end_time: end_time.timestamp(), Recordings.duration: duration, - Recordings.motion: segment_info.motion_area, + Recordings.motion: segment_info.motion_count, # TODO: update this to store list of active objects at some point Recordings.objects: segment_info.active_object_count, Recordings.regions: segment_info.region_count, diff --git a/frigate/test/test_record_retention.py b/frigate/test/test_record_retention.py index 4620c9a3e..b9aead9da 100644 --- a/frigate/test/test_record_retention.py +++ b/frigate/test/test_record_retention.py @@ -7,27 +7,27 @@ from frigate.record.maintainer import SegmentInfo class TestRecordRetention(unittest.TestCase): def test_motion_should_keep_motion_not_object(self): segment_info = SegmentInfo( - motion_area=1, active_object_count=0, region_count=0, average_dBFS=0 + motion_count=1, active_object_count=0, region_count=0, average_dBFS=0 ) assert not segment_info.should_discard_segment(RetainModeEnum.motion) assert segment_info.should_discard_segment(RetainModeEnum.active_objects) def test_object_should_keep_object_not_motion(self): segment_info = SegmentInfo( - motion_area=0, active_object_count=1, region_count=0, average_dBFS=0 + motion_count=0, active_object_count=1, region_count=0, average_dBFS=0 ) assert segment_info.should_discard_segment(RetainModeEnum.motion) assert not segment_info.should_discard_segment(RetainModeEnum.active_objects) def test_all_should_keep_all(self): segment_info = SegmentInfo( - motion_area=0, active_object_count=0, region_count=0, average_dBFS=0 + motion_count=0, active_object_count=0, region_count=0, average_dBFS=0 ) assert not segment_info.should_discard_segment(RetainModeEnum.all) def test_should_keep_audio_in_motion_mode(self): segment_info = SegmentInfo( - motion_area=0, active_object_count=0, region_count=0, average_dBFS=1 + motion_count=0, active_object_count=0, region_count=0, average_dBFS=1 ) assert not segment_info.should_discard_segment(RetainModeEnum.motion) assert segment_info.should_discard_segment(RetainModeEnum.active_objects)