Notice
This page is located in a preparation section.

Cvičení 6: 2D pole, matice

Inicializace a kopírování 2D polí

  • Projdeme si inicializaci a kopírování 1D a více-D polí. Spusťte následující kód a na konci si vytiskněte jednotlivá pole. Co pozorujeme?

# Inicializace pole
a = [0] * 5
 
# Jak správně zkopírovat pole?
b = a
c = a[:]
d = list(a)
 
a[3] = 3
b[0] = -5
c[4] = 4

  • Spusťte následující kód a opět si na konci vypište jednotlivá pole.

# Inicializace 2D pole přímo
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
 
# Inicializace po řádcích
f = []
for i in range(3):
    f.append([i] * 3)
 
# Inicializace po řádcích ve zkráceném zápisu
g = [[i] * 3 for i in range(3)]
 
# Jak správně zkopírovat pole?
b = a
c = a[:]
d = list(b)
e = [ r[:] for r in a ]
f = [ list(a[i]) for i in range(len(a))]
 
a[0][0] = -1
b[0][1] = -2 
c[0],c[1]=c[1],c[0]
d[1][0] = -3
e[1][1] = -4

  • Pokud chceme opravdovou kopii vícedimenzionálního pole, tvz. deep copy, můžeme použít modul copy a funkci deepcopy. Doplňte import a kopírování do předchozí ukázky a porovnejte výsledky.

import copy
 
d = copy.deepcopy(b)

Life

  • Hru Life navrhl v roce 1970 matematik John Horton Conway.
  • Pravidla hry jsou jednoduchá:
    • pokud jsou v okolí jedné buňky živé právě 3 buňky, pak v této buňce život vznikne (nebo zůstane)
    • pokud je buňka živá a v jejím okolí jsou právě 2 živé buňky, pak tato buňka bude žít i nadále
    • v ostatních případech buňka zahyne buď na osamění, nebo přemnoženost
  • Uvažujte osmiokolí: 8 sousedních buněk.
  • Uvažujte uzavřený svět, tedy sousední políčko pro první pole řádku je poslední pole řádku, sousední pole pro první řádek je poslední řádek
  • Napište program, který bude simulovat 40 kroků hry life pro toto počáteční pole:

a = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 1, 1, 1, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 1, 0, 1, 0, 0, 0, 0, 0],
     [0, 0, 0, 1, 1, 0, 0, 0, 0, 0],
     [0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
   ]

  • Vygenerování prázdného pole

[[0]*len(a[0]) for i in a]

  • Pro lepší zobrazení udělejte po každém kroku pauzu

import time
time.sleep(0.5)

  • Také můžete vylepšit zobrazení tak, že místo 1 budete tisknout X a místo 0 mezeru

''.join('X' if i!=0 else ' ' for i in x)

  • Matici je možné též vykreslit do png souborů, viz následující program. Vykreslení provede array2png(a, “soubor.png”)

#importujeme knihovny pro vykresleni matic do obrazku
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib import cm
 
 
def array2png(arr, output_filename,
                   cell_px=30, colormap='viridis',
                   show_colorbar=True, add_grid=True):
    """
    Draw a 2D array as colored rectangles (one per cell) and save to PNG.
 
    Parameters
    ----------
    arr : list of lists or 2D numpy array
        Values of any numeric range; they are normalized to the colormap.
    output_filename : str
        Path of the output PNG (e.g. 'grid.png').
    cell_px : int
        Width and height of each cell in pixels (default 30).
    colormap : str
        Name of a matplotlib colormap ('viridis', 'Greys', 'hot', ...).
    show_colorbar : bool
        Attach a colorbar showing the value→color mapping.
    add_grid : bool
        Draw thin dark borders around every cell.
    """
    arr = np.array(arr, dtype=float)
    n_rows, n_cols = arr.shape
    dpi = 100
 
    # ---- Figure size = grid pixels + optional colorbar space ----
    grid_w = n_cols * cell_px
    grid_h = n_rows * cell_px
    cbar_w = int(0.25 * cell_px) + 30 if show_colorbar else 0   # bar + padding
    fig_w = (grid_w + cbar_w) / dpi
    fig_h = grid_h / dpi
 
    fig, ax = plt.subplots(figsize=(fig_w, fig_h), dpi=dpi)
 
    # ---- Value → RGBA color via colormap ----
    vmin, vmax = arr.min(), arr.max()
    norm = plt.Normalize(vmin=vmin, vmax=vmax)
    cmap = cm.get_cmap(colormap)
 
    # ---- Draw one rectangle per cell ----
    for r in range(n_rows):
        for c in range(n_cols):
            color = cmap(norm(arr[r, c]))
            rect = Rectangle(
                (c * cell_px, r * cell_px),   # (x, y) in pixels
                cell_px, cell_px,
                facecolor=color,
                edgecolor='black' if add_grid else 'none',
                linewidth=0.8 if add_grid else 0,
            )
            ax.add_patch(rect)
 
    # ---- Canvas setup (pixel units, y pointing down) ----
    ax.set_xlim(0, grid_w)
    ax.set_ylim(grid_h, 0)                      # row 0 at the top
    ax.set_aspect('equal')
    ax.set_xticks([])
    ax.set_yticks([])
    ax.set_frame_on(False)
 
    # ---- Optional colorbar ----
    if show_colorbar:
        sm = cm.ScalarMappable(norm=norm, cmap=cmap)
        cb = fig.colorbar(sm, ax=ax, fraction=0.3, shrink=0.6, pad=0.08)
        cb.set_label('cell value')
 
    fig.savefig(output_filename, dpi=dpi, bbox_inches='tight', pad_inches=0.05)
    plt.close(fig)
    print(f"Saved: {output_filename}  ({grid_w}x{grid_h} px grid)")

