8  Arbeiten mit Bildern

Bilder werden digital als Matrizen gespeichert. Dabei werden pro Pixel drei Farbwerte (rot, grün, blau) gespeichert. Aus diesen drei Farbwerten (Wertebereich 0-255) werden dann alle gewünschten Farben zusammengestellt.

Schaubild, das zeigt, dass ein hochaufgelöstes Bild der Mona Lisa aus einzelnen Pixeln besteht, welche wiederum aus den drei Farben Rot, Grün und Blau zusammengesetzt sind.
Abbildung 8.1: Ein hochaufgelöstes Bild besteht aus sehr vielen Pixeln. Jedes Pixel enthält 3 Farbwerte, einen für die Farbe Rot, einen für Grün und einen für Blau.

Aufgrund der digitalen Darstellung von Bildern lassen sich diese mit den Werkzeugen von NumPy leicht bearbeiten. Wir verwenden für folgendes Beispiel als Bild die Mona Lisa. Das Bild ist unter folgendem Link zu finden.

Importieren wir dieses Bild nun mit der Funktion imread() aus dem matplotlib-package, sehen wir, dass es sich um ein dreidimensionales NumPy-Array handelt.

import matplotlib.pyplot as plt

data = plt.imread("00-bilder/mona_lisa.jpg")
print("Form:", data.shape)
Form: (1024, 677, 3)

Schauen wir uns einmal mit der print()-Funktion diese Daten an.

print(data)
[[[ 68  62  38]
  [ 88  82  56]
  [ 92  87  55]
  ...
  [ 54  97  44]
  [ 68 110  60]
  [ 69 111  63]]

 [[ 65  59  33]
  [ 68  63  34]
  [ 83  78  46]
  ...
  [ 66 103  51]
  [ 66 103  52]
  [ 66 102  56]]

 [[ 97  90  62]
  [ 87  80  51]
  [ 78  72  38]
  ...
  [ 79 106  53]
  [ 62  89  38]
  [ 62  88  41]]

 ...

 [[ 25  14  18]
  [ 21  10  14]
  [ 20   9  13]
  ...
  [ 11   5   9]
  [ 11   5   9]
  [ 10   4   8]]

 [[ 23  12  16]
  [ 23  12  16]
  [ 21  10  14]
  ...
  [ 11   5   9]
  [ 11   5   9]
  [ 10   4   8]]

 [[ 22  11  15]
  [ 26  15  19]
  [ 24  13  17]
  ...
  [ 11   5   9]
  [ 10   4   8]
  [  9   3   7]]]

Mit der Funktion plt.imshow() kann das Bild in Echtfarben dargestellt werden. Dies funktioniert, da die Funktion die einzelnen Ebenen, hier der letzte Index des Datensatzes, als Farbinformationen (Rot, Grün, Blau) interpretiert. Wäre noch eine vierte Ebene dabei, würde sie als Transparenzwert verwendet worden.

plt.imshow(data)

Natürlich können auch die einzelnen Farbebenen individuell betrachtet werden. Dazu wird der letzte Index festgehalten. Hier betrachten wir nur den roten Anteil des Bildes. Stellen wir ein einfaches Array dar, werden die Daten mit der Standardfarbpalette ‘viridis’ ausgegeben. Mit Hilfe der Option cmap='Reds' können wir die Farbskala anpassen.

# Als Farbskala wird die Rotskala 
# verwendet 'Reds'
plt.imshow( data[:,:,0], cmap='Reds' )
plt.colorbar()
plt.show()

Da die Bilddaten als Arrays gespeichert sind, sind viele der möglichen Optionen, z. B. zur Teilauswahl oder Operationen, verfügbar. Das untere Beispiel zeigt einen Ausschnitt im Rotkanal des Bildes.

bereich = np.array(data[450:500, 550:600,0], dtype=float)
plt.imshow( bereich, cmap="Greys" )
plt.colorbar()

Betrachten wir nun eine komplexere Operation an Bilddaten, den Laplace-Operator. Er kann genutzt werden, um Ränder von Objekten zu identifizieren. Dazu wird für jeden Bildpunkt \(B_{i,j}\) – außer an den Rändern – folgender Wert \(\phi_{i, j}\) berechnet:

