Calculate possible layout

This commit is contained in:
Nick Mowen 2023-06-06 17:57:03 -06:00
parent d3949eebfa
commit 9216a99b14

View File

@ -8,6 +8,7 @@ import queue
import signal import signal
import subprocess as sp import subprocess as sp
import threading import threading
import traceback
from wsgiref.simple_server import make_server from wsgiref.simple_server import make_server
import cv2 import cv2
@ -250,8 +251,8 @@ class BirdsEyeFrameManager:
copy_yuv_to_position( copy_yuv_to_position(
self.frame, self.frame,
self.layout_offsets[position], [position[1], position[0]],
self.layout_frame_shape, [position[3], position[2]],
frame, frame,
channel_dims, channel_dims,
) )
@ -267,6 +268,46 @@ class BirdsEyeFrameManager:
return True return True
def update_frame(self): def update_frame(self):
def calculate_layout(
canvas, cameras_to_add: list[str], coefficient
) -> tuple[any]:
camera_layout: list[list[any]] = []
camera_layout.append([])
x = 0
x_i = 0
y = 0
y_i = 0
max_height = 0
for camera in cameras_to_add:
detect_config = self.config.cameras[camera].detect
if self.config.cameras[camera].detect.width * coefficient <= canvas[0]:
# insert if camera can fit on current row
camera_layout[y_i].append(
(
camera,
(x, y, detect_config.width, detect_config.height),
)
)
x += detect_config.width
max_height = max(max_height, detect_config.height)
else:
# move on to the next row and insert
y = max_height
y_i += 1
camera_layout.append([])
x = 0
x_i = 0
camera_layout[y_i].append(
(
camera,
(x, y, detect_config.width, detect_config.height),
)
)
x += detect_config.width
return (camera_layout, y + max_height)
# determine how many cameras are tracking objects within the last 30 seconds # determine how many cameras are tracking objects within the last 30 seconds
active_cameras = set( active_cameras = set(
[ [
@ -337,63 +378,39 @@ class BirdsEyeFrameManager:
# this also converts added_cameras from a set to a list since we need # this also converts added_cameras from a set to a list since we need
# to pop elements in order # to pop elements in order
added_cameras = sorted( active_cameras_to_add = sorted(
added_cameras, active_cameras,
# sort cameras by order and by name if the order is the same # sort cameras by order and by name if the order is the same
key=lambda added_camera: ( key=lambda active_camera: (
self.config.cameras[added_camera].birdseye.order, self.config.cameras[active_camera].birdseye.order,
added_camera, active_camera,
), ),
# we're popping out elements from the end, so this needs to be reverse # we're popping out elements from the end, so this needs to be reverse
# as we want the last element to be the first # as we want the last element to be the first
reverse=True, reverse=True,
) )
# update each position in the layout canvas_width = self.frame_shape[1]
for position, camera in enumerate(self.camera_layout, start=0): canvas_height = self.frame_shape[0]
# if this camera was removed, replace it or clear it coefficient = 1
if camera in removed_cameras:
# if replacing this camera with a newly added one layout_candidate, total_height = calculate_layout(
if len(added_cameras) > 0: (canvas_width, canvas_height), active_cameras_to_add, coefficient
added_camera = added_cameras.pop() )
self.camera_layout[position] = added_camera
self.copy_to_position( if total_height > canvas_height:
position, coefficient = canvas_height / total_height
added_camera, layout_candidate = calculate_layout(
self.cameras[added_camera]["current_frame"], (canvas_width, canvas_height), active_cameras_to_add, coefficient
) )
self.cameras[added_camera]["layout_frame"] = self.cameras[
added_camera self.camera_layout = layout_candidate
]["current_frame"]
# if removing this camera with no replacement for row in self.camera_layout:
else: for position in row:
self.camera_layout[position] = None
self.copy_to_position(position)
removed_cameras.remove(camera)
# if an empty spot and there are cameras to add
elif camera is None and len(added_cameras) > 0:
added_camera = added_cameras.pop()
self.camera_layout[position] = added_camera
self.copy_to_position( self.copy_to_position(
position, position[1], position[0], self.cameras[position[0]]["current_frame"]
added_camera,
self.cameras[added_camera]["current_frame"],
) )
self.cameras[added_camera]["layout_frame"] = self.cameras[added_camera][
"current_frame"
]
# if not an empty spot and the camera has a newer frame, copy it
elif (
camera is not None
and self.cameras[camera]["current_frame"]
!= self.cameras[camera]["layout_frame"]
):
self.copy_to_position(
position, camera, self.cameras[camera]["current_frame"]
)
self.cameras[camera]["layout_frame"] = self.cameras[camera][
"current_frame"
]
return True return True
@ -523,19 +540,23 @@ def output_frames(config: FrigateConfig, video_output_queue):
for ws in websocket_server.manager for ws in websocket_server.manager
) )
): ):
if birdseye_manager.update( try:
camera, if birdseye_manager.update(
len([o for o in current_tracked_objects if not o["stationary"]]), camera,
len(motion_boxes), len([o for o in current_tracked_objects if not o["stationary"]]),
frame_time, len(motion_boxes),
frame, frame_time,
): frame,
frame_bytes = birdseye_manager.frame.tobytes() ):
frame_bytes = birdseye_manager.frame.tobytes()
if config.birdseye.restream: if config.birdseye.restream:
birdseye_buffer[:] = frame_bytes birdseye_buffer[:] = frame_bytes
converters["birdseye"].write(frame_bytes) converters["birdseye"].write(frame_bytes)
except Exception as e:
logger.error(f"Crash happened :: {e}")
logger.error(traceback.format_exc())
if camera in previous_frames: if camera in previous_frames:
frame_manager.delete(f"{camera}{previous_frames[camera]}") frame_manager.delete(f"{camera}{previous_frames[camera]}")