Updates dieser Seite:

  • 20.03.2022: v1 neues Semester

In diesem Kapitel lernen wir einen Weg, um Bilder in Python auf Pixelebene zu verarbeiten, so dass wir z.B. Konvolutionen ausprobieren können.

1 Bild laden und zeigen

Wir verwenden hier die Python-Bibliothek Pillow, um Bilder zu speichern und zu verarbeiten. Pillow ist das Nachfolgeprojekt der Python Image Library (PIL). Es wird aber immer noch die Abkürzung PIL im Code verwendet.

Siehe auch:

Um ein Bild aus dem Internet zu beziehen, benötigen wir außerdem BytesIO und requests.

Wir wandeln die Daten gleich in einem NumPy-Array um, damit wir damit in Keras arbeiten können. Sie sehen, dass es sich um ein Bild der Größe 600x450 mit 3 Kanälen (R, G, B) handelt.

In [1]:
from PIL import Image
from io import BytesIO
import numpy as np
import requests

url = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Edward_Snowden_2013-10-9_%281%29_%28cropped%29.jpg/450px-Edward_Snowden_2013-10-9_%281%29_%28cropped%29.jpg"
response = requests.get(url)
img = Image.open(BytesIO(response.content))
img.load

idat = np.asarray(img)

print("Shape:", idat.shape)
idat[:2]# Testausgabe
Shape: (600, 450, 3)
Out[1]:
array([[[214, 154, 118],
        [216, 156, 120],
        [217, 157, 121],
        ...,
        [200, 139, 111],
        [201, 140, 112],
        [201, 140, 112]],

       [[217, 157, 121],
        [217, 157, 121],
        [217, 157, 121],
        ...,
        [200, 139, 111],
        [201, 140, 112],
        [201, 140, 112]]], dtype=uint8)

Wir schauen uns das Image-Objekt an.

In [2]:
print(img)
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=450x600 at 0x7FE5734B93D0>
In [3]:
img.mode
Out[3]:
'RGB'
In [4]:
img.size
Out[4]:
(450, 600)

Im Package matplotlib gibt es die Funktion imshow (image show), um Bilder darzustellen.

In [5]:
from matplotlib.pyplot import imshow

imshow(img)
Bad key "text.kerning_factor" on line 4 in
/Users/kipp/anaconda3/envs/nndl/lib/python3.7/site-packages/matplotlib/mpl-data/stylelib/_classic_test_patch.mplstyle.
You probably need to get an updated matplotlibrc file from
https://github.com/matplotlib/matplotlib/blob/v3.1.3/matplotlibrc.template
or from the matplotlib source distribution
Out[5]:
<matplotlib.image.AxesImage at 0x7fe574554a10>

Tatsächlich kann man das auch so ausgeben:

In [6]:
img
Out[6]:

2 Bildmanipulation

2.1 Manipulation auf Pixelebene

Unsere RGB-Daten liegen als 3-dimensionaler Tensor vor. Wenn wir z.B. die Position (0, 0) betrachten, bekommen wir die drei Farbkanäle (RGB):

In [7]:
idat[0,0]
Out[7]:
array([214, 154, 118], dtype=uint8)

Bilder verändern

Um die rote Farbe zu löschen, können wir einfach die erste Zahl auf Null setzen.

Um ein Graustufenbild zu bekommen, können wir z.B. den Durchschnitt der drei Zahlen bilden:

In [8]:
idat[0,0].mean()
Out[8]:
162.0

Wir möchten jetzt neue Varianten herstellen. Für unser Bild ohne Rot kopieren wir einfach den NumPy-Array:

In [9]:
idat_noR = np.copy(idat)

Für unser Graustufenbild brauchen wir einen Tensor, der nur 2-dimensional ist. Wir stellen also einen Nulltensor mit den Dimensionen des Originalbilds her (600 x 450).

In [10]:
idat_grey = np.zeros((idat.shape[0], idat.shape[1]))

Jetzt durchlaufen wir alle Pixel des Originals und befüllen unsere beiden neuen Arrays:

In [11]:
for i in range(idat.shape[0]):
    for j in range(idat.shape[1]):
        idat_noR[i,j,0] = 0.0
        idat_grey[i,j] = idat[i,j].mean()

Mit Pillow erzeugen wir aus den Arrays entsprechende Bildobjekte:

In [12]:
img_noR = Image.fromarray(idat_noR, 'RGB')
img_grey = Image.fromarray(idat_grey)

Kontrolle

Wir schauen uns das mit imshow an. Zunächst das Graustufenbild:

In [13]:
imshow(img_grey)
Out[13]:
<matplotlib.image.AxesImage at 0x7fe574548ed0>

Jetzt das Bild, wo wir den Rotwert auf Null gesetzt hatten.

In [14]:
imshow(img_noR)
Out[14]:
<matplotlib.image.AxesImage at 0x7fe575040550>

2.2 Standardoperationen

Natürlich müssen Sie immer wieder mal die Bildgröße ändern oder das Bild zuschneiden. Man findet solche Standardoperationen unter https://pillow.readthedocs.io/en/5.3.x/reference/Image.html

Wir schauen uns die beiden erwähnten Operationen jetzt an.

Größe ändern

In [15]:
img_small = img.resize((int(img.size[0]/2), int(img.size[1]/2)))

Man sieht den Größenunterschied bei dieser Ausgabe lediglich an den Achsenbeschriftungen.

In [16]:
imshow(img_small)
Out[16]:
<matplotlib.image.AxesImage at 0x7fe57526cd50>