diff --git a/detect_objects.py b/detect_objects.py index 175d9742e..0eaca3494 100644 --- a/detect_objects.py +++ b/detect_objects.py @@ -18,7 +18,7 @@ from frigate.util import tonumpyarray from frigate.mqtt import MqttMotionPublisher, MqttObjectPublisher from frigate.objects import ObjectParser, ObjectCleaner from frigate.motion import detect_motion -from frigate.video import fetch_frames +from frigate.video import fetch_frames, FrameTracker from frigate.object_detection import detect_objects RTSP_URL = os.getenv('RTSP_URL') @@ -35,6 +35,7 @@ DEBUG = (os.getenv('DEBUG') == '1') def main(): DETECTED_OBJECTS = [] + recent_motion_frames = {} # Parse selected regions regions = [] for region_string in REGIONS.split(':'): @@ -120,6 +121,11 @@ def main(): motion_process.daemon = True motion_processes.append(motion_process) + # start a thread to store recent motion frames for processing + frame_tracker = FrameTracker(frame_arr, shared_frame_time, frame_ready, frame_lock, + recent_motion_frames, motion_changed, [region['motion_detected'] for region in regions]) + frame_tracker.start() + # start a thread to parse objects from the queue object_parser = ObjectParser(object_queue, objects_parsed, DETECTED_OBJECTS) object_parser.start() @@ -212,6 +218,7 @@ def main(): detection_process.join() for motion_process in motion_processes: motion_process.join() + frame_tracker.join() object_parser.join() object_cleaner.join() mqtt_publisher.join() diff --git a/frigate/video.py b/frigate/video.py index f9c95c718..5f13b3138 100644 --- a/frigate/video.py +++ b/frigate/video.py @@ -1,6 +1,7 @@ import time import datetime import cv2 +import threading from . util import tonumpyarray # fetch the frames as fast a possible, only decoding the frames when the @@ -38,4 +39,47 @@ def fetch_frames(shared_arr, shared_frame_time, frame_lock, frame_ready, frame_s with frame_ready: frame_ready.notify_all() - video.release() \ No newline at end of file + video.release() + +class FrameTracker(threading.Thread): + def __init__(self, shared_frame, frame_time, frame_ready, frame_lock, recent_frames, motion_changed, motion_regions): + threading.Thread.__init__(self) + self.shared_frame = shared_frame + self.frame_time = frame_time + self.frame_ready = frame_ready + self.frame_lock = frame_lock + self.recent_frames = recent_frames + self.motion_changed = motion_changed + self.motion_regions = motion_regions + + def run(self): + frame_time = 0.0 + while True: + # while there is motion + while len([r for r in self.motion_regions if r.is_set()]) > 0: + now = datetime.datetime.now().timestamp() + # wait for a frame + with self.frame_ready: + # if there isnt a frame ready for processing or it is old, wait for a signal + if self.frame_time.value == frame_time or (now - self.frame_time.value) > 0.5: + self.frame_ready.wait() + + # lock and make a copy of the frame + with self.frame_lock: + frame = self.shared_frame.copy().astype('uint8') + frame_time = self.frame_time.value + + # add the frame to recent frames + self.recent_frames[frame_time] = frame + + # delete any old frames + stored_frame_times = list(self.recent_frames.keys()) + for k in stored_frame_times: + if (now - k) > 2: + del self.recent_frames[k] + + print(stored_frame_times) + + # wait for the global motion flag to change + with self.motion_changed: + self.motion_changed.wait() \ No newline at end of file