Initial commit with project files
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.idea/
|
||||||
|
venv/
|
||||||
|
*.tflite
|
||||||
93
0_Einführung/README.md
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# Einführung
|
||||||
|
In diesem Kapitel werden Sie mit den nötigen Werkzeugen ausgestattet, um diesen Kurs zu meistern.
|
||||||
|
Dafür wird ihnen gezeigt, wie Sie dieses Repository korrekt auf Ihren Rechner installieren.
|
||||||
|
Sie werden grundlegend in die Programmiersprache Python und die Programmierumgebung PyCharm eingeführt. Arbeiten Sie die
|
||||||
|
folgenden Abschnitte in der gegebenen Reihenfolge durch.
|
||||||
|
|
||||||
|
**Hinweis:** Sollten Sie bereits Erfahrung mit Github, Python und Pycharm haben, können Sie dieses Einführung überspringen.
|
||||||
|
|
||||||
|
## Installation Python
|
||||||
|
Installieren Sie den Python-Interpreter in der Version 3.5 oder höher. Die Installation ist Abhängig von Ihrem Betriebssystem.
|
||||||
|
|
||||||
|
Für das Betriebssystem
|
||||||
|
- **Windows** finden Sie Python zum Download auf [https://www.python.org/downloads/windows/](https://www.python.org/downloads/windows/)
|
||||||
|
- **Mac OS** finden Sie Python zum Download auf [https://www.python.org/downloads/mac-osx/](https://www.python.org/downloads/mac-osx/)
|
||||||
|
- **Linux** ist Python auf den meisten Distributionen vorinstalliert
|
||||||
|
|
||||||
|
Eine detailliertes Tutorial zu Python finden Sie unter [https://wiki.python.org/moin/BeginnersGuide](https://wiki.python.org/moin/BeginnersGuide).
|
||||||
|
|
||||||
|
## Installation PyCharm Community Edition
|
||||||
|
Die Programmierumgebung PyCharm ist eine für private- und Lehrzwecke frei verfügbare Software, welche die Arbeit mit
|
||||||
|
Python sehr stark vereinfacht. Die Verwendung von PyCharm ist für diesen Kurs nicht notwendig aber dringend empfohlen!
|
||||||
|
|
||||||
|
Die Installation geschieht auf jedem Betriebssystem mithilfe einer Installationsdatei, welche für
|
||||||
|
- **Windows** unter [https://www.jetbrains.com/de-de/pycharm/download/#section=windows](https://www.jetbrains.com/de-de/pycharm/download/#section=windows)
|
||||||
|
- **Mac OS** unter [https://www.jetbrains.com/de-de/pycharm/download/#section=mac](https://www.jetbrains.com/de-de/pycharm/download/#section=mac)
|
||||||
|
- **Linux** unter [https://www.jetbrains.com/de-de/pycharm/download/#section=linux](https://www.jetbrains.com/de-de/pycharm/download/#section=linux)
|
||||||
|
|
||||||
|
erhältlich ist.
|
||||||
|
|
||||||
|
**Hinweis:** Sollten Sie Interesse an zusätzlichen Funktionen haben, können Sie als Student eine zeitlich limitierte
|
||||||
|
kostenlose *PyCharm-Professional* Lizenz für Lehrzwecke erwerben. Weitere Informationen finden Sie unter
|
||||||
|
[https://www.jetbrains.com/de-de/community/education/#students](https://www.jetbrains.com/de-de/community/education/#students).
|
||||||
|
|
||||||
|
## Download der Daten
|
||||||
|
Wenn Sie diesen Text lesen, werden Sie das Github Repository vermutlich bereits gefunden haben. Der Kurs wird auf der Platform
|
||||||
|
Github gehosted, um die Aufgaben kontinuierlich weiterentwickeln zu können und Ihnen dabei stets Zugriff auf den
|
||||||
|
neusten Entwicklungsstand zu geben. Weiterhin bietet Github die Möglichkeit, dass Sie aktiv bei der Mitgestaltung dieses
|
||||||
|
Kurses beitragen können.
|
||||||
|
|
||||||
|
Der Download der Daten kann entweder über **Git** oder die einfache **Download-Funktion** geschehen. Es wird die
|
||||||
|
Methode Git empfohlen. Weitere Informationen zu Git finden Sie unter
|
||||||
|
[https://guides.github.com/introduction/git-handbook/](https://guides.github.com/introduction/git-handbook/).
|
||||||
|
|
||||||
|
Sollten Sie sich gegen Git und für die Download-Funktion entscheiden, können Sie den Download wie im folgenden Bild
|
||||||
|
gezeigt starten.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Downloaden und speichern Sie die Daten an einem beliebigen Pfad, z.B. `C:\Users\Timo\Desktop\Digitale-Bildverarbeitung`.
|
||||||
|
Im folgenden wird der von Ihnen ausgesuchte Pfad als `WORKING_DIRECTORY` beschrieben. Sollten Sie die Daten erfolgreich
|
||||||
|
gespeichert haben, sollte diese README-Datei an der Stelle `WORKING_DIRECTORY\0_Einführung\README.md` liegen.
|
||||||
|
|
||||||
|
**Hinweis:** Sie sind herzlich dazu eingeladen Git *Merge Requests* zu verwenden, um eventuelle Fehler zu korrigieren oder
|
||||||
|
neue Aufgaben zu erstellen.
|
||||||
|
|
||||||
|
## Einrichtung einer Virtuellen Umgebung
|
||||||
|
Starten Sie PyCharm und erstellen Sie ein neues Projekt. Es wird ein Dialog geöffnet, welcher ähnlich der folgenden
|
||||||
|
Abbildung aussieht.
|
||||||
|
|
||||||
|

|
||||||
|
Wählen Sie ihr `WORKIND_DIRECTORY` in dem Feld *Location* aus und wählen Sie als Projekt Interpreter
|
||||||
|
*New environment using* und *Virtualenv* aus. Die Initialisierung kann einen Moment dauern!
|
||||||
|
|
||||||
|
Nachdem die Umgebung erfolgreich erstellt wurde, sollten Sie das Programm PyCharm in etwa wie in der nächsten Abbildung
|
||||||
|
dargstellt sehen.
|
||||||
|
|
||||||
|
Die rot markierten Felder **Explorer**, **Editor**, **Run** und **Terminal** sind für Ihre Arbeit von besonderem Interesse.
|
||||||
|
Dabei ist
|
||||||
|
- **Explorer** eine Projektübersicht, um zwischen den Dateien des Projektes zu wechseln
|
||||||
|
- **Editor** ein Fenster, um Dateien zu bearbeiten
|
||||||
|
- **Run** das Ausgabefenster eines Python Programms
|
||||||
|
- **Terminal** eine interne Kommandozeile
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Wenn Sie den Reiter `File/Settings/Project: Digitale-Bildverarbeitung/Project Interpreter` (variiert leicht bei den Betriebssystemen!)
|
||||||
|
öffnen, sollte die Ausgabe ähnlich zu der folgenden Abbildung sein. Die Anzahl der Packages kann dabei deutlich geringer sein.
|
||||||
|

|
||||||
|
|
||||||
|
Wechseln Sie nun in das Terminal und verwenden foldende Befehle:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
python -m pip install pipenv
|
||||||
|
pipenv install --skip-lock
|
||||||
|
```
|
||||||
|
Die Ausführung kann einen Moment dauern! Verwenden Sie folgenden Befehl um die korrekte Installation zu testen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python 0_Einführung/test_installation.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Herzlichen Glückwunsch, Sie haben den Kurs erfolgreich eingerichtet!
|
||||||
BIN
0_Einführung/data/git_download.png
Normal file
|
After Width: | Height: | Size: 105 KiB |
BIN
0_Einführung/data/pycharm1.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
0_Einführung/data/pycharm2.png
Normal file
|
After Width: | Height: | Size: 306 KiB |
BIN
0_Einführung/data/pycharm3.png
Normal file
|
After Width: | Height: | Size: 93 KiB |
13
0_Einführung/test_installation.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import cv2
|
||||||
|
import matplotlib
|
||||||
|
import numpy as np
|
||||||
|
import platform
|
||||||
|
|
||||||
|
if cv2.__version__ and np.__version__ and matplotlib.__version__:
|
||||||
|
print("Digital Image Processing is fun!")
|
||||||
|
print("OpenCV version:", cv2.__version__)
|
||||||
|
print("NumPy version:", np.__version__)
|
||||||
|
print("Matplotlib version:", matplotlib.__version__)
|
||||||
|
print("Python version:", platform.python_version())
|
||||||
|
else:
|
||||||
|
print("OpenCV, NumPy and/or Matplotlib are not installed.")
|
||||||
56
0_Einführung/ü1/README.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# Übung 1: Grundlagen Python
|
||||||
|
|
||||||
|
Das Erlernen der Programmiersprache Python gehört nicht zum Anspruch dieses Kurses. Trotzdem sollen einige grundlegende
|
||||||
|
Funktionen und Konventionen aus Python erläutert werden. Im Folgenden wird das simple Beispielprogramm erläutert:
|
||||||
|
|
||||||
|
````python
|
||||||
|
# Beispielprogramm
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
print(np.pi)
|
||||||
|
|
||||||
|
variable1 = 10
|
||||||
|
variable2 = [variable1, variable1 + 10, variable1 + 20]
|
||||||
|
|
||||||
|
print(variable2[0])
|
||||||
|
print(variable2[1])
|
||||||
|
print(variable2[2])
|
||||||
|
|
||||||
|
for var in variable2:
|
||||||
|
if (var / 10) % 2 == 1:
|
||||||
|
print("Die erste Ziffer Zahl %s ist ungerade!" % var)
|
||||||
|
|
||||||
|
````
|
||||||
|
## Imports
|
||||||
|
Es existieren viele vorgefertigte Pakete in Python. Sie können diese importieren, indem Sie ``import PAKET `` verwenden.
|
||||||
|
Im Beispielcode wird *numpy* importiert und mit dem Namen *np* versehen. Daraufhin können Sie auf Funktionen des Pakets
|
||||||
|
zugreifen, wie z.B. in Zeile 4 ``print(np.pi)``, in welcher der Werit von Pi ausgegben wird. Nutzen Sie Imports nach
|
||||||
|
Möglichkeit immer zu Beginn ihres Skripts.
|
||||||
|
|
||||||
|
## Variablen
|
||||||
|
In Python können Sie Variablen definieren, ohne einen Typ anzugeben. Im folgenden werden einige Typen gezeigt:
|
||||||
|
|
||||||
|
````python
|
||||||
|
a = "Ein Text" # string
|
||||||
|
b = 2 # int
|
||||||
|
c = 3.4 # float
|
||||||
|
d = [2, 3, 4] # list
|
||||||
|
e = (2, 3, 4) # tuple
|
||||||
|
````
|
||||||
|
Besondere Variablentypen sind Listen oder Tupel. Sie sind Container für mehrere andere Variablen. Auf die einzelnen
|
||||||
|
Elemente der Liste/Tupel kann mit einem Index zugegriffen werden:
|
||||||
|
|
||||||
|
````python
|
||||||
|
a = [2, 3, 4] # list
|
||||||
|
b = a[0] # Entspricht dem Wert 2
|
||||||
|
````
|
||||||
|
|
||||||
|
Die Indizierung beginnt bei dem Wert 0.
|
||||||
|
|
||||||
|
## print()
|
||||||
|
Sie können Werte oder Texte ausgeben, indem Sie den Befehl ``print(IRGENDEINE_VARIABLE)`` verwenden.
|
||||||
|
Sie müssen die Variablen vorher nicht zum Datentyp *string* konvertieren.
|
||||||
|
|
||||||
|
## Schleifen
|
||||||
|
|
||||||
|
Bitte recherchieren Sie zum Thema Schleifen unter [https://www.python-kurs.eu/schleifen.php](https://www.python-kurs.eu/schleifen.php).
|
||||||
14
0_Einführung/ü2/README.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Übung 2: Grundlagen Matrix-Operationen mit *Numpy*
|
||||||
|
|
||||||
|
In dieser Übung werden Ihnen grundlegende Matrixoperationen mit *numpy* erläutert. Das Python Paket *numpy* ist eine der
|
||||||
|
meistverwendeten Pakete für mathematische Funktionen und Grundlage für viele andere Python Pakete. Eine detaillierte
|
||||||
|
Dokumentation finden Sie unter [https://numpy.org/](https://numpy.org/).
|
||||||
|
|
||||||
|
Einige Grundlegende Funktionen werden in dieser Übung gezeigt.
|
||||||
|
|
||||||
|
# Aufgabe a)
|
||||||
|
Schauen Sie sich das Tutorial in [https://www.programiz.com/python-programming/matrix](https://www.programiz.com/python-programming/matrix) an und verstehen Sie die
|
||||||
|
Anwendung von Matrizen in *Numpy*!
|
||||||
|
|
||||||
|
# Aufgabe b)
|
||||||
|
Öffnen Sie die Datei [b.py](b.py) und machen Sie sich mit den Teilaufgaben vertraut.
|
||||||
50
0_Einführung/ü2/b.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
"""
|
||||||
|
ÜBUNG 1
|
||||||
|
|
||||||
|
In dieser Übung soll der Umgang mit grundlegenden Matrix-Operationen mithilfe von numpy erlernt werden.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
'''
|
||||||
|
a) Erstelle einen Zeilenvektor mit den Einträgen 1, 2, 3
|
||||||
|
'''
|
||||||
|
|
||||||
|
'''
|
||||||
|
b) Erstelle einen Spaltenvektor mit den Einträgen 1, 2, 3
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
c) Erstelle eine 2x3 Matrix
|
||||||
|
'''
|
||||||
|
|
||||||
|
'''
|
||||||
|
d) Erstelle eine 6x6 Matrix mit nur 0-Wert Einträgen
|
||||||
|
'''
|
||||||
|
|
||||||
|
'''
|
||||||
|
e) Erstelle eine 6x6 Matrix mit nur 1-Wert Einträgen
|
||||||
|
'''
|
||||||
|
|
||||||
|
'''
|
||||||
|
f) Erstelle eine 4x4 Einheitsmatrix
|
||||||
|
'''
|
||||||
|
|
||||||
|
'''
|
||||||
|
g) Ändere den Wert aus f) aus der zweiten Zeile und dritten Spalte zu dem Wert 5
|
||||||
|
'''
|
||||||
|
|
||||||
|
'''
|
||||||
|
h) Ändere alle Werte aus f) aus der zweiten Zeile zu dem Wert 4.5
|
||||||
|
'''
|
||||||
|
|
||||||
|
'''
|
||||||
|
i) Ändere die Werte aus f) aus der zweiten Zeile ab Spalte 3 zu dem Wert 3
|
||||||
|
'''
|
||||||
|
|
||||||
|
'''
|
||||||
|
j) Multipliziere, addiere, subtrahiere und dividiere die Matrizen a und b
|
||||||
|
'''
|
||||||
|
|
||||||
102
0_Einführung/ü2/l_b.py
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
"""
|
||||||
|
ÜBUNG 1
|
||||||
|
|
||||||
|
In dieser Übung soll der Umgang mit grundlegenden Matrix-Operationen mithilfe von numpy erlernt werden.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
'''
|
||||||
|
a) Erstelle einen Zeilenvektor mit den Einträgen 1, 2, 3
|
||||||
|
'''
|
||||||
|
A = [1, 2, 3]
|
||||||
|
A = np.asarray(A)
|
||||||
|
print("A", A)
|
||||||
|
|
||||||
|
'''
|
||||||
|
b) Erstelle einen Spaltenvektor mit den Einträgen 1, 2, 3
|
||||||
|
'''
|
||||||
|
B = [[1], [2], [3]]
|
||||||
|
B = np.asarray(B)
|
||||||
|
print("B")
|
||||||
|
print(B)
|
||||||
|
|
||||||
|
B = [
|
||||||
|
[1],
|
||||||
|
[2],
|
||||||
|
[3]
|
||||||
|
]
|
||||||
|
B = np.asarray(B)
|
||||||
|
print("B")
|
||||||
|
print(B)
|
||||||
|
|
||||||
|
'''
|
||||||
|
c) Erstelle eine 2x3 Matrix
|
||||||
|
'''
|
||||||
|
C = [
|
||||||
|
[1, 2, 3],
|
||||||
|
[4, 5, 6]
|
||||||
|
]
|
||||||
|
C = np.asarray(C)
|
||||||
|
print("C")
|
||||||
|
print(C)
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
d) Erstelle eine 6x6 Matrix mit nur 0-Wert Einträgen
|
||||||
|
'''
|
||||||
|
D = np.zeros(shape=(6, 6))
|
||||||
|
print("D")
|
||||||
|
print(D)
|
||||||
|
|
||||||
|
'''
|
||||||
|
e) Erstelle eine 6x6 Matrix mit nur 1-Wert Einträgen
|
||||||
|
'''
|
||||||
|
E = np.ones(shape=(6, 6))
|
||||||
|
print("E")
|
||||||
|
print(E)
|
||||||
|
|
||||||
|
'''
|
||||||
|
f) Erstelle eine 4x4 Einheitsmatrix
|
||||||
|
'''
|
||||||
|
F = np.eye(4)
|
||||||
|
print("F")
|
||||||
|
print(F)
|
||||||
|
|
||||||
|
'''
|
||||||
|
g) Ändere den Wert aus f) aus der zweiten Zeile und dritten Spalte zu dem Wert 5
|
||||||
|
'''
|
||||||
|
F[1, 2] = 5
|
||||||
|
print("G")
|
||||||
|
print(F)
|
||||||
|
|
||||||
|
'''
|
||||||
|
h) Ändere alle Werte aus f) aus der zweiten Zeile zu dem Wert 4.5
|
||||||
|
'''
|
||||||
|
F[1] = 4.5
|
||||||
|
print("H")
|
||||||
|
print(F)
|
||||||
|
|
||||||
|
'''
|
||||||
|
i) Ändere die Werte aus f) aus der zweiten Zeile ab Spalte 3 zu dem Wert 3
|
||||||
|
'''
|
||||||
|
F[1, 2:4] = 3
|
||||||
|
F[1, 2:] = 3
|
||||||
|
print("I")
|
||||||
|
print(F)
|
||||||
|
|
||||||
|
'''
|
||||||
|
j) Multipliziere, addiere, subtrahiere und dividiere die Matrizen a und b
|
||||||
|
'''
|
||||||
|
a = np.asarray([[1, 2], [3, 4]])
|
||||||
|
b = np.asarray([[5, 6], [7, 8]])
|
||||||
|
|
||||||
|
print("Elementweise Multiplikation")
|
||||||
|
print(
|
||||||
|
a * b
|
||||||
|
)
|
||||||
|
print("Matrixoperation Multiplikation")
|
||||||
|
print(np.matmul(a, b))
|
||||||
|
print(a + b)
|
||||||
|
print(a - b)
|
||||||
51
0_Einführung/ü3/README.md
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# OpenCV in Python
|
||||||
|
Die beliebte Bildverarbeitungs-Software OpenCV existiert auch in Python. In dieser Übung sollen Sie einige Befehle
|
||||||
|
erlernen, um grundlegende Funktionen mit OpenCV zu schreiben.
|
||||||
|
|
||||||
|
Um OpenCV zu nutzen, müssen Sie zuerst das Paker *cv2* installieren. Wenn Sie dieses Repository installiert haben,
|
||||||
|
ist das bereits geschehen. Es wird für die folgenden Schritte davon ausgegangen, das *cv2* bereits installiert ist.
|
||||||
|
Importieren Sie zu Beginn Ihres Skriptes das OpenCV Paket mit dem Befehl
|
||||||
|
|
||||||
|
````python
|
||||||
|
import cv2
|
||||||
|
````
|
||||||
|
|
||||||
|
Nun können Sie alle Funktionen von OpenCV mit dem vorangestellten Kürzel ``cv2.EIN_BEFEHL()`` nutzen.
|
||||||
|
|
||||||
|
## Bild laden
|
||||||
|
Bilder werden als MxN Matrizen (Grau- und Binärbilder) oder als MxNx3 Arrays (RGB-Farbbilder)
|
||||||
|
gespeichert und interpretiert. Um ein Bild einzulesen, wird die Funktion ``cv2.imread(PFAD_ZUM_BID)`` aufgerufen
|
||||||
|
und der Dateiname als Parameter in den Klammern übergeben.
|
||||||
|
````python
|
||||||
|
I = cv2.imread('myimage.bmp') # Farbbild einlesen
|
||||||
|
````
|
||||||
|
Mit dem Befehl ``Ì.shape`` kann die Größe einer Matrix bestimmt werden.
|
||||||
|
````python
|
||||||
|
m, n, k = I.shape # Größe ansehen
|
||||||
|
````
|
||||||
|
Bei einer Bildmatrix: Der erste Index ist der Zeilenindex (Bildkoordinaten: y-Achse), der zweite
|
||||||
|
Index ist der Spaltenindex (Bildkoordinaten: x-Achse), wobei der Punkt (0,0) dem linken oberen
|
||||||
|
Bildpunkt entspricht. Der dritte Index ist der Farbkanal.
|
||||||
|
|
||||||
|
## Bild anzeigen
|
||||||
|
Zum Anzeigen eines Bildes steht die Funktion ``cv2.imshow()`` zur Verfügung. Der Name des Fensters und die Bildvariable wird als
|
||||||
|
Parameter übergeben. Ein neues Fenster öffnet sich und zeigt das Bild an.
|
||||||
|
|
||||||
|
````python
|
||||||
|
cv2.imshow("Fenstername", I) #Bild anzeigen
|
||||||
|
cv2.waitKey(0) # Auf Tastendruck warten
|
||||||
|
````
|
||||||
|
Der Befehl ``cv2.waitKey(TIME)`` wird benötigt, damit das Programm auf eine Aktion des Benutzers wartet. Wenn der Parameter
|
||||||
|
dabei 0 ist, wartet das Programm unendlich lange auf den nächsten Tastendruck des Nutzers.
|
||||||
|
|
||||||
|
## Bild speichern
|
||||||
|
Zum Abspeichern der Bilddaten steht die Funktion ``cv2.imwrite(SPEICHER_PFAD, BILD)`` zur Verfügung. Die Bildvariable wird
|
||||||
|
als zweite Parameter und der Dateiname in Hochkommata als erster Parameter übergeben.
|
||||||
|
````python
|
||||||
|
cv2.imwrite('newimage.bmp', I) # Bilddaten abpeichern
|
||||||
|
````
|
||||||
|
Wenn die Verzeichnisstruktur nicht angegeben wird, speichert Python die Datei im aktuellen
|
||||||
|
Arbeitsverzeichnis.
|
||||||
|
|
||||||
|
# Aufgabe a)
|
||||||
|
Implementieren und testen Sie alle Funktion in einem neuen Skript [a.py](a.py)!
|
||||||
27
0_Einführung/ü4/README.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Übung 4: Grundlagen
|
||||||
|
|
||||||
|
Machen Sie sich mit den Grundlagen aus den vorherigen Übungen 1 vertraut. Diese Grundlagen werden nun praktisch angewandt
|
||||||
|
Nutzen Sie für diese Übung keine Funktionen aus *OpenCV*!
|
||||||
|
|
||||||
|
## Aufgabe a)
|
||||||
|
Führen Sie folgende Aufgabenschritte durch:
|
||||||
|
|
||||||
|
1. Erstellen Sie eine 10x10-Matrix mit den Werten von 0 bis 99 wie folgt:
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://latex.codecogs.com/svg.image?M&space;=&space;\begin{bmatrix}&space;0&&space;&space;1&&space;\ldots&space;&&space;&space;8&&space;9&space;\\&space;10&&space;&space;11&&space;&space;&&space;&space;18&&space;&space;19\\&space;\vdots&space;&&space;\vdots&space;&space;&&space;\ddots&space;&space;&&space;\vdots&space;&space;&&space;\vdots&space;&space;\\&space;80&&space;&space;81&&space;\ldots&space;&&space;88&space;&&space;89&space;\\&space;90&&space;91&space;&&space;\ldots&space;&&space;98&space;&&space;99&space;\\\end{bmatrix}&space;" title="M = \begin{bmatrix} 0& 1& \ldots & 8& 9 \\ 10& 11& & 18& 19\\ \vdots & \vdots & \ddots & \vdots & \vdots \\ 80& 81& \ldots & 88 & 89 \\ 90& 91 & \ldots & 98 & 99 \\\end{bmatrix} " />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
2. Erzeugen Sie einen Zeilenvektor der Dimension 10. Alle Komponenten sollen den Wert 20 haben:
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://latex.codecogs.com/svg.image?v&space;=&space;\begin{bmatrix}&space;20&&space;&space;20&&space;20&&space;20&&space;20&&space;20&&space;20&&space;20&&space;20&&space;20&space;\\\end{bmatrix}" title="v = \begin{bmatrix} 20& 20& 20& 20& 20& 20& 20& 20& 20& 20 \\\end{bmatrix}" />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
3. Subtrahieren Sie die zweite Zeile der Matrix M vom eben erzeugten Vektor v.
|
||||||
|
4. Multiplizieren Sie den resultierenden Vektor vr als Spaltenvektor von rechts mit der Matrix M
|
||||||
|
5. Teilen Sie die Komponenten des entstandenen Vektors jeweils durch 100 und runden Sie das Ergebnis.
|
||||||
|
6. Berechnen Sie das Maximum
|
||||||
|
|
||||||
|
Wie lautet das Ergebnis?
|
||||||
|
|
||||||
|
Die Musterlösung findet sich in [l_a.py](l_a.py)
|
||||||
24
0_Einführung/ü4/l_a.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import numpy as np
|
||||||
|
|
||||||
|
M = np.zeros((10, 10))
|
||||||
|
for i in range(10):
|
||||||
|
for j in range(10):
|
||||||
|
M[i, j] = 10 * i + j
|
||||||
|
|
||||||
|
print("(1) M=", M)
|
||||||
|
|
||||||
|
v = np.ones((1, 10)) * 20
|
||||||
|
print("(2) v=", v)
|
||||||
|
|
||||||
|
vr = v - M[1, :]
|
||||||
|
print("(3) vr:", vr)
|
||||||
|
|
||||||
|
res = np.matmul(M, np.transpose(vr, axes=(1, 0)))
|
||||||
|
print("(4) res:", res)
|
||||||
|
|
||||||
|
res = res / 100
|
||||||
|
res = np.round(res) # np.floor() np.ceil()
|
||||||
|
print("(5) res:", res)
|
||||||
|
|
||||||
|
maximum = np.max(res)
|
||||||
|
print("(6) maximum:", maximum)
|
||||||
17
1_Grundlagen/README.md
Normal 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
@@ -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" />
|
||||||
21
1_Grundlagen/ü1/README.md
Normal 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
@@ -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()
|
||||||
10
1_Grundlagen/ü2/README.md
Normal 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
@@ -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
@@ -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()
|
||||||
36
1_Grundlagen/ü3/README.md
Normal 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
|
||||||
|
:---:|:---
|
||||||
|
 | 
|
||||||
|
[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
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||||
36
1_Grundlagen/ü4/README.md
Normal 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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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
@@ -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)
|
||||||
BIN
1_Grundlagen/ü4/data/Mauer.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
19
1_Grundlagen/ü4/l_a.py
Normal 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)
|
||||||
31
1_Grundlagen/ü5/README.md
Normal 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:
|
||||||
|

|
||||||
|
|
||||||
|
Der Schematische Ablauf eines Rolling-Shutter Sensors hingegen sieht wie folgt aus:
|
||||||
|

|
||||||
|
|
||||||
|
## 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
@@ -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)
|
||||||
BIN
1_Grundlagen/ü5/data/global_shutter.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
1_Grundlagen/ü5/data/kitti1.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
1_Grundlagen/ü5/data/kitti2.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
1_Grundlagen/ü5/data/kitti3.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
1_Grundlagen/ü5/data/rolling_shutter.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
16
1_Grundlagen/ü5/l_a.py
Normal 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)
|
||||||
9
2_Bildbearbeitung/README.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Einführung in die Bildbearbeitung
|
||||||
|
|
||||||
|
In diesem Kapitel werden Ihnen verschiedene Klassen von Operationen und Methoden erläutert und mit Beispielen
|
||||||
|
exemplarisch dargestellt. Die Übungen zeigen Beispiele zu den Themen
|
||||||
|
- **Punktoperationen (Intensitätstransformationen)**
|
||||||
|
- **Lokale Operationen (Filterung)**
|
||||||
|
- **Globale Operationen**
|
||||||
|
- **Geometrische Transformationen**
|
||||||
|
|
||||||
19
2_Bildbearbeitung/ü1/README.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Übung 1: Helligkeitsausgleich
|
||||||
|
|
||||||
|
In dieser Übung wird ein Helligkeitsausgleich durchgeführt. Gegeben sind drei Bilder von Texten wie exemplarisch unten
|
||||||
|
dargestellt. Zu sehen ist, dass die mittlere Beleuchtung des Bildes lokal stark variiert. Auf Algorithmen, die beispielweise
|
||||||
|
Schwellwerte auf Gurndlage der Helligkeit nutzen, können diese Unterschiede störend wirken. Im folgenden soll daher ein
|
||||||
|
Helligkeitsausgleich durchgeführt werden, nachdem die mittlere lokale Helligkeit in jedem Bildsegment gleich ist.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Aufgabe a)
|
||||||
|
In der Datei [a.py](a.py) werden drei Bilder geladen. Führen Sie den Helligkeitsausgleich auf allen Bildern durch und zeigen
|
||||||
|
Sie sie an.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
13
2_Bildbearbeitung/ü1/a.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import numpy as np
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
KERNEL_SIZE = 20
|
||||||
|
|
||||||
|
# Einlesen des Bildes
|
||||||
|
filepath = "../../data/text_%s.jpg"
|
||||||
|
images = list()
|
||||||
|
for i in [1, 2, 3]:
|
||||||
|
img = cv2.imread(filepath % i)
|
||||||
|
img = cv2.resize(img, (500, 500))
|
||||||
|
images.append(img)
|
||||||
|
|
||||||
34
2_Bildbearbeitung/ü1/l_a.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import numpy as np
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
KERNEL_SIZE = 20
|
||||||
|
|
||||||
|
# Einlesen des Bildes
|
||||||
|
filepath = "../../data/text_%s.jpg"
|
||||||
|
images = list()
|
||||||
|
for i in [1, 2, 3]:
|
||||||
|
img = cv2.imread(filepath % i)
|
||||||
|
img = cv2.resize(img, (500, 500))
|
||||||
|
images.append(img)
|
||||||
|
|
||||||
|
|
||||||
|
def balance(img):
|
||||||
|
kernel = np.ones((KERNEL_SIZE, KERNEL_SIZE)) / (KERNEL_SIZE * KERNEL_SIZE)
|
||||||
|
blurred = cv2.filter2D(img, -1, kernel=kernel)
|
||||||
|
img = img / blurred
|
||||||
|
img = 255 * (img - np.min(img)) / (np.max(img) - np.min(img)) # Normieren auf Wertebereich {0, ..., 255}
|
||||||
|
img = img.astype(np.uint8)
|
||||||
|
print(np.max(img), np.min(img))
|
||||||
|
return img
|
||||||
|
|
||||||
|
|
||||||
|
balanced_images = list()
|
||||||
|
for img in images:
|
||||||
|
balanced_image = balance(img)
|
||||||
|
balanced_images.append(balanced_image)
|
||||||
|
|
||||||
|
for i, (image, balaced_image) in enumerate(zip(images, balanced_images)):
|
||||||
|
cv2.imshow("Text%s" % (i + 1), image)
|
||||||
|
cv2.imshow("AusgeglichenerText%s" % (i + 1), balaced_image)
|
||||||
|
|
||||||
|
cv2.waitKey(0)
|
||||||
22
2_Bildbearbeitung/ü10/README.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Übung 10: (Contrast Limited) Adaptive Histogramm Equalization
|
||||||
|
|
||||||
|
In dieser Übung soll die Adaptive Histogramm Equalization und die Contrast Limited Adaptive Histogramm Equalization
|
||||||
|
verwendet werden, um den Kontrast in einem Bild zu erhöhen.
|
||||||
|
|
||||||
|
## a) Adaptive Histogramm Equalization
|
||||||
|
|
||||||
|
Wenden Sie die adaptive Histogramm Equalization auf das Bild an, welches in dem Skript [a.py](a.py)
|
||||||
|
geladen wird. Adaptieren Sie für eine Region von 50x50 Pixel. Die Lösung ist in der Datei [l_a.py](l_a.py) zu finden!
|
||||||
|
|
||||||
|
## b) Contrast Limited Adaptive Histogramm Equalization
|
||||||
|
|
||||||
|
Wenden Sie die Kontrast-limitierte adaptive Histogramm Equalization auf das Bild an, welches in dem Skript [b.py](b.py)
|
||||||
|
geladen wird. Sie können ein selbst definiertes Clip-Limit definieren.
|
||||||
|
Adaptieren Sie für eine Region von 50x50 Pixel. Die Lösung ist in der Datei [l_b.py](l_b.py) zu finden!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
15
2_Bildbearbeitung/ü10/a.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
img = cv2.imread("../../data/car.png", cv2.IMREAD_GRAYSCALE)
|
||||||
|
img = cv2.resize(img, (500, 500))
|
||||||
|
# Do some preprocessing
|
||||||
|
img = img.astype(float)
|
||||||
|
img = 50 + (105 * img / 255)
|
||||||
|
cv2.imshow("Original", img.astype(np.uint8))
|
||||||
|
|
||||||
|
# Implement AHE
|
||||||
|
|
||||||
|
|
||||||
|
cv2.waitKey(0)
|
||||||
|
|
||||||
15
2_Bildbearbeitung/ü10/b.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
img = cv2.imread("../../data/car.png", cv2.IMREAD_GRAYSCALE)
|
||||||
|
img = cv2.resize(img, (500, 500))
|
||||||
|
# Do some preprocessing
|
||||||
|
img = img.astype(float)
|
||||||
|
img = 50 + (105 * img / 255)
|
||||||
|
cv2.imshow("Original", img.astype(np.uint8))
|
||||||
|
|
||||||
|
# Implement CLAHE
|
||||||
|
|
||||||
|
|
||||||
|
cv2.waitKey(0)
|
||||||
|
|
||||||
25
2_Bildbearbeitung/ü10/l_a.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
img = cv2.imread("../../data/car.png", cv2.IMREAD_GRAYSCALE)
|
||||||
|
img = cv2.resize(img, (500, 500))
|
||||||
|
# Do some preprocessing
|
||||||
|
img = img.astype(float)
|
||||||
|
img = 50 + (105 * img / 255)
|
||||||
|
cv2.imshow("Original", img.astype(np.uint8))
|
||||||
|
|
||||||
|
# Implement AHE
|
||||||
|
new_image = np.zeros_like(img)
|
||||||
|
height, width = img.shape
|
||||||
|
for x in range(width):
|
||||||
|
for y in range(height):
|
||||||
|
x1, x2 = np.maximum(0, x - 25), np.minimum(x + 25, height)
|
||||||
|
y1, y2 = np.maximum(0, y - 25), np.minimum(y + 25, height)
|
||||||
|
hist, values = np.histogram(img[y1:y2, x1:x2], bins=256, range=(0, 256))
|
||||||
|
cum_hist = np.cumsum(hist)
|
||||||
|
v = round(img[y, x])
|
||||||
|
new_image[y, x] = 255 * cum_hist[v] / cum_hist[255]
|
||||||
|
cv2.imshow("AHE", new_image.astype(np.uint8))
|
||||||
|
|
||||||
|
cv2.waitKey(0)
|
||||||
|
|
||||||
31
2_Bildbearbeitung/ü10/l_b.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
img = cv2.imread("../../data/car.png", cv2.IMREAD_GRAYSCALE)
|
||||||
|
img = cv2.resize(img, (500, 500))
|
||||||
|
# Do some preprocessing
|
||||||
|
img = img.astype(float)
|
||||||
|
img = 50 + (105 * img / 255)
|
||||||
|
cv2.imshow("Original", img.astype(np.uint8))
|
||||||
|
|
||||||
|
# Implement CLAHE
|
||||||
|
new_image = np.zeros_like(img)
|
||||||
|
height, width = img.shape
|
||||||
|
for x in range(width):
|
||||||
|
for y in range(height):
|
||||||
|
x1, x2 = np.maximum(0, x - 25), np.minimum(x + 25, height)
|
||||||
|
y1, y2 = np.maximum(0, y - 25), np.minimum(y + 25, height)
|
||||||
|
hist, values = np.histogram(img[y1:y2, x1:x2], bins=256, range=(0, 256))
|
||||||
|
clip_limit = 0.6 * round(np.max(hist))
|
||||||
|
higher_values = hist >= clip_limit
|
||||||
|
sum_of_higher_values = np.sum(hist[higher_values] - clip_limit)
|
||||||
|
hist = np.minimum(hist, clip_limit)
|
||||||
|
hist = hist + round(sum_of_higher_values / 256)
|
||||||
|
cum_hist = np.cumsum(hist)
|
||||||
|
v = round(img[y, x])
|
||||||
|
new_image[y, x] = 255 * cum_hist[v] / cum_hist[255]
|
||||||
|
|
||||||
|
cv2.imshow("CLAHE", new_image.astype(np.uint8))
|
||||||
|
|
||||||
|
cv2.waitKey(0)
|
||||||
|
|
||||||
109
2_Bildbearbeitung/ü2/README.md
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
# Übung 2: Lokale Bildoperationen
|
||||||
|
|
||||||
|
Lokale Bildoperationen berechnen den Pixelwert des Ausgangspixels aus der lokalen Umgebung des Eingangspixels. Die
|
||||||
|
Berechnungsvorschrift ist dabei für jedes Pixel gleich.
|
||||||
|
|
||||||
|
In dieser Übung werden einige Beispiele für lokale Bildoperationen behandelt. Dabei werden unter anderem
|
||||||
|
- Faltung
|
||||||
|
- Gradienten
|
||||||
|
- Rangfolgefilter
|
||||||
|
- Hochpass, Tiefpass, Bandpass
|
||||||
|
verwendet.
|
||||||
|
|
||||||
|
## Aufgabe a)
|
||||||
|
Das Bild zeigt ***I_in*** zwei sich schneidende Linien (eine horizontalen und eine vertikale) auf hellem
|
||||||
|
Hintergrund (außerhalb des eingezeichneten Rasters sind die Flächen wie angedeutet störungsfrei
|
||||||
|
fortgeführt). Es soll nun die Horizontale extrahiert und in binärer Form dargestellt werden, so dass
|
||||||
|
sich das Binärbild ***I_out*** ergibt. Im folgenden sind
|
||||||
|
die Bilder visualisiert und als Matrix dargestellt.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="./data/cross1.png" />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
```python
|
||||||
|
I_in = [
|
||||||
|
[200, 200, 100, 200, 200],
|
||||||
|
[200, 200, 100, 200, 200],
|
||||||
|
[100, 100, 100, 100, 100],
|
||||||
|
[200, 200, 100, 200, 200],
|
||||||
|
[200, 200, 100, 200, 200],
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="./data/cross2.png" />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
```python
|
||||||
|
I_out = [
|
||||||
|
[ 0, 0, 0, 0, 0],
|
||||||
|
[ 0, 0, 0, 0, 0],
|
||||||
|
[255, 255, 255, 255, 255],
|
||||||
|
[ 0, 0, 0, 0, 0],
|
||||||
|
[ 0, 0, 0, 0, 0],
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Für die Aufgabe stehen die folgenden Operationen zur Verfügung:
|
||||||
|
|
||||||
|
- Hochpassfilter mit 3x3 Faltungskern
|
||||||
|
|
||||||
|
```python
|
||||||
|
[
|
||||||
|
[ -1, -1, -1 ],
|
||||||
|
[ -1, 8, -1 ],
|
||||||
|
[ -1, -1, -1 ]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
- Kantenfilter mit 3x3 Faltungskern
|
||||||
|
|
||||||
|
```python
|
||||||
|
[
|
||||||
|
[ 1, 0, -1 ],
|
||||||
|
[ 1, 0, -1 ],
|
||||||
|
[ 1, 0, -1 ]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
- Kantenfilter mit 3x3 Faltungskern
|
||||||
|
|
||||||
|
```python
|
||||||
|
[
|
||||||
|
[ -1, -1, -1 ],
|
||||||
|
[ 0, 0, 0 ],
|
||||||
|
[ 1, 1, 1 ]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
- Punktoperation: Betragsbildung
|
||||||
|
- Punktoperation: Schwellwertoperation, Punkte mit einer Intensität *I_xy* < 128 werden auf *I_xy* = 0 gesetzt, ansonsten zu 255
|
||||||
|
- Median-Filter der Größe 3x3
|
||||||
|
|
||||||
|
Wählen Sie 4 der 6 Operationen und wenden Sie sie auf die das Bild an. Jede Operation darf dabei nur einmal verwendet werden.
|
||||||
|
Visualisieren Sie jeden Zwischenschritt.
|
||||||
|
Die Aufgabe soll in der Datei [a.py](a.py) bearbeitet werden! Die entsprechende Lösung finden Sie in [l_a.py](l_a.py).
|
||||||
|
|
||||||
|
**Hinweis:** Mehrere Lösungswege sind möglich!
|
||||||
|
|
||||||
|
|
||||||
|
## Aufgabe b)
|
||||||
|
Gegeben ist das Bild [edge_01.png](data/edge_01.png). Es zeigt zwei aneinander grenzende graue Flächen die mit Rauschen
|
||||||
|
versetzt sind. Ziel ist es, das Bild so zu filtern, dass die Kante als weichgezeichnete Linie auf
|
||||||
|
schwarzem Untergrund resultiert, wie in Bild [edge_02.png](data/edge_02.png) beispielhaft dargestellt ist.
|
||||||
|
|
||||||
|
*edge_01.png*:
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="./data/edge_01.png" />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
*edge_02.png*:
|
||||||
|
<p align="center">
|
||||||
|
<img src="./data/edge_02.png" />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Für die Bearbeitung können Sie sich verschiedener Filter bedienen. Beispiele dafür können sein
|
||||||
|
- Hochpass, Tiefpass, Bandpass
|
||||||
|
- Diverse Richtungsfilter
|
||||||
|
- Rangfolgefilter wie Minimum, Maximum, Median
|
||||||
|
|
||||||
|
Die Aufgabe soll in der Datei [b.py](b.py) bearbeitet werden! Die entsprechende Lösung finden Sie in [l_b.py](l_b.py).
|
||||||
BIN
2_Bildbearbeitung/ü2/data/cross1.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
2_Bildbearbeitung/ü2/data/cross2.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
2_Bildbearbeitung/ü2/data/edge_01.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
2_Bildbearbeitung/ü2/data/edge_02.png
Normal file
|
After Width: | Height: | Size: 359 B |
50
2_Bildbearbeitung/ü2/l_a.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import numpy as np
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
''' Einlesen des Bildes '''
|
||||||
|
I_in = [
|
||||||
|
[200, 200, 100, 200, 200],
|
||||||
|
[200, 200, 100, 200, 200],
|
||||||
|
[100, 100, 100, 100, 100],
|
||||||
|
[200, 200, 100, 200, 200],
|
||||||
|
[200, 200, 100, 200, 200],
|
||||||
|
]
|
||||||
|
|
||||||
|
I_in = np.asarray(I_in, dtype="uint8")
|
||||||
|
|
||||||
|
print("Bild vor der Bearbeitung:")
|
||||||
|
print(I_in)
|
||||||
|
print()
|
||||||
|
print(I_in.dtype)
|
||||||
|
|
||||||
|
''' Operation 1: Kantenfilter '''
|
||||||
|
edge = [
|
||||||
|
[-1, -1, -1],
|
||||||
|
[ 0, 0, 0],
|
||||||
|
[ 1, 1, 1]
|
||||||
|
]
|
||||||
|
edge = np.asarray(edge)
|
||||||
|
edge_conv = np.flip(edge)
|
||||||
|
I_in = cv2.filter2D(I_in, cv2.CV_64F, edge_conv, borderType=cv2.BORDER_REPLICATE)
|
||||||
|
print("Operation 1: Kantenfilter")
|
||||||
|
print(I_in)
|
||||||
|
print()
|
||||||
|
|
||||||
|
''' Operation 2: Absolutwertbildung '''
|
||||||
|
I_in = np.abs(I_in)
|
||||||
|
print("Operation 2: Absolutwertbildung")
|
||||||
|
print(I_in)
|
||||||
|
print()
|
||||||
|
|
||||||
|
''' Operation 3: Medianfilter'''
|
||||||
|
I_in = cv2.medianBlur(I_in.astype("float32"), 3)
|
||||||
|
print("Operation 3: Medianfilter")
|
||||||
|
print(I_in)
|
||||||
|
print()
|
||||||
|
|
||||||
|
''' Operation 4: Schwellwert '''
|
||||||
|
I_in = np.copy(I_in)
|
||||||
|
ret, I_out = cv2.threshold(I_in, 127, 255, cv2.THRESH_BINARY)
|
||||||
|
print("Operation 4: Schwellwert")
|
||||||
|
print(I_out)
|
||||||
|
print()
|
||||||
36
2_Bildbearbeitung/ü2/l_b.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import numpy as np
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
''' Einlesen des Bildes '''
|
||||||
|
I_in = cv2.imread("data/edge_01.png")
|
||||||
|
I_in = cv2.cvtColor(I_in, cv2.COLOR_BGR2GRAY)
|
||||||
|
cv2.imshow("Bild Schritt 0", I_in)
|
||||||
|
|
||||||
|
|
||||||
|
''' Operation 1: Median-Filter'''
|
||||||
|
I_in = cv2.medianBlur(I_in, 9)
|
||||||
|
cv2.imshow("Bild Schritt 1", I_in)
|
||||||
|
|
||||||
|
''' Operation 2: Kantenfilter'''
|
||||||
|
edge = [
|
||||||
|
[-1, 0, 1],
|
||||||
|
[-1, 0, 1],
|
||||||
|
[-1, 0, 1]
|
||||||
|
]
|
||||||
|
edge = np.asarray(edge)
|
||||||
|
I_in = cv2.filter2D(I_in, cv2.CV_64F, edge, borderType=cv2.BORDER_REPLICATE)
|
||||||
|
cv2.imshow("Bild Schritt 2", I_in)
|
||||||
|
|
||||||
|
''' Operation 3: Glättung / Tiefpass mit Boxfilter'''
|
||||||
|
edge = [
|
||||||
|
[1, 1, 1],
|
||||||
|
[1, 1, 1],
|
||||||
|
[1, 1, 1]
|
||||||
|
]
|
||||||
|
edge = np.asarray(edge) / 9
|
||||||
|
I_in = cv2.filter2D(I_in, cv2.CV_64F, edge, borderType=cv2.BORDER_REPLICATE)
|
||||||
|
I_in = I_in / np.max(I_in)
|
||||||
|
cv2.imshow("Bild Schritt 3", I_in)
|
||||||
|
|
||||||
|
''' Bilder anzeigen, Bis Taste gedrückt wird '''
|
||||||
|
cv2.waitKey(0)
|
||||||
56
2_Bildbearbeitung/ü3/README.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# Übung 3: Geometrische Transformationen
|
||||||
|
|
||||||
|
Geometrische Transformationen können auf Bilder angewendet werden, um den Wert eines Pixels im Eingangsbild auf eine
|
||||||
|
andere Position im Ausgangsbild abzubilden.
|
||||||
|
|
||||||
|
Geometrische Transformationen können unterschieden werden in
|
||||||
|
|
||||||
|
|Name| Freiheitsgrade| Beispiel|
|
||||||
|
|:---:|:---:|:---:|
|
||||||
|
|Translation|2||
|
||||||
|
|Rigide/Euklidische Transformation|3||
|
||||||
|
|Ähnlichkeits- Transformation|4||
|
||||||
|
|Affine Transformation|6||
|
||||||
|
|Projektive Transformation|8||
|
||||||
|
|
||||||
|
Zusätzliche Informationen über die Implementierung in OpenCV können Sie hier finden: [https://docs.opencv.org/3.4/d4/d61/tutorial_warp_affine.html](https://docs.opencv.org/3.4/d4/d61/tutorial_warp_affine.html)
|
||||||
|
|
||||||
|
## Aufgabe a)
|
||||||
|
Eine häufig verwendete Transformation ist die Skalierung, Diese sollen Sie nun implementieren. Arbeiten Sie dazu die
|
||||||
|
Fragen bzw. Teilschritte in [a.py](a.py) ab. Die entsprechende Lösung finden Sie in [l_a.py](l_a.py).
|
||||||
|
.
|
||||||
|
|
||||||
|
## Aufgabe b)
|
||||||
|
|
||||||
|
Betrachten Sie das folgende Eingangsbild sowie die daraus resultierenden Ausgangsbilder.
|
||||||
|
|
||||||
|
**Eingangsbild:**
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
**Ausgangsbilder:**
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
Gebeben sind folgende Transformationsforschriften:
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://latex.codecogs.com/svg.image?T(p)&space;=&space;\begin{pmatrix}cos(-\pi&space;/&space;4)&space;&&space;&space;-sin(-\pi&space;/&space;4)\\sin(-\pi&space;/&space;4)&&space;&space;cos(-\pi&space;/&space;4)\\\end{pmatrix}&space;p" title="T(p) = \begin{pmatrix}cos(\-pi / 4) & -sin(\-pi / 4)\\sin(\-pi / 4)& cos(\-pi / 4)\\\end{pmatrix} p" />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://latex.codecogs.com/svg.image?T(p)&space;=&space;\begin{pmatrix}cos(-\pi&space;/&space;4)&space;&&space;&space;-sin(-\pi&space;/&space;4)\\sin(-\pi&space;/&space;4)&&space;&space;cos(-\pi&space;/&space;4)\\\end{pmatrix}&space;(p&space;-&space;c)&space;+&space;c" title="T(p) = \begin{pmatrix}cos(\-pi / 4) & -sin(\-pi / 4)\\sin(\-pi / 4)& cos(\-pi / 4)\\\end{pmatrix} (p - c) + c" />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://latex.codecogs.com/svg.image?T(p)&space;=&space;\begin{pmatrix}1&space;&&space;&space;0.8&space;\\0&space;&&space;&space;1&space;\\\end{pmatrix}&space;(p&space;-&space;c)&space;+&space;c" title="T(p) = \begin{pmatrix}1 & 0.8 \\0 & 1 \\\end{pmatrix} (p - c) + c" /></p>
|
||||||
|
|
||||||
|
Wenden Sie die Transformationen in der Datei [b.py](b.py) auf das Eingangsbild an und finden Sie so heraus, welche
|
||||||
|
Transformation zu welchem Ausgangsbild gehört. Die Lösung findet sich in der Datei [l_b.py](l_b.py).
|
||||||
|
|
||||||
|
## Aufgabe c)
|
||||||
|
Weitere Fragen:
|
||||||
|
- Wie kann man sich die verschiedenen affinen Transformationsmatrizen aus a) herleiten ?
|
||||||
|
- Diskutieren Sie Vor- und Nachteile von Forward und Backwardmapping!
|
||||||
34
2_Bildbearbeitung/ü3/a.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import numpy as np
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
''' Einlesen des Bildes '''
|
||||||
|
img = cv2.imread("data/normal.jpg")
|
||||||
|
|
||||||
|
'''
|
||||||
|
Schritt 1: Geben Sie eine Transformationvorschrift T an, die das Eingangsbild
|
||||||
|
- mit dem Faktor s_x ungleich 0 in x-Richtung skaliert
|
||||||
|
- mit dem Faktor s_y ungleich 0 in y-Richtung skaliert
|
||||||
|
'''
|
||||||
|
s_x = 2
|
||||||
|
s_y = 2
|
||||||
|
|
||||||
|
'''
|
||||||
|
Schritt 2: Geben Sie geben sie die Inverse T_inv zu T an
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
Schritt 3: Implementieren Sie eine Funktion scale(img, sx, sy), welche das Bild nach der Skalierung wiedergibt.
|
||||||
|
Verwenden Sie für die Transformation das Backward-Mapping und für die Interpolation Nearest-Neighbour Interpolation.
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def scale(img, s_x, s_y):
|
||||||
|
|
||||||
|
return new_img
|
||||||
|
|
||||||
|
|
||||||
|
''' Ausgabe des Bildes '''
|
||||||
|
new_img = scale(img, 2, 2)
|
||||||
|
cv2.imshow('img', new_img)
|
||||||
|
cv2.waitKey(0)
|
||||||
BIN
2_Bildbearbeitung/ü3/data/center-rotated.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
2_Bildbearbeitung/ü3/data/normal.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
2_Bildbearbeitung/ü3/data/rotated.jpg
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
2_Bildbearbeitung/ü3/data/shear.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
57
2_Bildbearbeitung/ü3/l_a.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import numpy as np
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
''' Einlesen des Bildes '''
|
||||||
|
img = cv2.imread("data/normal.jpg")
|
||||||
|
|
||||||
|
'''
|
||||||
|
Schritt 1: Geben Sie eine Transformationvorschrift T an, die das Eingangsbild
|
||||||
|
- mit dem Faktor s_x ungleich 0 in x-Richtung skaliert
|
||||||
|
- mit dem Faktor s_y ungleich 0 in y-Richtung skaliert
|
||||||
|
'''
|
||||||
|
s_x = 2
|
||||||
|
s_y = 2
|
||||||
|
T = np.asarray(
|
||||||
|
[
|
||||||
|
[s_x, 0],
|
||||||
|
[0, s_y]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
'''
|
||||||
|
Schritt 2: Geben Sie geben sie die Inverse T_inv zu T an
|
||||||
|
'''
|
||||||
|
|
||||||
|
T_inv = np.linalg.inv(T)
|
||||||
|
|
||||||
|
'''
|
||||||
|
Schritt 3: Implementieren Sie eine Funktion scale(img, sx, sy), welche das Bild nach der Skalierung wiedergibt.
|
||||||
|
Verwenden Sie für die Transformation das Backward-Mapping und für die Interpolation Nearest-Neighbour Interpolation.
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def scale(img, s_x, s_y):
|
||||||
|
rows, cols, channels = img.shape
|
||||||
|
new_rows, new_cols = int(rows * s_y), int(cols * s_x)
|
||||||
|
T = np.asarray([[s_x, 0], [0, s_y]])
|
||||||
|
T_inv = np.linalg.inv(T)
|
||||||
|
|
||||||
|
new_img = np.zeros((new_rows, new_cols, channels))
|
||||||
|
for x in range(new_cols):
|
||||||
|
for y in range(new_rows):
|
||||||
|
position = np.asarray([x, y])
|
||||||
|
old_position = np.matmul(position, T_inv)
|
||||||
|
old_position = np.round(old_position).astype(int)
|
||||||
|
old_x, old_y = old_position[0], old_position[1]
|
||||||
|
# Überstpringen, wenn ausserhalb des Bildes
|
||||||
|
if not 0 <= old_x < cols or not 0 <= old_y < rows:
|
||||||
|
continue
|
||||||
|
new_img[y, x] = img[old_y, old_x]
|
||||||
|
return new_img.astype(np.uint8)
|
||||||
|
|
||||||
|
|
||||||
|
''' Ausgabe des Bildes '''
|
||||||
|
new_img = scale(img, 2, 2)
|
||||||
|
cv2.imshow('new_img', new_img)
|
||||||
|
cv2.imshow('img', img)
|
||||||
|
cv2.waitKey(0)
|
||||||
106
2_Bildbearbeitung/ü3/l_b.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import numpy as np
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
''' Einlesen des Bildes '''
|
||||||
|
img = cv2.imread("data/normal.jpg")
|
||||||
|
rows, cols, channels = img.shape
|
||||||
|
|
||||||
|
|
||||||
|
''' Transformation t1: Implementierung mit OpenCV '''
|
||||||
|
|
||||||
|
t_1 = np.float32(
|
||||||
|
[
|
||||||
|
[ np.cos(np.pi / 4), np.sin(np.pi / 4), 0],
|
||||||
|
[-np.sin(np.pi / 4), np.cos(np.pi / 4), 0]]
|
||||||
|
)
|
||||||
|
dst = cv2.warpAffine(img, t_1, (cols, rows))
|
||||||
|
cv2.imshow('img',dst)
|
||||||
|
cv2.waitKey(0)
|
||||||
|
|
||||||
|
''' Transformation t2: Implementierung ohne CV2 '''
|
||||||
|
c1, c2, c3, c4 = np.cos(np.pi / 4), np.sin(np.pi / 4), -np.sin(np.pi / 4), np.cos(np.pi / 4)
|
||||||
|
c_y, c_x = rows / 2, cols / 2
|
||||||
|
|
||||||
|
|
||||||
|
def new_pos(x, y):
|
||||||
|
new_x = round(c1 * (x - c_x) + c2 * (y - c_y) + c_x)
|
||||||
|
new_y = round(c3 * (x - c_x) + c4 * (y - c_y) + c_y)
|
||||||
|
return new_x, new_y
|
||||||
|
|
||||||
|
|
||||||
|
def old_pos(new_x, new_y):
|
||||||
|
x = (new_x/c1) - (c_x / c1) + c_x - c3 * c2 * c_x / (c4 * c1) - (c2 * new_y / (c1 * c4)) + (c_y * c2 / (c1 * c4))
|
||||||
|
x = x / (1 - c3*c2/(c4*c1))
|
||||||
|
y = c_y + (new_y - (c3 * (x - c_x)) - c_y) / c4
|
||||||
|
x = round(x)
|
||||||
|
y = round(y)
|
||||||
|
return x, y
|
||||||
|
|
||||||
|
|
||||||
|
# Forwardmapping
|
||||||
|
new_img = np.zeros_like(img)
|
||||||
|
for x in range(cols):
|
||||||
|
for y in range(rows):
|
||||||
|
new_x, new_y = new_pos(x, y)
|
||||||
|
# Überstpringen, wenn ausserhalb des Bildes
|
||||||
|
if not 0 <= new_x < cols or not 0 <= new_y < rows:
|
||||||
|
continue
|
||||||
|
new_img[new_y, new_x] = img[y, x]
|
||||||
|
cv2.imshow('img', new_img)
|
||||||
|
cv2.waitKey(0)
|
||||||
|
|
||||||
|
# Backwardmapping
|
||||||
|
new_img = np.zeros_like(img)
|
||||||
|
for x in range(cols):
|
||||||
|
for y in range(rows):
|
||||||
|
old_x, old_y = old_pos(x, y)
|
||||||
|
# Überstpringen, wenn ausserhalb des Bildes
|
||||||
|
if not 0 <= old_x < cols or not 0 <= old_y < rows:
|
||||||
|
continue
|
||||||
|
new_img[y, x] = img[old_y, old_x]
|
||||||
|
cv2.imshow('img', new_img)
|
||||||
|
cv2.waitKey(0)
|
||||||
|
|
||||||
|
''' Transformation t3: Implementierung ohne CV2 '''
|
||||||
|
c1, c2, c3, c4 = 1, 0.8, 0, 1
|
||||||
|
c_y, c_x = rows / 2, cols / 2
|
||||||
|
|
||||||
|
|
||||||
|
def new_pos(x, y):
|
||||||
|
new_x = round(c1 * (x - c_x) + c2 * (y - c_y) + c_x)
|
||||||
|
new_y = round(c3 * (x - c_x) + c4 * (y - c_y) + c_y)
|
||||||
|
return new_x, new_y
|
||||||
|
|
||||||
|
|
||||||
|
def old_pos(new_x, new_y):
|
||||||
|
x = (new_x/c1) - (c_x / c1) + c_x - c3 * c2 * c_x / (c4 * c1) - (c2 * new_y / (c1 * c4)) + (c_y * c2 / (c1 * c4))
|
||||||
|
x = x / (1 - c3*c2/(c4*c1))
|
||||||
|
y = c_y + (new_y - (c3 * (x - c_x)) - c_y) / c4
|
||||||
|
x = round(x)
|
||||||
|
y = round(y)
|
||||||
|
return x, y
|
||||||
|
|
||||||
|
|
||||||
|
# Forwardmapping
|
||||||
|
new_img = np.zeros_like(img)
|
||||||
|
for x in range(cols):
|
||||||
|
for y in range(rows):
|
||||||
|
new_x, new_y = new_pos(x, y)
|
||||||
|
# Überstpringen, wenn ausserhalb des Bildes
|
||||||
|
if not 0 <= new_x < cols or not 0 <= new_y < rows:
|
||||||
|
continue
|
||||||
|
new_img[new_y, new_x] = img[y, x]
|
||||||
|
cv2.imshow('img', new_img)
|
||||||
|
cv2.waitKey(0)
|
||||||
|
|
||||||
|
# Backwardmapping
|
||||||
|
new_img = np.zeros_like(img)
|
||||||
|
for x in range(cols):
|
||||||
|
for y in range(rows):
|
||||||
|
old_x, old_y = old_pos(x, y)
|
||||||
|
# Überstpringen, wenn ausserhalb des Bildes
|
||||||
|
if not 0 <= old_x < cols or not 0 <= old_y < rows:
|
||||||
|
continue
|
||||||
|
new_img[y, x] = img[old_y, old_x]
|
||||||
|
cv2.imshow('img', new_img)
|
||||||
|
cv2.waitKey(0)
|
||||||
24
2_Bildbearbeitung/ü3/l_c.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Lösung Aufgabe c)
|
||||||
|
|
||||||
|
## Wie kann man sich die verschiedenen affnen Transformationsmatrizen herleiten?
|
||||||
|
Für den Fall das die Abbildung linear ist, muss die Abbildung lediglich auf den Basisbildern
|
||||||
|
bestimmt werden. Zum Beispiel für die Basis `(1, 0)` und `(0, 1)` berechnet man die transformierten
|
||||||
|
Vektoren v1 und v2. Dann ist die Transformationsmatrix gegeben durch `T(p) = (v1, v2) p`. Bei
|
||||||
|
affinen Abbildungen kommt ensprechend noch eine Translation dazu. Wichtig für die Herleitung
|
||||||
|
der Transformationen sind daher Basiswechsel aus der linearen Algebra.
|
||||||
|
|
||||||
|
## Diskutieren Sie Vor- und Nachteile von Forward und Backwardmapping
|
||||||
|
|
||||||
|
Vorteile Backwardmapping:
|
||||||
|
- Geschwindigkeitsvorteil wenn lediglich ein bestimmter Bereich von Interesse ist. Dieser kann
|
||||||
|
direkt berechnet werden.
|
||||||
|
- Keine Löcher, keine Überlappungen im Ergebnisbild.
|
||||||
|
|
||||||
|
Vorteile Forwardmapping:
|
||||||
|
- Eventueller Vorteil da die Inverse der Transformation nicht bestimmt werden muss.
|
||||||
|
|
||||||
|
Nachteile:
|
||||||
|
- Es kann zu ÜUberlappung kommen. Mehrere Eingangspixel landen teilweise im gleichen Ergebnispixel.
|
||||||
|
(Hier muss aus diesen Werten ein finaler Wert interpoliert werden) Interpolation
|
||||||
|
erst nach kompletter Transformation möglich. Beim Backward-Mapping wird für jede Position
|
||||||
|
direkt eine Interpolation berechnet.
|
||||||
42
2_Bildbearbeitung/ü4/README.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# Übung 4: Filterkern
|
||||||
|
|
||||||
|
Ein Filterkern ist eine n-dimensionale Matrix, mit der üblicherweise eine lokale und lineare Operation auf Pixel im
|
||||||
|
Eingangsbild angewendet wird. In dieser Übung sollen Aufgaben mit Filterkernen manuell und mit Python gelößt werden.
|
||||||
|
|
||||||
|
## Aufgabe a) Separierung
|
||||||
|
Unter Umständen ist ein 2-dimensionaler Filterkern separierbar, d.h. er durch zwei 1-dimensonale Filterkerne dargestellt
|
||||||
|
werden.
|
||||||
|
|
||||||
|
Nehmen Sie die bereits separierten Filterkerne
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://latex.codecogs.com/svg.image?\bg_white&space;F_a&space;=&space;\begin{bmatrix}1&space;&&space;4&space;&&space;1&space;\\\end{bmatrix}&space;\quad&space;\text{und}\quad&space;F_b&space;=&space;\begin{bmatrix}&space;-1\\&space;0\\1\end{bmatrix}&space;" title="\bg_white F_a = \begin{bmatrix}1 & 4 & 1 \\\end{bmatrix} \quad \text{und} F_b = \begin{bmatrix} -1\\ 0\\1\end{bmatrix} " />
|
||||||
|
</p>
|
||||||
|
und erstellen den ursprünglichen Filterken, sowohl "von Hand" als auch in einem Python Skript.
|
||||||
|
|
||||||
|
|
||||||
|
Betrachten und separieren Sie zusätzlich den Filterkern
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://latex.codecogs.com/svg.image?\bg_white&space;\inline&space;F_C&space;=&space;\begin{bmatrix}-2&space;&&space;-3&space;&&space;-2&space;\\0&space;&&space;0&space;&&space;0&space;\\2&space;&&space;3&space;&&space;2&space;\\\end{bmatrix}&space;&space;" title="\bg_white \inline F_C = \begin{bmatrix}-2 & -3 & -2 \\0 & 0 & 0 \\2 & 3 & 2 \\\end{bmatrix} " />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
wenn möglich (manuell und in Python)! Die Lösung findet sich in der Datei [l_a.py](l_a.py).
|
||||||
|
|
||||||
|
## Aufgabe b)
|
||||||
|
Stellen Sie sich vor, Sie wenden die separierten oder nicht separierten Filterkerne auf ein durchschnittliches Bild an.
|
||||||
|
Wie viele Rechenoperationen pro Pixel führen Sie im Durchschnitt pro Pixel aus, wenn sie
|
||||||
|
|
||||||
|
- einen separierten 3x3 Filterkern
|
||||||
|
- einen nicht separierten 3x3 Filterkern
|
||||||
|
|
||||||
|
verwenden. Die Musterlösung befindet sich in der Datei [l_b.md](l_b.md).
|
||||||
|
|
||||||
|
## Aufgabe c)
|
||||||
|
Laden Sie ein beliebiges Bild ein und verwenden Sie die OpenCV-Methode *cv2.filter2D()* um Schärfefilter, Mittelwert-Filter und
|
||||||
|
Kantenfilter auf das Bild anzuwenden. Die Musterlösung befindet sich in der Datei [l_c.py](l_c.py).
|
||||||
|
|
||||||
|
## Aufgabe d)
|
||||||
|
Modifizieren Sie die Aufgabe c), indem Sie nur den Mittelwert-Filter verwenden und diesen vergrößern. Verwenden Sie
|
||||||
|
verschiedene Boundary Optionen durch das Argument *borderType* in der Funktion *cv2.filter2D()* und betrachten Sie das
|
||||||
|
Ergebnis. Vergleichen Sie die verschiedenen Optionen *cv2.BORDER_REFLECT*, *cv2.BORDER_REPLICATE* und *cv2.BORDER_CONSTANT*.
|
||||||
|
Visualisieren Sie weiterhin die Optionen, indem Sie einen Rand mit der Funktion *cv2.copyMakeBorder()* zu dem Bild
|
||||||
|
hinzufügen. Die Musterlösung befindet sich in der Datei [l_d.py](l_d.py).
|
||||||
82
2_Bildbearbeitung/ü4/l_a.py
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
""" Erstellen des Ursprünglichen Filterkerns"""
|
||||||
|
f_a = np.expand_dims(np.asarray([1, 4, 1]), 0)
|
||||||
|
f_b = np.expand_dims(np.asarray([-1, 0, 1]), 1)
|
||||||
|
f_orig = np.matmul(f_b, f_a)
|
||||||
|
print("TEIL 1")
|
||||||
|
print(f_a)
|
||||||
|
print(f_b)
|
||||||
|
print(f_orig)
|
||||||
|
|
||||||
|
""" Separieren des Filterkerns
|
||||||
|
|
||||||
|
Wir können das Problem als
|
||||||
|
|
||||||
|
f_a * f_b = f_C
|
||||||
|
|
||||||
|
mit
|
||||||
|
|
||||||
|
f_a = [a, b, c]^T
|
||||||
|
f_b = [d, e, f]
|
||||||
|
|
||||||
|
f_C = [
|
||||||
|
[ ad, ae, af ],
|
||||||
|
[ bd, be, bf ],
|
||||||
|
[ cd, ce, cf ],
|
||||||
|
]
|
||||||
|
|
||||||
|
modellieren. Wenn wir a=1 setzten, ergibt sich d=-2 e=-3 f=-2 (erste Zeile der Matrix) sodass sich ein linear
|
||||||
|
unabhängiges Gleichungssystem
|
||||||
|
f_C = [
|
||||||
|
[ -2a, -3a, -2a ],
|
||||||
|
[ -2b, -3b, -2b ],
|
||||||
|
[ -2c, -3c, -2c ],
|
||||||
|
] =
|
||||||
|
[
|
||||||
|
[-2, -3, -2],
|
||||||
|
[0, 0, 0],
|
||||||
|
[2, 3, 2],
|
||||||
|
]
|
||||||
|
|
||||||
|
=> -2a=-2, -2b=0, -2c=2
|
||||||
|
|
||||||
|
=> A * x = B
|
||||||
|
A = [
|
||||||
|
[-2, 0, 0],
|
||||||
|
[ 0, -2, 0],
|
||||||
|
[ 0, 0, -2],
|
||||||
|
]
|
||||||
|
x = [a, b, c]^T
|
||||||
|
B = [-2, 0, 2]^T
|
||||||
|
|
||||||
|
|
||||||
|
erstellen lässt. Dieses lässt sich leicht "von Hand" oder mit Numpy lösen.
|
||||||
|
=>
|
||||||
|
f_a = [1, 0, -1]^T
|
||||||
|
f_b = [-2, -3, -2]
|
||||||
|
Hinweis: Es gibt unendlich viele Lösungen (wenn separierbar)!
|
||||||
|
"""
|
||||||
|
f_C = np.asarray(
|
||||||
|
[
|
||||||
|
[-2, -3, -2],
|
||||||
|
[0, 0, 0],
|
||||||
|
[2, 3, 2],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
A = np.array([
|
||||||
|
[-2, 0, 0],
|
||||||
|
[ 0,-2, 0],
|
||||||
|
[ 0, 0,-2],
|
||||||
|
])
|
||||||
|
B = np.array([-2, 0, 2])
|
||||||
|
x = np.linalg.solve(A, B)
|
||||||
|
|
||||||
|
f_a = np.expand_dims(x, axis=1)
|
||||||
|
f_b = np.expand_dims(np.asarray([-2, -3, -2]), axis=0)
|
||||||
|
f_C_new = np.matmul(f_a, f_b)
|
||||||
|
print("TEIL 2")
|
||||||
|
print(f_C)
|
||||||
|
print(f_C_new)
|
||||||
32
2_Bildbearbeitung/ü4/l_b.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Lösung zu Aufgabe b)
|
||||||
|
Zuerst soll der Rechenaufwand für einen Pixel betrachtet werden:
|
||||||
|
|
||||||
|
**Filterkern mit 3x3-Matrix für einen Pixel:**
|
||||||
|
- 9 x Multiplikation
|
||||||
|
- 8 x Addition
|
||||||
|
- Insgesamt 17 x Rechenoperationen
|
||||||
|
|
||||||
|
|
||||||
|
**Filterkern mit separierten 3x1- bzw. 1x3-Vektoren für einen Pixel:**
|
||||||
|
- 12 x Multiplikation
|
||||||
|
- 8 x Addition Insgesamt
|
||||||
|
- 20 x Rechenoperationen
|
||||||
|
|
||||||
|
Berechnet man lediglich den Pixelwert in der Mitte, so ergibt sich kein Geschwindigkeitsvorteil.
|
||||||
|
Für das gesamte Bild ergibt sich jedoch ein Geschwindigkeitsvorteil pro Pixel, da die Zwischenergebnisse
|
||||||
|
aus der Filterung mit dem ersten Filterkern nicht neu berechnet werden müssen. Anstatt
|
||||||
|
9 Multiplikationen und 8 Additionen mit dem 3x3-Filterkern ergeben sich mit den separierten
|
||||||
|
Filterkomponenten durchschnittlich 6 Multiplikationen und 4 Additionen pro Pixel.
|
||||||
|
|
||||||
|
Gemittelte Anzahl Rechenoperationen pro Pixel für das gesamte Bild:
|
||||||
|
|
||||||
|
**Filterkern mit 3x3-Matrix für einen Pixel:**
|
||||||
|
- 9 x Multiplikation
|
||||||
|
- 8 x Addition
|
||||||
|
- Insgesamt 17 x Rechenoperationen
|
||||||
|
|
||||||
|
|
||||||
|
**Filterkern mit separierten 3x1- bzw. 1x3-Vektoren für einen Pixel:**
|
||||||
|
- 6 x Multiplikation
|
||||||
|
- 4 x Addition Insgesamt
|
||||||
|
- 10 x Rechenoperationen
|
||||||
37
2_Bildbearbeitung/ü4/l_c.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
img = cv2.imread("../../data/cameraman.png")
|
||||||
|
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||||||
|
|
||||||
|
k1 = (1 / 25) * np.asarray([
|
||||||
|
[1, 1, 1, 1, 1],
|
||||||
|
[1, 1, 1, 1, 1],
|
||||||
|
[1, 1, 1, 1, 1],
|
||||||
|
[1, 1, 1, 1, 1],
|
||||||
|
[1, 1, 1, 1, 1]
|
||||||
|
], dtype=np.uint8)
|
||||||
|
|
||||||
|
k2 = np.asarray([
|
||||||
|
[1, 0, -1],
|
||||||
|
[1, 0, -1],
|
||||||
|
[1, 0, -1],
|
||||||
|
], dtype=np.float32)
|
||||||
|
|
||||||
|
k3 = np.asarray([
|
||||||
|
[-1, -1, -1],
|
||||||
|
[-1, 9, -1],
|
||||||
|
[-1, -1, -1],
|
||||||
|
], dtype=np.float32)
|
||||||
|
|
||||||
|
img_k1 = cv2.filter2D(img, -1, k1)
|
||||||
|
img_k2 = cv2.filter2D(img.astype(np.float32), -1, k2)
|
||||||
|
img_k2 = np.maximum(img_k2, 0).astype(np.uint8)
|
||||||
|
img_k3 = cv2.filter2D(img.astype(np.float32), -1, k3)
|
||||||
|
img_k3 = np.maximum(img_k3, 0).astype(np.uint8)
|
||||||
|
|
||||||
|
cv2.imshow("img", img)
|
||||||
|
cv2.imshow("img_k1", img_k1)
|
||||||
|
cv2.imshow("img_k2", img_k2)
|
||||||
|
cv2.imshow("img_k3", img_k3)
|
||||||
|
cv2. waitKey()
|
||||||
25
2_Bildbearbeitung/ü4/l_d.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
img = cv2.imread("../../data/cameraman.png")
|
||||||
|
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||||||
|
|
||||||
|
k1 = (1 / (33 * 33)) * np.ones((33, 33), dtype=np.uint8)
|
||||||
|
|
||||||
|
border_types = [
|
||||||
|
("cv2.BORDER_REFLECT", cv2.BORDER_REFLECT, 255),
|
||||||
|
("cv2.BORDER_REPLICATE", cv2.BORDER_REPLICATE, 255),
|
||||||
|
("cv2.BORDER_CONSTANT", cv2.BORDER_CONSTANT, 0),
|
||||||
|
("cv2.BORDER_CONSTANT", cv2.BORDER_CONSTANT, 255),
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
cv2.imshow("img", img)
|
||||||
|
|
||||||
|
for name, border, value in border_types:
|
||||||
|
img_border = cv2.copyMakeBorder(img, 50, 50, 50, 50, borderType=border, value=value)
|
||||||
|
img_k1 = cv2.filter2D(img, -1, k1, borderType=border)
|
||||||
|
cv2.imshow("img_k1_" + name + str(value), img_k1)
|
||||||
|
cv2.imshow("img_border_" + name + str(value), img_border)
|
||||||
|
|
||||||
|
cv2. waitKey()
|
||||||
24
2_Bildbearbeitung/ü5/README.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Übung 5: Nichtlineare Filter
|
||||||
|
|
||||||
|
In dieser Übung wird der nichtlineare Median-Filter behandelt. Der Median-Filter ist ein Sonderfall des Rangfolge-Filters.
|
||||||
|
Bei einem Rangfolge-Filter werden die Werte des zu untersuchenden Bildausschnitts aufsteigend sortiert.
|
||||||
|
Je nach Filter-Definition wird dann der n-te Wert der Folge als neuer Pixelwert definiert. Sonderfälle des Rangfolge-Filters sind:
|
||||||
|
- Maximum-Filter: Letzter Wert der Folge
|
||||||
|
- Minimum-Filter: Erster Wert der Folge
|
||||||
|
- Median-Filter: Wert der mittleren Position der Folge
|
||||||
|
|
||||||
|
## Aufgabe a)
|
||||||
|
Gegeben ist folgender Bildausschnitt:
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://latex.codecogs.com/svg.image?I&space;=&space;\begin{bmatrix}1&space;&4&space;&space;&6&space;&space;\\&space;3&&space;2&space;&&space;1&space;\\&space;6&&space;&space;8&&space;&space;2\end{bmatrix}&space;" title="I = \begin{bmatrix}1 &4 &6 \\ 3& 2 & 1 \\ 6& 8& 2\end{bmatrix} " />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Geben Sie den Mittelwert und Median des Ausschnitts an!
|
||||||
|
Die Lösung finden Sie in der Datei [l_a.py](l_a.py).
|
||||||
|
|
||||||
|
## Aufgabe b)
|
||||||
|
Starten Sie das Program [b.py](b.py) um ein verrauschtes Bild zu erhalten und filtern Sie es
|
||||||
|
mit der OpenCV-Filterfunktion *cv2.medianBlur()*. Führen Sie die Filterung mit den Filtergrößen: 3x3, 5x5,
|
||||||
|
9x9. Vergleichen Sie die Ergebnisse durch Visualisierung des Ergebnisses mit *cv2.imshow()*.
|
||||||
|
|
||||||
|
Die Lösung finden Sie in der Datei [l_b.py](l_b.py).
|
||||||
18
2_Bildbearbeitung/ü5/b.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
img = cv2.imread("../../data/lena.png")
|
||||||
|
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||||||
|
|
||||||
|
''' 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[white] = 255
|
||||||
|
img[black] = 0
|
||||||
|
|
||||||
|
''' Bild anzeigen '''
|
||||||
|
cv2.imshow("img", img)
|
||||||
|
cv2. waitKey()
|
||||||
12
2_Bildbearbeitung/ü5/l_a.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import numpy as np
|
||||||
|
|
||||||
|
I = [
|
||||||
|
[1, 4, 6],
|
||||||
|
[3, 2, 1],
|
||||||
|
[6, 8, 2],
|
||||||
|
]
|
||||||
|
|
||||||
|
I = np.asarray(I)
|
||||||
|
|
||||||
|
print("Median", np.median(I))
|
||||||
|
print("Mittelwert", np.average(I))
|
||||||
24
2_Bildbearbeitung/ü5/l_b.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
img = cv2.imread("../../data/lena.png")
|
||||||
|
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||||||
|
|
||||||
|
''' 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[white] = 255
|
||||||
|
img[black] = 0
|
||||||
|
|
||||||
|
cv2.imshow("img", img)
|
||||||
|
|
||||||
|
''' Median Filter anwenden '''
|
||||||
|
sizes = [3, 5, 9]
|
||||||
|
for kernel_size in sizes:
|
||||||
|
img_filtered = cv2.medianBlur(img, kernel_size)
|
||||||
|
cv2.imshow("img_filtered_" + str(kernel_size), img_filtered)
|
||||||
|
|
||||||
|
cv2. waitKey()
|
||||||
22
2_Bildbearbeitung/ü6/README.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Übung 6: Forward-Mapping / Backward-Mapping
|
||||||
|
|
||||||
|
In dieser Übung wird das *Forward-Mapping* und das *Backward-Mapping* bei geometrischen Transformationen betrachtet.
|
||||||
|
Sie interessieren Sich für den Wert des Pixels an der Stelle **(x=12, y=38)** des Bildes
|
||||||
|
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
nach der Transformation mit der Transformationsvorschrift
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://latex.codecogs.com/svg.image?\begin{pmatrix}&space;x'\\y'\end{pmatrix}&space;=\begin{pmatrix}&space;0.5&space;&&space;0\\0&space;&&space;0.5\end{pmatrix}\cdot\begin{pmatrix}&space;x\\y\end{pmatrix}.&space;" title="\begin{pmatrix} x'\\y'\end{pmatrix} =\begin{pmatrix} 0.5 & 0\\0 & 0.5\end{pmatrix}\cdot\begin{pmatrix} x\\y\end{pmatrix} ." />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Berechnen Sie den Wert des Pixels an der Stelle **(x=12, y=38)** nach der Transformation unter Anwendung des Backward- und Forward-Mappings!
|
||||||
|
|
||||||
|
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!
|
||||||
|
|
||||||
|
|
||||||
|
Vergleichen Sie Die Methoden: Wie unterscheiden Sie sich? Welche Vor- und Nachteile haben die Methoden?
|
||||||
|
|
||||||
|
|
||||||
13
2_Bildbearbeitung/ü6/a.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
img = cv2.imread("../../data/car.png")
|
||||||
|
cv2.imshow("Car", img)
|
||||||
|
|
||||||
|
print("Image Shape:", img.shape)
|
||||||
|
|
||||||
|
print("\nForward-Mapping")
|
||||||
|
|
||||||
|
print("\nBackward-Mapping")
|
||||||
|
|
||||||
|
cv2.waitKey(0)
|
||||||
29
2_Bildbearbeitung/ü6/l_a.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
img = cv2.imread("../../data/car.png")
|
||||||
|
cv2.imshow("Car", img)
|
||||||
|
|
||||||
|
print("Image Shape:", img.shape)
|
||||||
|
|
||||||
|
|
||||||
|
print("\nForward-Mapping")
|
||||||
|
new_image = np.zeros((int(img.shape[0] / 2), int(img.shape[1] / 2), img.shape[2]), dtype=np.uint8)
|
||||||
|
|
||||||
|
for x in range(img.shape[1]):
|
||||||
|
for y in range(img.shape[0]):
|
||||||
|
new_image[int(y/2), int(x/2)] = img[y, x]
|
||||||
|
|
||||||
|
cv2.imshow("Forward-Mapping", new_image)
|
||||||
|
print("Pixel at position x=12, y=38", new_image[38, 12])
|
||||||
|
|
||||||
|
|
||||||
|
print("\nBackward-Mapping")
|
||||||
|
# Inverse Transformation:
|
||||||
|
# (x, y)^T = ([2, 0] * (x', y')^T
|
||||||
|
# [0, 2])
|
||||||
|
|
||||||
|
p_12_38 = img[38*2, 12*2]
|
||||||
|
print("Pixel at position x=12, y=38", p_12_38)
|
||||||
|
|
||||||
|
cv2.waitKey(0)
|
||||||
42
2_Bildbearbeitung/ü7/README.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# Übung 7: Interpolation
|
||||||
|
|
||||||
|
In dieser Übung wird die *Nächste Nachbar (Nearest Neighbour) Interpolation* und die *Bilineare Interpolation*
|
||||||
|
bei geometrischen Transformationen betrachtet.
|
||||||
|
|
||||||
|
Für diese Aufgabe haben Sie ein Bild bestehend aus vier Pixelwerten I_xy:
|
||||||
|
|
||||||
|
- I_00 = 1
|
||||||
|
- I_10 = 2
|
||||||
|
- I_01 = 3
|
||||||
|
- I_11 = 4
|
||||||
|
|
||||||
|
|
||||||
|
## a) Interpolation beim Backward Mapping
|
||||||
|
Sie transformieren das Bild mithilfe der Transformationsvorschrift **T** beziehungsweise der dazugehörigen inversen
|
||||||
|
Transformationsvorschrift mithilfe des Backward-Mappings. Die ursprüngliche Position I_xy auf dem Eingangsbild des Pixels I'_00 auf dem Ausgangsbild wird durch die die Inverse
|
||||||
|
Transformation gegeben. Berechnen Sie den Wert des Pixels I'_00 mithilfe der *Nächste Nachbar (Nearest Neighbour) Interpolation* und der *Bilineare Interpolation*, wenn die ursprüngliche Postition I_xy an den Koordinaten
|
||||||
|
|
||||||
|
- (x=0.3 | y=0.8)
|
||||||
|
- (x=0 | y=1)
|
||||||
|
- (x=0.5 | y=0.5)
|
||||||
|
|
||||||
|
liegt.
|
||||||
|
|
||||||
|
Sie können die Aufgabe handschriftlich oder mithilfe eines Skripts lösen. Die Lösung ist in der Datei [l_a.py](l_a.py) zu finden!
|
||||||
|
|
||||||
|
|
||||||
|
## b) Interpolation beim Forward Mapping
|
||||||
|
Sie transformieren das Bild mithilfe der Transformationsvorschrift **T** und des Forward-Mappings. Nach der Transformation ist die neue Position der gegeben
|
||||||
|
Pixel wie folgt:
|
||||||
|
|
||||||
|
- I_00 = 1: (x=0.5 | y=0.5)
|
||||||
|
- I_10 = 2: (x=1.5 | y=0.5)
|
||||||
|
- I_01 = 3: (x=0.5 | y=1.5)
|
||||||
|
- I_11 = 4: (x=1.5 | y=1.5)
|
||||||
|
|
||||||
|
Interpolieren Sie die Werte auf dem Zielbild mithilfe der *Nächste Nachbar (Nearest Neighbour) Interpolation* und der *Bilineare Interpolation* für die folgenden Pixel:
|
||||||
|
|
||||||
|
- I'_11
|
||||||
|
- I'_00
|
||||||
|
|
||||||
|
Sie können die Aufgabe handschriftlich oder mithilfe eines Skripts lösen. Die Lösung ist in der Datei [l_b.py](l_b.py) zu finden!
|
||||||
20
2_Bildbearbeitung/ü7/l_a.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
i_00 = 1
|
||||||
|
i_10 = 2
|
||||||
|
i_01 = 3
|
||||||
|
i_11 = 4
|
||||||
|
|
||||||
|
|
||||||
|
# 1)
|
||||||
|
i_new_bilinear = 0.2 * (0.7 * 1 + 0.3 * 2) + 0.8 * (0.7 * 3 + 0.3 * 4)
|
||||||
|
i_new_nn = 3
|
||||||
|
print(i_new_bilinear, i_new_nn)
|
||||||
|
|
||||||
|
# 2)
|
||||||
|
i_new_bilinear = 0 * (1 * 1 + 0 * 2) + 1 * (1 * 3 + 0 * 4)
|
||||||
|
i_new_nn = 3
|
||||||
|
print(i_new_bilinear, i_new_nn)
|
||||||
|
|
||||||
|
# 3)
|
||||||
|
i_new_bilinear = 0.5 * (0.5 * 1 + 0.5 * 2) + 0.5 * (0.5 * 3 + 0.5 * 4)
|
||||||
|
i_new_nn = 4 # Multiple solutions! Here: Ceil
|
||||||
|
print(i_new_bilinear, i_new_nn)
|
||||||
16
2_Bildbearbeitung/ü7/l_b.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
i_00 = 1 # New position: (x=0.5, y=0.5)
|
||||||
|
i_10 = 2 # New position: (x=1.5, y=0.5)
|
||||||
|
i_01 = 3 # New position: (x=0.5, y=1.5)
|
||||||
|
i_11 = 4 # New position: (x=1.5, y=1.5)
|
||||||
|
|
||||||
|
|
||||||
|
# 1)
|
||||||
|
i_new_bilinear = 0.5 * (0.5 * 1 + 0.5 * 2) + 0.5 * (0.5 * 3 + 0.5 * 4)
|
||||||
|
i_new_nn = 4 # Multiple solutions! Here: Ceil
|
||||||
|
print(i_new_bilinear, i_new_nn)
|
||||||
|
|
||||||
|
# 2)
|
||||||
|
# This solution is depending on the border behaviour! If no border behaviour is defined, there is not bilinear solution!
|
||||||
|
i_new_bilinear = ...
|
||||||
|
i_new_nn = 1
|
||||||
|
print(i_new_nn)
|
||||||
22
2_Bildbearbeitung/ü8/README.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Übung 8: Geometrische Transformation
|
||||||
|
|
||||||
|
In dieser Übung soll die Transformationsforschrift
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://latex.codecogs.com/svg.image?\begin{pmatrix}&space;x'\\y'\end{pmatrix}&space;=\begin{pmatrix}&space;a&space;&&space;b\\c&space;&&space;d\end{pmatrix}\cdot\begin{pmatrix}&space;x\\y\end{pmatrix}+&space;\begin{pmatrix}&space;e\\f\end{pmatrix}.&space;" title="\begin{pmatrix} x'\\y'\end{pmatrix} =\begin{pmatrix} 0.5 & 0\\0 & 0.5\end{pmatrix}\cdot\begin{pmatrix} x\\y\end{pmatrix} ." />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
für die Transformation des Bildes I1 zu I2 hergeleitet werden.
|
||||||
|
|
||||||
|
|
||||||
|
| I1 | I2 |
|
||||||
|
| --- | --- |
|
||||||
|
|  |  |
|
||||||
|
|
||||||
|
|
||||||
|
Leiten Sie die Transformationsvorschrift her und testen Sie die Vorschrift, indem Sie ein Skript in die Datei [a.py](a.py)
|
||||||
|
programmieren. Die Lösung ist in der Datei [l_a.py](l_a.py) zu finden!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
42
2_Bildbearbeitung/ü8/a.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
img = cv2.imread("../../data/car.png")
|
||||||
|
img = cv2.resize(img, (500, 500))
|
||||||
|
cv2.imshow("Car", img)
|
||||||
|
|
||||||
|
print("Image Shape:", img.shape)
|
||||||
|
|
||||||
|
|
||||||
|
def T(pos, rotation, translation):
|
||||||
|
""" Transformation Matrix """
|
||||||
|
new_pos = np.matmul(rotation, pos) + translation
|
||||||
|
|
||||||
|
return new_pos
|
||||||
|
|
||||||
|
|
||||||
|
new_image = np.zeros_like(img)
|
||||||
|
|
||||||
|
rotation = [
|
||||||
|
[..., ...],
|
||||||
|
[..., ...]
|
||||||
|
]
|
||||||
|
translation = [
|
||||||
|
...,
|
||||||
|
...
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
for x in range(img.shape[1]):
|
||||||
|
for y in range(img.shape[0]):
|
||||||
|
old_pos = np.asarray([[x], [y]])
|
||||||
|
new_pos = T(old_pos, rotation, translation)
|
||||||
|
new_pos = new_pos.astype(int)
|
||||||
|
if 0 <= new_pos[0] < img.shape[1] and 0 <= new_pos[1] < img.shape[0]:
|
||||||
|
new_image[new_pos[1], new_pos[0]] = img[y, x]
|
||||||
|
|
||||||
|
print(new_image.shape)
|
||||||
|
cv2.imshow("After Transformation", new_image)
|
||||||
|
|
||||||
|
cv2.waitKey(0)
|
||||||
|
|
||||||
BIN
2_Bildbearbeitung/ü8/data/new.jpg
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
2_Bildbearbeitung/ü8/data/original.jpg
Normal file
|
After Width: | Height: | Size: 77 KiB |
88
2_Bildbearbeitung/ü8/l_a.py
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
img = cv2.imread("../../data/car.png")
|
||||||
|
img = cv2.resize(img, (500, 500))
|
||||||
|
cv2.imshow("Car", img)
|
||||||
|
|
||||||
|
print("Image Shape:", img.shape)
|
||||||
|
|
||||||
|
|
||||||
|
def T(pos, rotation, translation):
|
||||||
|
""" Transformation Matrix """
|
||||||
|
new_pos = np.matmul(rotation, pos) + translation
|
||||||
|
|
||||||
|
return new_pos
|
||||||
|
|
||||||
|
|
||||||
|
new_image = np.zeros_like(img)
|
||||||
|
|
||||||
|
alpha = -0.5 * np.pi
|
||||||
|
rotation = [
|
||||||
|
[np.cos(alpha), -np.sin(alpha)],
|
||||||
|
[np.sin(alpha), np.cos(alpha)]
|
||||||
|
]
|
||||||
|
translation = [
|
||||||
|
[0],
|
||||||
|
[img.shape[1]]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
for x in range(img.shape[1]):
|
||||||
|
for y in range(img.shape[0]):
|
||||||
|
old_pos = np.asarray([[x], [y]])
|
||||||
|
new_pos = T(old_pos, rotation, translation)
|
||||||
|
new_pos = new_pos.astype(int)
|
||||||
|
if 0 <= new_pos[0] < img.shape[1] and 0 <= new_pos[1] < img.shape[0]:
|
||||||
|
new_image[new_pos[1], new_pos[0]] = img[y, x]
|
||||||
|
|
||||||
|
print(new_image.shape)
|
||||||
|
cv2.imshow("After Transformation", new_image)
|
||||||
|
|
||||||
|
"""
|
||||||
|
Naive Solution
|
||||||
|
|
||||||
|
1. Rotate the image with 90° -> alpha=90°
|
||||||
|
2. Translate in y axis with image length -> [ [0], [height] ]
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
Mathematical solution
|
||||||
|
|
||||||
|
1. Find correspondences
|
||||||
|
|
||||||
|
x,y --> x',y'
|
||||||
|
|
||||||
|
0,0 --> 0,1
|
||||||
|
1,0 --> 0,0
|
||||||
|
0,1 --> 1,1
|
||||||
|
1,1 --> 1,0
|
||||||
|
0.5,0.5 --> 0.5,0.5
|
||||||
|
|
||||||
|
|
||||||
|
2. Solve system:
|
||||||
|
[a, b] * [x, y]^T + [e, f]^T = [x', y']^T
|
||||||
|
[c, d]
|
||||||
|
|
||||||
|
ax + by + e = x'
|
||||||
|
cx + dy + f = y'
|
||||||
|
|
||||||
|
|
||||||
|
Translation (0,0 --> 0,1):
|
||||||
|
0 + 0 + e = 0 --> e = 0
|
||||||
|
0 + 0 + f = 1 --> f = 1
|
||||||
|
|
||||||
|
Rotation (1,0 --> 0,0):
|
||||||
|
a + 0 + 0 = 0 --> a = 0
|
||||||
|
c + 0 + 1 = 0 --> c = -1
|
||||||
|
|
||||||
|
Rotation (0,1 --> 1,1):
|
||||||
|
0 + b + 0 = 1 --> b = 1
|
||||||
|
0 + d + 1 = 1 --> d = 0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
cv2.waitKey(0)
|
||||||
|
|
||||||
18
2_Bildbearbeitung/ü9/README.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Übung 9: Gamma-Korrektur
|
||||||
|
|
||||||
|
In dieser Übung soll die Gamma-Korrektur
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://latex.codecogs.com/svg.image?g'(x,y)=\frac{255}{255^\gamma}\cdot&space;g(x,y)^\gamma" title="" />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
für die bessere Sichtbarkeit des Bilder
|
||||||
|

|
||||||
|
verwendet werden.
|
||||||
|
|
||||||
|
Wenden Sie die Gamma Korrektur mit den Gamma-Werte 0.5,1 und 2 auf das Bild an, indem Sie ein Skript in die Datei [a.py](a.py)
|
||||||
|
programmieren. Die Lösung ist in der Datei [l_a.py](l_a.py) zu finden!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
11
2_Bildbearbeitung/ü9/a.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
img = cv2.imread("../../data/car.png")
|
||||||
|
img = cv2.resize(img, (500, 500))
|
||||||
|
cv2.imshow("Original", img)
|
||||||
|
|
||||||
|
|
||||||
|
cv2.waitKey(0)
|
||||||
|
|
||||||
|
|
||||||
21
2_Bildbearbeitung/ü9/l_a.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
img = cv2.imread("../../data/car.png")
|
||||||
|
img = cv2.resize(img, (500, 500))
|
||||||
|
cv2.imshow("Original", img)
|
||||||
|
|
||||||
|
|
||||||
|
def gamma_correction(img, gamma):
|
||||||
|
img = img.astype(np.float)
|
||||||
|
img = 255 * np.power(img, gamma) / np.power(255, gamma)
|
||||||
|
print(np.max(img))
|
||||||
|
img = img.astype(np.uint8)
|
||||||
|
return img
|
||||||
|
|
||||||
|
|
||||||
|
for gamma in [0.5, 1, 2]:
|
||||||
|
cv2.imshow("%s" % gamma, gamma_correction(img, gamma))
|
||||||
|
|
||||||
|
cv2.waitKey(0)
|
||||||
|
|
||||||
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
@@ -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
|
After Width: | Height: | Size: 24 KiB |
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||||