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

View File

@@ -0,0 +1,15 @@
# Signalorientierte Bildverarbeitung
Bilder werden üblicherweise als örtlich-/zeitliches Signal betrachtet. In der Digitalen Bildverarbeitung werden Bilder
häufig auch in anderer Signalform betrachtet, z.B. im Frequenzraum. Die Grundlagen der signalorientierten Bildverarbeitung
werden in diesem Kapitel behandeln. Die Aufgaben in diesem Unterverzeichnis geben dazu Informationen und Beispiele zu den Themen
- **Das Bild als Signal**
- **Grundlagen unitäre Transformation**
- **Fourier-Transformation**
- **LSISysteme, Faltung und FourierTransformation**
- **Abtastung und Rekonstruktion, Abtasttheorem**
- **Filterung des Bildes**
- **Unitäre Transformationen: DCT, Hadamard, Haar, WaveletTransformation**
- **Bildpyramiden und Multiresolutiondarstellung**

View File

@@ -0,0 +1,38 @@
# Übung 1: Bildkompression
In dieser Übung wird der Informationsgehalt eines Bildes reduziert und die Auswirkung auf die Interpretierbarkeit
für den Menschen betrachtet. Die Reduzierung der Informationen kann für eine Komprimierung verwendet.
Wenden Sie die folgenden Aufgaben auf die Bilder **data/yellowlilly.jpg** und **data/cameraman.png** an.
## Aufgabe a) Entfernen hochfrequenter Frequenzen
Implementieren sie die Funktion und *remove_dft(img, rate)*, wobei mit der
diskreten Kosinus- bzw. Fouriertransformation folgende Schritte durchgeführt werden sollen:
- Iterieren Sie Blockweise über das Bild mithilfe zweier for-Schleifen und einer Blockgröße von 8x8 Pixel
- Verwenden Sie `np.fft.fft2()` um den Block in den Frequenzraum zu transformieren
- Entfernen Sie die *n* hochfrequentesten Koefizienten mit `n = 8 * 8 * rate`
- Transformieren Sie den Block zurück in den Ortsraum mit `np.fft.ifft2`
Wie stark wirkt sich der Parameter `rate` auf die Interpretierbarkeit des Bildes für den Menschen aus?
Die Lösung ist in der Date [l_a.py](l_a.py) zu finden.
## Aufgabe b) Diskrete Kosinus Transformation
Implementieren Sie eine Funktion `dct(a: np.ndarray)`, welche als input eine zweidimensionale Matrix erhält und
auf diese die 2D Diskrete Kosinus Transformation nach
![](./data/dct.png)
anwendet und ausgibt.
Validieren Sie Ihre Funktion, indem Sie die `fft2()` und `ifft2()` Funktion aus Aufgabe a) durch die `dct()` und `idct()` Funktionen ersetzen.
Die inverse der Transformation ist mit der Funktion `idct(a: np.ndarray)` gegeben, welche bereits in *l_b.py* implementiert ist.
## Aufgabe c) Fragen
- Wie kann die Reduzierung der Fourier-Koeffizienten für eine Komprimierung genutzt werden?
- Was versteht man unter diskreter Kosinustransformation und was ist der wesentliche Unterschied zur DFT?
- Welchen Vorteil bietet die DCT gegenüber der FFT in der Praxis?

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -0,0 +1,57 @@
import numpy as np
import cv2
import math
def remove_dft(img, rate):
"""
Diese Implementierung wendet die diskrete Fourier Transformation auf das Bild img an. Daraufhin werden die hoch-
frequenten Anteile anteilig der Rate rate entfernt. Am Ende wird das Bild wieder in den Bildbereich transformiert.
:param img:
:param rate:
:return:
"""
assert rate <= 1, "Die Rate muss kleiner gleich 1 sein!"
height, width = img.shape
for i in range(math.ceil(width / 8)):
for j in range(math.ceil(height / 8)):
# Block extrahieren
block = np.zeros((8, 8))
horizontal_pixel, vertical_pixel = min(8, width - i * 8), min(8, height - j * 8)
block[0:vertical_pixel, 0:horizontal_pixel] = \
img[j * 8: (j * 8) + vertical_pixel, i * 8: (i * 8) + horizontal_pixel]
# In den Frequenzbereich tranformieren
block_freq = np.fft.fft2(block)
# Hochfrequente Anteile löschen
values_to_delete = 8 * 8 * rate
values_deleted = 0
for m in range(0, 16):
for n in range(0, m + 1):
if values_deleted >= values_to_delete:
break
if 7 - m + n < 0 or 7 - n < 0:
continue
block_freq[7 - m + n, 7 - n] = 0. + 0.j
values_deleted += 1
# Rücktransformation in den Bildbereich
block = np.fft.ifft2(block_freq)
# Einfügen in Ursprungsbild
img[j * 8: (j * 8) + vertical_pixel, i * 8: (i * 8) + horizontal_pixel] = \
block[0:vertical_pixel, 0:horizontal_pixel]
return img
''' Bild laden '''
img = cv2.imread("../../data/cameraman.png")
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img = (img / 256).astype(np.float32)
''' Funktion anwenden '''
img = remove_dft(img, 0.9)
''' Bild anzeigen '''
cv2.imshow("IMG", img)
cv2.waitKey(0)

