Spaces:
Sleeping
Sleeping
File size: 3,597 Bytes
132e289 170c23f e81ca22 132e289 170c23f e81ca22 170c23f e81ca22 170c23f e81ca22 170c23f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | import time
import cv2
import numpy as np
import pytest
from camguard.zone import fill_outlines, points_in_zone, zone_from_layers
def outline(gap=0):
"""Máscara 200x200 con el contorno de un cuadrado (50,50)-(150,150), trazo de 10 px.
`gap` deja un hueco de ese ancho en el lado de arriba, como un trazo a mano que no cierra.
"""
mask = np.zeros((200, 200), np.uint8)
cv2.rectangle(mask, (50, 50), (150, 150), 1, 10)
if gap:
mask[40:60, 100 : 100 + gap] = 0
return mask.astype(bool)
@pytest.mark.parametrize("gap", [pytest.param(0, id="cerrado"), pytest.param(15, id="con-hueco")])
def test_fill_outlines_fills_the_drawn_contour(gap):
zone = fill_outlines(outline(gap))
assert zone[100, 100] # centro del cuadrado: adentro
assert zone[100, 53] and zone[100, 147] # justo adentro del borde marcado
# justo afuera: la mitad externa del trazo no cuenta como zona
assert not zone[100, 46] and not zone[100, 154]
def test_fill_outlines_keeps_a_painted_area_as_is():
mask = np.zeros((200, 200), bool)
mask[50:150, 50:150] = True
assert np.array_equal(fill_outlines(mask), mask)
def test_fill_outlines_is_fast_on_a_large_painted_area():
# Regresión: con un área grande el "grosor de trazo" estimado es enorme y cerrar huecos con
# ese radio tardaba ~100 s en 1080p.
mask = np.zeros((1080, 1920), bool)
mask[594:, 960:] = True
start = time.perf_counter()
assert np.array_equal(fill_outlines(mask), mask)
assert time.perf_counter() - start < 2
def test_zone_from_layers_fills_a_drawn_contour():
layer = np.zeros((200, 200, 4), np.uint8)
layer[outline()] = (255, 0, 0, 255)
assert zone_from_layers([layer], (200, 200))[100, 100]
def make_layer(shape, painted=None):
"""Capa RGBA del editor; `painted` es la región (slice) pintada."""
layer = np.zeros((*shape, 4), np.uint8)
if painted is not None:
layer[painted] = (255, 0, 0, 255)
return layer
@pytest.fixture
def zone():
"""Imagen de 10x10 con el cuarto inferior derecho restringido."""
mask = np.zeros((10, 10), bool)
mask[5:, 5:] = True
return mask
@pytest.mark.parametrize(
("point", "expected"),
[
pytest.param((7, 7), True, id="adentro"),
pytest.param((2, 2), False, id="afuera"),
pytest.param((7, 2), False, id="misma-columna-pero-arriba"),
pytest.param((5, 5), True, id="borde-de-la-zona"),
pytest.param((9.9, 9.9), True, id="decimales"),
pytest.param((50, 50), True, id="fuera-de-la-imagen-se-lleva-al-borde"),
],
)
def test_points_in_zone(zone, point, expected):
assert points_in_zone(np.array([point]), zone).tolist() == [expected]
def test_points_in_zone_without_people(zone):
assert points_in_zone(np.empty((0, 2)), zone).tolist() == []
def test_zone_from_layers_combines_all_layers():
layers = [make_layer((4, 4), np.s_[:2, :2]), make_layer((4, 4), np.s_[2:, 2:])]
mask = zone_from_layers(layers, (4, 4))
assert mask.sum() == 8
assert mask[0, 0] and mask[3, 3] and not mask[0, 3]
@pytest.mark.parametrize(
"layers",
[pytest.param([], id="sin-capas"), pytest.param([make_layer((4, 4))], id="capa-vacia")],
)
def test_zone_from_layers_requires_paint(layers):
with pytest.raises(ValueError, match="Pintá la zona"):
zone_from_layers(layers, (4, 4))
def test_zone_from_layers_resizes_to_video_size():
mask = zone_from_layers([make_layer((4, 4), np.s_[2:, :])], (8, 6))
assert mask.shape == (8, 6)
assert mask[4:].all()
assert not mask[:4].any()
|