Initial commit with project files

This commit is contained in:
2025-06-27 14:34:11 +02:00
commit 7ea3207e63
310 changed files with 9331 additions and 0 deletions

17
1_Grundlagen/README.md Normal file
View File

@@ -0,0 +1,17 @@
# Grundlagen
Um mit Methoden der Digitalen Bildverarbeitung zu arbeiten, lohnt sich ein Blick auf die Grundlagen.
Das Unterverzeichnis *1_Grundlagen* bietet Aufgaben zum Themengebiet "Grundlagen" in der Vorlesung.
Dabei sollen ins besondere die Themen
- **Das menschliche visuelle System**
- **Technische Bilderfassung/Sensoren**
- **Das Digitale Bild**
mit zusätzlichem Material unterstützt werden.

8
1_Grundlagen/todos.md Normal file
View File

@@ -0,0 +1,8 @@
# Zu erstellende Übungen
- ~~Luminanz vs. Chrominanz~~
- Machsches Gesetz
- ~~Visualisierung von Rauschen in der Kamera~~
- ~~Rolling Shutter vs. Global Shutter~~
- ~~Quantisierung eines Bildes: Wann erkennt man nichts mehr?~~
<img src="https://latex.codecogs.com/svg.image?\sum_1" title="\sum_1" />

View File

@@ -0,0 +1,21 @@
# Übung 1: Rauschen
In der Vorlesung wurden Ihnen einige Bildsensoren vorgestellt. In dieser Übung sollen Sie Ihren eigenen Bildsensor verwenden:
Ihre Webcam. In dieser Übung sollen Sie erlernen, wie Sie mit OpenCV eine Kamera öffnen und das Bild anzeigen.
Daraufhin werden Sie ein technisches Problem bei der Aufnahme von Bilddaten kennenlernen: Das Rauschen.
## Aufgabe a)
Implementieren Sie in die Datei [a.py](a.py) folgende Schritte:
1. Öffnen Sie Ihre Webcam
2. Schneiden Sie ein Bildausschnitt mit 50x50 Pixels aus dem Bild aus
3. Zeigen Sie den Bildausschnitt auf den ganzen Bildschirm vergrößert an
Recherchieren Sie im Internet und/oder im Einführungskapitel nach den Funktionen `cv2.VideoCapture()`, `cv2.resize()`
und `cv2.imshow()`. Eine Musterlösung finden Sie in der Datei [l_a.py](l_a.py).
Versuchen Sie den Inhalt vor der Kamera konstant zu halten.
## Fragen:
- Bleibt das Bild konstant oder sehen Sie Rauschen?
- Wenn nein: Worin kann das Rauschen begründet liegen?
- Wozu kann das Rauschen führen?

18
1_Grundlagen/ü1/l_a.py Normal file
View File

