Wykład 13, cz. 2 - obrazy i numpy¶

UWAGA: jeśli wczytywanie obrazów w notatniku sprawia problemy, można zastąpić https przez http w url obrazu.

Cel: reprezentacja obrazów jako tablice numpy i prosta manipulacja obrazami (jednocześnie jako tutorial operacji tablicowych numpy oraz prostych "niskopoziomowych" technik obróbki grafiki).

In [1]:
import matplotlib.pyplot as plt
import numpy as np
In [2]:
%matplotlib inline

Obrazki monochromatyczne, "ręcznie": tablice numpy $h \times w$ (wysokość na szerokość) z informacją o jasności piksela:

Reprezentacja obrazów jako tablica floatów z przedziału $[0,1]$¶

In [3]:
image = np.array([[1, 0.5, 1],
                  [0.5, 1, 0]])
In [4]:
plt.imshow(image)
plt.show()
In [5]:
plt.imshow(image, cmap="gray", vmin=0, vmax=1)
plt.show()
In [6]:
image = np.random.random(size=(100, 100))
plt.imshow(image, cmap="gray", vmin=0, vmax=1)
plt.show()

Jako tablica liczb całkowitych 0-255:¶

np.uint8 - unsigned 8-bit integer, liczba 8-bitowa bez znaku ($2^8 = 256$ możliwości, przy braku znaku daje to zakres wartości $0$-$255$).

In [7]:
image = np.array([[255, 128, 255],
                  [128, 255, 0]], dtype=np.uint8)
In [8]:
plt.imshow(image)
plt.show()
In [9]:
image = np.array([[255, 128, 255],
                  [128, 255, 255]], dtype=np.uint8)
plt.imshow(image, vmin=0, vmax=255)
plt.show()

Obrazy kolorowe: tablica $h \times w \times 3$ dla kanałów red, green, blue:

In [10]:
r = np.array([[255, 128, 255],
              [128, 255, 255]], dtype=np.uint8)
g = np.array([[0, 64, 80],
              [0, 0, 255]], dtype=np.uint8)
b = np.array([[0, 255, 64],
              [0, 255, 128]], dtype=np.uint8)
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
axes[0].set_title("red")
axes[0].imshow(r, vmin=0, vmax=255, cmap="gray")
axes[1].set_title("green")
axes[1].imshow(g, vmin=0, vmax=255, cmap="gray")
axes[2].set_title("blue")
axes[2].imshow(b, vmin=0, vmax=255, cmap="gray")
plt.show()
In [11]:
image = np.stack((r,g,b), axis=2) # ułożenie w stos względem osi 2 ("głębokości")
In [12]:
image.shape
Out[12]:
(2, 3, 3)
In [13]:
plt.imshow(image)
plt.show()
In [14]:
image = np.random.randint(0, 255, size=(100, 100, 3))
plt.imshow(image)
plt.show()

Automatyczna normalizacja kolorów:

In [15]:
image = np.random.randint(128, 255, size=(100, 100, 3))
plt.imshow(image)
plt.show()

Podobnie dla floatów:

In [16]:
image = np.random.uniform(0, 1, size=(100, 100, 3))
plt.imshow(image)
plt.show()
In [17]:
image = np.random.uniform(0.5, 1, size=(100, 100, 3))
plt.imshow(image)
plt.show()

Wczytywanie (i zapisywanie obrazów): szereg "standardowych" bibliotek, np. imageio, pillow.

pip install imageio
In [18]:
import imageio

mode="L" dla trybu monochromatycznego:

In [19]:
image = imageio.v2.imread("https://math.uni.wroc.pl/~jagiella/files/p1python/cats.jpg", mode="L")
In [20]:
type(image)
Out[20]:
numpy.ndarray
In [21]:
image.shape
Out[21]:
(361, 557)
In [22]:
image.dtype
Out[22]:
dtype('uint8')
In [23]:
image
Out[23]:
array([[224, 223, 221, ..., 212, 215, 216],
       [222, 228, 225, ..., 217, 209, 208],
       [226, 226, 220, ..., 214, 215, 212],
       ...,
       [161, 169, 171, ..., 172, 167, 162],
       [170, 165, 167, ..., 139, 167, 159],
       [171, 169, 167, ..., 161, 168, 167]], dtype=uint8)
In [24]:
plt.imshow(image, vmin=0, vmax=255, cmap="gray")
plt.show()

W kolorach:

In [25]:
image = imageio.v2.imread("https://math.uni.wroc.pl/~jagiella/files/p1python/cats.jpg")
In [26]:
image.shape
Out[26]:
(361, 557, 3)
In [27]:
image.dtype
Out[27]:
dtype('uint8')
In [28]:
plt.imshow(image)
plt.show()

Manipulacja obrazami "na surowo" w numpy:

Pojedyncza składowe:

