Initial commit with project files
This commit is contained in:
15
3_Signalorientierte_Bildverarbeitung/README.md
Normal file
15
3_Signalorientierte_Bildverarbeitung/README.md
Normal 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**
|
||||
- **LSI‐Systeme, Faltung und Fourier‐Transformation**
|
||||
- **Abtastung und Rekonstruktion, Abtasttheorem**
|
||||
- **Filterung des Bildes**
|
||||
- **Unitäre Transformationen: DCT, Hadamard‐, Haar‐, Wavelet‐Transformation**
|
||||
- **Bildpyramiden und Multiresolutiondarstellung**
|
||||
|
||||
38
3_Signalorientierte_Bildverarbeitung/ü1/README.md
Normal file
38
3_Signalorientierte_Bildverarbeitung/ü1/README.md
Normal 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
|
||||
|
||||

|
||||
|
||||
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?
|
||||
|
||||
BIN
3_Signalorientierte_Bildverarbeitung/ü1/data/dct.png
Normal file
BIN
3_Signalorientierte_Bildverarbeitung/ü1/data/dct.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
57
3_Signalorientierte_Bildverarbeitung/ü1/l_a.py
Normal file
57
3_Signalorientierte_Bildverarbeitung/ü1/l_a.py
Normal 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)
|
||||
93
3_Signalorientierte_Bildverarbeitung/ü1/l_b.py
Normal file
93
3_Signalorientierte_Bildverarbeitung/ü1/l_b.py
Normal 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)
|
||||
5
3_Signalorientierte_Bildverarbeitung/ü1/l_c.md
Normal file
5
3_Signalorientierte_Bildverarbeitung/ü1/l_c.md
Normal 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
|
||||
25
3_Signalorientierte_Bildverarbeitung/ü2/README.md
Normal file
25
3_Signalorientierte_Bildverarbeitung/ü2/README.md
Normal 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:
|
||||
|
||||

|
||||
|
||||
|
||||
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.
|
||||
41
3_Signalorientierte_Bildverarbeitung/ü2/a.py
Normal file
41
3_Signalorientierte_Bildverarbeitung/ü2/a.py
Normal 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()
|
||||
41
3_Signalorientierte_Bildverarbeitung/ü2/l_a.py
Normal file
41
3_Signalorientierte_Bildverarbeitung/ü2/l_a.py
Normal 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()
|
||||
43
3_Signalorientierte_Bildverarbeitung/ü2/l_b.py
Normal file
43
3_Signalorientierte_Bildverarbeitung/ü2/l_b.py
Normal 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()
|
||||
40
3_Signalorientierte_Bildverarbeitung/ü3/README.md
Normal file
40
3_Signalorientierte_Bildverarbeitung/ü3/README.md
Normal 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).
|
||||
20
3_Signalorientierte_Bildverarbeitung/ü3/a.py
Normal file
20
3_Signalorientierte_Bildverarbeitung/ü3/a.py
Normal 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()
|
||||
10
3_Signalorientierte_Bildverarbeitung/ü3/b.py
Normal file
10
3_Signalorientierte_Bildverarbeitung/ü3/b.py
Normal 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()
|
||||
24
3_Signalorientierte_Bildverarbeitung/ü3/c.py
Normal file
24
3_Signalorientierte_Bildverarbeitung/ü3/c.py
Normal 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)
|
||||
29
3_Signalorientierte_Bildverarbeitung/ü3/l_a.py
Normal file
29
3_Signalorientierte_Bildverarbeitung/ü3/l_a.py
Normal 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()
|
||||
28
3_Signalorientierte_Bildverarbeitung/ü3/l_b.py
Normal file
28
3_Signalorientierte_Bildverarbeitung/ü3/l_b.py
Normal 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()
|
||||
25
3_Signalorientierte_Bildverarbeitung/ü3/l_c.py
Normal file
25
3_Signalorientierte_Bildverarbeitung/ü3/l_c.py
Normal 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)
|
||||
31
3_Signalorientierte_Bildverarbeitung/ü4/README.md
Normal file
31
3_Signalorientierte_Bildverarbeitung/ü4/README.md
Normal 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
|
||||
---|---
|
||||
 | 
|
||||
|
||||
## 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).
|
||||
36
3_Signalorientierte_Bildverarbeitung/ü4/a.py
Normal file
36
3_Signalorientierte_Bildverarbeitung/ü4/a.py
Normal 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()
|
||||
46
3_Signalorientierte_Bildverarbeitung/ü4/l_a.py
Normal file
46
3_Signalorientierte_Bildverarbeitung/ü4/l_a.py
Normal 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()
|
||||
26
3_Signalorientierte_Bildverarbeitung/ü5/README.md
Normal file
26
3_Signalorientierte_Bildverarbeitung/ü5/README.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Übung 5: Homomorphe Filterung
|
||||
|
||||
In dem Skript [a.py](a.py) wird das Bild *I*
|
||||
|
||||

|
||||
|
||||
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+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!
|
||||
26
3_Signalorientierte_Bildverarbeitung/ü5/a.py
Normal file
26
3_Signalorientierte_Bildverarbeitung/ü5/a.py
Normal 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()
|
||||
42
3_Signalorientierte_Bildverarbeitung/ü5/l_a.py
Normal file
42
3_Signalorientierte_Bildverarbeitung/ü5/l_a.py
Normal 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()
|
||||
24
3_Signalorientierte_Bildverarbeitung/ü6/README.md
Normal file
24
3_Signalorientierte_Bildverarbeitung/ü6/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Übung 6: Unitäre Transformation
|
||||
|
||||
In dem Skript [a.py](a.py) wird das Bild von Lena eingeladen.
|
||||
|
||||

|
||||
|
||||
## 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).
|
||||
33
3_Signalorientierte_Bildverarbeitung/ü6/a.py
Normal file
33
3_Signalorientierte_Bildverarbeitung/ü6/a.py
Normal 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()
|
||||
60
3_Signalorientierte_Bildverarbeitung/ü6/l_a.py
Normal file
60
3_Signalorientierte_Bildverarbeitung/ü6/l_a.py
Normal 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()
|
||||
Reference in New Issue
Block a user