# Ilustración numérica: convolución 2D "valid" (sin padding) con doble bucle, como en aula
# Misma lógica que un Conv2D con stride 1, un canal y un filtro.
import numpy as np
imagen_5x5 = np.array(
[
[0.0, 0.0, 0.2, 0.0, 0.0],
[0.0, 0.2, 0.8, 0.2, 0.0],
[0.2, 0.8, 1.0, 0.8, 0.2],
[0.0, 0.2, 0.8, 0.2, 0.0],
[0.0, 0.0, 0.2, 0.0, 0.0],
],
dtype=np.float32,
)
kernel_3x3 = np.array(
[
[-1.0, 0.0, 1.0],
[-1.0, 0.0, 1.0],
[-1.0, 0.0, 1.0],
],
dtype=np.float32,
)
def convolucion_valid(matriz, kernel):
h, w = matriz.shape
kh, kw = kernel.shape
out_h, out_w = h - kh + 1, w - kw + 1
salida = np.zeros((out_h, out_w), dtype=matriz.dtype)
for i in range(out_h):
for j in range(out_w):
parche = matriz[i : i + kh, j : j + kw]
salida[i, j] = float(np.sum(parche * kernel))
return salida
mapa = convolucion_valid(imagen_5x5, kernel_3x3)
print("Imagen 5x5 (entrada):")
print(np.round(imagen_5x5, 2))
print("\nKernel 3x3 (un filtro; en Keras, muchos filtros = profundidad del mapa):")
print(np.round(kernel_3x3, 2))
print("\nMapa 3x3 (cada célula: respuesta bajo '¿el patrón w encaja aquí?'):")
print(np.round(mapa, 2))
parche00 = imagen_5x5[0:3, 0:3]
z00 = float(np.sum(parche00 * kernel_3x3))
print(f"\nCálculo en (0,0): suma(p_ij * w_ij) = {z00:.4f}")