2D konvoluce

  • Máme dvě matice $f$ (obrázek) a $g$ (funkce $g$ se v computer science nazývá “kernel” a má rozměry $M \times N$).
  • Konvoluce obrázku $f$ a kernelu $g$ se značí $(f*g)$. Jedná se o funkci dvou proměnných, které určují, na které pozici $(i,j)$ (řádek, sloupec) obrázku $f$ se konvoluce počítá. Konvoluce tedy je:

$$ (f * g)(i, j) = \sum_{m=0}^{M-1} \sum_{n=0}^{N-1} f(i + m,\, j + n) \cdot g(m, n) $$

  • Pro výpočet konvoluce na okrajích obrázku předpokládejme, že obrázek je obklopen hodnotou 0 (padding)
  • Naprogramujte funkci pro výpočet konvoluce na 2D matici.
  • Zkopírujte si následující program, který definuje obrázky číslic 0,1,…9

"""
obrazky cislic 0...9 ve formatu 7x5 (radky x sloupce).
1 predstavuje cerny pixel, 0 predstavuje bile pozadni
 
"""
 
Digit0 = [
    [0, 1, 1, 1, 0],
    [1, 0, 0, 0, 1],
    [1, 0, 0, 1, 1],
    [1, 0, 1, 0, 1],
    [1, 1, 0, 0, 1],
    [1, 0, 0, 0, 1],
    [0, 1, 1, 1, 0]
]
 
Digit1 = [
    [0, 0, 1, 0, 0],
    [0, 1, 1, 0, 0],
    [0, 0, 1, 0, 0],
    [0, 0, 1, 0, 0],
    [0, 0, 1, 0, 0],
    [0, 0, 1, 0, 0],
    [0, 1, 1, 1, 0]
]
 
Digit2 = [
    [0, 1, 1, 1, 0],
    [1, 0, 0, 0, 1],
    [0, 0, 0, 0, 1],
    [0, 0, 0, 1, 0],
    [0, 0, 1, 0, 0],
    [0, 1, 0, 0, 0],
    [1, 1, 1, 1, 1]
]
 
Digit3 = [
    [1, 1, 1, 1, 0],
    [0, 0, 0, 0, 1],
    [0, 0, 0, 0, 1],
    [0, 0, 1, 1, 0],
    [0, 0, 0, 0, 1],
    [0, 0, 0, 0, 1],
    [1, 1, 1, 1, 0]
]
 
Digit4 = [
    [0, 0, 0, 1, 0],
    [0, 0, 1, 1, 0],
    [0, 1, 0, 1, 0],
    [1, 0, 0, 1, 0],
    [1, 1, 1, 1, 1],
    [0, 0, 0, 1, 0],
    [0, 0, 0, 1, 0]
]
 
Digit5 = [
    [1, 1, 1, 1, 1],
    [1, 0, 0, 0, 0],
    [1, 1, 1, 1, 0],
    [0, 0, 0, 0, 1],
    [0, 0, 0, 0, 1],
    [1, 0, 0, 0, 1],
    [0, 1, 1, 1, 0]
]
 
Digit6 = [
    [0, 0, 1, 1, 0],
    [0, 1, 0, 0, 0],
    [1, 0, 0, 0, 0],
    [1, 1, 1, 1, 0],
    [1, 0, 0, 0, 1],
    [1, 0, 0, 0, 1],
    [0, 1, 1, 1, 0]
]
 
Digit7 = [
    [1, 1, 1, 1, 1],
    [0, 0, 0, 0, 1],
    [0, 0, 0, 1, 0],
    [0, 0, 1, 0, 0],
    [0, 0, 1, 0, 0],
    [0, 0, 1, 0, 0],
    [0, 0, 1, 0, 0]
]
 
Digit8 = [
    [0, 1, 1, 1, 0],
    [1, 0, 0, 0, 1],
    [1, 0, 0, 0, 1],
    [0, 1, 1, 1, 0],
    [1, 0, 0, 0, 1],
    [1, 0, 0, 0, 1],
    [0, 1, 1, 1, 0]
]
 
Digit9 = [
    [0, 1, 1, 1, 0],
    [1, 0, 0, 0, 1],
    [1, 0, 0, 0, 1],
    [0, 1, 1, 1, 1],
    [0, 0, 0, 0, 1],
    [0, 0, 0, 1, 0],
    [0, 1, 1, 0, 0]
]
 
DIGITS = [ Digit0, Digit1, Digit2, Digit3, Digit4, Digit5, Digit6, Digit7, Digit8, Digit9 ]

  • Následující pole představuje číslice vykreslené vedle sebe
  • Vykreslete si toto pole do souboru

img = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
[0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0], 
[0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1], 
[0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1], 
[0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1], 
[0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1], 
[0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], 
[0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0], 
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
 
array2png(img, "digits.png")

  • Takto vypadá pole img

  • Aplikujte 2D konvoluci s různými maskami na proměnnou img
  • Jako masky můžete použít proměnné Digit0 .. Digit9 z předchozího programu
  • Výsledek konvoluce si opět zobrazte do png souboru.
  • Čemu odpovídají vysoké hodnoty v matici?
  • Co se stane, když jako kernel použijete jednotkovou matici $3 \times 3$ nebo $7\times 7$?
courses/b3b33alp/cviceni/t06.txt · Last modified: 2026/07/28 16:03 by vonasvoj