@@ -0,0 +1,18 @@
import cv2
''' Öffnen einer Kamera '''
cap = cv2.VideoCapture(0)
cv2.namedWindow("Ergebnis", cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty("Ergebnis", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
''' Auslesen, Modifizieren und Ausgeben von Bildern'''
while True:
ret, frame = cap.read()
frame = frame[0:50, 0:50]
cv2.imshow('Ergebnis', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
''' Fenster schließen, nachdem q gedrückt wurde'''''
cap.release()
cv2.destroyAllWindows()

View File

@@ -0,0 +1,10 @@
# Übung 2: Luminanz vs. Chrominanz
Was glauben Sie: Hat die Farbinformation oder die Helligkeitsinformation eine höhere Interpretierbarkeit für den Menschen?
Programmieren Sie ein Skript, mit dem sie Ihre Webcam auslesen, modifizieren und ausgeben. Entfernen Sie die Helligkeitsinformation
bzw. Farbinformation und betrachten das Ergebnis. Wird Ihre initiale Einschätzung bestätigt? Schreiben Sie Ihr Skript in
die Datei [a.py](a.py). Die Lösung ist in der Datei [l_a.py](l_a.py) zu finden!
**Hinweis:** Verwenden Sie in Bild Ihrer Wahl, wenn keine Webcam zur Verfügung steht.

26
1_Grundlagen/ü2/a.py Normal file
View File

@@ -0,0 +1,26 @@
import cv2
import numpy as np
''' Öffnen einer Kamera und Initialisierung von Variablen '''
cap = cv2.VideoCapture(0)
mode = "CHROMINANZ" # CHROMINANZ, LUMINANZ
window_name = "Ergebnis mit %s" % mode
''' Auslesen, Modifizieren und Ausgeben von Bildern'''
while True:
ret, frame = cap.read()
if mode == "CHROMINANZ":
frame = ...
elif mode == "LUMINANZ":
frame = ...
else:
raise Exception("FALSCHER MODE!!!")
cv2.imshow(window_name, frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
''' Fenster schließen, nachdem q gedrückt wurde '''
cap.release()
cv2.destroyAllWindows()

31
1_Grundlagen/ü2/l_a.py Normal file
View File

@@ -0,0 +1,31 @@
import cv2
import numpy as np
''' Öffnen einer Kamera und Initialisierung von Variablen '''
cap = cv2.VideoCapture(0)
mode = "RGB" # CHROMINANZ, LUMINANZ
window_name = "Ergebnis mit %s" % mode
''' Auslesen, Modifizieren und Ausgeben von Bildern'''
while True:
ret, frame = cap.read()
if mode == "LUMINANZ":
# Farbinformationen entfernen
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
elif mode == "CHROMINANZ":
# Normalisieren: p_r / (p_r + p_g + p_b), p_g / (p_r + p_g + p_b), p_b / (p_r + p_g + p_b)
pixel_sum = np.sum(frame, keepdims=True, axis=2)
frame = frame.astype(np.float32) / pixel_sum
elif mode == "RGB":
pass
else:
raise Exception("FALSCHER MODE!!!")
cv2.imshow(window_name, frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
''' Fenster schließen, nachdem q gedrückt wurde'''''
cap.release()
cv2.destroyAllWindows()

View File

@@ -0,0 +1,36 @@
# Übung 3: Diskretisierung und Quantisierung
In dieser Übung wird die Quantisierung und Diskretisierung von Bildern betrachtet. In den folgenden Abbildungen sind beide
Methoden visualisiert.
Quantisierung | Diskretisierung
:---:|:---
![](https://upload.wikimedia.org/wikipedia/commons/thumb/7/70/Quantized.signal.svg/2880px-Quantized.signal.svg.png) | ![](https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/Zeroorderhold.signal.svg/2880px-Zeroorderhold.signal.svg.png)
[Link zum Bild](https://upload.wikimedia.org/wikipedia/commons/thumb/7/70/Quantized.signal.svg/2880px-Quantized.signal.svg.png) | [Link zum Bild](https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/Zeroorderhold.signal.svg/2880px-Zeroorderhold.signal.svg.png)
## Aufgabe a) Diskretisierung
In der Datei [a.py](a.py) wird ein Bild geladen. Das Bild hat die Größe 1526 x 1600 (Breite x Höhe).
Diskretisieren Sie das Bild mit dem Faktor *k* **ohne** und **mit** Verwendung der Funktion `cv2.resize()`. Dabei kann
*k* die Werte 4, 8, und 13.5 annehmen. Zeigen Sie die Bilder für den direkten Vergleich an! Achten Sie dabei darauf,
dass die Bilder in der gleichen Größe dargestellt werden.
## Aufgabe b) Quantisierung
In der Datei [b.py](b.py) wird ein Bild geladen. Das Bild ist im BGR-Farbraum repräsentiert und hat eine 8-Bit Quantisierung
(Wertebereich {0, ..., 255}.
Führen Sie folgende Schritte durch:
1. Quantisieren Sie das Bild in den Wertebereich {0, ..., 127}
2. Quantisieren Sie das Bild aus Schritt 1 in den Wertebereich {0, ..., 3}
3. Quantisieren Sie das Bild aus Schritt 2 zurück in den Wertebereich {0, ..., 255}
Zeigen Sie die Bilder aus allen Schritten für den direkten Vergleich an:
- Wie bewerten Sie die Qualität der Bilder?
- Was fällt auf?

22
1_Grundlagen/ü3/a.py Normal file
View File

@@ -0,0 +1,22 @@
import numpy as np
import cv2
# Hiermit kann die Methode für die Berechnung ausgewählt werden
METHOD = "MANUELL" # OpenCV
# Einlesen des Bildes
filepath = "../../data/flower.jpeg"
img = cv2.imread(filepath)
h, w, c = img.shape
print("Originale Breite:", w)
print("Originale Höhe:", h)
scales = [4, 8, 13.5]
images = []
# todo Methode MANUELL implementieren und 'images' mit diskretisierten Bildern füllen
# todo Methode OpenCV implementieren und 'images' mit diskretisierten Bildern füllen
# todo Bilder darstellen

13
1_Grundlagen/ü3/b.py Normal file
View File

@@ -0,0 +1,13 @@
import numpy as np
import cv2
# Hiermit kann die Methode für die Berechnung ausgewählt werden
METHOD = "MANUELL" # OpenCV
# Einlesen des Bildes
filepath = "../../data/lena.png"
img = cv2.imread(filepath)
h, w, c = img.shape
# todo Schritte 1-3 implementieren!

46
1_Grundlagen/ü3/l_a.py Normal file
View File

@@ -0,0 +1,46 @@
import numpy as np
import cv2
# Hiermit kann die Methode für die Berechnung ausgewählt werden
METHOD = "MANUELL" # OpenCV, MANUELL
# Einlesen des Bildes
filepath = "../../data/flower.jpeg"
img = cv2.imread(filepath)
h, w, c = img.shape
print("Originale Breite:", w)
print("Originale Höhe:", h)
scales = [4, 8, 13.5]
images = []
for scale in scales:
new_w, new_h = round(w / scale), round(h / scale)
if METHOD == "OpenCV":
new_image = cv2.resize(img, (new_w, new_h))
# Frage 1: Welche Interpolations-Methode wird hier verwendet?
elif METHOD == "MANUELL":
new_image = np.zeros((new_h, new_w, c), dtype=np.uint8)
for x in range(new_w):
for y in range(new_h):
x_projected, y_projected = min(w - 1, round(x * scale)), min(h - 1, round(y * scale))
new_image[y, x] = img[y_projected, x_projected]
# Frage 1: Welche Interpolations-Methode wird hier verwendet?
# Frage 2: Welches Mapping wird hier verwendet (For- oder Backwardmapping)?
else:
raise Exception("Da ist wohl ein Fehler unterlaufen!")
images.append(new_image)
# Bilder darstellen
show_w, show_h = 1200, 1200
img = cv2.resize(img, (show_w, show_h))
cv2.imshow("Original", img)
for scale, image in zip(scales, images):
image = cv2.resize(image, (show_w, show_h))
cv2.imshow("Scale %s" % scale, image)
cv2.waitKey(0)

36
1_Grundlagen/ü3/l_b.py Normal file
View File

@@ -0,0 +1,36 @@
import numpy as np
import cv2
# Einlesen des Bildes
filepath = "../../data/lena.png"
img = cv2.imread(filepath)
'''
Anwendung der Schritte:
0. Für die Berechnung werden die Bilder in das kontinuierliche np.float64 konvertiert.
1. In Wertebereich {0, ..., 127}
2. In Wertebereich {0, ..., 3}
3. In Wertebereich {0, ..., 255}
'''
img_step0 = img.astype(np.float64)
img_step1 = np.round(127 * np.copy(img_step0) / 255)
img_step2 = np.round(3 * np.copy(img_step1) / 127)
img_step3 = np.round(255 * np.copy(img_step2) / 3)
'''
Für die Darstellung von np.float64 Bildern wird der Wertebereich von {0, ..., n_max} in [0, 1] projeziert.
Dabei entspricht der Wert 1 dem ehemaligen Maximum n_max.
'''
img_step0 = img_step0 / 255
img_step1 = img_step1 / 127
img_step2 = img_step2 / 3
img_step3 = img_step3 / 255
cv2.imshow("Schritt 0", img_step0)
cv2.imshow("Schritt 1", img_step1)
cv2.imshow("Schritt 2", img_step2)
cv2.imshow("Schritt 3", img_step3)
cv2.waitKey(0)

View File

@@ -0,0 +1,36 @@
# Übung 4: Aliasing
In dieser Übung wird das *Aliasing* betrachtet. Der Effekt des *Aliasing* entsteht,
wenn eine Struktur mit einer zu geringen Rate abgetastet wird. Als Beispiel wird das Bild
![](./data/Mauer.png)
verwendet. Programmieren Sie ein Skript, mit dem das Bild eingelesen und mit den Faktoren 2, 4 und 10 skaliert wird.
Zeigen Sie sich die Bilder an. Verwenden Sie während der Skalierung die Nearest-Neighbour Interpolation!
Schreiben Sie Ihr Skript in die Datei [a.py](a.py). Die Lösung ist in der Datei [l_a.py](l_a.py) zu finden!
Was fällt Ihnen bei der Betrachtung der Bilder auf?
## Technische Beschreibung des Phänomens
Das Aliasing entsteht durch die Unterabtastung eines Signals. Um ein Signal korrekt darstellen zu können, muss das
[Nyquist-Shannon-Abtasttheorem](https://de.wikipedia.org/wiki/Nyquist-Shannon-Abtasttheorem) beachtet werden.
Die Kreisfrequenz der Abtastung <img src="https://latex.codecogs.com/svg.image?\Omega_T" title="\sum_1" />
muss demnach
<p align="center">
<img src="https://latex.codecogs.com/svg.image?\Omega_T>2\Omega_g" title="\sum_1" />
<p>
beziehungsweise die Abtastfrequenz <img src="https://latex.codecogs.com/svg.image?f_T" title="\sum_1" /> muss
<p align="center">
<img src="https://latex.codecogs.com/svg.image?f_T>2f_g" title="\sum_1" />
<p>
mit der maximalen Kreisfrequenz <img src="https://latex.codecogs.com/svg.image?\Omega_g" title="\sum_1" /> bzw.
maximalen Frequenz <img src="https://latex.codecogs.com/svg.image?f_g" title="\sum_1" /> des Signals sein.

7
1_Grundlagen/ü4/a.py Normal file
View File

@@ -0,0 +1,7 @@
import cv2
''' Öffnen einer Kamera und Initialisierung von Variablen '''
img = cv2.imread("./data/Mauer.png")
cv2.imshow("Original", img)
cv2.waitKey(0)

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

19
1_Grundlagen/ü4/l_a.py Normal file
View File

@@ -0,0 +1,19 @@
import cv2
''' Öffnen einer Kamera und Initialisierung von Variablen '''
img = cv2.imread("./data/Mauer.png")
cv2.imshow("Original", img)
downscaled2 = cv2.resize(img, dsize=None, fx=0.5, fy=0.5, interpolation=cv2.INTER_NEAREST)
downscaled2_original_size = cv2.resize(downscaled2, dsize=None, fx=2, fy=2, interpolation=cv2.INTER_NEAREST)
cv2.imshow("Abgetastet mit Faktor 2", downscaled2_original_size)
downscaled4 = cv2.resize(img, dsize=None, fx=0.25, fy=0.25, interpolation=cv2.INTER_NEAREST)
downscaled4_original_size = cv2.resize(downscaled4, dsize=None, fx=4, fy=4, interpolation=cv2.INTER_NEAREST)
cv2.imshow("Abgetastet mit Faktor 4", downscaled4_original_size)
downscaled10 = cv2.resize(img, dsize=None, fx=0.1, fy=0.1, interpolation=cv2.INTER_NEAREST)
downscaled10_original_size = cv2.resize(downscaled10, dsize=None, fx=10, fy=10, interpolation=cv2.INTER_NEAREST)
cv2.imshow("Abgetastet mit Faktor 10", downscaled10_original_size)
cv2.waitKey(0)

View File

@@ -0,0 +1,31 @@
# Übung 5: Global- und Rolling-Shutter
In dieser Übung werden zwei Typen von Bildsensoren betrachtet: Sensoren mit Global- und Rolling-Shutter Auslesefunktion.
Der Unterschied während des Auslesens bezieht sich auf die zeitliche Anordnung der Belichtung der einzelnen Halbleiter
innerhalb des Sensors. Ein Halbleiter entspricht dabei einem einem Bildpunkt. Beim Global-Shutter werden alle Halbleiter
gleichzeitig belichtet. Beim Rolling-Shutter werden die einzelnen Zeilen des Sensors sequenziell belichtet.
Der Schematische Ablauf eines Global-Shutter Sensors ist in dem folgenden Bild dargestellt:
![](data/global_shutter.png)
Der Schematische Ablauf eines Rolling-Shutter Sensors hingegen sieht wie folgt aus:
![](data/rolling_shutter.png)
## Vor- und Nachteile Rolling-/Global-Shutter
Vorteile Rolling-Shutter gegenüber Global-Shutter:
- Preisgünstiger
- Längere Belichtungszeit möglich (weniger Rauschen)
Nachteile Rolling-Shutter gegenüber Global-Shutter:
- Bewegungsverzerrung
## a) Bewegungsverzerrung
In dieser Aufgabe soll die Bewegungsverzerrung eines Rolling-Shutter Sensors künstlich erzeugt werden. In dem Skript
[a.py](a.py) werden drei Bilder aus dem [KITTI](http://www.cvlibs.net/datasets/kitti/) aus einem fahrenden Auto geladen.
Ihre Aufgabe ist die Simulation eines Rolling-Shutter Sensors, indem Sie ein resultierendes Bild aus den drei
Zeitpunkten des Videos konstruieren. Konstruieren Sie ein Bild, indem Sie die Zeile 1, 4, 7 ... aus dem ersten Bild,
Zeile 2, 5, 8 ... sowie die Zeilen 3, 6, 9, ... aus dem dritten Bild verwenden. Visualisieren Sie das Bild.
. Die Lösung ist in der Datei [l_a.py](l_a.py) zu finden!

10
1_Grundlagen/ü5/a.py Normal file
View File

@@ -0,0 +1,10 @@
import cv2
""" Read images """
img1 = cv2.imread("data/kitti1.png")
img2 = cv2.imread("data/kitti2.png")
img3 = cv2.imread("data/kitti3.png")
cv2.imshow("Global-Shutter", img3)
cv2.waitKey(0)

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

16
1_Grundlagen/ü5/l_a.py Normal file
View File

@@ -0,0 +1,16 @@
import cv2
""" Read images """
img1 = cv2.imread("data/kitti1.png")
img2 = cv2.imread("data/kitti2.png")
img3 = cv2.imread("data/kitti3.png")
cv2.imshow("Global-Shutter", img3)
""" Simulate rolling shutter"""
img3[0::3, :, :] = img1[0::3, :, :]
img3[1::3, :, :] = img2[1::3, :, :]
cv2.imshow("Rolling-Shutter", img3)
cv2.waitKey(0)