def cross_correlation2d(X, K):
"""Apply a 2D kernel as written, using valid cross-correlation."""
output_rows = X.shape[0] - K.shape[0] + 1
output_cols = X.shape[1] - K.shape[1] + 1
Y = np.zeros((output_rows, output_cols), dtype=float)
for i in range(output_rows):
for j in range(output_cols):
total = 0.0
for u in range(K.shape[0]):
for v in range(K.shape[1]):
total += X[i + u, j + v] * K[u, v]
Y[i, j] = total
return Y
def draw_number_matrix(ax, values, title, *, cmap="Greys", vmin=None,
vmax=None, text_color=None):
"""Display a small matrix with its numerical values."""
ax.imshow(values, cmap=cmap, vmin=vmin, vmax=vmax)
rows, cols = values.shape
norm = Normalize(vmin=np.min(values) if vmin is None else vmin,
vmax=np.max(values) if vmax is None else vmax)
color_map = plt.get_cmap(cmap)
for i in range(rows):
for j in range(cols):
value = 0.0 if np.isclose(values[i, j], 0.0) else values[i, j]
ax.add_patch(Rectangle(
(j - 0.5, i - 0.5), 1, 1,
fill=False, edgecolor="#7A7A7A", linewidth=1.6,
))
if text_color is None:
red, green, blue, _ = color_map(norm(value))
luminance = 0.2126 * red + 0.7152 * green + 0.0722 * blue
cell_text_color = "black" if luminance > 0.52 else "white"
else:
cell_text_color = text_color
ax.text(j, i, f"{value:g}", ha="center", va="center",
color=cell_text_color, fontsize=17, fontweight="bold")
ax.set_xticks([])
ax.set_yticks([])
ax.set_title(title, pad=12)
X_image = np.array([
[255, 255, 255, 255],
[255, 0, 0, 255],
[255, 0, 0, 255],
[255, 255, 255, 255],
], dtype=float)
K_edge = np.array([
[-1, 1],
[-1, 1],
], dtype=float)
Y_image = cross_correlation2d(X_image, K_edge)
placement_order = np.arange(1, 10).reshape(3, 3)
fig, axes = plt.subplots(
1, 3,
figsize=(11.4, 4.4),
gridspec_kw={"width_ratios": [1.25, 0.78, 1.0]},
)
draw_number_matrix(
axes[0], X_image, "Input image $X$", cmap="Greys_r", vmin=0, vmax=255,
)
axes[0].add_patch(Rectangle(
(-0.5, -0.5), 2, 2,
facecolor="none", edgecolor=ORANGE, linewidth=4,
))
draw_number_matrix(
axes[1], K_edge, "Kernel $K$", cmap="RdBu_r", vmin=-1, vmax=1,
)
draw_number_matrix(
axes[2], placement_order, "Nine valid placements", cmap="Greys",
vmin=0, vmax=100,
)
fig.tight_layout(w_pad=2.0)
plt.show()