\[ \phi_{i, j} = \left|B_{i-1, j} + B_{i, j-1} - 4\cdot B_{i, j} + B_{i+1, j} + B_{i, j+1}\right| \]

Folgende Funktion implementiert diese Operation. Darüber hinaus werden alle Werte von \(\phi\) unterhalb eines Schwellwerts auf Null und oberhalb auf 255 gesetzt.

def img_lap(data, schwellwert=25):
    
    # Erstellung einer Kopie der Daten, nun jedoch als
    # Array mit Gleitkommazahlen
    bereich = np.array(data, dtype=float)
    
    # Aufteilung der obigen Gleichung in zwei Teile
    lapx = bereich[2:, :] - 2*bereich[1:-1, :] + bereich[:-2, :]
    lapy = bereich[:, 2:] - 2*bereich[:, 1:-1] + bereich[:, :-2]
    
    # Zusammenführung der Teile und Bildung des Betrags
    lap = np.abs(lapx[:,1:-1] + lapy[1:-1, :])
    
    # Schwellwertanalyse
    lap[lap > schwellwert] = 255
    lap[lap < schwellwert] = 0
    
    return lap

Betrachten wir ein Bild vom Haspel Campus in Wuppertal. Die Anwendung des Laplace-Operators auf den oberen Bildausschnitt ergibt folgende Ausgabe:

data = plt.imread('01-daten/campus_haspel.jpeg')
bereich = np.array(data[1320:1620, 400:700, 1], dtype=float)

lap = img_lap(bereich)

plt.figure(figsize=(9, 3))

ax = plt.subplot(1, 3, 1)
ax.imshow(data, cmap="Greys_r")

ax = plt.subplot(1, 3, 2)
ax.imshow(bereich, cmap="Greys_r");

ax = plt.subplot(1, 3, 3)
ax.imshow(lap, cmap="Greys");

Aus drei Teilgrafiken bestehendes Bild. Links ist ein Gebäude am Haspel Campus  Wuppertal, in der Mitte als Bildausschnitt ein Fenster und rechts die mit dem Laplace-Operator herausgestellte Kontur des Fensters dargestellt.

Wir können damit ganz klar die Formen des Fensters erkennen.

Wollen wir zum Beispiel eine Farbkomponente bearbeiten und dann das Bild wieder zusammensetzen, benötigen wir die Funktion np.dstack((rot, grün, blau)).astype('uint8'), wobei rot, grünund blau die jeweiligen 2D-Arrays sind. Versuchen wir nun, die grüne Farbe aus dem Baum links zu entfernen.

Wichtig ist, dass die Daten nach dem Zusammensetzen im Format uint8 vorliegen, deswegen die Methode .astype('uint8').

data = plt.imread('01-daten/campus_haspel.jpeg')

# Speichern der einzelnen Farben in Arrays
rot = np.array(data[:, :, 0], dtype=float)
gruen = np.array(data[:, :, 1], dtype=float)
blau = np.array(data[:, :, 2], dtype=float)

# Setzen wir den Bereich des linken Baumes im Array auf 0
gruen_neu = gruen.copy()
gruen_neu[800:2000, 700:1700] = 0

zusammengesetzt = np.dstack((rot, gruen_neu, blau)).astype('uint8')

plt.figure(figsize=(8, 5))

ax = plt.subplot(1, 2, 1)
ax.imshow(data, cmap="Greys_r")

ax = plt.subplot(1, 2, 2)
ax.imshow(zusammengesetzt)

Links: Gebäude am Haspel Campus  Wuppertal. Rechts: Gebäude am Haspel Campus  Wuppertal mit manipuliertem Baum.

Lesen Sie folgendes Bild vom Haspel Campus in Wuppertal ein: Bild.

Extrahieren Sie den blauen Anteil und lassen Sie sich die Zeile in der Mitte des Bildes sowie einen beliebigen Bildauschnitt ausgeben.

import numpy as np
import matplotlib.pyplot as plt

data = plt.imread('01-daten/campus_haspel.jpeg')

form =  data.shape
print( "Form:", data.shape )

blau =  data[:,:,2]
plt.imshow(blau, cmap='Blues')

zeile =  data[int(form[0]/2),:,2]
print(zeile)

ausschnitt =  data[10:50,10:50,:]
plt.imshow(ausschnitt)
Form: (3024, 4032, 3)
[221 220 220 ...  28  28  28]