mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-27 10:52:11 +01:00 
			
		
		
		
	upgrade to python3.8 and switch from plasma store to shared_memory
This commit is contained in:
		
							parent
							
								
									b063099b2a
								
							
						
					
					
						commit
						ec4d048905
					
				
							
								
								
									
										25
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								Dockerfile
									
									
									
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| FROM ubuntu:18.04 | ||||
| FROM ubuntu:20.04 | ||||
| LABEL maintainer "blakeb@blakeshome.com" | ||||
| 
 | ||||
| ENV DEBIAN_FRONTEND=noninteractive | ||||
| @ -11,27 +11,26 @@ RUN apt -qq update && apt -qq install --no-install-recommends -y \ | ||||
|     # libcap-dev \ | ||||
|     && add-apt-repository ppa:deadsnakes/ppa -y \ | ||||
|     && apt -qq install --no-install-recommends -y \ | ||||
|         python3.7 \ | ||||
|         python3.7-dev \ | ||||
|         python3.8 \ | ||||
|         python3.8-dev \ | ||||
|         python3-pip \ | ||||
|         ffmpeg \ | ||||
|         # VAAPI drivers for Intel hardware accel | ||||
|         libva-drm2 libva2 i965-va-driver vainfo \ | ||||
|     && python3.7 -m pip install -U pip \ | ||||
|     && python3.7 -m pip install -U wheel setuptools \ | ||||
|     && python3.7 -m pip install -U \ | ||||
|     && python3.8 -m pip install -U pip \ | ||||
|     && python3.8 -m pip install -U wheel setuptools \ | ||||
|     && python3.8 -m pip install -U \ | ||||
|         opencv-python-headless \ | ||||
|         # python-prctl \ | ||||
|         numpy \ | ||||
|         imutils \ | ||||
|         scipy \ | ||||
|         psutil \ | ||||
|     && python3.7 -m pip install -U \ | ||||
|     && python3.8 -m pip install -U \ | ||||
|         Flask \ | ||||
|         paho-mqtt \ | ||||
|         PyYAML \ | ||||
|         matplotlib \ | ||||
|         pyarrow \ | ||||
|         click \ | ||||
|     && echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" > /etc/apt/sources.list.d/coral-edgetpu.list \ | ||||
|     && wget -q -O - https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - \ | ||||
| @ -39,10 +38,10 @@ RUN apt -qq update && apt -qq install --no-install-recommends -y \ | ||||
|     && echo "libedgetpu1-max libedgetpu/accepted-eula boolean true" | debconf-set-selections \ | ||||
|     && apt -qq install --no-install-recommends -y \ | ||||
|         libedgetpu1-max \ | ||||
|     ## Tensorflow lite (python 3.7 only) | ||||
|     && wget -q https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl \ | ||||
|     && python3.7 -m pip install tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl \ | ||||
|     && rm tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl \ | ||||
|     ## Tensorflow lite | ||||
|     && wget -q https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp38-cp38-linux_x86_64.whl \ | ||||
|     && python3.8 -m pip install tflite_runtime-2.1.0.post1-cp38-cp38-linux_x86_64.whl \ | ||||
|     && rm tflite_runtime-2.1.0.post1-cp38-cp38-linux_x86_64.whl \ | ||||
|     && rm -rf /var/lib/apt/lists/* \ | ||||
|     && (apt-get autoremove -y; apt-get autoclean -y) | ||||
| 
 | ||||
| @ -60,4 +59,4 @@ COPY detect_objects.py . | ||||
| COPY benchmark.py . | ||||
| COPY process_clip.py . | ||||
| 
 | ||||
| CMD ["python3.7", "-u", "detect_objects.py"] | ||||
| CMD ["python3.8", "-u", "detect_objects.py"] | ||||
|  | ||||
| @ -63,23 +63,13 @@ WEB_PORT = CONFIG.get('web_port', 5000) | ||||
| DEBUG = (CONFIG.get('debug', '0') == '1') | ||||
| TENSORFLOW_DEVICE = CONFIG.get('tensorflow_device') | ||||
| 
 | ||||
| def start_plasma_store(): | ||||
|     plasma_cmd = ['plasma_store', '-m', '400000000', '-s', '/tmp/plasma'] | ||||
|     plasma_process = sp.Popen(plasma_cmd, stdout=sp.DEVNULL, stderr=sp.DEVNULL) | ||||
|     time.sleep(1) | ||||
|     rc = plasma_process.poll() | ||||
|     if rc is not None: | ||||
|         return None | ||||
|     return plasma_process | ||||
| 
 | ||||
| class CameraWatchdog(threading.Thread): | ||||
|     def __init__(self, camera_processes, config, tflite_process, tracked_objects_queue, plasma_process, stop_event): | ||||
|     def __init__(self, camera_processes, config, tflite_process, tracked_objects_queue, stop_event): | ||||
|         threading.Thread.__init__(self) | ||||
|         self.camera_processes = camera_processes | ||||
|         self.config = config | ||||
|         self.tflite_process = tflite_process | ||||
|         self.tracked_objects_queue = tracked_objects_queue | ||||
|         self.plasma_process = plasma_process | ||||
|         self.stop_event = stop_event | ||||
| 
 | ||||
|     def run(self): | ||||
| @ -93,12 +83,6 @@ class CameraWatchdog(threading.Thread): | ||||
|                 break | ||||
| 
 | ||||
|             now = datetime.datetime.now().timestamp() | ||||
|              | ||||
|             # check the plasma process | ||||
|             rc = self.plasma_process.poll() | ||||
|             if rc != None: | ||||
|                 print(f"plasma_process exited unexpectedly with {rc}") | ||||
|                 self.plasma_process = start_plasma_store() | ||||
| 
 | ||||
|             # check the detection process | ||||
|             detection_start = self.tflite_process.detection_start.value | ||||
| @ -172,8 +156,6 @@ def main(): | ||||
|     client.connect(MQTT_HOST, MQTT_PORT, 60) | ||||
|     client.loop_start() | ||||
| 
 | ||||
|     plasma_process = start_plasma_store() | ||||
| 
 | ||||
|     ## | ||||
|     # Setup config defaults for cameras | ||||
|     ## | ||||
| @ -189,11 +171,16 @@ def main(): | ||||
| 
 | ||||
|     # Queue for clip processing | ||||
|     event_queue = mp.Queue() | ||||
| 
 | ||||
|     # create the detection pipes | ||||
|     detection_pipes = {} | ||||
|     for name in CONFIG['cameras'].keys(): | ||||
|         detection_pipes[name] = mp.Pipe(duplex=False) | ||||
|      | ||||
|     # Start the shared tflite process | ||||
|     tflite_process = EdgeTPUProcess(TENSORFLOW_DEVICE) | ||||
|     tflite_process = EdgeTPUProcess(result_connections={ key:value[1] for (key,value) in detection_pipes.items() }, tf_device=TENSORFLOW_DEVICE) | ||||
| 
 | ||||
|     # start the camera processes | ||||
|     # create the camera processes | ||||
|     camera_processes = {} | ||||
|     for name, config in CONFIG['cameras'].items(): | ||||
|         # Merge the ffmpeg config with the global config | ||||
| @ -236,6 +223,8 @@ def main(): | ||||
|             frame_shape = (config['height'], config['width'], 3) | ||||
|         else: | ||||
|             frame_shape = get_frame_shape(ffmpeg_input) | ||||
|          | ||||
|         config['frame_shape'] = frame_shape | ||||
| 
 | ||||
|         frame_size = frame_shape[0] * frame_shape[1] * frame_shape[2] | ||||
|         take_frame = config.get('take_frame', 1) | ||||
| @ -275,12 +264,13 @@ def main(): | ||||
|         } | ||||
| 
 | ||||
|         camera_process = mp.Process(target=track_camera, args=(name, config, frame_queue, frame_shape, | ||||
|             tflite_process.detection_queue, tracked_objects_queue, camera_processes[name]['process_fps'],  | ||||
|             tflite_process.detection_queue, detection_pipes[name][0], tracked_objects_queue, camera_processes[name]['process_fps'],  | ||||
|             camera_processes[name]['detection_fps'],  | ||||
|             camera_processes[name]['read_start'], camera_processes[name]['detection_frame'], stop_event)) | ||||
|         camera_process.daemon = True | ||||
|         camera_processes[name]['process'] = camera_process | ||||
| 
 | ||||
|     # start the camera_processes | ||||
|     for name, camera_process in camera_processes.items(): | ||||
|         camera_process['process'].start() | ||||
|         print(f"Camera_process started for {name}: {camera_process['process'].pid}") | ||||
| @ -291,7 +281,7 @@ def main(): | ||||
|     object_processor = TrackedObjectProcessor(CONFIG['cameras'], client, MQTT_TOPIC_PREFIX, tracked_objects_queue, event_queue, stop_event) | ||||
|     object_processor.start() | ||||
|      | ||||
|     camera_watchdog = CameraWatchdog(camera_processes, CONFIG['cameras'], tflite_process, tracked_objects_queue, plasma_process, stop_event) | ||||
|     camera_watchdog = CameraWatchdog(camera_processes, CONFIG['cameras'], tflite_process, tracked_objects_queue, stop_event) | ||||
|     camera_watchdog.start() | ||||
| 
 | ||||
|     def receiveSignal(signalNumber, frame): | ||||
| @ -300,11 +290,9 @@ def main(): | ||||
|         event_processor.join() | ||||
|         object_processor.join() | ||||
|         camera_watchdog.join() | ||||
|         for name, camera_process in camera_processes.items(): | ||||
|         for camera_process in camera_processes.values(): | ||||
|             camera_process['capture_thread'].join() | ||||
|         rc = camera_watchdog.plasma_process.poll() | ||||
|         if rc == None: | ||||
|             camera_watchdog.plasma_process.terminate() | ||||
|         tflite_process.stop() | ||||
|         sys.exit() | ||||
|      | ||||
|     signal.signal(signal.SIGTERM, receiveSignal) | ||||
| @ -368,9 +356,6 @@ def main(): | ||||
|             'pid': tflite_process.detect_process.pid | ||||
|         } | ||||
| 
 | ||||
|         rc = camera_watchdog.plasma_process.poll() | ||||
|         stats['plasma_store_rc'] = rc | ||||
| 
 | ||||
|         return jsonify(stats) | ||||
| 
 | ||||
|     @app.route('/<camera_name>/<label>/best.jpg') | ||||
| @ -448,8 +433,6 @@ def main(): | ||||
|     app.run(host='0.0.0.0', port=WEB_PORT, debug=False) | ||||
| 
 | ||||
|     object_processor.join() | ||||
|      | ||||
|     plasma_process.terminate() | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     main() | ||||
|  | ||||
| @ -2,12 +2,14 @@ import os | ||||
| import datetime | ||||
| import hashlib | ||||
| import multiprocessing as mp | ||||
| import queue | ||||
| from multiprocessing.connection import Connection | ||||
| from abc import ABC, abstractmethod | ||||
| from typing import Dict | ||||
| import numpy as np | ||||
| import pyarrow.plasma as plasma | ||||
| import tflite_runtime.interpreter as tflite | ||||
| from tflite_runtime.interpreter import load_delegate | ||||
| from frigate.util import EventsPerSecond, listen | ||||
| from frigate.util import EventsPerSecond, listen, SharedMemoryFrameManager | ||||
| 
 | ||||
| def load_labels(path, encoding='utf-8'): | ||||
|   """Loads labels from file (with or without index numbers). | ||||
| @ -100,73 +102,77 @@ class LocalObjectDetector(ObjectDetector): | ||||
|          | ||||
|         return detections | ||||
| 
 | ||||
| def run_detector(detection_queue, avg_speed, start, tf_device): | ||||
| def run_detector(detection_queue, result_connections: Dict[str, Connection], avg_speed, start, tf_device): | ||||
|     print(f"Starting detection process: {os.getpid()}") | ||||
|     listen() | ||||
|     plasma_client = plasma.connect("/tmp/plasma") | ||||
|     frame_manager = SharedMemoryFrameManager() | ||||
|     object_detector = LocalObjectDetector(tf_device=tf_device) | ||||
| 
 | ||||
|     while True: | ||||
|         object_id_str = detection_queue.get() | ||||
|         object_id_hash = hashlib.sha1(str.encode(object_id_str)) | ||||
|         object_id = plasma.ObjectID(object_id_hash.digest()) | ||||
|         object_id_out = plasma.ObjectID(hashlib.sha1(str.encode(f"out-{object_id_str}")).digest()) | ||||
|         input_frame = plasma_client.get(object_id, timeout_ms=0) | ||||
|         connection_id = detection_queue.get() | ||||
|         input_frame = frame_manager.get(connection_id, (1,300,300,3)) | ||||
| 
 | ||||
|         if input_frame is plasma.ObjectNotAvailable: | ||||
|         if input_frame is None: | ||||
|             continue | ||||
| 
 | ||||
|         # detect and put the output in the plasma store | ||||
|         start.value = datetime.datetime.now().timestamp() | ||||
|         plasma_client.put(object_detector.detect_raw(input_frame), object_id_out) | ||||
|         # TODO: what is the overhead for pickling this result vs writing back to shared memory? | ||||
|         #       I could try using an Event() and waiting in the other process before looking in memory... | ||||
|         detections = object_detector.detect_raw(input_frame) | ||||
|         result_connections[connection_id].send(detections) | ||||
|         duration = datetime.datetime.now().timestamp()-start.value | ||||
|         start.value = 0.0 | ||||
| 
 | ||||
|         avg_speed.value = (avg_speed.value*9 + duration)/10 | ||||
|          | ||||
| class EdgeTPUProcess(): | ||||
|     def __init__(self, tf_device=None): | ||||
|     def __init__(self, result_connections, tf_device=None): | ||||
|         self.result_connections = result_connections | ||||
|         self.detection_queue = mp.Queue() | ||||
|         self.avg_inference_speed = mp.Value('d', 0.01) | ||||
|         self.detection_start = mp.Value('d', 0.0) | ||||
|         self.detect_process = None | ||||
|         self.tf_device = tf_device | ||||
|         self.start_or_restart() | ||||
|      | ||||
|     def stop(self): | ||||
|         self.detect_process.terminate() | ||||
|         print("Waiting for detection process to exit gracefully...") | ||||
|         self.detect_process.join(timeout=30) | ||||
|         if self.detect_process.exitcode is None: | ||||
|             print("Detection process didnt exit. Force killing...") | ||||
|             self.detect_process.kill() | ||||
|             self.detect_process.join() | ||||
| 
 | ||||
|     def start_or_restart(self): | ||||
|         self.detection_start.value = 0.0 | ||||
|         if (not self.detect_process is None) and self.detect_process.is_alive(): | ||||
|             self.detect_process.terminate() | ||||
|             print("Waiting for detection process to exit gracefully...") | ||||
|             self.detect_process.join(timeout=30) | ||||
|             if self.detect_process.exitcode is None: | ||||
|                 print("Detection process didnt exit. Force killing...") | ||||
|                 self.detect_process.kill() | ||||
|                 self.detect_process.join() | ||||
|         self.detect_process = mp.Process(target=run_detector, args=(self.detection_queue, self.avg_inference_speed, self.detection_start, self.tf_device)) | ||||
|             self.stop() | ||||
|         self.detect_process = mp.Process(target=run_detector, args=(self.detection_queue, self.result_connections, self.avg_inference_speed, self.detection_start, self.tf_device)) | ||||
|         self.detect_process.daemon = True | ||||
|         self.detect_process.start() | ||||
| 
 | ||||
| class RemoteObjectDetector(): | ||||
|     def __init__(self, name, labels, detection_queue): | ||||
|     def __init__(self, name, labels, detection_queue, result_connection: Connection): | ||||
|         self.labels = load_labels(labels) | ||||
|         self.name = name | ||||
|         self.fps = EventsPerSecond() | ||||
|         self.plasma_client = plasma.connect("/tmp/plasma") | ||||
|         self.detection_queue = detection_queue | ||||
|         self.result_connection = result_connection | ||||
|         self.shm = mp.shared_memory.SharedMemory(name=self.name, create=True, size=300*300*3) | ||||
|         self.np_shm = np.ndarray((1,300,300,3), dtype=np.uint8, buffer=self.shm.buf) | ||||
|      | ||||
|     def detect(self, tensor_input, threshold=.4): | ||||
|         detections = [] | ||||
| 
 | ||||
|         now = f"{self.name}-{str(datetime.datetime.now().timestamp())}" | ||||
|         object_id_frame = plasma.ObjectID(hashlib.sha1(str.encode(now)).digest()) | ||||
|         object_id_detections = plasma.ObjectID(hashlib.sha1(str.encode(f"out-{now}")).digest()) | ||||
|         self.plasma_client.put(tensor_input, object_id_frame) | ||||
|         self.detection_queue.put(now) | ||||
|         raw_detections = self.plasma_client.get(object_id_detections, timeout_ms=10000) | ||||
| 
 | ||||
|         if raw_detections is plasma.ObjectNotAvailable: | ||||
|             self.plasma_client.delete([object_id_frame]) | ||||
|         # copy input to shared memory | ||||
|         # TODO: what if I just write it there in the first place? | ||||
|         self.np_shm[:] = tensor_input[:] | ||||
|         self.detection_queue.put(self.name) | ||||
|         if self.result_connection.poll(10): | ||||
|             raw_detections = self.result_connection.recv() | ||||
|         else: | ||||
|             return detections | ||||
| 
 | ||||
|         for d in raw_detections: | ||||
| @ -177,6 +183,5 @@ class RemoteObjectDetector(): | ||||
|                 float(d[1]), | ||||
|                 (d[2], d[3], d[4], d[5]) | ||||
|             )) | ||||
|         self.plasma_client.delete([object_id_frame, object_id_detections]) | ||||
|         self.fps.update() | ||||
|         return detections | ||||
|  | ||||
| @ -10,9 +10,8 @@ import copy | ||||
| import numpy as np | ||||
| from collections import Counter, defaultdict | ||||
| import itertools | ||||
| import pyarrow.plasma as plasma | ||||
| import matplotlib.pyplot as plt | ||||
| from frigate.util import draw_box_with_label, PlasmaFrameManager | ||||
| from frigate.util import draw_box_with_label, SharedMemoryFrameManager | ||||
| from frigate.edgetpu import load_labels | ||||
| from typing import Callable, Dict | ||||
| from statistics import mean, median | ||||
| @ -59,7 +58,7 @@ class CameraState(): | ||||
|         self.object_status = defaultdict(lambda: 'OFF') | ||||
|         self.tracked_objects = {} | ||||
|         self.zone_objects = defaultdict(lambda: []) | ||||
|         self.current_frame = np.zeros((720,1280,3), np.uint8) | ||||
|         self.current_frame = np.zeros(self.config['frame_shape'], np.uint8) | ||||
|         self.current_frame_time = 0.0 | ||||
|         self.previous_frame_id = None | ||||
|         self.callbacks = defaultdict(lambda: []) | ||||
| @ -88,7 +87,7 @@ class CameraState(): | ||||
|         self.current_frame_time = frame_time | ||||
|         # get the new frame and delete the old frame | ||||
|         frame_id = f"{self.name}{frame_time}" | ||||
|         self.current_frame = self.frame_manager.get(frame_id) | ||||
|         self.current_frame = self.frame_manager.get(frame_id, self.config['frame_shape']) | ||||
|         if not self.previous_frame_id is None: | ||||
|             self.frame_manager.delete(self.previous_frame_id) | ||||
|         self.previous_frame_id = frame_id | ||||
| @ -238,7 +237,7 @@ class TrackedObjectProcessor(threading.Thread): | ||||
|         self.event_queue = event_queue | ||||
|         self.stop_event = stop_event | ||||
|         self.camera_states: Dict[str, CameraState] = {} | ||||
|         self.plasma_client = PlasmaFrameManager(self.stop_event) | ||||
|         self.frame_manager = SharedMemoryFrameManager() | ||||
| 
 | ||||
|         def start(camera, obj): | ||||
|             # publish events to mqtt | ||||
| @ -273,7 +272,7 @@ class TrackedObjectProcessor(threading.Thread): | ||||
|             self.client.publish(f"{self.topic_prefix}/{camera}/{object_name}", status, retain=False) | ||||
| 
 | ||||
|         for camera in self.camera_config.keys(): | ||||
|             camera_state = CameraState(camera, self.camera_config[camera], self.plasma_client) | ||||
|             camera_state = CameraState(camera, self.camera_config[camera], self.frame_manager) | ||||
|             camera_state.on('start', start) | ||||
|             camera_state.on('update', update) | ||||
|             camera_state.on('end', end) | ||||
|  | ||||
| @ -9,7 +9,8 @@ import cv2 | ||||
| import threading | ||||
| import matplotlib.pyplot as plt | ||||
| import hashlib | ||||
| import pyarrow.plasma as plasma | ||||
| from multiprocessing import shared_memory | ||||
| from typing import AnyStr | ||||
| 
 | ||||
| def draw_box_with_label(frame, x_min, y_min, x_max, y_max, label, info, thickness=2, color=None, position='ul'): | ||||
|     if color is None: | ||||
| @ -148,12 +149,16 @@ def listen(): | ||||
|     signal.signal(signal.SIGUSR1, print_stack) | ||||
| 
 | ||||
| class FrameManager(ABC): | ||||
|     @abstractmethod | ||||
|     def create(self, name, size) -> AnyStr: | ||||
|         pass | ||||
| 
 | ||||
|     @abstractmethod | ||||
|     def get(self, name, timeout_ms=0): | ||||
|         pass | ||||
| 
 | ||||
|     @abstractmethod | ||||
|     def put(self, name, frame): | ||||
|     def close(self, name): | ||||
|         pass | ||||
| 
 | ||||
|     @abstractmethod | ||||
| @ -164,66 +169,45 @@ class DictFrameManager(FrameManager): | ||||
|     def __init__(self): | ||||
|         self.frames = {} | ||||
|      | ||||
|     def get(self, name, timeout_ms=0): | ||||
|         return self.frames.get(name) | ||||
|     def create(self, name, size) -> AnyStr: | ||||
|         mem = bytearray(size) | ||||
|         self.frames[name] = mem | ||||
|         return mem | ||||
|      | ||||
|     def put(self, name, frame): | ||||
|         self.frames[name] = frame | ||||
|     def get(self, name, shape): | ||||
|         mem = self.frames[name] | ||||
|         return np.ndarray(shape, dtype=np.uint8, buffer=mem) | ||||
|      | ||||
|     def close(self, name): | ||||
|         pass | ||||
|      | ||||
|     def delete(self, name): | ||||
|         del self.frames[name] | ||||
| 
 | ||||
| class PlasmaFrameManager(FrameManager): | ||||
|     def __init__(self, stop_event=None): | ||||
|         self.stop_event = stop_event | ||||
|         self.connect() | ||||
| class SharedMemoryFrameManager(FrameManager): | ||||
|     def __init__(self): | ||||
|         self.shm_store = {} | ||||
|      | ||||
|     def connect(self): | ||||
|         while True: | ||||
|             if self.stop_event != None and self.stop_event.is_set(): | ||||
|                 return | ||||
|             try: | ||||
|                 self.plasma_client = plasma.connect("/tmp/plasma") | ||||
|                 return | ||||
|             except: | ||||
|                 print(f"TrackedObjectProcessor: unable to connect plasma client") | ||||
|                 time.sleep(10) | ||||
|     def create(self, name, size) -> AnyStr: | ||||
|         shm = shared_memory.SharedMemory(name=name, create=True, size=size) | ||||
|         self.shm_store[name] = shm | ||||
|         return shm.buf | ||||
| 
 | ||||
|     def get(self, name, timeout_ms=0): | ||||
|         object_id = plasma.ObjectID(hashlib.sha1(str.encode(name)).digest()) | ||||
|         while True: | ||||
|             if self.stop_event != None and self.stop_event.is_set(): | ||||
|                 return | ||||
|             try: | ||||
|                 frame = self.plasma_client.get(object_id, timeout_ms=timeout_ms) | ||||
|                 if frame is plasma.ObjectNotAvailable: | ||||
|                     return None | ||||
|                 return frame | ||||
|             except: | ||||
|                 self.connect() | ||||
|                 time.sleep(1) | ||||
|     def get(self, name, shape): | ||||
|         if name in self.shm_store: | ||||
|             shm = self.shm_store[name] | ||||
|         else: | ||||
|             shm = shared_memory.SharedMemory(name=name) | ||||
|             self.shm_store[name] = shm | ||||
|         return np.ndarray(shape, dtype=np.uint8, buffer=shm.buf) | ||||
| 
 | ||||
|     def put(self, name, frame): | ||||
|         object_id = plasma.ObjectID(hashlib.sha1(str.encode(name)).digest()) | ||||
|         while True: | ||||
|             if self.stop_event != None and self.stop_event.is_set(): | ||||
|                 return | ||||
|             try: | ||||
|                 self.plasma_client.put(frame, object_id) | ||||
|                 return | ||||
|             except Exception as e: | ||||
|                 print(f"Failed to put in plasma: {e}") | ||||
|                 self.connect() | ||||
|                 time.sleep(1) | ||||
|     def close(self, name): | ||||
|         if name in self.shm_store: | ||||
|             self.shm_store[name].close() | ||||
|             del self.shm_store[name] | ||||
| 
 | ||||
|     def delete(self, name): | ||||
|         object_id = plasma.ObjectID(hashlib.sha1(str.encode(name)).digest()) | ||||
|         while True: | ||||
|             if self.stop_event != None and self.stop_event.is_set(): | ||||
|                 return | ||||
|             try: | ||||
|                 self.plasma_client.delete([object_id]) | ||||
|                 return | ||||
|             except: | ||||
|                 self.connect() | ||||
|                 time.sleep(1) | ||||
|         if name in self.shm_store: | ||||
|             self.shm_store[name].close() | ||||
|             self.shm_store[name].unlink() | ||||
|             del self.shm_store[name] | ||||
| @ -5,7 +5,6 @@ import cv2 | ||||
| import queue | ||||
| import threading | ||||
| import ctypes | ||||
| import pyarrow.plasma as plasma | ||||
| import multiprocessing as mp | ||||
| import subprocess as sp | ||||
| import numpy as np | ||||
| @ -15,7 +14,7 @@ import json | ||||
| import base64 | ||||
| from typing import Dict, List | ||||
| from collections import defaultdict | ||||
| from frigate.util import draw_box_with_label, area, calculate_region, clipped, intersection_over_union, intersection, EventsPerSecond, listen, FrameManager, PlasmaFrameManager | ||||
| from frigate.util import draw_box_with_label, area, calculate_region, clipped, intersection_over_union, intersection, EventsPerSecond, listen, FrameManager, SharedMemoryFrameManager | ||||
| from frigate.objects import ObjectTracker | ||||
| from frigate.edgetpu import RemoteObjectDetector | ||||
| from frigate.motion import MotionDetector | ||||
| @ -154,11 +153,10 @@ def capture_frames(ffmpeg_process, camera_name, frame_shape, frame_manager: Fram | ||||
|             continue | ||||
| 
 | ||||
|         # put the frame in the frame manager | ||||
|         frame_manager.put(f"{camera_name}{current_frame.value}", | ||||
|                 np | ||||
|                     .frombuffer(frame_bytes, np.uint8) | ||||
|                     .reshape(frame_shape) | ||||
|             ) | ||||
|         frame_buffer = frame_manager.create(f"{camera_name}{current_frame.value}", frame_size) | ||||
|         frame_buffer[:] = frame_bytes[:] | ||||
|         frame_manager.close(f"{camera_name}{current_frame.value}") | ||||
| 
 | ||||
|         # add to the queue | ||||
|         frame_queue.put(current_frame.value) | ||||
|         last_frame = current_frame.value | ||||
| @ -173,7 +171,7 @@ class CameraCapture(threading.Thread): | ||||
|         self.take_frame = take_frame | ||||
|         self.fps = fps | ||||
|         self.skipped_fps = EventsPerSecond() | ||||
|         self.plasma_client = PlasmaFrameManager(stop_event) | ||||
|         self.frame_manager = SharedMemoryFrameManager() | ||||
|         self.ffmpeg_process = ffmpeg_process | ||||
|         self.current_frame = mp.Value('d', 0.0) | ||||
|         self.last_frame = 0 | ||||
| @ -182,10 +180,10 @@ class CameraCapture(threading.Thread): | ||||
| 
 | ||||
|     def run(self): | ||||
|         self.skipped_fps.start() | ||||
|         capture_frames(self.ffmpeg_process, self.name, self.frame_shape, self.plasma_client, self.frame_queue, self.take_frame, | ||||
|         capture_frames(self.ffmpeg_process, self.name, self.frame_shape, self.frame_manager, self.frame_queue, self.take_frame, | ||||
|             self.fps, self.skipped_fps, self.stop_event, self.detection_frame, self.current_frame) | ||||
| 
 | ||||
| def track_camera(name, config, frame_queue, frame_shape, detection_queue, detected_objects_queue, fps, detection_fps, read_start, detection_frame, stop_event): | ||||
| def track_camera(name, config, frame_queue, frame_shape, detection_queue, result_connection, detected_objects_queue, fps, detection_fps, read_start, detection_frame, stop_event): | ||||
|     print(f"Starting process for {name}: {os.getpid()}") | ||||
|     listen() | ||||
| 
 | ||||
| @ -218,13 +216,13 @@ def track_camera(name, config, frame_queue, frame_shape, detection_queue, detect | ||||
|         mask[:] = 255 | ||||
| 
 | ||||
|     motion_detector = MotionDetector(frame_shape, mask, resize_factor=6) | ||||
|     object_detector = RemoteObjectDetector(name, '/labelmap.txt', detection_queue) | ||||
|     object_detector = RemoteObjectDetector(name, '/labelmap.txt', detection_queue, result_connection) | ||||
| 
 | ||||
|     object_tracker = ObjectTracker(10) | ||||
| 
 | ||||
|     plasma_client = PlasmaFrameManager() | ||||
|     frame_manager = SharedMemoryFrameManager() | ||||
| 
 | ||||
|     process_frames(name, frame_queue, frame_shape, plasma_client, motion_detector, object_detector, | ||||
|     process_frames(name, frame_queue, frame_shape, frame_manager, motion_detector, object_detector, | ||||
|         object_tracker, detected_objects_queue, fps, detection_fps, detection_frame, objects_to_track, object_filters, mask, stop_event) | ||||
| 
 | ||||
|     print(f"{name}: exiting subprocess") | ||||
| @ -281,7 +279,7 @@ def process_frames(camera_name: str, frame_queue: mp.Queue, frame_shape, | ||||
|          | ||||
|         current_frame_time.value = frame_time | ||||
| 
 | ||||
|         frame = frame_manager.get(f"{camera_name}{frame_time}") | ||||
|         frame = frame_manager.get(f"{camera_name}{frame_time}", frame_shape) | ||||
| 
 | ||||
|         if frame is None: | ||||
|             print(f"{camera_name}: frame {frame_time} is not in memory store.") | ||||
| @ -364,3 +362,5 @@ def process_frames(camera_name: str, frame_queue: mp.Queue, frame_shape, | ||||
|         detected_objects_queue.put((camera_name, frame_time, object_tracker.tracked_objects)) | ||||
| 
 | ||||
|         detection_fps.value = object_detector.fps.eps() | ||||
| 
 | ||||
|         frame_manager.close(f"{camera_name}{frame_time}") | ||||
|  | ||||
| @ -4,7 +4,7 @@ import os | ||||
| import datetime | ||||
| from unittest import TestCase, main | ||||
| from frigate.video import process_frames, start_or_restart_ffmpeg, capture_frames, get_frame_shape | ||||
| from frigate.util import DictFrameManager, EventsPerSecond, draw_box_with_label | ||||
| from frigate.util import DictFrameManager, SharedMemoryFrameManager, EventsPerSecond, draw_box_with_label | ||||
| from frigate.motion import MotionDetector | ||||
| from frigate.edgetpu import LocalObjectDetector | ||||
| from frigate.objects import ObjectTracker | ||||
| @ -19,6 +19,7 @@ class ProcessClip(): | ||||
|         self.frame_shape = frame_shape | ||||
|         self.camera_name = 'camera' | ||||
|         self.frame_manager = DictFrameManager() | ||||
|         # self.frame_manager = SharedMemoryFrameManager() | ||||
|         self.frame_queue = mp.Queue() | ||||
|         self.detected_objects_queue = mp.Queue() | ||||
|         self.camera_state = CameraState(self.camera_name, config, self.frame_manager) | ||||
| @ -72,13 +73,15 @@ class ProcessClip(): | ||||
|             for obj in self.camera_state.tracked_objects.values(): | ||||
|                 print(f"{frame_time}: {obj['id']} - {obj['computed_score']} - {obj['score_history']}") | ||||
|          | ||||
|         self.frame_manager.delete(self.camera_state.previous_frame_id) | ||||
|          | ||||
|         return { | ||||
|             'object_detected': obj_detected, | ||||
|             'top_score': top_computed_score | ||||
|         } | ||||
|      | ||||
|     def save_debug_frame(self, debug_path, frame_time, tracked_objects): | ||||
|         current_frame = self.frame_manager.get(f"{self.camera_name}{frame_time}") | ||||
|         current_frame = self.frame_manager.get(f"{self.camera_name}{frame_time}", self.frame_shape) | ||||
|         # draw the bounding boxes on the frame | ||||
|         for obj in tracked_objects: | ||||
|             thickness = 2 | ||||
| @ -132,6 +135,7 @@ def process(path, label, threshold, debug_path): | ||||
|     results = [] | ||||
|     for c in clips: | ||||
|         frame_shape = get_frame_shape(c) | ||||
|         config['frame_shape'] = frame_shape | ||||
|         process_clip = ProcessClip(c, frame_shape, config) | ||||
|         process_clip.load_frames() | ||||
|         process_clip.process_frames(objects_to_track=config['objects']['track']) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user