mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
add layout calculations
This commit is contained in:
parent
8e2ba4a8ea
commit
4eed27e178
@ -1,12 +1,14 @@
|
|||||||
|
import datetime
|
||||||
|
import math
|
||||||
import multiprocessing as mp
|
import multiprocessing as mp
|
||||||
import queue
|
import queue
|
||||||
import signal
|
import signal
|
||||||
import subprocess as sp
|
import subprocess as sp
|
||||||
import threading
|
import threading
|
||||||
import numpy as np
|
|
||||||
from multiprocessing import shared_memory
|
from multiprocessing import shared_memory
|
||||||
from wsgiref.simple_server import make_server
|
from wsgiref.simple_server import make_server
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
from setproctitle import setproctitle
|
from setproctitle import setproctitle
|
||||||
from ws4py.server.wsgirefserver import (
|
from ws4py.server.wsgirefserver import (
|
||||||
WebSocketWSGIHandler,
|
WebSocketWSGIHandler,
|
||||||
@ -68,29 +70,80 @@ class BroadcastThread(threading.Thread):
|
|||||||
|
|
||||||
class BirdsEyeFrameManager:
|
class BirdsEyeFrameManager:
|
||||||
def __init__(self, height, width):
|
def __init__(self, height, width):
|
||||||
frame_shape = (height, width)
|
self.frame_shape = (height, width)
|
||||||
yuv_shape = (height * 3 // 2, width)
|
self.yuv_shape = (height * 3 // 2, width)
|
||||||
self.frame = np.ndarray(yuv_shape, dtype=np.uint8)
|
self.frame = np.ndarray(self.yuv_shape, dtype=np.uint8)
|
||||||
|
|
||||||
# initialize the frame as black and with the frigate logo
|
# initialize the frame as black and with the frigate logo
|
||||||
self.blank_frame = np.zeros(yuv_shape, np.uint8)
|
self.blank_frame = np.zeros(self.yuv_shape, np.uint8)
|
||||||
self.blank_frame[:] = 128
|
self.blank_frame[:] = 128
|
||||||
self.blank_frame[0 : frame_shape[0], 0 : frame_shape[1]] = 16
|
self.blank_frame[0 : self.frame_shape[0], 0 : self.frame_shape[1]] = 16
|
||||||
|
|
||||||
self.frame[:] = self.blank_frame
|
self.frame[:] = self.blank_frame
|
||||||
|
|
||||||
def update(self, camera, object_count, motion_count, frame_time, frame):
|
self.last_active_frames = {}
|
||||||
# determine how many cameras are tracking objects (or recently were)
|
self.camera_layout = []
|
||||||
|
|
||||||
|
def clear_frame(self):
|
||||||
|
self.frame[:] = self.blank_frame
|
||||||
|
|
||||||
|
def update(self, camera, object_count, motion_count, frame_time, frame) -> bool:
|
||||||
|
|
||||||
|
# maintain time of most recent active frame for each camera
|
||||||
|
if object_count > 0:
|
||||||
|
self.last_active_frames[camera] = frame_time
|
||||||
|
|
||||||
|
# TODO: avoid the remaining work if exceeding 5 fps and return False
|
||||||
|
|
||||||
|
# determine how many cameras are tracking objects within the last 30 seconds
|
||||||
|
now = datetime.datetime.now().timestamp()
|
||||||
|
active_cameras = [
|
||||||
|
cam
|
||||||
|
for cam, frame_time in self.last_active_frames.items()
|
||||||
|
if now - frame_time < 30
|
||||||
|
]
|
||||||
|
|
||||||
|
if len(active_cameras) == 0 and len(self.camera_layout) == 0:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# if the sqrt of the layout and the active cameras don't round to the same value,
|
||||||
|
# we need to resize the layout
|
||||||
|
if round(math.sqrt(len(active_cameras))) != round(
|
||||||
|
math.sqrt(len(self.camera_layout))
|
||||||
|
):
|
||||||
# decide on a layout for the birdseye view (try to avoid too much churn)
|
# decide on a layout for the birdseye view (try to avoid too much churn)
|
||||||
# calculate position of each camera
|
self.columns = math.ceil(math.sqrt(len(active_cameras)))
|
||||||
|
self.rows = round(math.sqrt(len(active_cameras)))
|
||||||
|
|
||||||
|
self.camera_layout = [None] * (self.columns * self.rows)
|
||||||
|
self.clear_frame()
|
||||||
|
|
||||||
|
# remove inactive cameras from the layout
|
||||||
|
self.camera_layout = [
|
||||||
|
cam if cam in active_cameras else None for cam in self.camera_layout
|
||||||
|
]
|
||||||
|
# place the active cameras in the layout
|
||||||
|
while len(active_cameras) > 0:
|
||||||
|
cam = active_cameras.pop()
|
||||||
|
if cam in self.camera_layout:
|
||||||
|
continue
|
||||||
|
# place camera in the first available spot in the layout
|
||||||
|
for i in range(0, len(self.camera_layout) - 1):
|
||||||
|
if self.camera_layout[i] is None:
|
||||||
|
self.camera_layout[i] = cam
|
||||||
|
break
|
||||||
|
|
||||||
# calculate resolution of each position in the layout
|
# calculate resolution of each position in the layout
|
||||||
# if layout is changing, wipe the frame black again
|
width = self.frame_shape[1] / self.columns
|
||||||
# For each camera currently tracking objects (alphabetical):
|
height = self.frame_shape[0] / self.rows
|
||||||
|
|
||||||
|
# For each camera in the layout:
|
||||||
# - resize the current frame and copy into the birdseye view
|
# - resize the current frame and copy into the birdseye view
|
||||||
# signal to birdseye process that the frame is ready to send
|
|
||||||
|
|
||||||
self.frame[:] = frame
|
self.frame[:] = frame
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def output_frames(config, video_output_queue):
|
def output_frames(config, video_output_queue):
|
||||||
threading.current_thread().name = f"output"
|
threading.current_thread().name = f"output"
|
||||||
@ -170,13 +223,13 @@ def output_frames(config, video_output_queue):
|
|||||||
ws.environ["PATH_INFO"].endswith("birdseye")
|
ws.environ["PATH_INFO"].endswith("birdseye")
|
||||||
for ws in websocket_server.manager
|
for ws in websocket_server.manager
|
||||||
):
|
):
|
||||||
birdseye_manager.update(
|
if birdseye_manager.update(
|
||||||
camera,
|
camera,
|
||||||
len(current_tracked_objects),
|
len(current_tracked_objects),
|
||||||
len(motion_boxes),
|
len(motion_boxes),
|
||||||
frame_time,
|
frame_time,
|
||||||
frame,
|
frame,
|
||||||
)
|
):
|
||||||
converters["birdseye"].write(birdseye_manager.frame.tobytes())
|
converters["birdseye"].write(birdseye_manager.frame.tobytes())
|
||||||
|
|
||||||
if camera in previous_frames:
|
if camera in previous_frames:
|
||||||
|
Loading…
Reference in New Issue
Block a user