In [29]:
r = image[:, :, 0]
g = image[:, :, 1]
b = image[:, :, 2]
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
axes[0].set_title("red")
axes[0].imshow(r, vmin=0, vmax=255, cmap="gray")
axes[1].set_title("green")
axes[1].imshow(g, vmin=0, vmax=255, cmap="gray")
axes[2].set_title("blue")
axes[2].imshow(b, vmin=0, vmax=255, cmap="gray")
plt.show()
In [30]:
red_only = image.copy()
red_only[:,:,1:] = 0
In [31]:
red_only
Out[31]:
array([[[238,   0,   0],
        [237,   0,   0],
        [234,   0,   0],
        ...,
        [225,   0,   0],
        [228,   0,   0],
        [229,   0,   0]],

       [[236,   0,   0],
        [242,   0,   0],
        [238,   0,   0],
        ...,
        [230,   0,   0],
        [222,   0,   0],
        [221,   0,   0]],

       [[240,   0,   0],
        [239,   0,   0],
        [233,   0,   0],
        ...,
        [227,   0,   0],
        [228,   0,   0],
        [225,   0,   0]],

       ...,

       [[186,   0,   0],
        [194,   0,   0],
        [196,   0,   0],
        ...,
        [197,   0,   0],
        [192,   0,   0],
        [189,   0,   0]],

       [[194,   0,   0],
        [189,   0,   0],
        [192,   0,   0],
        ...,
        [167,   0,   0],
        [195,   0,   0],
        [187,   0,   0]],

       [[196,   0,   0],
        [194,   0,   0],
        [192,   0,   0],
        ...,
        [186,   0,   0],
        [193,   0,   0],
        [192,   0,   0]]], dtype=uint8)
In [32]:
plt.imshow(red_only)
plt.show()
In [33]:
green_only = image.copy()
green_only[:,:,[0, 2]] = 0
plt.imshow(green_only)
plt.show()
In [34]:
blue_only = image.copy()
blue_only[:,:,:2] = 0
plt.imshow(blue_only)
plt.show()

Wycinki, manipulacja obrazami¶

In [35]:
cat_head = image[40:150, 70:180, :]
plt.imshow(cat_head)
plt.show()
In [36]:
cat_head[:, :, 0] = 0
plt.imshow(cat_head)
plt.show()
In [37]:
plt.imshow(image)
plt.show()
In [38]:
image = imageio.v2.imread("https://math.uni.wroc.pl/~jagiella/files/p1python/cats.jpg")
In [39]:
rcat = image[100:350, 300:480, :]
plt.imshow(rcat)
plt.show()
In [40]:
image[100:350, 100:280] = rcat
plt.imshow(image)
plt.show()
In [41]:
image = imageio.v2.imread("https://math.uni.wroc.pl/~jagiella/files/p1python/cats.jpg")
In [42]:
image[100:350, 100:280, 0] = rcat[:, :, 1]
plt.imshow(image)
plt.show()
In [43]:
image = imageio.v2.imread("https://math.uni.wroc.pl/~jagiella/files/p1python/cats.jpg")
In [44]:
image[100:350, 280:100:-1] = rcat
plt.imshow(image)
plt.show()

Permutacja składowych:

In [45]:
np.array([0, 10, 20, 30, 40, 50])[[2, 3, 1]] # przykład indeksowania ciągiem indeksów
Out[45]:
array([20, 30, 10])
In [46]:
image = imageio.v2.imread("https://math.uni.wroc.pl/~jagiella/files/p1python/cats.jpg")
image = image[:, :, [2, 1, 0]]
In [47]:
plt.imshow(image)
plt.show()

Negatyw¶

In [48]:
image = imageio.v2.imread("https://math.uni.wroc.pl/~jagiella/files/p1python/cats.jpg")
image = 255 - image
In [49]:
plt.imshow(image)
plt.show()

Zmiana na float (bez normalizacji)¶

In [50]:
image = imageio.v2.imread("https://math.uni.wroc.pl/~jagiella/files/p1python/cats.jpg")
image = image / 255
plt.imshow(image)
plt.show()

"Naiwna" zmiana jasności:

In [51]:
plt.imshow(image / 2)
plt.show()
In [52]:
plt.imshow(0.5 + image / 2)
plt.show()

Korekta gamma:

Dla $\gamma > 0$ zmieniamy natężenie piksela (lub natężenie kanału piksela) zgodnie z przekształceniem $x \mapsto x^\gamma$.

In [53]:
image = imageio.v2.imread("https://math.uni.wroc.pl/~jagiella/files/p1python/cats.jpg")
image = image / 255
In [54]:
fig, axes = plt.subplots(2, 2)

for ax, gamma in zip(axes.ravel(), [0.5, 1, 1.5, 2]):
    ax.set_title(f"$\gamma = {gamma}$")
    ax.imshow(image ** gamma)
plt.tight_layout()

Maskowanie¶

In [55]:
image = imageio.v2.imread("https://math.uni.wroc.pl/~jagiella/files/p1python/cats.jpg", mode="L") / 255 # monochromatyczny
In [56]:
dark_parts = image < 0.5
In [57]:
dark_parts
Out[57]:
array([[False, False, False, ..., False, False, False],
       [False, False, False, ..., False, False, False],
       [False, False, False, ..., False, False, False],
       ...,
       [False, False, False, ..., False, False, False],
       [False, False, False, ..., False, False, False],
       [False, False, False, ..., False, False, False]])
In [58]:
plt.imshow(dark_parts)
plt.show()
In [59]:
image[dark_parts] = 0
In [60]:
plt.imshow(image, cmap="gray", vmin=0, vmax=1)
plt.show()
In [61]:
light_parts = image > 0.8
image[light_parts] = 1
plt.imshow(image, cmap="gray", vmin=0, vmax=1)
plt.show()
In [62]:
image = imageio.v2.imread("https://math.uni.wroc.pl/~jagiella/files/p1python/cats.jpg") / 255
image[image < 0.5] = 0
plt.imshow(image)
plt.show()