mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-05 18:55:23 +03:00
Save canvas size and don't recalculate
This commit is contained in:
parent
bf3bc9c49c
commit
08412a444d
@ -29,6 +29,38 @@ from frigate.util import SharedMemoryFrameManager, copy_yuv_to_position, get_yuv
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_standard_aspect_ratio(camera_width, camera_height) -> tuple[int, int]:
|
||||
"""Ensure that only standard aspect ratios are used."""
|
||||
known_aspects = [
|
||||
(16, 9),
|
||||
(9, 16),
|
||||
(32, 9),
|
||||
(12, 9),
|
||||
(9, 12),
|
||||
] # aspects are scaled to have common relative size
|
||||
known_aspects_ratios = list(
|
||||
map(lambda aspect: aspect[0] / aspect[1], known_aspects)
|
||||
)
|
||||
closest = min(
|
||||
known_aspects_ratios,
|
||||
key=lambda x: abs(x - (camera_width / camera_height)),
|
||||
)
|
||||
return known_aspects[known_aspects_ratios.index(closest)]
|
||||
|
||||
|
||||
class Canvas:
|
||||
def __init__(self, canvas_width: int, canvas_height: int) -> None:
|
||||
canvas_gcd = math.gcd(canvas_width, canvas_height)
|
||||
self.aspect = get_standard_aspect_ratio(
|
||||
(canvas_width / canvas_gcd), (canvas_height / canvas_gcd)
|
||||
)
|
||||
self.width = canvas_width
|
||||
self.height = (self.width * self.aspect[1]) / self.aspect[0]
|
||||
|
||||
def get_aspect(self, coefficient: int) -> tuple[int, int]:
|
||||
return (self.aspect[0] * coefficient, self.aspect[1] * coefficient)
|
||||
|
||||
|
||||
class FFMpegConverter:
|
||||
def __init__(
|
||||
self,
|
||||
@ -170,6 +202,7 @@ class BirdsEyeFrameManager:
|
||||
self.frame_shape = (height, width)
|
||||
self.yuv_shape = (height * 3 // 2, width)
|
||||
self.frame = np.ndarray(self.yuv_shape, dtype=np.uint8)
|
||||
self.canvas = Canvas(width, height)
|
||||
self.stop_event = stop_event
|
||||
|
||||
# initialize the frame as black and with the Frigate logo
|
||||
@ -318,16 +351,15 @@ class BirdsEyeFrameManager:
|
||||
),
|
||||
)
|
||||
|
||||
canvas_width = self.config.birdseye.width
|
||||
canvas_height = self.config.birdseye.height
|
||||
|
||||
if len(active_cameras) == 1:
|
||||
# show single camera as fullscreen
|
||||
camera = active_cameras_to_add[0]
|
||||
camera_dims = self.cameras[camera]["dimensions"].copy()
|
||||
scaled_width = int(canvas_height * camera_dims[0] / camera_dims[1])
|
||||
scaled_width = int(self.canvas.height * camera_dims[0] / camera_dims[1])
|
||||
coefficient = (
|
||||
1 if scaled_width <= canvas_width else canvas_width / scaled_width
|
||||
1
|
||||
if scaled_width <= self.canvas.width
|
||||
else self.canvas.width / scaled_width
|
||||
)
|
||||
self.camera_layout = [
|
||||
[
|
||||
@ -337,7 +369,7 @@ class BirdsEyeFrameManager:
|
||||
0,
|
||||
0,
|
||||
int(scaled_width * coefficient),
|
||||
int(canvas_height * coefficient),
|
||||
int(self.canvas.height * coefficient),
|
||||
),
|
||||
)
|
||||
]
|
||||
@ -353,7 +385,6 @@ class BirdsEyeFrameManager:
|
||||
return
|
||||
|
||||
layout_candidate = self.calculate_layout(
|
||||
(canvas_width, canvas_height),
|
||||
active_cameras_to_add,
|
||||
coefficient,
|
||||
)
|
||||
@ -378,29 +409,9 @@ class BirdsEyeFrameManager:
|
||||
|
||||
return True
|
||||
|
||||
def calculate_layout(
|
||||
self, canvas, cameras_to_add: list[str], coefficient
|
||||
) -> tuple[any]:
|
||||
def calculate_layout(self, cameras_to_add: list[str], coefficient) -> tuple[any]:
|
||||
"""Calculate the optimal layout for 2+ cameras."""
|
||||
|
||||
def get_standard_aspect_ratio(camera_width, camera_height) -> tuple[int, int]:
|
||||
"""Ensure that only standard aspect ratios are used."""
|
||||
known_aspects = [
|
||||
(16, 9),
|
||||
(9, 16),
|
||||
(32, 9),
|
||||
(12, 9),
|
||||
(9, 12),
|
||||
] # aspects are scaled to have common relative size
|
||||
known_aspects_ratios = list(
|
||||
map(lambda aspect: aspect[0] / aspect[1], known_aspects)
|
||||
)
|
||||
closest = min(
|
||||
known_aspects_ratios,
|
||||
key=lambda x: abs(x - (camera_width / camera_height)),
|
||||
)
|
||||
return known_aspects[known_aspects_ratios.index(closest)]
|
||||
|
||||
def map_layout(row_height: int):
|
||||
"""Map the calculated layout."""
|
||||
candidate_layout = []
|
||||
@ -427,8 +438,8 @@ class BirdsEyeFrameManager:
|
||||
|
||||
# layout is too large
|
||||
if (
|
||||
x + scaled_width > canvas_width
|
||||
or y + scaled_height > canvas_height
|
||||
x + scaled_width > self.canvas.width
|
||||
or y + scaled_height > self.canvas.height
|
||||
):
|
||||
return 0, 0, None
|
||||
|
||||
@ -440,16 +451,9 @@ class BirdsEyeFrameManager:
|
||||
|
||||
return max_width, y, candidate_layout
|
||||
|
||||
canvas_width = canvas[0]
|
||||
canvas_aspect_x, canvas_aspect_y = self.canvas.get_aspect(coefficient)
|
||||
camera_layout: list[list[any]] = []
|
||||
camera_layout.append([])
|
||||
canvas_gcd = math.gcd(canvas_width, canvas[1])
|
||||
canvas_aspect = get_standard_aspect_ratio(
|
||||
(canvas_width / canvas_gcd), (canvas[1] / canvas_gcd)
|
||||
)
|
||||
canvas_aspect_x = canvas_aspect[0] * coefficient
|
||||
canvas_aspect_y = canvas_aspect[1] * coefficient
|
||||
canvas_height = (canvas_width * canvas_aspect_y) / canvas_aspect_x
|
||||
starting_x = 0
|
||||
x = starting_x
|
||||
y = 0
|
||||
@ -506,15 +510,16 @@ class BirdsEyeFrameManager:
|
||||
if y + max_y > canvas_aspect_y:
|
||||
return None
|
||||
|
||||
row_height = int(canvas_height / coefficient)
|
||||
row_height = int(self.canvas.height / coefficient)
|
||||
total_width, total_height, standard_candidate_layout = map_layout(row_height)
|
||||
|
||||
# layout can't be optimized more
|
||||
if total_width / canvas_width >= 0.99:
|
||||
if total_width / self.canvas.width >= 0.99:
|
||||
return standard_candidate_layout
|
||||
|
||||
scale_up_percent = min(
|
||||
1 - (total_width / canvas_width), 1 - (total_height / canvas_height)
|
||||
1 - (total_width / self.canvas.width),
|
||||
1 - (total_height / self.canvas.height),
|
||||
)
|
||||
row_height = int(row_height * (1 + round(scale_up_percent, 1)))
|
||||
_, _, scaled_layout = map_layout(row_height)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user