View File

@@ -0,0 +1,93 @@
import numpy as np
import cv2
import math
def dct(a: np.ndarray):
a_freq = np.zeros_like(a)
N, M = a_freq.shape[1], a_freq.shape[0]
# Iteriere über jeden Koeffizienten
for k in range(N):
for m in range(M):
dct_k_m = 0
# Iteriere über jede Position im Ortsraum
for x in range(N):
for y in range(M):
dct_k_m += a[y, x] * np.cos(k*np.pi*(2*x+1)/(2*N)) * np.cos(m*np.pi*(2*y+1)/(2*M))
dct_k_m = 4 * dct_k_m / (np.sqrt(2*N) * np.sqrt(2*M))
a_freq[m, k] = dct_k_m
return a_freq
def idct(a_freq: np.ndarray):
a = np.zeros_like(a_freq)
N, M = a_freq.shape[1], a_freq.shape[0]
a_freq = (np.sqrt(2*N) * np.sqrt(2*M)) * a_freq / 16
a_freq[0, :] = a_freq[0, :] / 2
a_freq[:, 0] = a_freq[:, 0] / 2
# Iteriere über jeden Koeffizienten
for x in range(N):
for y in range(M):
f_x_y = 0 #a_freq[0, 0] / (4)# * np.sqrt(2))
# Iteriere über jede Position im Ortsraum
for k in range(N):
for m in range(M):
f_x_y += a_freq[m, k] * np.cos(k*np.pi*(2*x+1)/(2*N)) * np.cos(m*np.pi*(2*y+1)/(2*M))
f_x_y = f_x_y / 4
a[y, x] = f_x_y
return a
def remove_dct(img, rate):
"""
Diese Implementierung wendet die diskrete Fourier Transformation auf das Bild img an. Daraufhin werden die hoch-
frequenten Anteile anteilig der Rate rate entfernt. Am Ende wird das Bild wieder in den Bildbereich transformiert.
:param img:
:param rate:
:return:
"""
assert rate <= 1, "Die Rate muss kleiner gleich 1 sein!"
height, width = img.shape
for i in range(math.ceil(width / 8)):
for j in range(math.ceil(height / 8)):
# Block extrahieren
block = np.zeros((8, 8))
horizontal_pixel, vertical_pixel = min(8, width - i * 8), min(8, height - j * 8)
block[0:vertical_pixel, 0:horizontal_pixel] = \
img[j * 8: (j * 8) + vertical_pixel, i * 8: (i * 8) + horizontal_pixel]
# In den Frequenzbereich tranformieren
block_freq = dct(block)
# Hochfrequente Anteile löschen
values_to_delete = 8 * 8 * rate
values_deleted = 0
for m in range(0, 16):
for n in range(0, m + 1):
if values_deleted >= values_to_delete:
break
if 7 - m + n < 0 or 7 - n < 0:
continue
block_freq[7 - m + n, 7 - n] = 0.
values_deleted += 1
# Rücktransformation in den Bildbereich
block = idct(block_freq)
# Einfügen in Ursprungsbild
img[j * 8: (j * 8) + vertical_pixel, i * 8: (i * 8) + horizontal_pixel] = \
block[0:vertical_pixel, 0:horizontal_pixel]
return img
''' Bild laden '''
img = cv2.imread("../../data/cameraman.png")
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img = cv2.resize(img, (160, 160))
img = (img.astype(np.float64) / 256)
cv2.imshow("ORIGINAL", img)
''' Funktion anwenden '''
img = remove_dct(img, 0.8)
''' Bild anzeigen '''
cv2.imshow("IMG", img)
cv2.waitKey(0)

