El usuario reportó dos problemas relacionados con el cálculo de patrones de protección:
- Patrón "Aleatorio" (random): Solo aplicaba el patrón en una franja superior del JSON cargado, no en toda la imagen
- Patrón "Centro" (center): Detectaba el centro en la parte superior en lugar del centro real del JSON
El problema estaba en cómo se calculaba el bounding box y el centro en las funciones de patrones (pixel_patterns.py):
def _center(changes: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""Ordenar píxeles desde el centro hacia afuera."""
min_x, max_x, min_y, max_y = _bbox(changes) # ❌ Calcula bbox solo de los CAMBIOS
cx = (min_x + max_x) / 2.0
cy = (min_y + max_y) / 2.0
return sorted(changes, key=lambda c: math.hypot(int(c['x']) - cx, int(c['y']) - cy))El problema: _bbox(changes) calculaba el bounding box solo de los píxeles con cambios detectados, no del área completa del JSON.
-
Usuario carga un JSON Guard con área completa:
{startX: 0, startY: 0, width: 200, height: 200} -
Bot detecta cambios solo en zona superior: píxeles en coordenadas
y: 10-50 -
La función
_center()calcula centro basándose solo en esos cambios:min_y = 10,max_y = 50- Centro calculado:
cy = (10 + 50) / 2 = 30❌ - Centro real del JSON:
cy = (0 + 200) / 2 = 100✅
-
Resultado: El patrón "centro" prioriza píxeles cerca de
y=30(parte superior) en lugar dey=100(centro real)
Los siguientes patrones calculaban incorrectamente el centro/bounding box:
- ✅
center- Desde el centro hacia afuera - ✅
borders- Desde los bordes hacia el centro - ✅
spiral/spiralClockwise/spiralCounterClockwise- Espirales desde el centro - ✅
priority- Prioridad centro vs bordes - ✅
quadrant- Distribución por cuadrantes - ✅
anchorPoints- Puntos de anclaje estratégicos
Archivo: server/pixel_patterns.py
Agregado parámetro opcional area a todas las funciones que calculan centro o bounding box:
def _center(changes: List[Dict[str, Any]], area: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
"""Ordenar píxeles desde el centro hacia afuera.
Args:
changes: Lista de cambios a ordenar
area: Área completa del JSON (opcional) para calcular el centro correcto
"""
if area and isinstance(area, dict):
# ✅ Usar el área COMPLETA del JSON para calcular el centro
start_x = area.get('startX', 0)
start_y = area.get('startY', 0)
width = area.get('width', 0)
height = area.get('height', 0)
if width > 0 and height > 0:
cx = start_x + width / 2.0
cy = start_y + height / 2.0
else:
# Fallback al bounding box de los cambios si el área no es válida
min_x, max_x, min_y, max_y = _bbox(changes)
cx = (min_x + max_x) / 2.0
cy = (min_y + max_y) / 2.0
else:
# Usar bounding box de los cambios si no hay área (retrocompatibilidad)
min_x, max_x, min_y, max_y = _bbox(changes)
cx = (min_x + max_x) / 2.0
cy = (min_y + max_y) / 2.0
return sorted(changes, key=lambda c: math.hypot(int(c['x']) - cx, int(c['y']) - cy))def select_pixels_by_pattern(
pattern: str,
changes: List[Dict[str, Any]],
count: int,
area: Optional[Dict[str, Any]] = None # ✅ Nuevo parámetro
) -> List[Dict[str, Any]]:
"""Seleccionar píxeles usando un patrón específico.
Args:
pattern: Nombre del patrón a usar
changes: Lista de cambios disponibles
count: Número máximo de píxeles a seleccionar
area: Área completa del JSON (opcional) con campos startX, startY, width, height
Returns:
Lista de píxeles ordenados según el patrón
"""Todos los patrones que necesitan área ahora la reciben:
if p == 'center':
ordered = _center(pool, area) # ✅ Pasa área
elif p == 'borders':
ordered = _borders(pool, area) # ✅ Pasa área
elif p == 'spiral':
ordered = _spiral_like(pool, None, area) # ✅ Pasa área
elif p == 'spiralClockwise':
ordered = _spiral_like(pool, True, area) # ✅ Pasa área
# ... etcArchivo: server/session_orchestrator.py
# Extraer área del preview para calcular centros correctos
area = None
try:
area = preview.get('protectedArea') or preview.get('area')
except Exception:
pass
try:
selected = select_pixels_by_pattern(
str(guard_config.get('protectionPattern', 'random')),
changes,
pick,
area # ✅ Pasa el área completa del JSON
)
except Exception:
selected = changes[:pick]JSON cargado: {startX: 0, startY: 0, width: 200, height: 200}
Cambios detectados: píxeles en y: 10-50 (zona superior)
Patrón "center":
Centro calculado: (100, 30) ← basado solo en los cambios
Prioriza píxeles en parte superior
Patrón "random":
Aplica solo en franja superior donde hay cambios
JSON cargado: {startX: 0, startY: 0, width: 200, height: 200}
Cambios detectados: píxeles en y: 10-50 (zona superior)
Patrón "center":
Centro calculado: (100, 100) ← basado en área COMPLETA del JSON
Prioriza píxeles más cercanos al centro real
Patrón "random":
Aplica en toda el área del JSON, priorizando cambios detectados
| Patrón | Problema | Corrección |
|---|---|---|
center |
Centro calculado solo en zona con cambios | Usa centro del área completa |
borders |
Bordes calculados solo en zona con cambios | Usa bordes del área completa |
spiral / spiralClockwise / spiralCounterClockwise |
Espiral desde centro incorrecto | Espiral desde centro del área completa |
priority |
Prioridad centro/bordes incorrecta | Usa centro y bordes del área completa |
quadrant |
Cuadrantes calculados solo en zona con cambios | Divide área completa en 4 cuadrantes |
anchorPoints |
Puntos de anclaje solo en zona con cambios | Ancla en esquinas y centro del área completa |
lineUp/Down/Left/Right |
✅ No afectados (ordenan por coordenadas) | Sin cambios |
zigzag |
✅ No afectado (ordena por filas) | Sin cambios |
diagonal |
✅ No afectado (ordena por suma x+y) | Sin cambios |
random |
✅ No afectado (shuffle aleatorio) | Sin cambios |
- Carga un JSON Guard con área grande (ej: 200x200)
- Asegúrate que solo hay cambios en una zona pequeña (ej: esquina superior)
- Selecciona patrón "Centro"
- Inicia sesión y observa qué píxeles se reparan primero
- Resultado esperado: Se deben priorizar píxeles más cercanos al centro del JSON (100, 100), no al centro de la zona con cambios
-
✅
server/pixel_patterns.py:- Agregado parámetro
areaaselect_pixels_by_pattern() - Actualizado
_center(),_borders(),_spiral_like(),_priority(),_quadrant(),_anchor_points() - Actualizado switch de patrones para pasar área
- Agregado parámetro
-
✅
server/session_orchestrator.py:- Extraer área del preview antes de llamar a
select_pixels_by_pattern() - Pasar área en ambas llamadas (orchestrate_loop y _do_one_guard_round)
- Extraer área del preview antes de llamar a
El parámetro area es opcional con valor por defecto None. Si no se proporciona:
- ✅ Funciona como antes (usa bounding box de los cambios)
- ✅ No rompe código existente
- ✅ Compatible con llamadas antiguas que no pasen área
Fecha: 1 de octubre de 2025
Reportado por: Usuario (alvaroalonso)
Fix por: GitHub Copilot