Переглянути джерело

manage 2 seconds worth of motion frames for processing

blakeblackshear 6 роки тому
батько
коміт
2e3c9da650
2 змінених файлів з 53 додано та 2 видалено
  1. 8 1
      detect_objects.py
  2. 45 1
      frigate/video.py

+ 8 - 1
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()

+ 45 - 1
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()
+    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()