View File

@@ -0,0 +1,5 @@
# Lösung zu 1c)
- entfernen hoher Frequenzen, da diese für den Menschen nicht so **aussagekräftig** erscheinen
- siehe Formeln
- keine komplexen Zahlen

View File

@@ -0,0 +1,25 @@
# Übung 2: Bildrekonstruktion mit Wiener Filter & Inverser Filterung
Gegeben ist eine Abbildung der ETH-Zürich mit einer Bildstörung wie im folgenden zu sehen:
![../../data/eth_blurred.png](../../data/eth_blurred.png)
Als Bildstörung ist hier Motion Blur einer gleichförmigen Kamerabewegung von 31 Pixel
und einem Winkel von 11 Grad (gegen den Uhrzeigersinn) verwendet.
Berechnen
# Aufgabe a) Inverse Filterung
Benutzen Sie inverse Filterung um die Bildstörung (Motion Blur und Rauschen) im Bild
zu entfernen. Die Inverse Filterung muss anhand der Formeln von der Vorlesung selbst programmiert werden.
Verwenden Sie eine geeignete "cutoff"-Frequenz.
Nutzen Sie die Datei [a.py](a.py) um Ihre Lösung zu implementieren. In der Datei ist die "Point Spread Function" (PSF)
bereits implementiert und in den Frequenzbereich transformiert. Die PSF entspricht der Transferfuntkion der
Bildstörung.
# Aufgabe b) Wiener Filterung
Nutzen Sie ebenfalls Datei [a.py](a.py),
Benutzen Sie Wiener Filterung um die Bildstörung (Motion Blur und Rauschen) im Bild
zu entfernen. Die Wiener Filterung muss anhand der Formeln von der Vorlesung selbst programmiert werden.
Verwenden Sie einen geeigneten Parameter K für den Wiener Filter.

View File

@@ -0,0 +1,41 @@
import numpy as np
import cv2
def get_motion_psf(kernel_size, motion_angle, motion_dis):
""" "Point Spread Function" um Bewegung zu simulieren """
psf = np.zeros(kernel_size) # point spread function
x_center = (kernel_size[0] - 1) / 2
y_center = (kernel_size[1] - 1) / 2
sin_val = np.sin(motion_angle * np.pi / 180)
cos_val = np.cos(motion_angle * np.pi / 180)
for i in range(motion_dis):
x_offset = round(sin_val * i)
y_offset = round(cos_val * i)
psf[int(x_center - x_offset), int(y_center + y_offset)] = 1
return psf / psf.sum()
''' Bild laden und in den Frequenzraum transformieren '''
img = cv2.imread("../../data/eth_blurred.png", cv2.IMREAD_GRAYSCALE)
IMG = np.fft.fft2(img)
''' Erstellen des Filterkernels und Transformation in den Frequenzraum '''
rows, cols = img.shape
h = get_motion_psf(kernel_size=(rows, cols), motion_angle=11, motion_dis=31)
h = np.fft.fftshift(h) # Muss gemacht werden, da der "Motion Blur Vector" mittig zentriert ist
H = np.fft.fft2(h)
''' Ergebnis anzeigen '''
cv2.imshow("Original", img)
cv2.imshow("Inverses Filter", img_filtered)
cv2.waitKey()

View File

@@ -0,0 +1,41 @@
import numpy as np
import cv2
def get_motion_psf(kernel_size, motion_angle, motion_dis):
""" "Point Spread Function" um Bewegung zu simulieren """
psf = np.zeros(kernel_size) # point spread function
x_center = (kernel_size[0] - 1) / 2
y_center = (kernel_size[1] - 1) / 2
sin_val = np.sin(motion_angle * np.pi / 180)
cos_val = np.cos(motion_angle * np.pi / 180)
for i in range(motion_dis):
x_offset = round(sin_val * i)
y_offset = round(cos_val * i)
psf[int(x_center - x_offset), int(y_center + y_offset)] = 1
return psf / psf.sum()
''' Bild laden und in den Frequenzraum transformieren '''
img = cv2.imread("../../data/eth_blurred.png", cv2.IMREAD_GRAYSCALE)
IMG = np.fft.fft2(img)
''' Erstellen des Filterkernels und Transformation in den Frequenzraum '''
rows, cols = img.shape
h = get_motion_psf(kernel_size=(rows, cols), motion_angle=11, motion_dis=31)
h = np.fft.fftshift(h) # Muss gemacht werden, da der "Motion Blur Vector" mittig zentriert ist
H = np.fft.fft2(h)
H[np.abs(H) < 0.01] = 0.01 # Begrenzen der Degradationsfunktion um numerische Probleme zu verhindern
''' Inverses Filter anwenden '''
IMG_FILTERED = IMG / H
img_filtered = np.fft.ifft2(IMG_FILTERED).clip(0, 255).astype(np.uint8)
''' Ergebnis anzeigen '''
cv2.imshow("Original", img)
cv2.imshow("Inverses Filter", img_filtered)
cv2.waitKey()

View File

@@ -0,0 +1,43 @@
import numpy as np
import cv2
def get_motion_psf(kernel_size, motion_angle, motion_dis):
""" "Point Spread Function" um Bewegung zu simulieren """
psf = np.zeros(kernel_size) # point spread function
x_center = (kernel_size[0] - 1) / 2
y_center = (kernel_size[1] - 1) / 2
sin_val = np.sin(motion_angle * np.pi / 180)
cos_val = np.cos(motion_angle * np.pi / 180)
for i in range(motion_dis):
x_offset = round(sin_val * i)
y_offset = round(cos_val * i)
psf[int(x_center - x_offset), int(y_center + y_offset)] = 1
return psf / psf.sum()
''' Bild laden und in den Frequenzraum transformieren '''
img = cv2.imread("../../data/eth_blurred.png", cv2.IMREAD_GRAYSCALE)
IMG = np.fft.fft2(img)
''' Erstellen des Filterkernels und Transformation in den Frequenzraum '''
rows, cols = img.shape
h = get_motion_psf(kernel_size=(rows, cols), motion_angle=11, motion_dis=31)
h = np.fft.fftshift(h) # Muss gemacht werden, da der "Motion Blur Vector" mittig zentriert ist
H = np.fft.fft2(h)
H[np.abs(H) < 0.01] = 0.01 # Begrenzen der Degradationsfunktion um numerische Probleme zu verhindern
''' Wiener Filter anwenden '''
K = 0.001
W = np.power(np.abs(H), 2) / (H * np.power(np.abs(H), 2) + K)
IMG_FILTERED = W * IMG
img_filtered = np.fft.ifft2(IMG_FILTERED).clip(0, 255).astype(np.uint8)
''' Ergebnis anzeigen '''
cv2.imshow("Original", img)
cv2.imshow("Wiener Filter", img_filtered)
cv2.waitKey()

View File

@@ -0,0 +1,40 @@
# Übung 3: Fouriertransformation
In dieser Übung soll die Fouriertransformation betrachtet werden.
## Aufgabe a) Rauschen im Orts- und Frequenzbereich
Um den Umgang mit Orts- und Frequenzbereich in Python zu verdeutlichen und die Grundlage
für die Folgeaufgaben zu stellen, soll ein Programm geschrieben werden, das die folgenden Schritte
durchführt:
1. Öffnen Sie das Skript [a.py](a.py)
2. Transformieren Sie die Bilder *img* und *img_noise* mit ``np.fft.fft2(img)`` in den Frequenzbereich.
3. Berechnen Sie den Betrag/Amplitude der Transformierten und stellen Sie diese als Bild dar.
4. Worin unterscheiden sich die Bilder?
Die Musterlösung befindet sich in der Datei [l_a.py](l_a.py).
**Hinweise:**
- Mit der Funktion ``np.fft.fftshift(IMAGE)`` wird der Gleichanteil des Frequenzbereiches in die Mitte
des Bildes gelegt.
- Zur besseren Visualisierung des Frequenzbereiches ist es empfehlenswert, die anzuzeigenden Werte mit einem Faktor
zu reduzieren. Das kann z.B. ``magnitudes = magnitudes / 100000`` sein.
## Aufgabe b) Amplituden und Phasenspektrum vertauschen
In der Datei [b.py](b.py) werden zwei Bilder geladen. Transformieren Sie sie in den Frequenzbereich und tauschen Sie die
Winkel und Amplituden. Stellen Sie die Bilder vor und nach dem Tausch dar!
Die Musterlösung befindet sich in der Datei [l_b.py](l_b.py).
## Aufgabe c) Tiefpassfilter
In der Datei [c.py](c.py) wird ein Bild eines Teppichs geladen. Der Teppich hat Fehler in den Maschen, die Sie finden möchten.
Um die Fehler besser finden zu können, möchten Sie das Bild mithilfe der Fourier-Transformation optisch anpassen.
Transformieren Sie das Bild in den Frequenzbereich und löschen Sie verschiedene hochfrequente und/oder niederfrequente Anteile.
Transformieren Sie das Spektrum darauf wieder in den Ortsbereich und stellen die Bilder dar!
Welche Frequenzen scheinen für die Aufgabe interessanter zu sein?
Die Musterlösung befindet sich in der Datei [l_c.py](l_c.py).

View File

@@ -0,0 +1,20 @@
import cv2
import numpy as np
img = cv2.imread("../../data/lena.png", cv2.IMREAD_GRAYSCALE)
''' Rauschen hinzufügen '''
h, w = img.shape
saltpepper_noise = np.zeros((h, w), dtype=np.uint8)
saltpepper_noise = cv2.randu(saltpepper_noise, 0, 255)
black = saltpepper_noise < 15
white = saltpepper_noise > 240
img_noise = np.copy(img)
img_noise[white] = 255
img_noise[black] = 0
''' Bild anzeigen '''
cv2.imshow("img", img)
cv2.imshow("img_noise", img_noise)
cv2. waitKey()

View File

@@ -0,0 +1,10 @@
import cv2
import numpy as np
car = cv2.imread("../../data/car.png", cv2.IMREAD_GRAYSCALE)
dog = cv2.imread("../../data/dog.png", cv2.IMREAD_GRAYSCALE)
cv2.imshow("car", car)
cv2.imshow("dog", dog)
cv2. waitKey()

View File

@@ -0,0 +1,24 @@
import cv2
import numpy as np
img = cv2.imread("../../data/teppich.png", cv2.IMREAD_GRAYSCALE)
''' FFT '''
IMG = np.fft.fft2(img)
MAGNITUDE = np.abs(IMG)
ANGLE = np.angle(IMG)
''' Filter out frequencies '''
''' IFFT '''
IMG = MAGNITUDE * np.exp(1j * ANGLE)
filtered_image = np.fft.ifft2(IMG).astype(np.float32)
''' Bild anzeigen '''
cv2.imshow("img", img)
cv2.imshow("filtered", filtered_image / np.max(filtered_image))
cv2.waitKey(0)

View File

@@ -0,0 +1,29 @@
import cv2
import numpy as np
img = cv2.imread("../../data/lena.png", cv2.IMREAD_GRAYSCALE)
''' Rauschen hinzufügen '''
h, w = img.shape
saltpepper_noise = np.zeros((h, w), dtype=np.uint8)
saltpepper_noise = cv2.randu(saltpepper_noise, 0, 255)
black = saltpepper_noise < 15
white = saltpepper_noise > 240
img_noise = np.copy(img)
img_noise[white] = 255
img_noise[black] = 0
''' FFT '''
visual_factor = 100000
IMG = np.fft.fftshift(np.fft.fft2(img))
IMG_magnitude = np.abs(IMG)
cv2.imshow("IMG_magnitude", IMG_magnitude / visual_factor)
IMG_NOISE = np.fft.fftshift(np.fft.fft2(img_noise))
IMG_NOISE_magnitude = np.abs(IMG_NOISE)
cv2.imshow("IMG_NOISE_magnitude", IMG_NOISE_magnitude / visual_factor)
''' Bild anzeigen '''
cv2.imshow("img", img)
cv2.imshow("img_noise", img_noise)
cv2. waitKey()

View File

@@ -0,0 +1,28 @@
import cv2
import numpy as np
car = cv2.imread("../../data/car.png", cv2.IMREAD_GRAYSCALE)
dog = cv2.imread("../../data/dog.png", cv2.IMREAD_GRAYSCALE)
''' FFT '''
CAR = np.fft.fft2(car)
CAR_magnitude = np.abs(CAR)
CAR_angle = np.angle(CAR)
DOG = np.fft.fft2(dog)
DOG_magnitude = np.abs(DOG)
DOG_angle = np.angle(DOG)
mix1 = CAR_magnitude * np.exp(1j * DOG_angle)
mix2 = DOG_magnitude * np.exp(1j * CAR_angle)
mix1 = np.fft.ifft2(mix1).astype(np.float32)
mix2 = np.fft.ifft2(mix2).astype(np.float32)
''' Bild anzeigen '''
cv2.imshow("car", car)
cv2.imshow("dog", dog)
cv2.imshow("mix1", mix1 / np.max(mix1))
cv2.imshow("mix2", mix2 / np.max(mix2))
cv2.waitKey()

View File

@@ -0,0 +1,25 @@
import cv2
import numpy as np
img = cv2.imread("../../data/teppich.png", cv2.IMREAD_GRAYSCALE)
''' FFT '''
IMG = np.fft.fft2(img)
MAGNITUDE = np.abs(IMG)
ANGLE = np.angle(IMG)
''' Filter out frequencies '''
print("Number of frequencies:", MAGNITUDE.shape)
MAGNITUDE[0:150, 0:150] = 0
''' IFFT '''
IMG = MAGNITUDE * np.exp(1j * ANGLE)
filtered_image = np.fft.ifft2(IMG).astype(np.float32)
''' Bild anzeigen '''
cv2.imshow("img", img)
cv2.imshow("filtered", filtered_image / np.max(filtered_image))
cv2.waitKey(0)

View File

@@ -0,0 +1,31 @@
# Übung 4: Notch-Filter im Frequenzraum
In dem Skript [a.py](a.py) wird das Bild von Lena eingeladen.
Gleichzeitig wird ein gestörtes Bild von Lena eingeladen.
Dem Bild wurde ein Raster überlagert.
Original | Gestört
---|---
![](../../data/lena.png) | ![](../../data/lena_raster.png)
## Aufgabe a)
Das Raster soll unter Benutzung des Frequenzbereiches auf einfache Weise für
den subjektiven Eindruck entfernt werden.
Gehen Sie dabei wie folgt vor:
1. Transformieren Sie die Bilder in den Frequenzbereich und betrachten Sie charakteristische
Unterschiede.
2. Maskieren Sie die gestörten Bereiche aus, in dem Sie geeigente Bereiche der Matrix auf Null
setzen. Die Zentren der Störungen liegen etwa bei (nach fftshift):
- [85, 85]
- [255, 85]
- [425, 85]
- [85, 255]
- [255, 425]
- [425, 255]
- [85, 425]
- [425, 425]
3. Transformieren Sie das Bild in den Ortsbereich zurück.
Sie finden die Musterlösung in der Datei [l_a.py](l_a.py).

View File

@@ -0,0 +1,36 @@
import cv2
import numpy as np
raster = cv2.imread("../../data/lena_raster.png", cv2.IMREAD_GRAYSCALE)
normal = cv2.imread("../../data/lena.png", cv2.IMREAD_GRAYSCALE)
''' FFT '''
RASTER = np.fft.fftshift(np.fft.fft2(raster))
RASTER_magnitude = np.abs(RASTER)
RASTER_angle = np.angle(RASTER)
NORMAL = np.fft.fftshift(np.fft.fft2(normal))
NORMAL_magnitude = np.abs(NORMAL)
NORMAL_angle = np.angle(NORMAL)
''' Maskieren '''
centroids = [
[85, 85],
[255, 85],
[425, 85],
[85, 255],
[255, 425],
[425, 255],
[85, 425],
[425, 425]
]
''' Bild anzeigen '''
cv2.imshow("raster", raster)
cv2.imshow("normal", normal)
cv2.imshow("RASTER_magnitude", 255 * RASTER_magnitude / np.max(RASTER_magnitude))
cv2.imshow("NORMAL_magnitude", 255 * NORMAL_magnitude / np.max(NORMAL_magnitude))
cv2.waitKey()

View File

@@ -0,0 +1,46 @@
import cv2
import numpy as np
raster = cv2.imread("../../data/lena_raster.png", cv2.IMREAD_GRAYSCALE)
normal = cv2.imread("../../data/lena.png", cv2.IMREAD_GRAYSCALE)
''' FFT '''
RASTER = np.fft.fftshift(np.fft.fft2(raster))
RASTER_magnitude = np.abs(RASTER)
RASTER_angle = np.angle(RASTER)
NORMAL = np.fft.fftshift(np.fft.fft2(normal))
NORMAL_magnitude = np.abs(NORMAL)
NORMAL_angle = np.angle(NORMAL)
''' Bild anzeigen '''
cv2.imshow("raster", raster)
cv2.imshow("normal", normal)
cv2.imshow("RASTER_magnitude", 255 * RASTER_magnitude / np.max(RASTER_magnitude))
cv2.imshow("NORMAL_magnitude", 255 * NORMAL_magnitude / np.max(NORMAL_magnitude))
''' Maskieren '''
centroids = [
[85, 85],
[255, 85],
[425, 85],
[85, 255],
[255, 425],
[425, 255],
[85, 425],
[425, 425]
]
s = 10
for x, y in centroids:
RASTER[np.maximum(0, y - s):y + s, np.maximum(0, x - s):x + s] = 0
FILTERED_magnitude = np.abs(RASTER)
''' Inverse fft '''
filtered = np.fft.ifft2(np.fft.ifftshift(RASTER)).astype(np.uint8)
''' Lösung anzeigen '''
cv2.imshow("FILTERED_magnitude", 255 * FILTERED_magnitude / np.max(FILTERED_magnitude))
cv2.imshow("filtered", filtered)
cv2.waitKey()

View File

@@ -0,0 +1,26 @@
# Übung 5: Homomorphe Filterung
In dem Skript [a.py](a.py) wird das Bild *I*
![](../../data/car2.png)
geladen. Das Bild zeigt eine schlecht belichtete Szene, in der Details nicht
gut zu erkennen sind. In dieser Übung soll der Kontrast verbessert werden, damit
mehr Details erkennbar sind.
## Aufgabe a)
Wenden Sie die Homomorphe Filterung auf das Bild *I* an, indem Sie folgende Schritte implementieren:
1. Logarithmieren Sie die Werte in Grauwerte in *I*
2. Transformieren Sie *I* in den Frequenzbereich
3. Unterdrücken Sie niedrige Frequenzen durch die Funktion H(k,l)<p align="center"><img src="https://latex.codecogs.com/svg.image?H(k,l)=\begin{cases}&space;1,&&space;k=0&space;\&space;\cap&space;\&space;l=0&space;\\&space;\gamma_1&space;-&space;(\gamma_1&space;-&space;\gamma_2)e^{(-\frac{k^2&plus;l^2}{\gamma_3})}&space;&&space;\text{sonst}\end{cases}&space;" title="" /></p>
5. Transformieren Sie *I* zurück in den Bildbereich
6. Kehren Sie die Logarithmierung aus Schritt 1. durch die Exponentialfunktion um
Der erste Teil der Aufgabe ist in der Datei [a.py](a.py) zu finden.
Sie finden die Musterlösung in der Datei [l_a.py](l_a.py).
**Hinweis:** Arbeiten Sie mit einem Wertebereich zwischen 0 und 1!

View File

@@ -0,0 +1,26 @@
import numpy as np
import cv2
''' Bild laden und in den Frequenzraum transformieren '''
img = cv2.imread("../../data/car2.png", cv2.IMREAD_GRAYSCALE)
img = img.astype(float)
i_max, i_min = np.max(img), np.min(img)
img = (img - i_min) / (i_max - i_min)
cv2.imshow("Original", img )
''' 1. Logarithmieren '''
''' 2. in den Frequenzbereich transformieren '''
''' 3. Niedrige mit H(k,l)Frequenzen unterdrücken '''
''' 4. Rücktransformation '''
''' 5. Umkehrfunktion der Logarithmierung '''
''' Ergebnis anzeigen '''
i_max, i_min = np.max(img_filtered), np.min(img_filtered)
img_filtered = (img_filtered - i_min) / (i_max - i_min)
cv2.imshow("Homomorphe Filterung", img_filtered)
cv2.waitKey()

View File

@@ -0,0 +1,42 @@
import numpy as np
import cv2
''' Bild laden und in den Frequenzraum transformieren '''
img = cv2.imread("../../data/car2.png", cv2.IMREAD_GRAYSCALE)
img = img.astype(float)
i_max, i_min = np.max(img), np.min(img)
img = (img - i_min) / (i_max - i_min)
cv2.imshow("Original", img )
''' 1. Logarithmieren '''
img_log = np.maximum(img, 1/255) # log(0) ist illegal!
img_log = np.log(img_log)
''' 2. in den Frequenzbereich transformieren '''
IMG = np.fft.fft2(img_log)
''' 3. Niedrige mit H(k,l)Frequenzen unterdrücken '''
gamma1, gamma2, gamma3 = 0.5, 0., 4
H = np.zeros_like(img_log)
for l in range(H.shape[0]):
for k in range(H.shape[1]):
if k < 1 and l < 1:
H[l, k] = 1
else:
H[l, k] = gamma1 - (gamma1 - gamma2) * np.exp(-(k*k + l*l) / (gamma3 * gamma3))
IMG = IMG * H
''' 4. Rücktransformation '''
img_filtered = np.fft.ifft2(IMG)
img_filtered = img_filtered.astype(float)
''' 5. Umkehrfunktion der Logarithmierung '''
img_filtered = np.exp(img_filtered)
''' Ergebnis anzeigen '''
i_max, i_min = np.max(img_filtered), np.min(img_filtered)
img_filtered = (img_filtered - i_min) / (i_max - i_min)
cv2.imshow("Homomorphe Filterung", img_filtered)
cv2.waitKey()

View File

@@ -0,0 +1,24 @@
# Übung 6: Unitäre Transformation
In dem Skript [a.py](a.py) wird das Bild von Lena eingeladen.
![](../../data/lena.png)
## Aufgabe a) Haar-Transformation
Das Bild soll in die hohen tiefen Frequenzen mithilfe der Haar-Transformation zerlegt werden.
Erstellen Sie dafür eine Haar-Koeffizientnmatrix der Größe 512x512 mit der Berechnungsvorschrift
<img src="https://latex.codecogs.com/svg.image?H^{(N)}_{ij}:=\begin{cases}\frac{1}{\sqrt{2}},&space;&&space;\text{if}\&space;i\leq&space;\frac{N}{2},&space;j\in&space;\{2i-1,2i&space;\}&space;&space;\\\frac{1}{\sqrt{2}},&space;&&space;\text{if}\&space;i>\frac{N}{2},&space;j=2(i-\frac{N}{2})-1&space;\\-\frac{1}{\sqrt{2}},&space;&&space;\text{if}\&space;i>\frac{N}{2},&space;j=2(i-\frac{N}{2})\end{cases}" title="" />
und wenden Sie diese auf das Bild mithilfe von
<img src="https://latex.codecogs.com/svg.image?I'=HI">
an. Zeigen Sie das Bild, und geben Sie einige interessante Koeffizienten aus H an. Prüfen Sie Ihre Berechnungen,
indem Sie die Rücktransformation mithilfe von
<img src="https://latex.codecogs.com/svg.image?I=H^T(HI)">
anwenden und prüfen, ob Änderungen im Bild vorhanden sind.
Sie finden die Musterlösung in der Datei [l_a.py](l_a.py).

View File

@@ -0,0 +1,33 @@
import cv2
import numpy as np
normal = cv2.imread("../../data/lena.png", cv2.IMREAD_GRAYSCALE)
def valid_rows(N):
n = np.log2(N)
n = np.ceil(n)
N = np.power(2, n)
return N
def create_H(m, N):
...
''' Reshape to valid resolution '''
N, m = normal.shape
new_N = valid_rows(N)
print("Original Resolution:", m, "x", N)
print("New Resolution:", m, "x", new_N)
if N != new_N:
_ = np.zeros((new_N, m))
_[:N, :m] = normal
normal = _
''' Show images '''
cv2.imshow("normal", normal)
cv2.waitKey()

View File

@@ -0,0 +1,60 @@
import cv2
import numpy as np
normal = cv2.imread("../../data/lena.png", cv2.IMREAD_GRAYSCALE)
def valid_rows(N):
n = np.log2(N)
n = np.ceil(n)
N = np.power(2, n)
return N
def create_H(m, N):
"""
m: Columns
n: Rows
"""
H = np.zeros((int(N), int(m)))
for i in range(1, int(N) + 1):
for j in range(1, int(m) + 1):
if i <= (N/2):
if j == (2*i -1) or j == 2*i:
H[i-1,j-1] = 1 / np.sqrt(2)
else:
#print(j, i)
if j == (2 * (i - N/2) - 1):
H[i-1,j-1] = 1 / np.sqrt(2)
elif j == (2 * (i - N/2)):
H[i-1,j-1] = -1 / np.sqrt(2)
return H
''' Reshape to valid resolution '''
N, m = normal.shape
new_N = valid_rows(N)
print("Original Resolution:", m, "x", N)
print("New Resolution:", m, "x", new_N)
if N != new_N:
_ = np.zeros((new_N, m))
_[:N, :m] = normal
normal = _
''' Get Haar-Matrix '''
H = create_H(m, new_N)
print(H[0:5, 0:5])
print(H[256:261, 0:5])
''' Filter with HxI'''
haar = np.matmul(H, normal)
''' Invert Filter '''
haar_inv = np.matmul(np.transpose(H), haar)
''' Show images '''
cv2.imshow("normal", normal)
cv2.imshow("haar", haar / 255)
cv2.imshow("haar_inv", haar_inv / 255)
print("Difference:", np.sum(np.abs(normal-haar_inv)))
cv2.waitKey()