commit 7ea3207e6329469c10c8344df4496a54ae6cb3d7 Author: tobias Date: Fri Jun 27 14:34:11 2025 +0200 Initial commit with project files diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b2ff91d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +venv/ +*.tflite \ No newline at end of file diff --git a/0_Einführung/README.md b/0_Einführung/README.md new file mode 100644 index 0000000..6394202 --- /dev/null +++ b/0_Einführung/README.md @@ -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. + +![alt text](./data/git_download.png) + +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. + +![alt text](./data/pycharm1.png) +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 + +![alt text](./data/pycharm2.png) + +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. +![alt text](./data/pycharm3.png) + +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! diff --git a/0_Einführung/data/git_download.png b/0_Einführung/data/git_download.png new file mode 100644 index 0000000..0a457f4 Binary files /dev/null and b/0_Einführung/data/git_download.png differ diff --git a/0_Einführung/data/pycharm1.png b/0_Einführung/data/pycharm1.png new file mode 100644 index 0000000..ea407f0 Binary files /dev/null and b/0_Einführung/data/pycharm1.png differ diff --git a/0_Einführung/data/pycharm2.png b/0_Einführung/data/pycharm2.png new file mode 100644 index 0000000..01abc61 Binary files /dev/null and b/0_Einführung/data/pycharm2.png differ diff --git a/0_Einführung/data/pycharm3.png b/0_Einführung/data/pycharm3.png new file mode 100644 index 0000000..e1b5207 Binary files /dev/null and b/0_Einführung/data/pycharm3.png differ diff --git a/0_Einführung/test_installation.py b/0_Einführung/test_installation.py new file mode 100644 index 0000000..9610a6d --- /dev/null +++ b/0_Einführung/test_installation.py @@ -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.") diff --git a/0_Einführung/ü1/README.md b/0_Einführung/ü1/README.md new file mode 100644 index 0000000..3d9a736 --- /dev/null +++ b/0_Einführung/ü1/README.md @@ -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). \ No newline at end of file diff --git a/0_Einführung/ü2/README.md b/0_Einführung/ü2/README.md new file mode 100644 index 0000000..0071999 --- /dev/null +++ b/0_Einführung/ü2/README.md @@ -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. diff --git a/0_Einführung/ü2/b.py b/0_Einführung/ü2/b.py new file mode 100644 index 0000000..3674f66 --- /dev/null +++ b/0_Einführung/ü2/b.py @@ -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 +''' + diff --git a/0_Einführung/ü2/l_b.py b/0_Einführung/ü2/l_b.py new file mode 100644 index 0000000..17cddf7 --- /dev/null +++ b/0_Einführung/ü2/l_b.py @@ -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) diff --git a/0_Einführung/ü3/README.md b/0_Einführung/ü3/README.md new file mode 100644 index 0000000..dc75b9b --- /dev/null +++ b/0_Einführung/ü3/README.md @@ -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)! \ No newline at end of file diff --git a/0_Einführung/ü4/README.md b/0_Einführung/ü4/README.md new file mode 100644 index 0000000..014b7e8 --- /dev/null +++ b/0_Einführung/ü4/README.md @@ -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: +

+ +

+ +2. Erzeugen Sie einen Zeilenvektor der Dimension 10. Alle Komponenten sollen den Wert 20 haben: + +

+ +

+ +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) \ No newline at end of file diff --git a/0_Einführung/ü4/l_a.py b/0_Einführung/ü4/l_a.py new file mode 100644 index 0000000..5bcbee2 --- /dev/null +++ b/0_Einführung/ü4/l_a.py @@ -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) diff --git a/1_Grundlagen/README.md b/1_Grundlagen/README.md new file mode 100644 index 0000000..bb8cf5b --- /dev/null +++ b/1_Grundlagen/README.md @@ -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. + + + + + + diff --git a/1_Grundlagen/todos.md b/1_Grundlagen/todos.md new file mode 100644 index 0000000..7424feb --- /dev/null +++ b/1_Grundlagen/todos.md @@ -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?~~ + + diff --git a/1_Grundlagen/ü1/README.md b/1_Grundlagen/ü1/README.md new file mode 100644 index 0000000..232599e --- /dev/null +++ b/1_Grundlagen/ü1/README.md @@ -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? \ No newline at end of file diff --git a/1_Grundlagen/ü1/l_a.py b/1_Grundlagen/ü1/l_a.py new file mode 100644 index 0000000..a7c6016 --- /dev/null +++ b/1_Grundlagen/ü1/l_a.py @@ -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() diff --git a/1_Grundlagen/ü2/README.md b/1_Grundlagen/ü2/README.md new file mode 100644 index 0000000..d3f5b54 --- /dev/null +++ b/1_Grundlagen/ü2/README.md @@ -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. \ No newline at end of file diff --git a/1_Grundlagen/ü2/a.py b/1_Grundlagen/ü2/a.py new file mode 100644 index 0000000..899fa75 --- /dev/null +++ b/1_Grundlagen/ü2/a.py @@ -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() \ No newline at end of file diff --git a/1_Grundlagen/ü2/l_a.py b/1_Grundlagen/ü2/l_a.py new file mode 100644 index 0000000..00c0cb0 --- /dev/null +++ b/1_Grundlagen/ü2/l_a.py @@ -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() diff --git a/1_Grundlagen/ü3/README.md b/1_Grundlagen/ü3/README.md new file mode 100644 index 0000000..f1a432d --- /dev/null +++ b/1_Grundlagen/ü3/README.md @@ -0,0 +1,36 @@ +# Übung 3: Diskretisierung und Quantisierung + +In dieser Übung wird die Quantisierung und Diskretisierung von Bildern betrachtet. In den folgenden Abbildungen sind beide +Methoden visualisiert. + +Quantisierung | Diskretisierung +:---:|:--- +![](https://upload.wikimedia.org/wikipedia/commons/thumb/7/70/Quantized.signal.svg/2880px-Quantized.signal.svg.png) | ![](https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/Zeroorderhold.signal.svg/2880px-Zeroorderhold.signal.svg.png) +[Link zum Bild](https://upload.wikimedia.org/wikipedia/commons/thumb/7/70/Quantized.signal.svg/2880px-Quantized.signal.svg.png) | [Link zum Bild](https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/Zeroorderhold.signal.svg/2880px-Zeroorderhold.signal.svg.png) + + +## Aufgabe a) Diskretisierung +In der Datei [a.py](a.py) wird ein Bild geladen. Das Bild hat die Größe 1526 x 1600 (Breite x Höhe). + +Diskretisieren Sie das Bild mit dem Faktor *k* **ohne** und **mit** Verwendung der Funktion `cv2.resize()`. Dabei kann +*k* die Werte 4, 8, und 13.5 annehmen. Zeigen Sie die Bilder für den direkten Vergleich an! Achten Sie dabei darauf, +dass die Bilder in der gleichen Größe dargestellt werden. + + +## Aufgabe b) Quantisierung +In der Datei [b.py](b.py) wird ein Bild geladen. Das Bild ist im BGR-Farbraum repräsentiert und hat eine 8-Bit Quantisierung +(Wertebereich {0, ..., 255}. + +Führen Sie folgende Schritte durch: + 1. Quantisieren Sie das Bild in den Wertebereich {0, ..., 127} + 2. Quantisieren Sie das Bild aus Schritt 1 in den Wertebereich {0, ..., 3} + 3. Quantisieren Sie das Bild aus Schritt 2 zurück in den Wertebereich {0, ..., 255} + +Zeigen Sie die Bilder aus allen Schritten für den direkten Vergleich an: + + - Wie bewerten Sie die Qualität der Bilder? + - Was fällt auf? + + + + diff --git a/1_Grundlagen/ü3/a.py b/1_Grundlagen/ü3/a.py new file mode 100644 index 0000000..2d69d0f --- /dev/null +++ b/1_Grundlagen/ü3/a.py @@ -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 diff --git a/1_Grundlagen/ü3/b.py b/1_Grundlagen/ü3/b.py new file mode 100644 index 0000000..52f9071 --- /dev/null +++ b/1_Grundlagen/ü3/b.py @@ -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! \ No newline at end of file diff --git a/1_Grundlagen/ü3/l_a.py b/1_Grundlagen/ü3/l_a.py new file mode 100644 index 0000000..ce4d877 --- /dev/null +++ b/1_Grundlagen/ü3/l_a.py @@ -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) diff --git a/1_Grundlagen/ü3/l_b.py b/1_Grundlagen/ü3/l_b.py new file mode 100644 index 0000000..6350fce --- /dev/null +++ b/1_Grundlagen/ü3/l_b.py @@ -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) diff --git a/1_Grundlagen/ü4/README.md b/1_Grundlagen/ü4/README.md new file mode 100644 index 0000000..ede7d87 --- /dev/null +++ b/1_Grundlagen/ü4/README.md @@ -0,0 +1,36 @@ +# Übung 4: Aliasing + +In dieser Übung wird das *Aliasing* betrachtet. Der Effekt des *Aliasing* entsteht, +wenn eine Struktur mit einer zu geringen Rate abgetastet wird. Als Beispiel wird das Bild + +![](./data/Mauer.png) + + + +verwendet. Programmieren Sie ein Skript, mit dem das Bild eingelesen und mit den Faktoren 2, 4 und 10 skaliert wird. +Zeigen Sie sich die Bilder an. Verwenden Sie während der Skalierung die Nearest-Neighbour Interpolation! + +Schreiben Sie Ihr Skript in die Datei [a.py](a.py). Die Lösung ist in der Datei [l_a.py](l_a.py) zu finden! + +Was fällt Ihnen bei der Betrachtung der Bilder auf? + +## Technische Beschreibung des Phänomens + +Das Aliasing entsteht durch die Unterabtastung eines Signals. Um ein Signal korrekt darstellen zu können, muss das +[Nyquist-Shannon-Abtasttheorem](https://de.wikipedia.org/wiki/Nyquist-Shannon-Abtasttheorem) beachtet werden. +Die Kreisfrequenz der Abtastung + muss demnach + +

+ +

+ +beziehungsweise die Abtastfrequenz muss + +

+ +

+ +mit der maximalen Kreisfrequenz bzw. +maximalen Frequenz des Signals sein. + diff --git a/1_Grundlagen/ü4/a.py b/1_Grundlagen/ü4/a.py new file mode 100644 index 0000000..df538c6 --- /dev/null +++ b/1_Grundlagen/ü4/a.py @@ -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) \ No newline at end of file diff --git a/1_Grundlagen/ü4/data/Mauer.png b/1_Grundlagen/ü4/data/Mauer.png new file mode 100644 index 0000000..49884f2 Binary files /dev/null and b/1_Grundlagen/ü4/data/Mauer.png differ diff --git a/1_Grundlagen/ü4/l_a.py b/1_Grundlagen/ü4/l_a.py new file mode 100644 index 0000000..0af20d2 --- /dev/null +++ b/1_Grundlagen/ü4/l_a.py @@ -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) \ No newline at end of file diff --git a/1_Grundlagen/ü5/README.md b/1_Grundlagen/ü5/README.md new file mode 100644 index 0000000..9885e60 --- /dev/null +++ b/1_Grundlagen/ü5/README.md @@ -0,0 +1,31 @@ +# Übung 5: Global- und Rolling-Shutter + +In dieser Übung werden zwei Typen von Bildsensoren betrachtet: Sensoren mit Global- und Rolling-Shutter Auslesefunktion. +Der Unterschied während des Auslesens bezieht sich auf die zeitliche Anordnung der Belichtung der einzelnen Halbleiter +innerhalb des Sensors. Ein Halbleiter entspricht dabei einem einem Bildpunkt. Beim Global-Shutter werden alle Halbleiter +gleichzeitig belichtet. Beim Rolling-Shutter werden die einzelnen Zeilen des Sensors sequenziell belichtet. + +Der Schematische Ablauf eines Global-Shutter Sensors ist in dem folgenden Bild dargestellt: +![](data/global_shutter.png) + +Der Schematische Ablauf eines Rolling-Shutter Sensors hingegen sieht wie folgt aus: +![](data/rolling_shutter.png) + +## Vor- und Nachteile Rolling-/Global-Shutter + +Vorteile Rolling-Shutter gegenüber Global-Shutter: + - Preisgünstiger + - Längere Belichtungszeit möglich (weniger Rauschen) + +Nachteile Rolling-Shutter gegenüber Global-Shutter: + - Bewegungsverzerrung + +## a) Bewegungsverzerrung +In dieser Aufgabe soll die Bewegungsverzerrung eines Rolling-Shutter Sensors künstlich erzeugt werden. In dem Skript +[a.py](a.py) werden drei Bilder aus dem [KITTI](http://www.cvlibs.net/datasets/kitti/) aus einem fahrenden Auto geladen. + +Ihre Aufgabe ist die Simulation eines Rolling-Shutter Sensors, indem Sie ein resultierendes Bild aus den drei +Zeitpunkten des Videos konstruieren. Konstruieren Sie ein Bild, indem Sie die Zeile 1, 4, 7 ... aus dem ersten Bild, +Zeile 2, 5, 8 ... sowie die Zeilen 3, 6, 9, ... aus dem dritten Bild verwenden. Visualisieren Sie das Bild. + +. Die Lösung ist in der Datei [l_a.py](l_a.py) zu finden! \ No newline at end of file diff --git a/1_Grundlagen/ü5/a.py b/1_Grundlagen/ü5/a.py new file mode 100644 index 0000000..5d8a3f0 --- /dev/null +++ b/1_Grundlagen/ü5/a.py @@ -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) \ No newline at end of file diff --git a/1_Grundlagen/ü5/data/global_shutter.png b/1_Grundlagen/ü5/data/global_shutter.png new file mode 100644 index 0000000..ea1e04d Binary files /dev/null and b/1_Grundlagen/ü5/data/global_shutter.png differ diff --git a/1_Grundlagen/ü5/data/kitti1.png b/1_Grundlagen/ü5/data/kitti1.png new file mode 100644 index 0000000..e8dee06 Binary files /dev/null and b/1_Grundlagen/ü5/data/kitti1.png differ diff --git a/1_Grundlagen/ü5/data/kitti2.png b/1_Grundlagen/ü5/data/kitti2.png new file mode 100644 index 0000000..016fb6a Binary files /dev/null and b/1_Grundlagen/ü5/data/kitti2.png differ diff --git a/1_Grundlagen/ü5/data/kitti3.png b/1_Grundlagen/ü5/data/kitti3.png new file mode 100644 index 0000000..1725e46 Binary files /dev/null and b/1_Grundlagen/ü5/data/kitti3.png differ diff --git a/1_Grundlagen/ü5/data/rolling_shutter.png b/1_Grundlagen/ü5/data/rolling_shutter.png new file mode 100644 index 0000000..42d64d9 Binary files /dev/null and b/1_Grundlagen/ü5/data/rolling_shutter.png differ diff --git a/1_Grundlagen/ü5/l_a.py b/1_Grundlagen/ü5/l_a.py new file mode 100644 index 0000000..d9145c8 --- /dev/null +++ b/1_Grundlagen/ü5/l_a.py @@ -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) \ No newline at end of file diff --git a/2_Bildbearbeitung/README.md b/2_Bildbearbeitung/README.md new file mode 100644 index 0000000..3bb8db5 --- /dev/null +++ b/2_Bildbearbeitung/README.md @@ -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** + diff --git a/2_Bildbearbeitung/ü1/README.md b/2_Bildbearbeitung/ü1/README.md new file mode 100644 index 0000000..0b0f72f --- /dev/null +++ b/2_Bildbearbeitung/ü1/README.md @@ -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. + +![alt text](../../data/text_3.jpg) + +## 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. + + + + + + + diff --git a/2_Bildbearbeitung/ü1/a.py b/2_Bildbearbeitung/ü1/a.py new file mode 100644 index 0000000..8a26842 --- /dev/null +++ b/2_Bildbearbeitung/ü1/a.py @@ -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) + diff --git a/2_Bildbearbeitung/ü1/l_a.py b/2_Bildbearbeitung/ü1/l_a.py new file mode 100644 index 0000000..e7125a9 --- /dev/null +++ b/2_Bildbearbeitung/ü1/l_a.py @@ -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) diff --git a/2_Bildbearbeitung/ü10/README.md b/2_Bildbearbeitung/ü10/README.md new file mode 100644 index 0000000..ee2da4c --- /dev/null +++ b/2_Bildbearbeitung/ü10/README.md @@ -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! + + + + + + + diff --git a/2_Bildbearbeitung/ü10/a.py b/2_Bildbearbeitung/ü10/a.py new file mode 100644 index 0000000..1cf9d6e --- /dev/null +++ b/2_Bildbearbeitung/ü10/a.py @@ -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) + diff --git a/2_Bildbearbeitung/ü10/b.py b/2_Bildbearbeitung/ü10/b.py new file mode 100644 index 0000000..9cc30c8 --- /dev/null +++ b/2_Bildbearbeitung/ü10/b.py @@ -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) + diff --git a/2_Bildbearbeitung/ü10/l_a.py b/2_Bildbearbeitung/ü10/l_a.py new file mode 100644 index 0000000..bc1e634 --- /dev/null +++ b/2_Bildbearbeitung/ü10/l_a.py @@ -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) + diff --git a/2_Bildbearbeitung/ü10/l_b.py b/2_Bildbearbeitung/ü10/l_b.py new file mode 100644 index 0000000..4e4fa7f --- /dev/null +++ b/2_Bildbearbeitung/ü10/l_b.py @@ -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) + diff --git a/2_Bildbearbeitung/ü2/README.md b/2_Bildbearbeitung/ü2/README.md new file mode 100644 index 0000000..29467d2 --- /dev/null +++ b/2_Bildbearbeitung/ü2/README.md @@ -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. + +

+ +

+ +```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], + ] +``` + +

+ +

+ +```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*: + +

+ +

+ +*edge_02.png*: +

+ +

+ +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). diff --git a/2_Bildbearbeitung/ü2/data/cross1.png b/2_Bildbearbeitung/ü2/data/cross1.png new file mode 100644 index 0000000..9fdf2b9 Binary files /dev/null and b/2_Bildbearbeitung/ü2/data/cross1.png differ diff --git a/2_Bildbearbeitung/ü2/data/cross2.png b/2_Bildbearbeitung/ü2/data/cross2.png new file mode 100644 index 0000000..a67c207 Binary files /dev/null and b/2_Bildbearbeitung/ü2/data/cross2.png differ diff --git a/2_Bildbearbeitung/ü2/data/edge_01.png b/2_Bildbearbeitung/ü2/data/edge_01.png new file mode 100644 index 0000000..e1d8b18 Binary files /dev/null and b/2_Bildbearbeitung/ü2/data/edge_01.png differ diff --git a/2_Bildbearbeitung/ü2/data/edge_02.png b/2_Bildbearbeitung/ü2/data/edge_02.png new file mode 100644 index 0000000..c48587c Binary files /dev/null and b/2_Bildbearbeitung/ü2/data/edge_02.png differ diff --git a/2_Bildbearbeitung/ü2/l_a.py b/2_Bildbearbeitung/ü2/l_a.py new file mode 100644 index 0000000..e1e31c7 --- /dev/null +++ b/2_Bildbearbeitung/ü2/l_a.py @@ -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() diff --git a/2_Bildbearbeitung/ü2/l_b.py b/2_Bildbearbeitung/ü2/l_b.py new file mode 100644 index 0000000..b85d5f7 --- /dev/null +++ b/2_Bildbearbeitung/ü2/l_b.py @@ -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) \ No newline at end of file diff --git a/2_Bildbearbeitung/ü3/README.md b/2_Bildbearbeitung/ü3/README.md new file mode 100644 index 0000000..b11573e --- /dev/null +++ b/2_Bildbearbeitung/ü3/README.md @@ -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:** + +![](./data/normal.jpg) + +**Ausgangsbilder:** + +![](./data/center-rotated.jpg) +![](./data/rotated.jpg) +![](./data/shear.jpg) + +Gebeben sind folgende Transformationsforschriften: + +

+ +

+ +

+ +

+ +

+

+ +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! diff --git a/2_Bildbearbeitung/ü3/a.py b/2_Bildbearbeitung/ü3/a.py new file mode 100644 index 0000000..8af4b9d --- /dev/null +++ b/2_Bildbearbeitung/ü3/a.py @@ -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) diff --git a/2_Bildbearbeitung/ü3/data/center-rotated.jpg b/2_Bildbearbeitung/ü3/data/center-rotated.jpg new file mode 100644 index 0000000..eceaa7c Binary files /dev/null and b/2_Bildbearbeitung/ü3/data/center-rotated.jpg differ diff --git a/2_Bildbearbeitung/ü3/data/normal.jpg b/2_Bildbearbeitung/ü3/data/normal.jpg new file mode 100644 index 0000000..83dd42a Binary files /dev/null and b/2_Bildbearbeitung/ü3/data/normal.jpg differ diff --git a/2_Bildbearbeitung/ü3/data/rotated.jpg b/2_Bildbearbeitung/ü3/data/rotated.jpg new file mode 100644 index 0000000..3f44ef0 Binary files /dev/null and b/2_Bildbearbeitung/ü3/data/rotated.jpg differ diff --git a/2_Bildbearbeitung/ü3/data/shear.jpg b/2_Bildbearbeitung/ü3/data/shear.jpg new file mode 100644 index 0000000..fbcfe65 Binary files /dev/null and b/2_Bildbearbeitung/ü3/data/shear.jpg differ diff --git a/2_Bildbearbeitung/ü3/l_a.py b/2_Bildbearbeitung/ü3/l_a.py new file mode 100644 index 0000000..4dd719c --- /dev/null +++ b/2_Bildbearbeitung/ü3/l_a.py @@ -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) diff --git a/2_Bildbearbeitung/ü3/l_b.py b/2_Bildbearbeitung/ü3/l_b.py new file mode 100644 index 0000000..237284f --- /dev/null +++ b/2_Bildbearbeitung/ü3/l_b.py @@ -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) \ No newline at end of file diff --git a/2_Bildbearbeitung/ü3/l_c.md b/2_Bildbearbeitung/ü3/l_c.md new file mode 100644 index 0000000..90d0ad6 --- /dev/null +++ b/2_Bildbearbeitung/ü3/l_c.md @@ -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. \ No newline at end of file diff --git a/2_Bildbearbeitung/ü4/README.md b/2_Bildbearbeitung/ü4/README.md new file mode 100644 index 0000000..82041c4 --- /dev/null +++ b/2_Bildbearbeitung/ü4/README.md @@ -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 +

+ +

+und erstellen den ursprünglichen Filterken, sowohl "von Hand" als auch in einem Python Skript. + + +Betrachten und separieren Sie zusätzlich den Filterkern +

+ +

+ +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). diff --git a/2_Bildbearbeitung/ü4/l_a.py b/2_Bildbearbeitung/ü4/l_a.py new file mode 100644 index 0000000..59d4d2e --- /dev/null +++ b/2_Bildbearbeitung/ü4/l_a.py @@ -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) diff --git a/2_Bildbearbeitung/ü4/l_b.md b/2_Bildbearbeitung/ü4/l_b.md new file mode 100644 index 0000000..cca1864 --- /dev/null +++ b/2_Bildbearbeitung/ü4/l_b.md @@ -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 diff --git a/2_Bildbearbeitung/ü4/l_c.py b/2_Bildbearbeitung/ü4/l_c.py new file mode 100644 index 0000000..42b9ae3 --- /dev/null +++ b/2_Bildbearbeitung/ü4/l_c.py @@ -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() \ No newline at end of file diff --git a/2_Bildbearbeitung/ü4/l_d.py b/2_Bildbearbeitung/ü4/l_d.py new file mode 100644 index 0000000..bc27181 --- /dev/null +++ b/2_Bildbearbeitung/ü4/l_d.py @@ -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() \ No newline at end of file diff --git a/2_Bildbearbeitung/ü5/README.md b/2_Bildbearbeitung/ü5/README.md new file mode 100644 index 0000000..4368aa0 --- /dev/null +++ b/2_Bildbearbeitung/ü5/README.md @@ -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: +

+ +

+ +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). diff --git a/2_Bildbearbeitung/ü5/b.py b/2_Bildbearbeitung/ü5/b.py new file mode 100644 index 0000000..ba3488a --- /dev/null +++ b/2_Bildbearbeitung/ü5/b.py @@ -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() diff --git a/2_Bildbearbeitung/ü5/l_a.py b/2_Bildbearbeitung/ü5/l_a.py new file mode 100644 index 0000000..fa3e2af --- /dev/null +++ b/2_Bildbearbeitung/ü5/l_a.py @@ -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)) diff --git a/2_Bildbearbeitung/ü5/l_b.py b/2_Bildbearbeitung/ü5/l_b.py new file mode 100644 index 0000000..62b817f --- /dev/null +++ b/2_Bildbearbeitung/ü5/l_b.py @@ -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() diff --git a/2_Bildbearbeitung/ü6/README.md b/2_Bildbearbeitung/ü6/README.md new file mode 100644 index 0000000..075a977 --- /dev/null +++ b/2_Bildbearbeitung/ü6/README.md @@ -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 + + +![](../../data/car.png) + +nach der Transformation mit der Transformationsvorschrift + +

+ +

+ +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? + + diff --git a/2_Bildbearbeitung/ü6/a.py b/2_Bildbearbeitung/ü6/a.py new file mode 100644 index 0000000..0dd236d --- /dev/null +++ b/2_Bildbearbeitung/ü6/a.py @@ -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) \ No newline at end of file diff --git a/2_Bildbearbeitung/ü6/l_a.py b/2_Bildbearbeitung/ü6/l_a.py new file mode 100644 index 0000000..82bce8c --- /dev/null +++ b/2_Bildbearbeitung/ü6/l_a.py @@ -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) \ No newline at end of file diff --git a/2_Bildbearbeitung/ü7/README.md b/2_Bildbearbeitung/ü7/README.md new file mode 100644 index 0000000..f505a71 --- /dev/null +++ b/2_Bildbearbeitung/ü7/README.md @@ -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! diff --git a/2_Bildbearbeitung/ü7/l_a.py b/2_Bildbearbeitung/ü7/l_a.py new file mode 100644 index 0000000..d548a50 --- /dev/null +++ b/2_Bildbearbeitung/ü7/l_a.py @@ -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) diff --git a/2_Bildbearbeitung/ü7/l_b.py b/2_Bildbearbeitung/ü7/l_b.py new file mode 100644 index 0000000..ace9afa --- /dev/null +++ b/2_Bildbearbeitung/ü7/l_b.py @@ -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) diff --git a/2_Bildbearbeitung/ü8/README.md b/2_Bildbearbeitung/ü8/README.md new file mode 100644 index 0000000..56d50e7 --- /dev/null +++ b/2_Bildbearbeitung/ü8/README.md @@ -0,0 +1,22 @@ +# Übung 8: Geometrische Transformation + +In dieser Übung soll die Transformationsforschrift + +

+ +

+ +für die Transformation des Bildes I1 zu I2 hergeleitet werden. + + +| I1 | I2 | +| --- | --- | +| ![](./data/original.jpg) | ![](./data/new.jpg) | + + +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! + + + + diff --git a/2_Bildbearbeitung/ü8/a.py b/2_Bildbearbeitung/ü8/a.py new file mode 100644 index 0000000..a494cdd --- /dev/null +++ b/2_Bildbearbeitung/ü8/a.py @@ -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) + diff --git a/2_Bildbearbeitung/ü8/data/new.jpg b/2_Bildbearbeitung/ü8/data/new.jpg new file mode 100644 index 0000000..31397e9 Binary files /dev/null and b/2_Bildbearbeitung/ü8/data/new.jpg differ diff --git a/2_Bildbearbeitung/ü8/data/original.jpg b/2_Bildbearbeitung/ü8/data/original.jpg new file mode 100644 index 0000000..70f4861 Binary files /dev/null and b/2_Bildbearbeitung/ü8/data/original.jpg differ diff --git a/2_Bildbearbeitung/ü8/l_a.py b/2_Bildbearbeitung/ü8/l_a.py new file mode 100644 index 0000000..b90d503 --- /dev/null +++ b/2_Bildbearbeitung/ü8/l_a.py @@ -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) + diff --git a/2_Bildbearbeitung/ü9/README.md b/2_Bildbearbeitung/ü9/README.md new file mode 100644 index 0000000..7f734a3 --- /dev/null +++ b/2_Bildbearbeitung/ü9/README.md @@ -0,0 +1,18 @@ +# Übung 9: Gamma-Korrektur + +In dieser Übung soll die Gamma-Korrektur + +

+ +

+ +für die bessere Sichtbarkeit des Bilder + ![](../../data/car.png) +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! + + + + diff --git a/2_Bildbearbeitung/ü9/a.py b/2_Bildbearbeitung/ü9/a.py new file mode 100644 index 0000000..7dc477c --- /dev/null +++ b/2_Bildbearbeitung/ü9/a.py @@ -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) + + diff --git a/2_Bildbearbeitung/ü9/l_a.py b/2_Bildbearbeitung/ü9/l_a.py new file mode 100644 index 0000000..f31736f --- /dev/null +++ b/2_Bildbearbeitung/ü9/l_a.py @@ -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) + diff --git a/3_Signalorientierte_Bildverarbeitung/README.md b/3_Signalorientierte_Bildverarbeitung/README.md new file mode 100644 index 0000000..b9e9761 --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/README.md @@ -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** + diff --git a/3_Signalorientierte_Bildverarbeitung/ü1/README.md b/3_Signalorientierte_Bildverarbeitung/ü1/README.md new file mode 100644 index 0000000..aa1f98d --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü1/README.md @@ -0,0 +1,38 @@ +# Übung 1: Bildkompression + +In dieser Übung wird der Informationsgehalt eines Bildes reduziert und die Auswirkung auf die Interpretierbarkeit +für den Menschen betrachtet. Die Reduzierung der Informationen kann für eine Komprimierung verwendet. + +Wenden Sie die folgenden Aufgaben auf die Bilder **data/yellowlilly.jpg** und **data/cameraman.png** an. + +## Aufgabe a) Entfernen hochfrequenter Frequenzen +Implementieren sie die Funktion und *remove_dft(img, rate)*, wobei mit der +diskreten Kosinus- bzw. Fouriertransformation folgende Schritte durchgeführt werden sollen: + +- Iterieren Sie Blockweise über das Bild mithilfe zweier for-Schleifen und einer Blockgröße von 8x8 Pixel +- Verwenden Sie `np.fft.fft2()` um den Block in den Frequenzraum zu transformieren +- Entfernen Sie die *n* hochfrequentesten Koefizienten mit `n = 8 * 8 * rate` +- Transformieren Sie den Block zurück in den Ortsraum mit `np.fft.ifft2` + +Wie stark wirkt sich der Parameter `rate` auf die Interpretierbarkeit des Bildes für den Menschen aus? + +Die Lösung ist in der Date [l_a.py](l_a.py) zu finden. + +## Aufgabe b) Diskrete Kosinus Transformation +Implementieren Sie eine Funktion `dct(a: np.ndarray)`, welche als input eine zweidimensionale Matrix erhält und +auf diese die 2D Diskrete Kosinus Transformation nach + +![](./data/dct.png) + +anwendet und ausgibt. + +Validieren Sie Ihre Funktion, indem Sie die `fft2()` und `ifft2()` Funktion aus Aufgabe a) durch die `dct()` und `idct()` Funktionen ersetzen. +Die inverse der Transformation ist mit der Funktion `idct(a: np.ndarray)` gegeben, welche bereits in *l_b.py* implementiert ist. + + + +## Aufgabe c) Fragen +- Wie kann die Reduzierung der Fourier-Koeffizienten für eine Komprimierung genutzt werden? +- Was versteht man unter diskreter Kosinustransformation und was ist der wesentliche Unterschied zur DFT? +- Welchen Vorteil bietet die DCT gegenüber der FFT in der Praxis? + diff --git a/3_Signalorientierte_Bildverarbeitung/ü1/data/dct.png b/3_Signalorientierte_Bildverarbeitung/ü1/data/dct.png new file mode 100644 index 0000000..975a6ad Binary files /dev/null and b/3_Signalorientierte_Bildverarbeitung/ü1/data/dct.png differ diff --git a/3_Signalorientierte_Bildverarbeitung/ü1/l_a.py b/3_Signalorientierte_Bildverarbeitung/ü1/l_a.py new file mode 100644 index 0000000..0fd10e1 --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü1/l_a.py @@ -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) diff --git a/3_Signalorientierte_Bildverarbeitung/ü1/l_b.py b/3_Signalorientierte_Bildverarbeitung/ü1/l_b.py new file mode 100644 index 0000000..88e8fb3 --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü1/l_b.py @@ -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) diff --git a/3_Signalorientierte_Bildverarbeitung/ü1/l_c.md b/3_Signalorientierte_Bildverarbeitung/ü1/l_c.md new file mode 100644 index 0000000..06d0cba --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü1/l_c.md @@ -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 diff --git a/3_Signalorientierte_Bildverarbeitung/ü2/README.md b/3_Signalorientierte_Bildverarbeitung/ü2/README.md new file mode 100644 index 0000000..b157588 --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü2/README.md @@ -0,0 +1,25 @@ +# Übung 2: Bildrekonstruktion mit Wiener Filter & Inverser Filterung +Gegeben ist eine Abbildung der ETH-Zürich mit einer Bildstörung wie im folgenden zu sehen: + +![../../data/eth_blurred.png](../../data/eth_blurred.png) + + +Als Bildstörung ist hier Motion Blur einer gleichförmigen Kamerabewegung von 31 Pixel +und einem Winkel von 11 Grad (gegen den Uhrzeigersinn) verwendet. +Berechnen + +# Aufgabe a) Inverse Filterung +Benutzen Sie inverse Filterung um die Bildstörung (Motion Blur und Rauschen) im Bild +zu entfernen. Die Inverse Filterung muss anhand der Formeln von der Vorlesung selbst programmiert werden. + +Verwenden Sie eine geeignete "cutoff"-Frequenz. +Nutzen Sie die Datei [a.py](a.py) um Ihre Lösung zu implementieren. In der Datei ist die "Point Spread Function" (PSF) +bereits implementiert und in den Frequenzbereich transformiert. Die PSF entspricht der Transferfuntkion der +Bildstörung. + +# Aufgabe b) Wiener Filterung +Nutzen Sie ebenfalls Datei [a.py](a.py), +Benutzen Sie Wiener Filterung um die Bildstörung (Motion Blur und Rauschen) im Bild +zu entfernen. Die Wiener Filterung muss anhand der Formeln von der Vorlesung selbst programmiert werden. + +Verwenden Sie einen geeigneten Parameter K für den Wiener Filter. \ No newline at end of file diff --git a/3_Signalorientierte_Bildverarbeitung/ü2/a.py b/3_Signalorientierte_Bildverarbeitung/ü2/a.py new file mode 100644 index 0000000..75496dd --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü2/a.py @@ -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() diff --git a/3_Signalorientierte_Bildverarbeitung/ü2/l_a.py b/3_Signalorientierte_Bildverarbeitung/ü2/l_a.py new file mode 100644 index 0000000..74726e6 --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü2/l_a.py @@ -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() diff --git a/3_Signalorientierte_Bildverarbeitung/ü2/l_b.py b/3_Signalorientierte_Bildverarbeitung/ü2/l_b.py new file mode 100644 index 0000000..a7b9151 --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü2/l_b.py @@ -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() diff --git a/3_Signalorientierte_Bildverarbeitung/ü3/README.md b/3_Signalorientierte_Bildverarbeitung/ü3/README.md new file mode 100644 index 0000000..961cef8 --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü3/README.md @@ -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). diff --git a/3_Signalorientierte_Bildverarbeitung/ü3/a.py b/3_Signalorientierte_Bildverarbeitung/ü3/a.py new file mode 100644 index 0000000..8bf5389 --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü3/a.py @@ -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() \ No newline at end of file diff --git a/3_Signalorientierte_Bildverarbeitung/ü3/b.py b/3_Signalorientierte_Bildverarbeitung/ü3/b.py new file mode 100644 index 0000000..e820c04 --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü3/b.py @@ -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() diff --git a/3_Signalorientierte_Bildverarbeitung/ü3/c.py b/3_Signalorientierte_Bildverarbeitung/ü3/c.py new file mode 100644 index 0000000..2cca4e1 --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü3/c.py @@ -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) diff --git a/3_Signalorientierte_Bildverarbeitung/ü3/l_a.py b/3_Signalorientierte_Bildverarbeitung/ü3/l_a.py new file mode 100644 index 0000000..32847da --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü3/l_a.py @@ -0,0 +1,29 @@ +import cv2 +import numpy as np + +img = cv2.imread("../../data/lena.png", cv2.IMREAD_GRAYSCALE) + +''' Rauschen hinzufügen ''' +h, w = img.shape +saltpepper_noise = np.zeros((h, w), dtype=np.uint8) +saltpepper_noise = cv2.randu(saltpepper_noise, 0, 255) +black = saltpepper_noise < 15 +white = saltpepper_noise > 240 +img_noise = np.copy(img) +img_noise[white] = 255 +img_noise[black] = 0 + +''' FFT ''' +visual_factor = 100000 +IMG = np.fft.fftshift(np.fft.fft2(img)) +IMG_magnitude = np.abs(IMG) +cv2.imshow("IMG_magnitude", IMG_magnitude / visual_factor) + +IMG_NOISE = np.fft.fftshift(np.fft.fft2(img_noise)) +IMG_NOISE_magnitude = np.abs(IMG_NOISE) +cv2.imshow("IMG_NOISE_magnitude", IMG_NOISE_magnitude / visual_factor) + +''' Bild anzeigen ''' +cv2.imshow("img", img) +cv2.imshow("img_noise", img_noise) +cv2. waitKey() \ No newline at end of file diff --git a/3_Signalorientierte_Bildverarbeitung/ü3/l_b.py b/3_Signalorientierte_Bildverarbeitung/ü3/l_b.py new file mode 100644 index 0000000..f841bb1 --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü3/l_b.py @@ -0,0 +1,28 @@ +import cv2 +import numpy as np + +car = cv2.imread("../../data/car.png", cv2.IMREAD_GRAYSCALE) +dog = cv2.imread("../../data/dog.png", cv2.IMREAD_GRAYSCALE) + +''' FFT ''' +CAR = np.fft.fft2(car) +CAR_magnitude = np.abs(CAR) +CAR_angle = np.angle(CAR) + +DOG = np.fft.fft2(dog) +DOG_magnitude = np.abs(DOG) +DOG_angle = np.angle(DOG) + +mix1 = CAR_magnitude * np.exp(1j * DOG_angle) +mix2 = DOG_magnitude * np.exp(1j * CAR_angle) + +mix1 = np.fft.ifft2(mix1).astype(np.float32) +mix2 = np.fft.ifft2(mix2).astype(np.float32) + +''' Bild anzeigen ''' +cv2.imshow("car", car) +cv2.imshow("dog", dog) +cv2.imshow("mix1", mix1 / np.max(mix1)) +cv2.imshow("mix2", mix2 / np.max(mix2)) + +cv2.waitKey() diff --git a/3_Signalorientierte_Bildverarbeitung/ü3/l_c.py b/3_Signalorientierte_Bildverarbeitung/ü3/l_c.py new file mode 100644 index 0000000..97e944d --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü3/l_c.py @@ -0,0 +1,25 @@ +import cv2 +import numpy as np + +img = cv2.imread("../../data/teppich.png", cv2.IMREAD_GRAYSCALE) + + +''' FFT ''' +IMG = np.fft.fft2(img) +MAGNITUDE = np.abs(IMG) +ANGLE = np.angle(IMG) + +''' Filter out frequencies ''' +print("Number of frequencies:", MAGNITUDE.shape) +MAGNITUDE[0:150, 0:150] = 0 + + +''' IFFT ''' +IMG = MAGNITUDE * np.exp(1j * ANGLE) +filtered_image = np.fft.ifft2(IMG).astype(np.float32) + +''' Bild anzeigen ''' +cv2.imshow("img", img) +cv2.imshow("filtered", filtered_image / np.max(filtered_image)) + +cv2.waitKey(0) diff --git a/3_Signalorientierte_Bildverarbeitung/ü4/README.md b/3_Signalorientierte_Bildverarbeitung/ü4/README.md new file mode 100644 index 0000000..2fb9fa4 --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü4/README.md @@ -0,0 +1,31 @@ +# Übung 4: Notch-Filter im Frequenzraum + +In dem Skript [a.py](a.py) wird das Bild von Lena eingeladen. +Gleichzeitig wird ein gestörtes Bild von Lena eingeladen. +Dem Bild wurde ein Raster überlagert. + +Original | Gestört +---|--- +![](../../data/lena.png) | ![](../../data/lena_raster.png) + +## Aufgabe a) +Das Raster soll unter Benutzung des Frequenzbereiches auf einfache Weise für +den subjektiven Eindruck entfernt werden. + +Gehen Sie dabei wie folgt vor: +1. Transformieren Sie die Bilder in den Frequenzbereich und betrachten Sie charakteristische +Unterschiede. +2. Maskieren Sie die gestörten Bereiche aus, in dem Sie geeigente Bereiche der Matrix auf Null +setzen. Die Zentren der Störungen liegen etwa bei (nach fftshift): + + - [85, 85] + - [255, 85] + - [425, 85] + - [85, 255] + - [255, 425] + - [425, 255] + - [85, 425] + - [425, 425] +3. Transformieren Sie das Bild in den Ortsbereich zurück. + +Sie finden die Musterlösung in der Datei [l_a.py](l_a.py). \ No newline at end of file diff --git a/3_Signalorientierte_Bildverarbeitung/ü4/a.py b/3_Signalorientierte_Bildverarbeitung/ü4/a.py new file mode 100644 index 0000000..28ef5ec --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü4/a.py @@ -0,0 +1,36 @@ +import cv2 +import numpy as np + +raster = cv2.imread("../../data/lena_raster.png", cv2.IMREAD_GRAYSCALE) +normal = cv2.imread("../../data/lena.png", cv2.IMREAD_GRAYSCALE) + +''' FFT ''' +RASTER = np.fft.fftshift(np.fft.fft2(raster)) +RASTER_magnitude = np.abs(RASTER) +RASTER_angle = np.angle(RASTER) + +NORMAL = np.fft.fftshift(np.fft.fft2(normal)) +NORMAL_magnitude = np.abs(NORMAL) +NORMAL_angle = np.angle(NORMAL) + +''' Maskieren ''' +centroids = [ + [85, 85], + [255, 85], + [425, 85], + [85, 255], + [255, 425], + [425, 255], + [85, 425], + [425, 425] +] + + +''' Bild anzeigen ''' +cv2.imshow("raster", raster) +cv2.imshow("normal", normal) +cv2.imshow("RASTER_magnitude", 255 * RASTER_magnitude / np.max(RASTER_magnitude)) +cv2.imshow("NORMAL_magnitude", 255 * NORMAL_magnitude / np.max(NORMAL_magnitude)) + + +cv2.waitKey() diff --git a/3_Signalorientierte_Bildverarbeitung/ü4/l_a.py b/3_Signalorientierte_Bildverarbeitung/ü4/l_a.py new file mode 100644 index 0000000..8eb3928 --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü4/l_a.py @@ -0,0 +1,46 @@ +import cv2 +import numpy as np + +raster = cv2.imread("../../data/lena_raster.png", cv2.IMREAD_GRAYSCALE) +normal = cv2.imread("../../data/lena.png", cv2.IMREAD_GRAYSCALE) + +''' FFT ''' +RASTER = np.fft.fftshift(np.fft.fft2(raster)) +RASTER_magnitude = np.abs(RASTER) +RASTER_angle = np.angle(RASTER) + +NORMAL = np.fft.fftshift(np.fft.fft2(normal)) +NORMAL_magnitude = np.abs(NORMAL) +NORMAL_angle = np.angle(NORMAL) + +''' Bild anzeigen ''' +cv2.imshow("raster", raster) +cv2.imshow("normal", normal) +cv2.imshow("RASTER_magnitude", 255 * RASTER_magnitude / np.max(RASTER_magnitude)) +cv2.imshow("NORMAL_magnitude", 255 * NORMAL_magnitude / np.max(NORMAL_magnitude)) + +''' Maskieren ''' +centroids = [ + [85, 85], + [255, 85], + [425, 85], + [85, 255], + [255, 425], + [425, 255], + [85, 425], + [425, 425] +] + +s = 10 +for x, y in centroids: + RASTER[np.maximum(0, y - s):y + s, np.maximum(0, x - s):x + s] = 0 +FILTERED_magnitude = np.abs(RASTER) + +''' Inverse fft ''' +filtered = np.fft.ifft2(np.fft.ifftshift(RASTER)).astype(np.uint8) + +''' Lösung anzeigen ''' +cv2.imshow("FILTERED_magnitude", 255 * FILTERED_magnitude / np.max(FILTERED_magnitude)) +cv2.imshow("filtered", filtered) + +cv2.waitKey() diff --git a/3_Signalorientierte_Bildverarbeitung/ü5/README.md b/3_Signalorientierte_Bildverarbeitung/ü5/README.md new file mode 100644 index 0000000..aa95168 --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü5/README.md @@ -0,0 +1,26 @@ +# Übung 5: Homomorphe Filterung + +In dem Skript [a.py](a.py) wird das Bild *I* + +![](../../data/car2.png) + +geladen. Das Bild zeigt eine schlecht belichtete Szene, in der Details nicht +gut zu erkennen sind. In dieser Übung soll der Kontrast verbessert werden, damit +mehr Details erkennbar sind. + +## Aufgabe a) + + +Wenden Sie die Homomorphe Filterung auf das Bild *I* an, indem Sie folgende Schritte implementieren: + +1. Logarithmieren Sie die Werte in Grauwerte in *I* +2. Transformieren Sie *I* in den Frequenzbereich +3. Unterdrücken Sie niedrige Frequenzen durch die Funktion H(k,l)

+5. Transformieren Sie *I* zurück in den Bildbereich +6. Kehren Sie die Logarithmierung aus Schritt 1. durch die Exponentialfunktion um + +Der erste Teil der Aufgabe ist in der Datei [a.py](a.py) zu finden. + +Sie finden die Musterlösung in der Datei [l_a.py](l_a.py). + +**Hinweis:** Arbeiten Sie mit einem Wertebereich zwischen 0 und 1! diff --git a/3_Signalorientierte_Bildverarbeitung/ü5/a.py b/3_Signalorientierte_Bildverarbeitung/ü5/a.py new file mode 100644 index 0000000..e553dae --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü5/a.py @@ -0,0 +1,26 @@ +import numpy as np +import cv2 + +''' Bild laden und in den Frequenzraum transformieren ''' +img = cv2.imread("../../data/car2.png", cv2.IMREAD_GRAYSCALE) +img = img.astype(float) +i_max, i_min = np.max(img), np.min(img) +img = (img - i_min) / (i_max - i_min) + +cv2.imshow("Original", img ) + +''' 1. Logarithmieren ''' + +''' 2. in den Frequenzbereich transformieren ''' + +''' 3. Niedrige mit H(k,l)Frequenzen unterdrücken ''' + +''' 4. Rücktransformation ''' + +''' 5. Umkehrfunktion der Logarithmierung ''' + +''' Ergebnis anzeigen ''' +i_max, i_min = np.max(img_filtered), np.min(img_filtered) +img_filtered = (img_filtered - i_min) / (i_max - i_min) +cv2.imshow("Homomorphe Filterung", img_filtered) +cv2.waitKey() \ No newline at end of file diff --git a/3_Signalorientierte_Bildverarbeitung/ü5/l_a.py b/3_Signalorientierte_Bildverarbeitung/ü5/l_a.py new file mode 100644 index 0000000..52fd2c2 --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü5/l_a.py @@ -0,0 +1,42 @@ +import numpy as np +import cv2 + +''' Bild laden und in den Frequenzraum transformieren ''' +img = cv2.imread("../../data/car2.png", cv2.IMREAD_GRAYSCALE) +img = img.astype(float) +i_max, i_min = np.max(img), np.min(img) +img = (img - i_min) / (i_max - i_min) + +cv2.imshow("Original", img ) + +''' 1. Logarithmieren ''' +img_log = np.maximum(img, 1/255) # log(0) ist illegal! +img_log = np.log(img_log) + +''' 2. in den Frequenzbereich transformieren ''' +IMG = np.fft.fft2(img_log) + +''' 3. Niedrige mit H(k,l)Frequenzen unterdrücken ''' +gamma1, gamma2, gamma3 = 0.5, 0., 4 +H = np.zeros_like(img_log) +for l in range(H.shape[0]): + for k in range(H.shape[1]): + if k < 1 and l < 1: + H[l, k] = 1 + else: + H[l, k] = gamma1 - (gamma1 - gamma2) * np.exp(-(k*k + l*l) / (gamma3 * gamma3)) + +IMG = IMG * H + +''' 4. Rücktransformation ''' +img_filtered = np.fft.ifft2(IMG) +img_filtered = img_filtered.astype(float) + +''' 5. Umkehrfunktion der Logarithmierung ''' +img_filtered = np.exp(img_filtered) + +''' Ergebnis anzeigen ''' +i_max, i_min = np.max(img_filtered), np.min(img_filtered) +img_filtered = (img_filtered - i_min) / (i_max - i_min) +cv2.imshow("Homomorphe Filterung", img_filtered) +cv2.waitKey() \ No newline at end of file diff --git a/3_Signalorientierte_Bildverarbeitung/ü6/README.md b/3_Signalorientierte_Bildverarbeitung/ü6/README.md new file mode 100644 index 0000000..86eae54 --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü6/README.md @@ -0,0 +1,24 @@ +# Übung 6: Unitäre Transformation + +In dem Skript [a.py](a.py) wird das Bild von Lena eingeladen. + +![](../../data/lena.png) + +## Aufgabe a) Haar-Transformation +Das Bild soll in die hohen tiefen Frequenzen mithilfe der Haar-Transformation zerlegt werden. +Erstellen Sie dafür eine Haar-Koeffizientnmatrix der Größe 512x512 mit der Berechnungsvorschrift + + + +und wenden Sie diese auf das Bild mithilfe von + + + +an. Zeigen Sie das Bild, und geben Sie einige interessante Koeffizienten aus H an. Prüfen Sie Ihre Berechnungen, +indem Sie die Rücktransformation mithilfe von + + + +anwenden und prüfen, ob Änderungen im Bild vorhanden sind. + +Sie finden die Musterlösung in der Datei [l_a.py](l_a.py). \ No newline at end of file diff --git a/3_Signalorientierte_Bildverarbeitung/ü6/a.py b/3_Signalorientierte_Bildverarbeitung/ü6/a.py new file mode 100644 index 0000000..f21e37f --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü6/a.py @@ -0,0 +1,33 @@ +import cv2 +import numpy as np + +normal = cv2.imread("../../data/lena.png", cv2.IMREAD_GRAYSCALE) + + +def valid_rows(N): + n = np.log2(N) + n = np.ceil(n) + N = np.power(2, n) + return N + + +def create_H(m, N): + ... + +''' Reshape to valid resolution ''' +N, m = normal.shape +new_N = valid_rows(N) +print("Original Resolution:", m, "x", N) +print("New Resolution:", m, "x", new_N) +if N != new_N: + _ = np.zeros((new_N, m)) + _[:N, :m] = normal + normal = _ + + + + +''' Show images ''' +cv2.imshow("normal", normal) + +cv2.waitKey() diff --git a/3_Signalorientierte_Bildverarbeitung/ü6/l_a.py b/3_Signalorientierte_Bildverarbeitung/ü6/l_a.py new file mode 100644 index 0000000..feb1afd --- /dev/null +++ b/3_Signalorientierte_Bildverarbeitung/ü6/l_a.py @@ -0,0 +1,60 @@ +import cv2 +import numpy as np + +normal = cv2.imread("../../data/lena.png", cv2.IMREAD_GRAYSCALE) + + +def valid_rows(N): + n = np.log2(N) + n = np.ceil(n) + N = np.power(2, n) + return N + + +def create_H(m, N): + """ + m: Columns + n: Rows + """ + H = np.zeros((int(N), int(m))) + for i in range(1, int(N) + 1): + for j in range(1, int(m) + 1): + if i <= (N/2): + if j == (2*i -1) or j == 2*i: + H[i-1,j-1] = 1 / np.sqrt(2) + else: + #print(j, i) + if j == (2 * (i - N/2) - 1): + H[i-1,j-1] = 1 / np.sqrt(2) + elif j == (2 * (i - N/2)): + H[i-1,j-1] = -1 / np.sqrt(2) + return H + +''' Reshape to valid resolution ''' +N, m = normal.shape +new_N = valid_rows(N) +print("Original Resolution:", m, "x", N) +print("New Resolution:", m, "x", new_N) +if N != new_N: + _ = np.zeros((new_N, m)) + _[:N, :m] = normal + normal = _ + +''' Get Haar-Matrix ''' +H = create_H(m, new_N) +print(H[0:5, 0:5]) +print(H[256:261, 0:5]) + +''' Filter with HxI''' +haar = np.matmul(H, normal) + +''' Invert Filter ''' +haar_inv = np.matmul(np.transpose(H), haar) + +''' Show images ''' +cv2.imshow("normal", normal) +cv2.imshow("haar", haar / 255) +cv2.imshow("haar_inv", haar_inv / 255) +print("Difference:", np.sum(np.abs(normal-haar_inv))) + +cv2.waitKey() diff --git a/4_Farbrepräsentationen/README.md b/4_Farbrepräsentationen/README.md new file mode 100644 index 0000000..f41fb8b --- /dev/null +++ b/4_Farbrepräsentationen/README.md @@ -0,0 +1,10 @@ +# Farbrepräsentation + +Die Wahrnehmung von "Farbe" wird in technischen Anwendungen in verschiedenen Formen dargestellt und codiert. Zu +den Grundlagen der Farbrepräsentationen werden in diesem Kapitel Aufgaben und Beispiele bereitgestellt. +Die Aufgaben behandeln die Themengebiete + +- **Additive Subtraktive Farbmischung** +- **Farbempfinden und technische Repräsentation von Farbe** +- **Farbmodelle/Farbräume und Konvertierung** +- **Weißabgleich** \ No newline at end of file diff --git a/4_Farbrepräsentationen/ü1/README.md b/4_Farbrepräsentationen/ü1/README.md new file mode 100644 index 0000000..03b4acc --- /dev/null +++ b/4_Farbrepräsentationen/ü1/README.md @@ -0,0 +1,35 @@ +# Übung 1: BGR zu HSV + +In dieser Übung wird der HSV Farbraum betrachtet. Die Information der Farbe wird +durch die drei Werte + + - H: Helligkeit (Hue) + - S: Sättigung (Saturation) + - V: Value (Helligkeit) + +repräsentiert. + +In der folgenden Abbildung wird der Farbraum visuell dargestellt: + +![alt text](https://upload.wikimedia.org/wikipedia/commons/f/f1/HSV_cone.jpg) + + +## Aufgabe a) +In der Datei *a.py* wird ein Bild geladen. Nach dem Laden befindet sich das Bild +im BGR-Farbraum. Konvertieren Sie das Bild manuell und +ohne Hilfe von OpenCV in den HSV Farbraum. + +Sie können die Rechenvorschriften der Konvertierung von RGB zu HSV aus der [OpenCV-Dokumentation](https://docs.opencv.org/3.4/de/d25/imgproc_color_conversions.html) +nutzen. Beachten Sie, dass die Farbkanäle in OpenCV in BGR und nicht in RGB abgespeichert sind! + + +## Aufgabe b) +Konvertieren Sie das Bild mithilfe der OpenCV Funktion ```cv2.cvtColor()``` in den HSV +Farbraum. Vergleichen Sie das Ergebnis dann mit dem Ergebnis aus Aufgabenteil a). + +Sind die Ergebnisse gleich? Wenn nicht, woran kann es liegen? + + + + + diff --git a/4_Farbrepräsentationen/ü1/a.py b/4_Farbrepräsentationen/ü1/a.py new file mode 100644 index 0000000..6dc8056 --- /dev/null +++ b/4_Farbrepräsentationen/ü1/a.py @@ -0,0 +1,39 @@ +import numpy as np +import cv2 + + +# Einlesen des Bildes +filepath = "../../data/balls.png" + + +''' a) Manuelles Konvertieren ''' +img_norm = img.astype(np.float32) / 255.0 +height, width, channels = img.shape +hsv_img = np.zeros_like(img_norm) + +for x in range(width): + for y in range(int(height)): + + +hsv_img = np.round(hsv_img * 255) +hsv_img = hsv_img.astype(np.uint8) + +''' b) Konvertieren mit OpenCV ''' +hsv_img2 = + + +''' Das Ergebnis überprüfen ''' +img2 = cv2.cvtColor(hsv_img, cv2.COLOR_HSV2BGR) +img3 = cv2.cvtColor(hsv_img2, cv2.COLOR_HSV2BGR) + +difference = np.sum(np.abs(img2 - img3)) +print("Totale Differenz zwischen den Ergebnissen:", difference) +max_difference = np.max(np.abs(img2 - img3)) +print("Maximale Abweichung pro Pixel/Kanal:", max_difference) +example_differences = img2[0:10, 0:10] - img3[0:10, 0:10] +print("Beispiel Differenzen:\n", example_differences) + +cv2.imshow("ORIGINAL", img) +cv2.imshow("MANUELL", img2) +cv2.imshow("OPENCV", img3) +cv2.waitKey(0) diff --git a/4_Farbrepräsentationen/ü1/l_a.py b/4_Farbrepräsentationen/ü1/l_a.py new file mode 100644 index 0000000..048ff8f --- /dev/null +++ b/4_Farbrepräsentationen/ü1/l_a.py @@ -0,0 +1,66 @@ +import numpy as np +import cv2 + + +# Einlesen des Bildes +filepath = "../../data/balls.png" +img = cv2.imread(filepath) + +''' a) Manuelles Konvertieren ''' +img_norm = img.astype(np.float32) / 255.0 +height, width, channels = img.shape +hsv_img = np.zeros_like(img_norm) + +for x in range(width): + for y in range(int(height)): + minimum = np.min(img_norm[y, x]) + b, g, r = img_norm[y, x, 0], img_norm[y, x, 1], img_norm[y, x, 2] + # V Wert + v = np.max(img_norm[y, x].copy()) + + # S Wert + if v == 0: + s = 0 + else: + s = (v - minimum) / v + + # H Wert + max_channel_index = np.argmax(img_norm[y, x]) + if (v - np.min(img_norm[y, x])) == 0: + h = np.zeros(1) + elif max_channel_index == 2: # Rot + h = 60 * (g - b) / (v - minimum) + elif max_channel_index == 1: # Grün + h = 120 + 60 * (b - r) / (v - minimum) + else: # Blau + h = 240 + 60 * (r - g) / (v - minimum) + if h < 0: + h += 360 + h /= (2 * 255) + + hsv_img[y, x, 0] = h + hsv_img[y, x, 1] = s + hsv_img[y, x, 2] = v + +hsv_img = np.round(hsv_img * 255) +hsv_img = hsv_img.astype(np.uint8) + +''' b) Konvertieren mit OpenCV ''' +hsv_img2 = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) + + +''' Das Ergebnis überprüfen ''' +img2 = cv2.cvtColor(hsv_img, cv2.COLOR_HSV2BGR) +img3 = cv2.cvtColor(hsv_img2, cv2.COLOR_HSV2BGR) + +difference = np.sum(np.abs(img2 - img3)) +print("Totale Differenz zwischen den Ergebnissen:", difference) +max_difference = np.max(np.abs(img2 - img3)) +print("Maximale Abweichung pro Pixel/Kanal:", max_difference) +example_differences = img2[0:3, 0:3] - img3[0:3, 0:3] +print("Beispiel Differenzen:\n", example_differences) + +cv2.imshow("ORIGINAL", img) +cv2.imshow("MANUELL", img2) +cv2.imshow("OPENCV", img3) +cv2.waitKey(0) diff --git a/4_Farbrepräsentationen/ü2/README.md b/4_Farbrepräsentationen/ü2/README.md new file mode 100644 index 0000000..8ab9121 --- /dev/null +++ b/4_Farbrepräsentationen/ü2/README.md @@ -0,0 +1,32 @@ +# Übung 2: BGR zu HSV + +In dieser Übung wird der HSV Farbraum betrachtet. Die Information der Farbe wird +durch die drei Werte + + - H: Helligkeit (Hue) + - S: Sättigung (Saturation) + - V: Value (Helligkeit) + +repräsentiert. + +In der folgenden Abbildung wird der Farbraum visuell dargestellt: + +![alt text](https://upload.wikimedia.org/wikipedia/commons/f/f1/HSV_cone.jpg) + + +## Aufgabe a) +Lesen Sie Ihre Kamera aus und geben Sie das Bild "live" wieder. +Konvertieren Sie den eingelesenen Videostream aus Aufgabe in den HSV Farbraum. +Reduzieren Sie die Helligkeit, indem Sie einen der drei Farbkanäle um 30% reduzieren. +Konvertieren Sie das Bild daraufhin zurück in den RGB Farbraum. + +Die Lösung findet sich in der Datei [l_a.py](l_a.py). + +## Aufgabe b) +Modifizieren Sie Aufgabe a) so, dass die Helligkeit zyklisch zwischen 0% und 100% +variiert. +Die Lösung findet sich in der Datei [l_b.py](l_b.py). + + + + diff --git a/4_Farbrepräsentationen/ü2/a.py b/4_Farbrepräsentationen/ü2/a.py new file mode 100644 index 0000000..e69de29 diff --git a/4_Farbrepräsentationen/ü2/l_a.py b/4_Farbrepräsentationen/ü2/l_a.py new file mode 100644 index 0000000..b9d72cd --- /dev/null +++ b/4_Farbrepräsentationen/ü2/l_a.py @@ -0,0 +1,24 @@ +import numpy as np +import cv2 + +camera = cv2.VideoCapture(0) + +signum = 1 +factor = 0.3 +while True: + ret, bgr = camera.read() + + ''' Aufgabe a) ''' + hsv = cv2.cvtColor(bgr, cv2.COLOR_BGR2HSV) + hsv[:, :, 2] = np.round(hsv[:, :, 2] * factor) + bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR) + + ''' Visualisierung ''' + # Display the resulting frame + cv2.imshow('frame', bgr) + if 27 == cv2.waitKey(1): # Taste "q" + break + +# When everything done, release the capture +camera.release() +cv2.destroyAllWindows() diff --git a/4_Farbrepräsentationen/ü2/l_b.py b/4_Farbrepräsentationen/ü2/l_b.py new file mode 100644 index 0000000..5d66d52 --- /dev/null +++ b/4_Farbrepräsentationen/ü2/l_b.py @@ -0,0 +1,33 @@ +import numpy as np +import cv2 + +camera = cv2.VideoCapture(0) + +signum = 1 +factor = 0.3 +while True: + ret, bgr = camera.read() + + ''' Aufgabe a) ''' + hsv = cv2.cvtColor(bgr, cv2.COLOR_BGR2HSV) + hsv[:, :, 2] = np.round(hsv[:, :, 2] * factor) + bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR) + + ''' Aufgabe b) ''' + if factor == 0: + signum = 1 + elif factor == 1: + signum = -1 + factor += signum * 0.02 + factor = min(1, factor) + factor = max(0, factor) + + ''' Visualisierung ''' + # Display the resulting frame + cv2.imshow('frame', bgr) + if 27 == cv2.waitKey(1): # Taste "q" + break + +# When everything done, release the capture +camera.release() +cv2.destroyAllWindows() \ No newline at end of file diff --git a/4_Farbrepräsentationen/ü3/README.md b/4_Farbrepräsentationen/ü3/README.md new file mode 100644 index 0000000..39fcd5b --- /dev/null +++ b/4_Farbrepräsentationen/ü3/README.md @@ -0,0 +1,22 @@ +# Übung 3: Binärbild Repräsentationen + +In dieser Übung werden Darstellungsformen von Binärbildern betrachtet. Sie lernen Binär und Quaternärbäume kennen. + + +## Aufgabe a) Binärbaum +Gegeben ist folgender Binärbaum: + +![](./data/binary_tree.png) + +Rekonstruieren Sie die Bildzeile, die durch den Binärbaum dargestellt wird. +Sie können die Aufgabe mit Papier und Stift erledigen. Die Lösung wird in dem Skript *l_a.py* visualisiert. + +## Aufgabe b) Quaternärbaum +Gegeben ist folgender Quaternärbaum (Quadtree) mit einer Zuordnung der vier Quadranten: +![](./data/quad_tree.png) + +Rekonstruieren Sie das Binärbild, die durch den Quaternärbaum dargestellt wird. +Sie können die Aufgabe mit Papier und Stift erledigen. Die Lösung wird in dem Skript *l_b.py* visualisiert. + + + diff --git a/4_Farbrepräsentationen/ü3/data/binary_tree.png b/4_Farbrepräsentationen/ü3/data/binary_tree.png new file mode 100644 index 0000000..13cc2a0 Binary files /dev/null and b/4_Farbrepräsentationen/ü3/data/binary_tree.png differ diff --git a/4_Farbrepräsentationen/ü3/data/quad_tree.png b/4_Farbrepräsentationen/ü3/data/quad_tree.png new file mode 100644 index 0000000..3d37b0a Binary files /dev/null and b/4_Farbrepräsentationen/ü3/data/quad_tree.png differ diff --git a/4_Farbrepräsentationen/ü3/l_a.py b/4_Farbrepräsentationen/ü3/l_a.py new file mode 100644 index 0000000..40329ec --- /dev/null +++ b/4_Farbrepräsentationen/ü3/l_a.py @@ -0,0 +1,16 @@ +import numpy as np +import cv2 + +line = np.asarray( + [[1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1]], +) +# Resize image +line = np.repeat(line, 50, axis=1) +line = np.repeat(line, 50, axis=0) +# Add seperators +line[0::2, ::50] = 1 +line[1::2, ::50] = 0 +# Show image +line = line.astype(np.float64) +cv2.imshow("Binaerbaum", line) +cv2.waitKey(0) \ No newline at end of file diff --git a/4_Farbrepräsentationen/ü3/l_b.py b/4_Farbrepräsentationen/ü3/l_b.py new file mode 100644 index 0000000..0050bee --- /dev/null +++ b/4_Farbrepräsentationen/ü3/l_b.py @@ -0,0 +1,32 @@ +import numpy as np +import cv2 + +line = np.asarray( + [ + [1,1, 1,1, 1,1, 1,1], + [0,0, 1,1, 1,1, 1,1], + + [0,0, 1,1, 0,0, 0,1], + [0,0, 1,0, 0,0, 1,1], + + [0,0, 0,0, 0,0, 1,1], + [0,0, 0,0, 0,0, 1,1], + + [0,0, 0,0, 1,0, 1,1], + [0,0, 0,0, 1,1, 1,1], + ], +) +# Resize image +line = np.repeat(line, 50, axis=1) +line = np.repeat(line, 50, axis=0) + +# Add seperators +line[0::2, ::50] = 1 +line[1::2, ::50] = 0 +line[::50, 0::2] = 1 +line[::50, 1::2] = 0 + +# Show image +line = line.astype(np.float64) +cv2.imshow("Quadtree", line) +cv2.waitKey(0) diff --git a/4_Farbrepräsentationen/ü4/README.md b/4_Farbrepräsentationen/ü4/README.md new file mode 100644 index 0000000..471481c --- /dev/null +++ b/4_Farbrepräsentationen/ü4/README.md @@ -0,0 +1,25 @@ +# Übung 4: Weißabgleich + +Bei Digitalaufnahmen lässt sich über Bildverarbeitungssoftware der Weißabgleich zu einem gewissen +Grad per Software korrigieren. Dazu skaliert man die relativen Luminanzen der Kanäle Rot, +Grün und Blau. Die Skalierung wird über eine Multiplikation mit der folgenden Diagonalmatrix +realisiert. + +

+ +

+ +Das Problem ist nun die Parameter für den optimalen Weißpunkt zu wählen. + +## Aufgabe a) + +Laden Sie das Bild [../../data/obst.png](../../data/obst.png) und geben Sie er aus. Führen Sie danach den Weißabgleich durch. +Wählen Sie als Parameter Werte, sodass die Farbwerte des Pixels an Stelle x=127 y=146 den Farbwert (255, 255, 255) haben. +Zeigen Sie ebenfalls das abgeglichene Bild an. Die Musterlösung findet sich in der Datei [l_a.py](l_a.py). + +![](../../data/obst.png) + +## Aufgabe b) + +Führen Sie den Weißabgleich auf Ihrem Webcam-Stream durch. Sie können die Parameter frei wählen und variieren. +Die Musterlösung findet sich in der Datei [l_b.py](l_b.py). \ No newline at end of file diff --git a/4_Farbrepräsentationen/ü4/l_a.py b/4_Farbrepräsentationen/ü4/l_a.py new file mode 100644 index 0000000..1f650b4 --- /dev/null +++ b/4_Farbrepräsentationen/ü4/l_a.py @@ -0,0 +1,19 @@ +import cv2 +import numpy as np + +img = cv2.imread("../../data/model.png") + +#white_balancing_factor = np.asarray([[[1, 1, 1]]]) +white_balancing_factor = 255 / img[146, 127].astype(np.float32) +white_balancing_factor = np.expand_dims(white_balancing_factor, 0) +white_balancing_factor = np.expand_dims(white_balancing_factor, 1) + +img_balanced = img * white_balancing_factor +img_balanced = np.clip(img_balanced, 0, 255) +img_balanced = img_balanced.astype(np.uint8) + +cv2.imshow("Normal", img) +cv2.imshow("Abgeglichen", img_balanced) + +cv2.waitKey() + diff --git a/4_Farbrepräsentationen/ü4/l_b.py b/4_Farbrepräsentationen/ü4/l_b.py new file mode 100644 index 0000000..7674a25 --- /dev/null +++ b/4_Farbrepräsentationen/ü4/l_b.py @@ -0,0 +1,16 @@ +import cv2 +import numpy as np + +white_balancing_factor = np.asarray([[[0.5, 0.3, 0.95]]]) + +cap = cv2.VideoCapture(0) + +while True: + ret, img = cap.read() + img_balanced = img * white_balancing_factor + img_balanced = np.clip(img_balanced, 0, 255) + img_balanced = img_balanced.astype(np.uint8) + cv2.imshow("Normal", img) + cv2.imshow("Abgeglichen", img_balanced) + cv2.waitKey(1) + diff --git a/4_Farbrepräsentationen/ü5/README.md b/4_Farbrepräsentationen/ü5/README.md new file mode 100644 index 0000000..04a54e2 --- /dev/null +++ b/4_Farbrepräsentationen/ü5/README.md @@ -0,0 +1,45 @@ +# Übung 5: Kettencode + +Eine Variante für die Abbildung von Konturen is der Kettencode. Im folgenden sollten Bilder in den Kettencode codiert und +Kettencodes in Konturen decodiert werden. + +Für die Codierung mit dem Kettencode soll folgende Zuordnung verwendet werden: +

+ +

+ + +Für die Codierung mit dem differentiellen Kettencode soll folgende Zuordnung verwendet werden: +

+ +

+ + + +## Aufgabe a) Kettencode + +Erstellen Sie für das Bild + +![](./data/1.png) + +einen Kettencode! Beginnen Sie mit dem weißen Pixel oben links und dem Wert 0. + +## Aufgabe b) Kettencode + +Erstellen Sie das Bild für den Kettencode + +```[6 4 6 3 4 5 6 4 2 2 3 2 2 0 0 7 0 2 0 0 7 6]``` + + +## Aufgabe c) Differentieller Kettencode + +Erstellen Sie für das Bild aus Aufgabe a) +einen differenziellen Kettencode! Beginnen Sie mit dem Pixel oben links und dem Wert 0. + +## Aufgabe d) Differentieller Kettencode + +Erstellen Sie das Bild für den differentiellen Kettencode + +```[-2 -2 2 -3 1 1 1 -2 -2 0 1 -1 0 -2 0 -1 1 2 -2 0 -1 -1]``` + +Nutzen Sie als Startrichtung die Richtung 0 nach Definition des Kettencodes. diff --git a/4_Farbrepräsentationen/ü5/data/1.png b/4_Farbrepräsentationen/ü5/data/1.png new file mode 100644 index 0000000..6f9b196 Binary files /dev/null and b/4_Farbrepräsentationen/ü5/data/1.png differ diff --git a/4_Farbrepräsentationen/ü5/l_a.py b/4_Farbrepräsentationen/ü5/l_a.py new file mode 100644 index 0000000..e8fc8cf --- /dev/null +++ b/4_Farbrepräsentationen/ü5/l_a.py @@ -0,0 +1,34 @@ +import numpy as np +import cv2 + +line = np.asarray( + [ + [0,0, 0,0, 0,0, 0,0], + [1,1, 1,0, 1,1, 1,0], + [1,0, 0,1, 1,0, 0,1], + [1,0, 0,0, 0,0, 1,1], + [0,1, 0,1, 1,1, 1,0], + [0,1, 1,0, 0,1, 0,0], + [0,1, 1,0, 0,0, 0,0], + [0,0, 0,0, 0,0, 0,0], + ], +) + +# Resize image +line = np.repeat(line, 50, axis=1) +line = np.repeat(line, 50, axis=0) + +# Add seperators +line[0::2, ::50] = 1 +line[1::2, ::50] = 0 +line[::50, 0::2] = 1 +line[::50, 1::2] = 0 + +# Show image +line = line.astype(np.float64) +cv2.imshow("1", line) +cv2.imwrite("./data/1.png", line*255) +cv2.waitKey(0) + +chaincode = [0, 0, 7, 0, 2, 0, 0, 7, 6, 4, 6, 4, 6, 3, 4, 5, 6, 4, 2, 2, 3, 2] +print(chaincode) \ No newline at end of file diff --git a/4_Farbrepräsentationen/ü5/l_b.py b/4_Farbrepräsentationen/ü5/l_b.py new file mode 100644 index 0000000..a498592 --- /dev/null +++ b/4_Farbrepräsentationen/ü5/l_b.py @@ -0,0 +1,29 @@ +import numpy as np +import cv2 + +line = np.asarray( + [ + [0,0, 0,0, 0,0, 0,0], + [1,1, 1,0, 1,1, 1,0], + [1,0, 0,1, 1,0, 0,1], + [1,0, 0,0, 0,0, 1,1], + [0,1, 0,1, 1,1, 1,0], + [0,1, 1,0, 0,1, 0,0], + [0,1, 1,0, 0,0, 0,0], + [0,0, 0,0, 0,0, 0,0], + ], +) +# Resize image +line = np.repeat(line, 50, axis=1) +line = np.repeat(line, 50, axis=0) + +# Add seperators +line[0::2, ::50] = 1 +line[1::2, ::50] = 0 +line[::50, 0::2] = 1 +line[::50, 1::2] = 0 + +# Show image +line = line.astype(np.float64) +cv2.imshow("b", line) +cv2.waitKey(0) \ No newline at end of file diff --git a/4_Farbrepräsentationen/ü5/l_c.py b/4_Farbrepräsentationen/ü5/l_c.py new file mode 100644 index 0000000..97a054a --- /dev/null +++ b/4_Farbrepräsentationen/ü5/l_c.py @@ -0,0 +1,33 @@ +import numpy as np +import cv2 + +line = np.asarray( + [ + [0,0, 0,0, 0,0, 0,0], + [1,1, 1,0, 1,1, 1,0], + [1,0, 0,1, 1,0, 0,1], + [1,0, 0,0, 0,0, 1,1], + [0,1, 0,1, 1,1, 1,0], + [0,1, 1,0, 0,1, 0,0], + [0,1, 1,0, 0,0, 0,0], + [0,0, 0,0, 0,0, 0,0], + ], +) +# Resize image +line = np.repeat(line, 50, axis=1) +line = np.repeat(line, 50, axis=0) + +# Add seperators +line[0::2, ::50] = 1 +line[1::2, ::50] = 0 +line[::50, 0::2] = 1 +line[::50, 1::2] = 0 + +# Show image +#line = line.astype(np.float64) +#cv2.imshow("1", line) +#cv2.imwrite("./data/1.png", line*255) +#cv2.waitKey(0) + +chaincode = [0, 0, -1, 1, 2, -2, 0, -1, -1, -2, 2, -2, 2, -3, 1, 1, 1, -2, -2, 0, 1, -1] +print(chaincode) \ No newline at end of file diff --git a/4_Farbrepräsentationen/ü5/l_d.py b/4_Farbrepräsentationen/ü5/l_d.py new file mode 100644 index 0000000..e452538 --- /dev/null +++ b/4_Farbrepräsentationen/ü5/l_d.py @@ -0,0 +1,29 @@ +import numpy as np +import cv2 + +line = np.asarray( + [ + [0,0, 0,0, 0,0, 0,0], + [1,1, 1,0, 1,1, 1,0], + [1,0, 0,1, 1,0, 0,1], + [1,0, 0,0, 0,0, 1,1], + [0,1, 0,1, 1,1, 1,0], + [0,1, 1,0, 0,1, 0,0], + [0,1, 1,0, 0,0, 0,0], + [0,0, 0,0, 0,0, 0,0], + ], +) +# Resize image +line = np.repeat(line, 50, axis=1) +line = np.repeat(line, 50, axis=0) + +# Add seperators +line[0::2, ::50] = 1 +line[1::2, ::50] = 0 +line[::50, 0::2] = 1 +line[::50, 1::2] = 0 + +# Show image +line = line.astype(np.float64) +cv2.imshow("d", line) +cv2.waitKey(0) \ No newline at end of file diff --git a/4_Farbrepräsentationen/ü6/README.md b/4_Farbrepräsentationen/ü6/README.md new file mode 100644 index 0000000..92a1f3f --- /dev/null +++ b/4_Farbrepräsentationen/ü6/README.md @@ -0,0 +1,39 @@ +# Übung 6: Additive / Subtraktive Farbmischung + +In dieser Übung soll die Additive und Subtraktive Farbmischung betrachtet werden. +Es soll ein simples Bild mit der Auflösung 500x300 (BxH) erstellt und angezeigt werden, in der jeweils +von oben aufsteigend jeweils 50 Pixel in der Farbe + - rot + - orange + - gelb + - grün + - blau + - lila + +In dieser Übung haben Sie die beiden Farbrepräsentationen "Additiv BGR" und "Subtraktiv BGR" zur Verfügung. +In der folgenden Tabelle sind beide Repräsentationen dargestellt: + +| Additiv | Subtraktiv | +| --- | --- | +|![./data/add.png](./data/add.png) | ![./data/add.png](./data/sub.png)| + +Bei der Additiven Farbmischung wird eine Farbe durch das Hinzufügen von Farbe zum Komplementär Schwarz erreicht. +Auf dem Rechner entsprechen daher höhere Werte in einem Farbkanal einer stärkeren Präsenz der Farbe im resultierenden +Pixel. + +Bei der Subtraktiven Farbmischung wird eine Farbe durch das Abziehen von Farbe zum Komplementär Weiß erreicht. +Auf dem Rechner entsprechen daher höhere Werte in einem Farbkanal einer geringeren Präsenz der Farbe im resultierenden +Pixel. + + +## Aufgabe a) + +In der Datei [a.py](a.py) ist ein leeres Bild vordefiniert. Ergänzen Sie die Farben, um das Bild zu vervollständigen. +In dieser Aufgabe wird eine Farbe im additiven BGR Farbraum dargestellt. Die Musterlösung findet sich in der Datei [l_a.py](l_a.py). + + +## Aufgabe b) + +In der Datei [b.py](b.py) ist ein leeres Bild vordefiniert. Ergänzen Sie die Farben, um das Bild zu vervollständigen. +In dieser Aufgabe wird eine Farbe im subtraktiven BGR Farbraum dargestellt. Die Musterlösung findet sich in der Datei [l_b.py](l_b.py). + diff --git a/4_Farbrepräsentationen/ü6/a.py b/4_Farbrepräsentationen/ü6/a.py new file mode 100644 index 0000000..7feeb9b --- /dev/null +++ b/4_Farbrepräsentationen/ü6/a.py @@ -0,0 +1,14 @@ +import numpy as np + +from color_code import additive_color_plot + +img = np.zeros((300, 500, 3), dtype=np.uint8) + +img[0:50, 0:500] = [0, 0, 0] +img[50:100, 0:500] = [0, 0, 0] +img[100:150, 0:500] = [0, 0, 0] +img[150:200, 0:500] = [0, 0, 0] +img[200:250, 0:500] = [0, 0, 0] +img[250:300, 0:500] = [0, 0, 0] + +additive_color_plot(img) diff --git a/4_Farbrepräsentationen/ü6/b.py b/4_Farbrepräsentationen/ü6/b.py new file mode 100644 index 0000000..b562307 --- /dev/null +++ b/4_Farbrepräsentationen/ü6/b.py @@ -0,0 +1,14 @@ +import numpy as np + +from color_code import subtractive_color_plot + +img = np.zeros((300, 500, 3), dtype=np.uint8) + +img[0:50, 0:500] = [0, 0, 0] +img[50:100, 0:500] = [0, 0, 0] +img[100:150, 0:500] = [0, 0, 0] +img[150:200, 0:500] = [0, 0, 0] +img[200:250, 0:500] = [0, 0, 0] +img[250:300, 0:500] = [0, 0, 0] + +subtractive_color_plot(img) diff --git a/4_Farbrepräsentationen/ü6/color_code.py b/4_Farbrepräsentationen/ü6/color_code.py new file mode 100644 index 0000000..abb376a --- /dev/null +++ b/4_Farbrepräsentationen/ü6/color_code.py @@ -0,0 +1,12 @@ +import cv2 + + +def additive_color_plot(img): + cv2.imshow("Additive", img) + cv2.waitKey(0) + + +def subtractive_color_plot(img): + img = 255 - img + cv2.imshow("Subtractive", img) + cv2.waitKey(0) diff --git a/4_Farbrepräsentationen/ü6/data/add.png b/4_Farbrepräsentationen/ü6/data/add.png new file mode 100644 index 0000000..4815246 Binary files /dev/null and b/4_Farbrepräsentationen/ü6/data/add.png differ diff --git a/4_Farbrepräsentationen/ü6/data/sub.png b/4_Farbrepräsentationen/ü6/data/sub.png new file mode 100644 index 0000000..2773fb8 Binary files /dev/null and b/4_Farbrepräsentationen/ü6/data/sub.png differ diff --git a/4_Farbrepräsentationen/ü6/l_a.py b/4_Farbrepräsentationen/ü6/l_a.py new file mode 100644 index 0000000..2682fc8 --- /dev/null +++ b/4_Farbrepräsentationen/ü6/l_a.py @@ -0,0 +1,14 @@ +import numpy as np + +from color_code import additive_color_plot + +img = np.zeros((300, 500, 3), dtype=np.uint8) + +img[0:50, 0:500] = [0, 0, 255] +img[50:100, 0:500] = [0, 136, 255] +img[100:150, 0:500] = [0, 255, 255] +img[150:200, 0:500] = [0, 255, 0] +img[200:250, 0:500] = [255, 0, 0] +img[250:300, 0:500] = [255, 0, 136] + +additive_color_plot(img) diff --git a/4_Farbrepräsentationen/ü6/l_b.py b/4_Farbrepräsentationen/ü6/l_b.py new file mode 100644 index 0000000..12f785d --- /dev/null +++ b/4_Farbrepräsentationen/ü6/l_b.py @@ -0,0 +1,14 @@ +import numpy as np + +from color_code import subtractive_color_plot + +img = np.zeros((300, 500, 3), dtype=np.uint8) + +img[0:50, 0:500] = [255, 255, 0] +img[50:100, 0:500] = [255, 119, 0] +img[100:150, 0:500] = [255, 0, 0] +img[150:200, 0:500] = [255, 0, 255] +img[200:250, 0:500] = [0, 255, 255] +img[250:300, 0:500] = [0, 255, 119] + +subtractive_color_plot(img) diff --git a/5_Bildanalyse/README.md b/5_Bildanalyse/README.md new file mode 100644 index 0000000..97db0b3 --- /dev/null +++ b/5_Bildanalyse/README.md @@ -0,0 +1,11 @@ +# Bildanalyse + +Ein Ziel der Digitalen Bildverarbeitung ist die Extrahierung von Informationen aus Bilddaten, um nachfolgende Aufgaben +zu lösen. In diesem Kapitel werden einige Beispiele und Aufgaben zur Bildanalyse bereitgestellt. Dabei werden die Themen + +- **Diskrete Geometrie und Analyse von Binärbildern** +- **Bildsegmentierung** +- **Template-Matching und Korrelation** +- **Hough** + +behandelt. \ No newline at end of file diff --git a/5_Bildanalyse/ü1/README.md b/5_Bildanalyse/ü1/README.md new file mode 100644 index 0000000..beda07c --- /dev/null +++ b/5_Bildanalyse/ü1/README.md @@ -0,0 +1,37 @@ +# Übung 1: Differenzbild + +In dieser Übung wird Bewegung mithilfe eines Differenzbildes detektiert. Mithilfe von Bewegungsdetektion können Applikationen +wie z.B. Lichtsteuerungen oder Alarmsysteme gefertigt werden. + +Gegeben ist eine statische Kamera, welche +zwei Bilder in einer zeitlichen Abfolge aufgenommen hat. Die Bilder sehen Sie in den folgenden Abbildungen: + + +

+ +

+

+ +

+ + + +## Aufgabe a) +Implementieren sie in der Datei [a.py](a.py) die folgenden Schritte, um die Bewegungsdetektion zu realisieren. + + 1. Öffnen Sie die Bilder mit der Funktion `cv2.imread()` + 2. Konvertieren Sie die Bilder in Grauwertbilder mit der Funktion `cv2.cvtColor()` + 3. Erzeugen Sie das Differenzbild unter Ausnutzung des vollen Wertebereichs von 0 bis 1 unter Verwendung der folgenden + Punktoperationen: + - Pixelweise Addition/Subtraktion + - Addition/Subtraktion einer Konstanten + - Multiplikation/Division mit einer Konstanten + 4. Stellen Sie das Differenzbild mithilfe von `cv2.imshow()` dar + 5. Setzen Sie alle Pixel mit Intensität kleiner 0.5 auf 0 und zeigen Sie das resultierende Bild an + +Die Musterlösung findet sich unter [l_a.py](l_a.py). + + + + + diff --git a/5_Bildanalyse/ü1/a.py b/5_Bildanalyse/ü1/a.py new file mode 100644 index 0000000..8a26842 --- /dev/null +++ b/5_Bildanalyse/ü1/a.py @@ -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) + diff --git a/5_Bildanalyse/ü1/l_a.py b/5_Bildanalyse/ü1/l_a.py new file mode 100644 index 0000000..c45b1f9 --- /dev/null +++ b/5_Bildanalyse/ü1/l_a.py @@ -0,0 +1,34 @@ +import numpy as np +import cv2 + +KERNEL_SIZE = 20 + +''' Schritt 1: Einlesen der Bilder ''' +surv1 = cv2.imread("../../data/surv_01.png") +surv2 = cv2.imread("../../data/surv_02.png") + +''' Schritt 2: Konvertieren in den Grauwertbereich ''' +surv1 = cv2.cvtColor(surv1, cv2.COLOR_BGR2GRAY) +surv2 = cv2.cvtColor(surv2, cv2.COLOR_BGR2GRAY) + +''' Schritt 3: Erzeugen des Differenzbildes ''' +print("Minimam und Maximum bevor Transformation:", np.min(surv1), np.max(surv1)) +print(" -> Wertebereich ist {0, ..., 255}") +surv1 = surv1 / 255 +surv2 = surv2 / 255 +print("Minimam und Maximum nach Transformation:", np.min(surv1), np.max(surv1)) +print(" -> Wertebereich ist [0, 1]") + +diff1 = surv1 - surv2 +diff1 = np.abs(diff1) # Absolutwertbildung für die Darstellellung (OpenCV kennt nur positive Werte!) + +''' Schritt 4: Darstellen des Differenzbildes ''' +cv2.imshow("Differenz ohne Schwellwert ", diff1) + +''' Schritt 5: Darstellen des Differenzbildes mit Schwellwert ''' +diff2 = np.copy(diff1) +diff2[diff2 < 0.5] = 0 +cv2.imshow("Differenz mit Schwellwert ", diff2) + +cv2.waitKey(0) # Dieser Befehl ist nötig, um die Darstellung auf dem Bildschirm zu behalten + diff --git a/5_Bildanalyse/ü10/README.md b/5_Bildanalyse/ü10/README.md new file mode 100644 index 0000000..488dc03 --- /dev/null +++ b/5_Bildanalyse/ü10/README.md @@ -0,0 +1,32 @@ +# Übung 10: Objekt Detektion + +Sie haben folgendes Bild gegeben, in dem Sie eine Flasche detektieren wollen: +![](../../data/flasche_rechteckig.png) + +Weiterhin haben Sie bereits ein Kantenbild und ein Template erhalten: + +| Kantenbild | Template | +| ---------- | -------- | +| ![](data/edges.png) | ![](data/template.png) | + + +## a) Template Matching + +Sie sollen ein Template Matching durchführen, um die Position zu finden, +an welcher eine Flasche mit der größten Wahrscheinlichkeit steht. Nutzen Sie dafür das gegebene Template einer Flasche. +Um die Aufgabe zu lösen, implementieren Sie die folgenden Schritte: + + 1. Laden Sie das Template und das Kantenbild + 2. Legen Sie das Template auf jeden möglichen Bildausschnitts des Kantenbildes und erstellen Sie einen Matching-Score. + 1. Schneiden Sie einen Bildausschnitt in der Größe des Templates aus + 2. Berechnen Sie Fläche des Querschnitt des Templates und des Bildausschnitts. Dies ist der Matching-Score dieser Position. + 3. Speichern Sie den Matching Score für die Position + 3. Finden Sie die Position mit dem größten Matching-Score und visualisieren Sie ihn in dem originalen Bild. + +**Hinweise:** + - In dieser Übung sollen nur Bildausschnitte betrachtet werden, auf die das gesamte Template passt + - Das Template soll **NICHT** skaliert werden (Größen-Variant) + + +Bitte führen Sie für die Bearbeitung der Aufgabe das Skript [a.py](a.py) fort. +Die Lösung befindet sich in Datei [l_a.py](l_a.py). diff --git a/5_Bildanalyse/ü10/a.py b/5_Bildanalyse/ü10/a.py new file mode 100644 index 0000000..bad0166 --- /dev/null +++ b/5_Bildanalyse/ü10/a.py @@ -0,0 +1,31 @@ +import numpy as np +import cv2 + +# Load images and template +original_img = cv2.imread("../../data/flasche_rechteckig.png") +original_img = cv2.resize(original_img, (int(original_img.shape[1]/ 2), int(original_img.shape[0] / 2))) +cv2.imshow("original_img", original_img) + +# The original canny edge code wascode was: +# img = cv2.cvtColor(original_img, cv2.COLOR_BGR2GRAY) +# edges = cv2.Canny(img, 10, 100) + +edges = cv2.imread("data/edges.png")[:, :, 0] / 255 +cv2.imshow("canny-edges", edges.astype(np.float32) * 255) +template = cv2.imread("data/template.png")[:, :, 0] / 255 +cv2.imshow("template", template.astype(np.float32) * 255) + +# Sliding window over the edge image +h_edge, w_edge = edges.shape +h_template, w_template = template.shape +offset_h, offset_w = int(h_template / 2), int(w_template / 2) +print("Shape of edge image:", edges.shape) +print("Shape of template:", template.shape) +print("Offset of template:", offset_h, offset_w) + + +# YOUR CODE +# ... + + +cv2.waitKey(0) diff --git a/5_Bildanalyse/ü10/data/edges.png b/5_Bildanalyse/ü10/data/edges.png new file mode 100644 index 0000000..94dd096 Binary files /dev/null and b/5_Bildanalyse/ü10/data/edges.png differ diff --git a/5_Bildanalyse/ü10/data/template.png b/5_Bildanalyse/ü10/data/template.png new file mode 100644 index 0000000..4e91840 Binary files /dev/null and b/5_Bildanalyse/ü10/data/template.png differ diff --git a/5_Bildanalyse/ü10/l_a.py b/5_Bildanalyse/ü10/l_a.py new file mode 100644 index 0000000..a0e4680 --- /dev/null +++ b/5_Bildanalyse/ü10/l_a.py @@ -0,0 +1,44 @@ +import numpy as np +import cv2 + +# Load images and template +original_img = cv2.imread("../../data/flasche_rechteckig.png") +original_img = cv2.resize(original_img, (int(original_img.shape[1]/ 2), int(original_img.shape[0] / 2))) +cv2.imshow("original_img", original_img) + +# The original canny edge code wascode was: +# img = cv2.cvtColor(original_img, cv2.COLOR_BGR2GRAY) +# edges = cv2.Canny(img, 10, 100) + +edges = cv2.imread("data/edges.png")[:, :, 0] / 255 +cv2.imshow("canny-edges", edges.astype(np.float32) * 255) +template = cv2.imread("data/template.png")[:, :, 0] / 255 +cv2.imshow("template", template.astype(np.float32) * 255) + +# Sliding window over the edge image +h_edge, w_edge = edges.shape +h_template, w_template = template.shape +offset_h, offset_w = int(h_template / 2), int(w_template / 2) +print("Shape of edge image:", edges.shape) +print("Shape of template:", template.shape) +print("Offset of template:", offset_h, offset_w) + +heatmap = np.zeros_like(edges).astype(np.float32) +for x in range(0, w_edge - w_template): + for y in range(0, h_edge - h_template): + overlapping_pixel = edges[y:y+h_template, x:x+w_template] * template + num_overlapping_pixel = np.sum(overlapping_pixel) + heatmap[y + offset_h, x + offset_w] = num_overlapping_pixel + +heatmap = heatmap / np.max(heatmap) +cv2.imshow("heatmap", heatmap) + +# Find maximum and print it so the original image +max_pos = np.unravel_index(heatmap.argmax(), heatmap.shape) +print("The maximal position is:", max_pos) +red = [0, 0, 255] +original_img[max_pos[0]-5:max_pos[0]+5, max_pos[1]-5:max_pos[1]+5] = red +cv2.imshow("best_match", original_img) + + +cv2.waitKey(0) diff --git a/5_Bildanalyse/ü11/README.md b/5_Bildanalyse/ü11/README.md new file mode 100644 index 0000000..6f87e79 --- /dev/null +++ b/5_Bildanalyse/ü11/README.md @@ -0,0 +1,29 @@ +# Übung 11: Objekt Klassifikation + +In dieser Aufgabe sollen Sie einen Algorithmus für die Klassifikation von bereits segmentierten Objekten schreiben. +Dabei sollen Sie jedem der 6 folgenden Bilder eine Klasse zuordnen. Die Möglichen Klassen sind dabei + +- Mensch +- Ball +- Fenster + +| ![](data/kasten2.png) | ![](data/mensch2.png) | ![](data/ball2.png) | +| ---------- | -------- | ----- | +| ![](data/ball.png) | ![](data/kasten.png) | ![](data/mensch.png) | + + +## a) Erzeugung von Merkmalen + +Erstellen Sie enige Merkmale, welche Größe oder Form der Objekte quantitativ beschreiben. Achten Sie darauf, +dass die Merkmale möglichst diskriminativ sind, sodass sie zur Unterscheidung in die verschiedenen Klassen genutzt +werden können. + + +Bitte führen Sie für die Bearbeitung der Aufgabe das Skript [a.py](a.py) fort. +Die Lösung befindet sich in Datei [l_a.py](l_a.py). + +## b) Klassifikation von Merkmalen +Erstellen Sie nun qualitative Regeln mit den in Aufgabe a) erstellen Merkmalen, um die Elemente in den Bildern zu +klassifizieren. Sie brauchen dabei nicht programmieren, sondern lediglich Regeln für die Klassifizierung erstellen. + +Eine mögliche Lösung befindet sich in Datei [l_b.md](l_b.md). diff --git a/5_Bildanalyse/ü11/a.py b/5_Bildanalyse/ü11/a.py new file mode 100644 index 0000000..9d166c9 --- /dev/null +++ b/5_Bildanalyse/ü11/a.py @@ -0,0 +1,20 @@ +import numpy as np +import cv2 + + +''' Load images ''' +img1 = cv2.imread("data/mensch.png", cv2.IMREAD_GRAYSCALE) +img2 = cv2.imread("data/mensch2.png", cv2.IMREAD_GRAYSCALE) +img3 = cv2.imread("data/kasten.png", cv2.IMREAD_GRAYSCALE) +img4 = cv2.imread("data/kasten2.png", cv2.IMREAD_GRAYSCALE) +img5 = cv2.imread("data/ball.png", cv2.IMREAD_GRAYSCALE) +img6 = cv2.imread("data/ball2.png", cv2.IMREAD_GRAYSCALE) + +''' Define features ''' + + +''' Show parameter ''' +for name, img in [("img1", img1), ("img2", img2), ("img3", img3), ("img4", img4), ("img5", img5), ("img6", img6)]: + print("Image:", name) + print(" feature =", ...) + diff --git a/5_Bildanalyse/ü11/data/ball.png b/5_Bildanalyse/ü11/data/ball.png new file mode 100644 index 0000000..15b19af Binary files /dev/null and b/5_Bildanalyse/ü11/data/ball.png differ diff --git a/5_Bildanalyse/ü11/data/ball2.png b/5_Bildanalyse/ü11/data/ball2.png new file mode 100644 index 0000000..874025b Binary files /dev/null and b/5_Bildanalyse/ü11/data/ball2.png differ diff --git a/5_Bildanalyse/ü11/data/kasten.png b/5_Bildanalyse/ü11/data/kasten.png new file mode 100644 index 0000000..72b726a Binary files /dev/null and b/5_Bildanalyse/ü11/data/kasten.png differ diff --git a/5_Bildanalyse/ü11/data/kasten2.png b/5_Bildanalyse/ü11/data/kasten2.png new file mode 100644 index 0000000..7c1e516 Binary files /dev/null and b/5_Bildanalyse/ü11/data/kasten2.png differ diff --git a/5_Bildanalyse/ü11/data/mensch.png b/5_Bildanalyse/ü11/data/mensch.png new file mode 100644 index 0000000..95e2351 Binary files /dev/null and b/5_Bildanalyse/ü11/data/mensch.png differ diff --git a/5_Bildanalyse/ü11/data/mensch2.png b/5_Bildanalyse/ü11/data/mensch2.png new file mode 100644 index 0000000..ad10503 Binary files /dev/null and b/5_Bildanalyse/ü11/data/mensch2.png differ diff --git a/5_Bildanalyse/ü11/l_a.py b/5_Bildanalyse/ü11/l_a.py new file mode 100644 index 0000000..a831bde --- /dev/null +++ b/5_Bildanalyse/ü11/l_a.py @@ -0,0 +1,60 @@ +import numpy as np +import cv2 + +''' Load images ''' +img1 = cv2.imread("data/mensch.png", cv2.IMREAD_GRAYSCALE) +img2 = cv2.imread("data/mensch2.png", cv2.IMREAD_GRAYSCALE) +img3 = cv2.imread("data/kasten.png", cv2.IMREAD_GRAYSCALE) +img4 = cv2.imread("data/kasten2.png", cv2.IMREAD_GRAYSCALE) +img5 = cv2.imread("data/ball.png", cv2.IMREAD_GRAYSCALE) +img6 = cv2.imread("data/ball2.png", cv2.IMREAD_GRAYSCALE) + +''' Define features ''' + + +def height_and_width(img): + rows, cols = np.where(img != 0) + x1, x2, y1, y2 = np.min(cols), np.max(cols), np.min(rows), np.max(rows) + h = y2 - y1 + w = x2 - x1 + return h, w + + +def height_over_width(w, h): + return h / w + + +def perimeter(img): + kernel = np.asarray([[0, 1, 0], [1, 1, 1], [0, 1, 0]], dtype=np.uint8) + small_img = cv2.erode(img, kernel) + edges = img - small_img + peri = np.sum(edges / np.max(edges)) + return peri + + +def area(img): + return np.sum(img / np.max(img)) + + +def roundness(perimeter, area, h, w): + # (2 pi r) / (pi r^2) = perimeter / area = 2 / r for round objects + # r = h / 2 = w / 2 + r = 0.5 * (h / 2 + w / 2) + round = r * perimeter / (2 * area) + return round + + +''' Show parameter ''' +for name, img in [("img1", img1), ("img2", img2), ("img3", img3), ("img4", img4), ("img5", img5), ("img6", img6)]: + print("Image:", name) + object_height, object_width = height_and_width(img) + print(" h =", object_height) + print(" w =", object_width) + object_height_over_width = height_over_width(object_width, object_height) + print(" height_over_width =", object_height_over_width) + object_perimeter = perimeter(img) + print(" perimeter =", object_perimeter) + object_area = area(img) + print(" area =", object_area) + object_roundness = roundness(object_perimeter, object_area, object_height, object_width) + print(" roundness =", object_roundness) \ No newline at end of file diff --git a/5_Bildanalyse/ü11/l_b.md b/5_Bildanalyse/ü11/l_b.md new file mode 100644 index 0000000..c0f4388 --- /dev/null +++ b/5_Bildanalyse/ü11/l_b.md @@ -0,0 +1,60 @@ +# Lösung b): Klassifikation von Merkmalen + +Basierend auf den Merkmalen in Teilaufgabe a) können einige Regelen für die Klassifikation von Objekten erstellt werden. +Diese Lösung ist eine von vielen möglichen Lösungen und bezieht sich auf die Ausgabe aus Aufgabe a): + +````shell +Image: img1 + h = 119 + w = 60 + height_over_width = 1.9833333333333334 + perimeter = 535.0 + area = 2925.0 + roundness = 4.092521367521368 +Image: img2 + h = 96 + w = 53 + height_over_width = 1.8113207547169812 + perimeter = 494.0 + area = 1981.0 + roundness = 4.6444977284199895 +Image: img3 + h = 98 + w = 117 + height_over_width = 0.8376068376068376 + perimeter = 1120.0 + area = 2489.0 + roundness = 12.093210124548012 +Image: img4 + h = 73 + w = 56 + height_over_width = 1.3035714285714286 + perimeter = 631.0 + area = 884.0 + roundness = 11.510039592760181 +Image: img5 + h = 48 + w = 50 + height_over_width = 0.96 + perimeter = 140.0 + area = 1960.0 + roundness = 0.875 +Image: img6 + h = 49 + w = 56 + height_over_width = 0.875 + perimeter = 382.0 + area = 2111.0 + roundness = 2.3750592136428232 + +Process finished with exit code 0 + +```` + +- **Menschen** sind im stehenden Zustand ca. doppelt so hoch wie breit. Daher sollte bei einem Menschen *height_over_width* ca. 2 sein. Zusätzlich sollte die *roundness* deutlich ungleich 1 sein. +- **Bälle** sind unabhängig von ihrer Größe rund. Die *roundness* sollte daher in der Nähe von 1 liegen. +- **Fenster** haben meistens aufgrund der "Kacheln" eine geringe Fläche, verglichen zu dem Umfang. + + +Diese Regeln müssen nicht auf jedes Objekt zutreffen. Sie sollen lediglich veranschaulichen, wie Regeln für einen Klassifikator +aus Merkmalen erstellt werden können. \ No newline at end of file diff --git a/5_Bildanalyse/ü12/README.md b/5_Bildanalyse/ü12/README.md new file mode 100644 index 0000000..86eb8b1 --- /dev/null +++ b/5_Bildanalyse/ü12/README.md @@ -0,0 +1,53 @@ +# Übung 12: Automatische Schwellwertfindung nach Otsu + +Sie haben folgendes Bild gegeben und sollen den Kamera-Mann und seine Kamera möglichst gut mit einem binären Schwellwert +segmentieren: +![](../../data/cameraman.png) + +Hierzu soll das Verfahren von Otsu verwendet werden. + +Quelle: [https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=4310076](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=4310076) + +## a) Otsu + +Berechnen Sie für jeden Schwellwert zwischen {0, ..., 255} die Mittelwerte und Varianzen der beiden Gaussverteilungen + +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +und maximieren Sie den Quotienten + +

+ +

+ +mit dem Mittelwert des Grauwertbildes +

+ +

+ +sodass Sie den optimalen Schwellwert s bekommen. + +Bitte führen Sie für die Bearbeitung der Aufgabe das Skript [a.py](a.py) fort. +Die Lösung befindet sich in Datei [l_a.py](l_a.py). diff --git a/5_Bildanalyse/ü12/a.py b/5_Bildanalyse/ü12/a.py new file mode 100644 index 0000000..97b1e00 --- /dev/null +++ b/5_Bildanalyse/ü12/a.py @@ -0,0 +1,41 @@ +import numpy as np +import cv2 +from matplotlib import pyplot as plt + + +def n1(hist, s): + ... + + +def n2(hist, s): + ... + + +def mean(hist): + ... + + +def mu1(hist, s, n): + ... + + +def mu2(hist, s, n): + ... + + +def sigma1(hist, s, n, mu): + ... + + +def sigma2(hist, s, n, mu): + ... + + +def Q(hist, s): + ... + + +''' Load data ''' +# Load images and template +img = cv2.imread("../../data/cameraman.png", cv2.IMREAD_GRAYSCALE) + diff --git a/5_Bildanalyse/ü12/l_a.py b/5_Bildanalyse/ü12/l_a.py new file mode 100644 index 0000000..5caab78 --- /dev/null +++ b/5_Bildanalyse/ü12/l_a.py @@ -0,0 +1,77 @@ +import numpy as np +import cv2 +from matplotlib import pyplot as plt + + +def n1(hist, s): + return np.sum(hist[0:s+1]) + + +def n2(hist, s): + return np.sum(hist[s+1:256]) + + +def mean(hist): + k = np.arange(0, 256) + return np.sum((hist * k)) / np.sum(hist) + + +def mu1(hist, s, n): + k = np.arange(0, 256) + return (1 / n) * np.sum((hist * k)[0:s+1]) + + +def mu2(hist, s, n): + k = np.arange(0, 256) + return (1 / n) * np.sum((hist * k)[s+1:256]) + + +def sigma1(hist, s, n, mu): + k = np.arange(0, 256) + return np.sqrt((1 / n) * np.sum((hist * np.power(k - mu, 2))[0:s+1])) + + +def sigma2(hist, s, n, mu): + k = np.arange(0, 256) + return np.sqrt((1 / n) * np.sum((hist * np.power(k - mu, 2))[s+1:256])) + + +def Q(hist, s): + n_1, n_2 = n1(hist, s), n2(hist, s) + if n_1 == 0 or n_2 == 0: + return 0 + mu_1, mu_2 = mu1(hist, s, n_1), mu2(hist, s, n_2) + sigma_1, sigma_2 = sigma1(hist, s, n_1, mu_1), sigma2(hist, s, n_2, mu_2) + _mean = mean(hist) + + sigma_zw = n_1 * np.power(mu_1 - _mean, 2) + n_2 * np.power(mu_2 - _mean, 2) + sigma_in = n_1 * np.power(sigma_1, 2) + n_2 * np.power(sigma_2, 2) + q = np.power(sigma_zw, 2) / np.power(sigma_in, 2) + return q + +''' Load data ''' +# Load images and template +img = cv2.imread("../../data/cameraman.png", cv2.IMREAD_GRAYSCALE) + +histr = cv2.calcHist([img], [0], None, [256], [0, 256]) +histr = histr[:, 0] +plt.plot(histr) +plt.xlim([0, 256]) + +''' Iterate over all s ''' +q_list = list() + +for s in range(1, 255): + q_list.append(Q(histr, s)) + +optimal_s = np.argmax(np.asarray(q_list)) +print("Threshold:", optimal_s) + +''' Visualize result ''' +mask = img >= optimal_s + +cv2.imshow("img", img) +cv2.imshow("mask", mask.astype(np.uint8) * 255) + +plt.show() +cv2.waitKey(0) \ No newline at end of file diff --git a/5_Bildanalyse/ü13/README.md b/5_Bildanalyse/ü13/README.md new file mode 100644 index 0000000..29c9ffc --- /dev/null +++ b/5_Bildanalyse/ü13/README.md @@ -0,0 +1,49 @@ +# Übung 13: Instanzsegmentierung + +In dieser Aufgabe sollen verschiedene Instanzen von Objekten in einem binär segmentierten Bild gefunden werden. + + +## a) Zeilenkoinzidenzverfahren + +Betrachten Sie das folgende Bild und die dazugehörige Instanzsegmentierung: + +| Binärbild | Instanz-segmentiertes Bild | +| --- | --- | +| ![](data/bild.png) | ![](data/result.jpg)| + + +Finden Sie in dem Binärbild zusammenhängende bzw. getrennte Objekte nach dem Zeilenkoinzidenzverfahren nach der foldengen +Anleitung: + +![](data/verfahren.png) + +Geben Sie dabei jedem neuen Objekt eine eigene ID und visualisieren Sie das Ergebnis. + + +Bitte führen Sie für die Bearbeitung der Aufgabe das Skript [a.py](a.py) fort. +Eine Lösung befindet sich in Datei [l_a.py](l_a.py). + + +## b) Watershed Algorithmus + +Betrachten Sie das folgende Bild und die dazugehörige Instanzsegmentierung: + +| RGB-Bild | Instanz-segmentiertes Bild | +| --- | --- | +| ![](data/students_checklist.jpg) | ![](data/students_checklist_result.jpg)| + + + +Führen Sie nun die Instanzsegmentierung mit der folgenden +Anleitung selbst durch: + +- Binarisieren Sie das Bild, sodass der Hintergrund das Label 0 und die Sticker das Label 1 haben +- Füllen Sie im Binärbild kleine Löcher und entfernen Sie kleine Regionen (Rauschen) +- Erstellen Sie Seed-Punkte/Regionen, indem Sie das Binärbild stark erodieren und das Zeilenkoinzidenzverfahren (siehe oben) anwenden +- "Füllen" Sie iterativ die Pixel mit dem Label 1 zu den Seedpunkten hinzu + +Geben Sie am Ende jedem Objekt eine eigene ID und visualisieren Sie das Ergebnis. + + +Bitte führen Sie für die Bearbeitung der Aufgabe das Skript [b.py](b.py) fort. +Eine Lösung befindet sich in Datei [l_b.py](l_b.py). diff --git a/5_Bildanalyse/ü13/a.py b/5_Bildanalyse/ü13/a.py new file mode 100644 index 0000000..ebefee1 --- /dev/null +++ b/5_Bildanalyse/ü13/a.py @@ -0,0 +1,9 @@ +import numpy as np +import cv2 + + +''' Load image ''' +img = cv2.imread("data/bild.png", cv2.IMREAD_GRAYSCALE) +cv2.imshow("img", img) + +cv2.waitKey(0) \ No newline at end of file diff --git a/5_Bildanalyse/ü13/data/bild.png b/5_Bildanalyse/ü13/data/bild.png new file mode 100644 index 0000000..02d6176 Binary files /dev/null and b/5_Bildanalyse/ü13/data/bild.png differ diff --git a/5_Bildanalyse/ü13/data/result.jpg b/5_Bildanalyse/ü13/data/result.jpg new file mode 100644 index 0000000..dd72f3e Binary files /dev/null and b/5_Bildanalyse/ü13/data/result.jpg differ diff --git a/5_Bildanalyse/ü13/data/students_checklist.jpg b/5_Bildanalyse/ü13/data/students_checklist.jpg new file mode 100644 index 0000000..86e07f2 Binary files /dev/null and b/5_Bildanalyse/ü13/data/students_checklist.jpg differ diff --git a/5_Bildanalyse/ü13/data/students_checklist_result.jpg b/5_Bildanalyse/ü13/data/students_checklist_result.jpg new file mode 100644 index 0000000..14e1a0d Binary files /dev/null and b/5_Bildanalyse/ü13/data/students_checklist_result.jpg differ diff --git a/5_Bildanalyse/ü13/data/verfahren.png b/5_Bildanalyse/ü13/data/verfahren.png new file mode 100644 index 0000000..b7f4126 Binary files /dev/null and b/5_Bildanalyse/ü13/data/verfahren.png differ diff --git a/5_Bildanalyse/ü13/l_a.py b/5_Bildanalyse/ü13/l_a.py new file mode 100644 index 0000000..5f6935f --- /dev/null +++ b/5_Bildanalyse/ü13/l_a.py @@ -0,0 +1,61 @@ +import numpy as np +import cv2 + + +''' Load image ''' +img = cv2.imread("data/bild.png", cv2.IMREAD_GRAYSCALE) +cv2.imshow("img", img) + +''' Iterate over rows / columns''' +label_map = np.zeros_like(img) +next_id = 1 +for i in range(img.shape[0]): + for j in range(img.shape[1]): + if img[i, j] != 0: + upper_label = label_map[i - 1, j] if i > 0 else 0 + left_label = label_map[i, j - 1] if j > 0 else 0 + if upper_label == 0 and left_label == 0: + label_map[i, j] = next_id + next_id += 1 + elif upper_label == 0 and left_label != 0: + label_map[i, j] = left_label + elif upper_label != 0 and left_label == 0: + label_map[i, j] = upper_label + elif upper_label != 0 and left_label != 0: + if upper_label == left_label: + label_map[i, j] = upper_label + else: + new_label = min(upper_label, left_label) + old_label = max(upper_label, left_label) + label_map[label_map == old_label] = new_label + label_map[i, j] = new_label + +''' Rename labels (not necessary, but for visualisation) ''' +labels = sorted(np.unique(label_map)) +next_id = 1 +for l in labels: + if l == 0: + continue + label_map[label_map == l] = next_id + next_id += 1 + +''' Visualize label map ''' +color_map = { + 1: [255, 0, 0], + 2: [255, 255, 0], + 3: [255, 255, 255], + 4: [0, 255, 0], + 5: [0, 255, 255], + 6: [0, 0, 255], + 7: [100, 100, 100], + 8: [50, 200, 80], + 9: [200, 140, 88], + 10: [120, 0, 190], +} + +colored_image = np.zeros((img.shape[0], img.shape[1], 3)) +for c, value in color_map.items(): + colored_image[label_map == c] = value + +cv2.imshow("colored_image", colored_image.astype(np.uint8)) +cv2.waitKey(0) diff --git a/5_Bildanalyse/ü13/l_b.py b/5_Bildanalyse/ü13/l_b.py new file mode 100644 index 0000000..1cd07c0 --- /dev/null +++ b/5_Bildanalyse/ü13/l_b.py @@ -0,0 +1,91 @@ +import numpy as np +import cv2 + + +''' Load image and apply histogramm equalization ''' +img = cv2.imread("data/students_checklist.jpg").astype(np.float32) +img[:, :, 0] = 255 * (img[:, :, 0] - np.min(img[:, :, 0])) / (np.max(img[:, :, 0]) - np.min(img[:, :, 0])) +img[:, :, 1] = 255 * (img[:, :, 1] - np.min(img[:, :, 1])) / (np.max(img[:, :, 1]) - np.min(img[:, :, 1])) +img[:, :, 2] = 255 * (img[:, :, 2] - np.min(img[:, :, 2])) / (np.max(img[:, :, 2]) - np.min(img[:, :, 2])) +cv2.imshow("img", img.astype(np.uint8)) + +''' Binary segmentation ''' +mask = (img[:, :, 0] > 100) * (img[:, :, 1] > 100) * (img[:, :, 2] > 100) *\ + (img[:, :, 2] - img[:, :, 1] < 20) * (img[:, :, 2] - img[:, :, 0] < 20) +mask = 1 - mask + +''' Morphologigcal operations ''' +kernel = np.ones((3, 3)) +mask = cv2.erode(mask.astype(np.uint8) * 255, kernel, iterations=15) +mask = cv2.dilate(mask, kernel, iterations=15) + +cv2.imshow("mask", mask) + +''' Finding seed point ''' +seeds = cv2.erode(mask, kernel, iterations=70) +cv2.imshow("seeds", seeds) + +''' Labeling seeds ''' +label_map = np.zeros_like(seeds) +next_id = 1 +for i in range(img.shape[0]): + for j in range(img.shape[1]): + if seeds[i, j] != 0: + upper_label = label_map[i - 1, j] if i > 0 else 0 + left_label = label_map[i, j - 1] if j > 0 else 0 + if upper_label == 0 and left_label == 0: + label_map[i, j] = next_id + next_id += 1 + elif upper_label == 0 and left_label != 0: + label_map[i, j] = left_label + elif upper_label != 0 and left_label == 0: + label_map[i, j] = upper_label + elif upper_label != 0 and left_label != 0: + if upper_label == left_label: + label_map[i, j] = upper_label + else: + new_label = min(upper_label, left_label) + old_label = max(upper_label, left_label) + label_map[label_map == old_label] = new_label + label_map[i, j] = new_label +labels = sorted(np.unique(label_map)) +next_id = 1 +for l in labels: + if l == 0: + continue + label_map[label_map == l] = next_id + next_id += 1 + +''' Create distance labels for all labels ''' +mask = mask != 0 + +while np.sum(mask > 0): + for l in np.unique(label_map): + if l == 0: + continue + kernel = np.ones((3, 3)) + current_label = label_map == l + current_label = cv2.dilate(current_label.astype(np.uint8), kernel, iterations=1) + current_label = current_label * mask + mask[current_label != 0] = 0 + label_map[current_label != 0] = l + + +''' Visualize label map ''' +color_map = { + 1: [255, 0, 0], + 2: [255, 255, 0], + 3: [255, 255, 255], + 4: [0, 255, 0], + 5: [0, 255, 255], + 6: [0, 0, 255], + 7: [100, 100, 100], + 8: [50, 200, 80], + 9: [200, 140, 88], + 10: [120, 0, 190], +} +colored_image = np.zeros((img.shape[0], img.shape[1], 3)) +for c, value in color_map.items(): + colored_image[label_map == c] = value +cv2.imshow("colored_image", colored_image.astype(np.uint8)) +cv2.waitKey(0) diff --git a/5_Bildanalyse/ü2/README.md b/5_Bildanalyse/ü2/README.md new file mode 100644 index 0000000..d71d60c --- /dev/null +++ b/5_Bildanalyse/ü2/README.md @@ -0,0 +1,21 @@ +# Übung 2: Morphologische Operatoren + +In dieser Übung werden die morphologischen Operatoren *Dilatation* und *Erosion* behandelt. + +## Aufgabe a) +Geben Sie die Definition der Dilatation und der Erosion an! Die Lösung findet sich in [l_a.md](l_a.md). + +## Aufgabe b) +Geben Sie die Definition von *Opening* und *Closing* als Funktion von Dilatation und der Erosion an! Die Lösung findet sich in [l_b.md](l_b.md). + +## Aufgabe c) +Wenn ein Binärbild nach einer Erosion an einer Position (x, y) den Wert 1 hat, muss dann +das ursprüngliche Bild ebenfalls an der Stelle (x, y) den Wert 1 haben? Die Lösung findet sich in [l_c.md](l_c.md). + +## Aufgabe d) +Gegeben seien folgendes Binärbild (links) und Strukturelement (rechts, Ursprung in der Mitte). +Berechnen Sie das Ergebnisbild nach dem Ausführen einer Opening-Operation. + +![data/morph.png](data/morph.png) + +Das Binärbild finden Sie in der Datei [d.py](d.py). Die dazugehörige Musterlösung in der Datei [l_d.py](l_d.py). diff --git a/5_Bildanalyse/ü2/d.py b/5_Bildanalyse/ü2/d.py new file mode 100644 index 0000000..210c64d --- /dev/null +++ b/5_Bildanalyse/ü2/d.py @@ -0,0 +1,22 @@ +import cv2 +import numpy as np + +I = np.asarray([ + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 1, 0, 1, 1, 0, 1, 0], + [0, 1, 0, 1, 1, 0, 1, 1, 1, 0], + [0, 0, 1, 0, 0, 0, 0, 1, 1, 0], + [0, 0, 1, 0, 0, 1, 0, 0, 1, 0], + [0, 0, 1, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0, 1, 0], + [0, 0, 0, 1, 1, 1, 0, 1, 1, 0], + [0, 1, 0, 1, 1, 1, 0, 1, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], +], dtype=np.uint8) + +s = np.asarray([ + [0, 1, 0], + [0, 1, 1], + [0, 0, 0], +], dtype=np.uint8) + diff --git a/5_Bildanalyse/ü2/data/dilatation.png b/5_Bildanalyse/ü2/data/dilatation.png new file mode 100644 index 0000000..7df22ea Binary files /dev/null and b/5_Bildanalyse/ü2/data/dilatation.png differ diff --git a/5_Bildanalyse/ü2/data/erosion.png b/5_Bildanalyse/ü2/data/erosion.png new file mode 100644 index 0000000..f6e5ffe Binary files /dev/null and b/5_Bildanalyse/ü2/data/erosion.png differ diff --git a/5_Bildanalyse/ü2/data/morph.png b/5_Bildanalyse/ü2/data/morph.png new file mode 100644 index 0000000..d61b00d Binary files /dev/null and b/5_Bildanalyse/ü2/data/morph.png differ diff --git a/5_Bildanalyse/ü2/l_a.md b/5_Bildanalyse/ü2/l_a.md new file mode 100644 index 0000000..c73822f --- /dev/null +++ b/5_Bildanalyse/ü2/l_a.md @@ -0,0 +1,20 @@ +# Musterlösung Aufgabe a) + +Die beiden Basisoperatoren in der morphologischen Filterung sind die dualen Filter Erosion +(Verkleinerung, Ausdünnung) und Dilatation (Vergrößerung, Aufblähung). + +Bei einer Dilatation (lat: dilaterare: ausbreiten, dehnen) werden Hintergrundpixel, die bestimmte +Voraussetzungen erfüllen, in den Vordergrund aufgenommen. Eine bestimmte Pixelposition (Ankerpunkt) +wird auf 1 gesetzt (also dem Vordergrund zugeordnet), falls das Strukturelement mindestens +ein Pixel mit Wert 1 des Bildes überdeckt. + +![data/dilatation.png](data/dilatation.png) + + +Die der Dilatation entgegengesetzte Operation nennt man Erosion (lat: erodere = abnagen). Diese +Operation verkleinert die Segmente, indem bestimmte Segmentpixel dem Hintergrund beigeordnet +werden. Hier wird der Ankerpunkt auf 0 gesetzt (also dem Hintergrund zugeordnet), falls das +Strukturelement mindestens ein Pixel des Binärbildes mit den Wert 0 überdeckt. Andernfalls wird +der Ankerpunkt auf 1 gesetzt. + +![data/erosion.png](data/erosion.png) diff --git a/5_Bildanalyse/ü2/l_b.md b/5_Bildanalyse/ü2/l_b.md new file mode 100644 index 0000000..168dfbc --- /dev/null +++ b/5_Bildanalyse/ü2/l_b.md @@ -0,0 +1,26 @@ +# Musterlösung Aufgabe b) + +**Erosion:** + +

+ +

+ +**Dilatation:** + +

+ +

+ +**Opening:** + +

+ +

+ +**Closing:** + +

+ +

+ diff --git a/5_Bildanalyse/ü2/l_c.md b/5_Bildanalyse/ü2/l_c.md new file mode 100644 index 0000000..c37c3d0 --- /dev/null +++ b/5_Bildanalyse/ü2/l_c.md @@ -0,0 +1,10 @@ +# Musterlösung Aufgabe c) +Antwort: Nein! + +Beweis: +Verwendet man als Strukturelement zum Beispiel +

+ +

+so kann die Erosion zusätzliche +Binärpixel erzeugen, welche nicht im Ursprungsbild waren. \ No newline at end of file diff --git a/5_Bildanalyse/ü2/l_d.py b/5_Bildanalyse/ü2/l_d.py new file mode 100644 index 0000000..67398e1 --- /dev/null +++ b/5_Bildanalyse/ü2/l_d.py @@ -0,0 +1,35 @@ +import cv2 +import numpy as np + +I = np.asarray([ + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 1, 0, 1, 1, 0, 1, 0], + [0, 1, 0, 1, 1, 0, 1, 1, 1, 0], + [0, 0, 1, 0, 0, 0, 0, 1, 1, 0], + [0, 0, 1, 0, 0, 1, 0, 0, 1, 0], + [0, 0, 1, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0, 1, 0], + [0, 0, 0, 1, 1, 1, 0, 1, 1, 0], + [0, 1, 0, 1, 1, 1, 0, 1, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], +], dtype=np.uint8) + +s = np.asarray([ + [0, 1, 0], + [0, 1, 1], + [0, 0, 0], +], dtype=np.uint8) + + +I_new = cv2.erode(I, s) +I_new = cv2.dilate(I_new, s) + +# Resize image +I = np.repeat(I, 50, axis=1) +I = np.repeat(I, 50, axis=0) +I_new = np.repeat(I_new, 50, axis=1) +I_new = np.repeat(I_new, 50, axis=0) + +cv2.imshow("Original", I * 255) +cv2.imshow("Opening", I_new * 255) +cv2.waitKey(0) diff --git a/5_Bildanalyse/ü3/README.md b/5_Bildanalyse/ü3/README.md new file mode 100644 index 0000000..bc4cbdd --- /dev/null +++ b/5_Bildanalyse/ü3/README.md @@ -0,0 +1,25 @@ +# Übung 3: Split and Merge + +Sie haben folgendes Grauwertbild gegeben: + + +![](data/splitmerge.png) + +Dabei gilt die Homogenitätsbedingung: + +

+ +

+ + +## Aufgabe a: +Wenden Sie den "Split and Merge" Algorithmus auf **F** an. + +## Aufgabe b: +Zerlegen Sie das Bild in eine Quad-Tree Sruktur. + +## Aufgabe c) +Zeichnen Sie das Segmentierungsergebnis. + +## Aufgabe d) +Ist das Ergebnis eindeutig? diff --git a/5_Bildanalyse/ü3/data/l_ac.png b/5_Bildanalyse/ü3/data/l_ac.png new file mode 100644 index 0000000..c0bc960 Binary files /dev/null and b/5_Bildanalyse/ü3/data/l_ac.png differ diff --git a/5_Bildanalyse/ü3/data/l_b.png b/5_Bildanalyse/ü3/data/l_b.png new file mode 100644 index 0000000..91edb78 Binary files /dev/null and b/5_Bildanalyse/ü3/data/l_b.png differ diff --git a/5_Bildanalyse/ü3/data/splitmerge.png b/5_Bildanalyse/ü3/data/splitmerge.png new file mode 100644 index 0000000..15cd73f Binary files /dev/null and b/5_Bildanalyse/ü3/data/splitmerge.png differ diff --git a/5_Bildanalyse/ü3/l_ac.md b/5_Bildanalyse/ü3/l_ac.md new file mode 100644 index 0000000..8d04c8b --- /dev/null +++ b/5_Bildanalyse/ü3/l_ac.md @@ -0,0 +1,12 @@ +# Lösung Aufgabe a) +1. Rekursive Zerlegung aller Regionen in vier nicht zusammenhängende Quadraten, falls das +Homogenitätskriterium für die entsprechende Region nicht erfüllt ist. +2. Rekursive Zusammenfassung +aller benachbarten Regionen, sofern auch dies mit dem Homogenitätskriterium +vereinbaren lässt. + +# Lösung Aufgabe c) +Die Abbildung i) zeigt das Zwischenergebnis nach dem Split. Die Lösung ii) zeigt das Ergebnis +nach dem Merge. + +![](data/l_ac.png) \ No newline at end of file diff --git a/5_Bildanalyse/ü3/l_b.md b/5_Bildanalyse/ü3/l_b.md new file mode 100644 index 0000000..b5e854d --- /dev/null +++ b/5_Bildanalyse/ü3/l_b.md @@ -0,0 +1,4 @@ +# Lösung Aufgabe b) + + +![](data/l_b.png) \ No newline at end of file diff --git a/5_Bildanalyse/ü3/l_d.md b/5_Bildanalyse/ü3/l_d.md new file mode 100644 index 0000000..e4f920a --- /dev/null +++ b/5_Bildanalyse/ü3/l_d.md @@ -0,0 +1,3 @@ +# Lösung Aufgabe d) +Das Segmentierungsergebnis ist nur dann eindeutig, wenn der Quad-Tree während der Zusammenfassung +immer in der gleichen Reihenfolge durchlaufen wird. \ No newline at end of file diff --git a/5_Bildanalyse/ü4/README.md b/5_Bildanalyse/ü4/README.md new file mode 100644 index 0000000..7762070 --- /dev/null +++ b/5_Bildanalyse/ü4/README.md @@ -0,0 +1,15 @@ +# Übung 4: Region Growing +Gegeben ist der folgende Bildausschnitt: + +

+ +

+ + +

+ +

+ +## Aufgabe a) +Wenden Sie auf diesen Bildausschnitt das Region Growing Verfahren sowohl für die 4-Nachbarschaft als auch für die 8-Nachbarschaft an. Der Seed-Punkt ist in der ersten Reihe, Spalte 5. Verwenden Sie als Homogenitätskriterium den Abstand zum mittleren Grauwert +der Region und als Schwellwert 30. diff --git a/5_Bildanalyse/ü4/data/a.png b/5_Bildanalyse/ü4/data/a.png new file mode 100644 index 0000000..0e8b1b0 Binary files /dev/null and b/5_Bildanalyse/ü4/data/a.png differ diff --git a/5_Bildanalyse/ü4/data/n4.png b/5_Bildanalyse/ü4/data/n4.png new file mode 100644 index 0000000..aba2647 Binary files /dev/null and b/5_Bildanalyse/ü4/data/n4.png differ diff --git a/5_Bildanalyse/ü4/data/n8.png b/5_Bildanalyse/ü4/data/n8.png new file mode 100644 index 0000000..b578b6b Binary files /dev/null and b/5_Bildanalyse/ü4/data/n8.png differ diff --git a/5_Bildanalyse/ü4/l_a.md b/5_Bildanalyse/ü4/l_a.md new file mode 100644 index 0000000..1662bb4 --- /dev/null +++ b/5_Bildanalyse/ü4/l_a.md @@ -0,0 +1,11 @@ +# Lösung Aufgabe a) + +N4 Nachbarschadt | N8 Nachbarschaft +---|--- +![](data/n4.png) | ![](data/n8.png) + + + +Der in der Vorlesung beschriebene Algorithmus ist nicht deterministisch. Damit der Alsgorithmus deterministisch ist, muss er genauer spezifiziert und stets eingehalten werden: +- Reihenfolge in der die Nachbarschaft abgelaufen wird +- Werden Pixel die nicht zur Region gehören nur einmal oder mehrmals getestet? diff --git a/5_Bildanalyse/ü5/README.md b/5_Bildanalyse/ü5/README.md new file mode 100644 index 0000000..5d0b43d --- /dev/null +++ b/5_Bildanalyse/ü5/README.md @@ -0,0 +1,8 @@ +# Übung 5: Medialachsentransformation + +Führen Sie die Medialachsentransformation mit der 8-Nachbarschaft (N8) für die folgende Region +durch: + +![](data/mat1.png) + +Die Lösung befindet sich in Datei [l_a.md](l_a.md). \ No newline at end of file diff --git a/5_Bildanalyse/ü5/data/mat1.png b/5_Bildanalyse/ü5/data/mat1.png new file mode 100644 index 0000000..47302b2 Binary files /dev/null and b/5_Bildanalyse/ü5/data/mat1.png differ diff --git a/5_Bildanalyse/ü5/data/mat2.png b/5_Bildanalyse/ü5/data/mat2.png new file mode 100644 index 0000000..fb97b99 Binary files /dev/null and b/5_Bildanalyse/ü5/data/mat2.png differ diff --git a/5_Bildanalyse/ü5/data/mat3.png b/5_Bildanalyse/ü5/data/mat3.png new file mode 100644 index 0000000..c24d359 Binary files /dev/null and b/5_Bildanalyse/ü5/data/mat3.png differ diff --git a/5_Bildanalyse/ü5/l_a.md b/5_Bildanalyse/ü5/l_a.md new file mode 100644 index 0000000..efa601a --- /dev/null +++ b/5_Bildanalyse/ü5/l_a.md @@ -0,0 +1,6 @@ +# Lösung Aufgabe a) + +Schritt 1 | Schritt 2 +---|--- +Berechnung der Abstände zum Rand | Bestimmung der Maxima (in grün eingezeichnet) +![](data/mat2.png) | ![](data/mat3.png) diff --git a/5_Bildanalyse/ü6/README.md b/5_Bildanalyse/ü6/README.md new file mode 100644 index 0000000..d59e171 --- /dev/null +++ b/5_Bildanalyse/ü6/README.md @@ -0,0 +1,29 @@ +# Übung 6: Hough-Akkumulator + +Betrachten Sie das folgende Binärbild: + +![](data/houghImg.png) + + +Dabei sind die schwarzen Pixel als Kantenpixel zu verstehen. +Im folgenden sollen Sie mittels der Hough-Transformation Linien im Binärbild finden. +Bearbeiten Sie dazu folgende Aufgaben: + +## a) Akkumulator + +Nutzen Sie für die Hough-Transformation den folgenden Hough-Akkumulator mit der +Parametrisierung **y=mx+n**. + +![](data/houghAcc.png) + + +Erstellen Sie die finale Akkumulator-Matrix H. + +Die Lösung befindet sich in Datei [l_a.py](l_a.py). + +## b) Parametrierung + +Geben Sie die Parametrierung der Geraden an, +fuer welche die Akkumulator-Matrix H den größten Wert hat. + +Die Lösung befindet sich in Datei [l_b.py](l_b.py). diff --git a/5_Bildanalyse/ü6/data/houghAcc.png b/5_Bildanalyse/ü6/data/houghAcc.png new file mode 100644 index 0000000..578c9ff Binary files /dev/null and b/5_Bildanalyse/ü6/data/houghAcc.png differ diff --git a/5_Bildanalyse/ü6/data/houghImg.png b/5_Bildanalyse/ü6/data/houghImg.png new file mode 100644 index 0000000..fd035a3 Binary files /dev/null and b/5_Bildanalyse/ü6/data/houghImg.png differ diff --git a/5_Bildanalyse/ü6/l_a.py b/5_Bildanalyse/ü6/l_a.py new file mode 100644 index 0000000..73fa12d --- /dev/null +++ b/5_Bildanalyse/ü6/l_a.py @@ -0,0 +1,10 @@ +import numpy as np + +acc = [ + [1, 0, 1, 1, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 1, 2, 0, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 1, 3] +] + +acc = np.asarray(acc) +print(acc) \ No newline at end of file diff --git a/5_Bildanalyse/ü6/l_b.py b/5_Bildanalyse/ü6/l_b.py new file mode 100644 index 0000000..509f945 --- /dev/null +++ b/5_Bildanalyse/ü6/l_b.py @@ -0,0 +1,6 @@ +import numpy as np + +n = 4 +m = -1 + +print("%s * x + %s" % (m, n)) diff --git a/5_Bildanalyse/ü7/README.md b/5_Bildanalyse/ü7/README.md new file mode 100644 index 0000000..ec68d57 --- /dev/null +++ b/5_Bildanalyse/ü7/README.md @@ -0,0 +1,18 @@ +# Übung 7: Distanzmetriken + +Betrachten Sie das folgende Binärbild: + +![](data/a.png) + + +Es soll der Abstand zwischen dem obersten Pixel an der Position (0,1) und dem +Pixel an der Stelle (5, 4) berechnet werden. + +## a) + +Berechnen Sie + - die City-Block Distanz + - den euklidischen Abstand + - die Schachbrett Distanz (Tschebyschew-Abstand). + +Die Lösung befindet sich in Datei [l_a.py](l_a.py). diff --git a/5_Bildanalyse/ü7/data/a.png b/5_Bildanalyse/ü7/data/a.png new file mode 100644 index 0000000..2cd584e Binary files /dev/null and b/5_Bildanalyse/ü7/data/a.png differ diff --git a/5_Bildanalyse/ü7/l_a.py b/5_Bildanalyse/ü7/l_a.py new file mode 100644 index 0000000..d49fab0 --- /dev/null +++ b/5_Bildanalyse/ü7/l_a.py @@ -0,0 +1,44 @@ +import numpy as np +import cv2 + +p_1 = (0, 1) +p_2 = (5, 4) +matrix = np.zeros((6, 6)) +matrix[p_1[1], p_1[0]] = 1 +matrix[p_2[1], p_2[0]] = 1 + +# Resize image +matrix = np.repeat(matrix, 50, axis=1) +matrix = np.repeat(matrix, 50, axis=0) + +# Add seperators +matrix[0::2, ::50] = 1 +matrix[1::2, ::50] = 0 +matrix[::50, 0::2] = 1 +matrix[::50, 1::2] = 0 + + +def city_block(p1, p2): + dx, dy = p2[0] - p1[0], p2[1] - p1[1] + return np.abs(dx) + np.abs(dy) + + +def euklidean(p1, p2): + dx, dy = p2[0] - p1[0], p2[1] - p1[1] + return np.sqrt(dx * dx + dy * dy) + + +def tschebyschew(p1, p2): + dx, dy = p2[0] - p1[0], p2[1] - p1[1] + return np.maximum(np.abs(dx), np.abs(dy)) + + +print("City-Block:", city_block(p_1, p_2)) +print("Euklidischer Abstand:", euklidean(p_1, p_2)) +print("Schachbrett Distanz (Tschebyschew):", tschebyschew(p_1, p_2)) + +# Show image +matrix = matrix.astype(np.float64) +cv2.imshow("a", matrix) +cv2.imwrite("data/a.png", matrix * 255) +cv2.waitKey(0) diff --git a/5_Bildanalyse/ü8/README.md b/5_Bildanalyse/ü8/README.md new file mode 100644 index 0000000..aa51ec3 --- /dev/null +++ b/5_Bildanalyse/ü8/README.md @@ -0,0 +1,13 @@ +# Übung 8: Vereinigung und Querschnitt + +Betrachten Sie die folgenden Binärbilder: + +| Objekt 1 | Objekt 2 | +| -------- | -------- | +| ![](data/a.png) | ![](data/b.png) | + + +## a) Vereinigung + +Zeichnen Sie die Vereinigung der beiden Objekte. +Die Lösung befindet sich in Datei [l_a.py](l_a.py). diff --git a/5_Bildanalyse/ü8/data/a.png b/5_Bildanalyse/ü8/data/a.png new file mode 100644 index 0000000..9b26617 Binary files /dev/null and b/5_Bildanalyse/ü8/data/a.png differ diff --git a/5_Bildanalyse/ü8/data/b.png b/5_Bildanalyse/ü8/data/b.png new file mode 100644 index 0000000..cc80b08 Binary files /dev/null and b/5_Bildanalyse/ü8/data/b.png differ diff --git a/5_Bildanalyse/ü8/l_a.py b/5_Bildanalyse/ü8/l_a.py new file mode 100644 index 0000000..4b504e8 --- /dev/null +++ b/5_Bildanalyse/ü8/l_a.py @@ -0,0 +1,66 @@ +import numpy as np +import cv2 + +obj1 = np.asarray([ + [0, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 1, 1, 1, 1, 0, 0], + [0, 1, 1, 0, 1, 1, 0, 0], + [0, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0], +]) + +obj2 = np.asarray([ + [0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 1, 1, 0, 0, 0], + [0, 0, 0, 1, 1, 0, 0, 0], + [0, 0, 0, 1, 1, 1, 0, 0], + [0, 0, 0, 0, 1, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0], +]) + +# obj1 = np.ones((5, 5)) +# obj2 = np.ones((5, 5)) + +union = np.maximum(obj1, obj2) + + +# Visualize images + +# Resize image +obj1 = np.repeat(obj1, 50, axis=1) +obj1 = np.repeat(obj1, 50, axis=0) +obj2 = np.repeat(obj2, 50, axis=1) +obj2 = np.repeat(obj2, 50, axis=0) +union = np.repeat(union, 50, axis=1) +union = np.repeat(union, 50, axis=0) + +# Add seperators +obj1[0::2, ::50] = 1 +obj1[1::2, ::50] = 0 +obj1[::50, 0::2] = 1 +obj1[::50, 1::2] = 0 +obj2[0::2, ::50] = 1 +obj2[1::2, ::50] = 0 +obj2[::50, 0::2] = 1 +obj2[::50, 1::2] = 0 +union[0::2, ::50] = 1 +union[1::2, ::50] = 0 +union[::50, 0::2] = 1 +union[::50, 1::2] = 0 + +# Show image +obj1 = obj1.astype(np.float64) +obj2 = obj2.astype(np.float64) +union = union.astype(np.float64) + +cv2.imshow("obj1", obj1) +cv2.imshow("obj2", obj2) +cv2.imshow("union", union) +cv2.imwrite("data/white.png", obj1 * 255) + +cv2.waitKey(0) diff --git a/5_Bildanalyse/ü8/l_b.py b/5_Bildanalyse/ü8/l_b.py new file mode 100644 index 0000000..1dddc7a --- /dev/null +++ b/5_Bildanalyse/ü8/l_b.py @@ -0,0 +1,63 @@ +import numpy as np +import cv2 + +obj1 = np.asarray([ + [0, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 1, 1, 1, 1, 0, 0], + [0, 1, 1, 0, 1, 1, 0, 0], + [0, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0], +]) + +obj2 = np.asarray([ + [0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 1, 1, 0, 0, 0], + [0, 0, 0, 1, 1, 0, 0, 0], + [0, 0, 0, 1, 1, 1, 0, 0], + [0, 0, 0, 0, 1, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0], +]) + + +intersection = obj1 * obj2 + + +# Visualize images + +# Resize image +obj1 = np.repeat(obj1, 50, axis=1) +obj1 = np.repeat(obj1, 50, axis=0) +obj2 = np.repeat(obj2, 50, axis=1) +obj2 = np.repeat(obj2, 50, axis=0) +intersection = np.repeat(intersection, 50, axis=1) +intersection = np.repeat(intersection, 50, axis=0) + +# Add seperators +obj1[0::2, ::50] = 1 +obj1[1::2, ::50] = 0 +obj1[::50, 0::2] = 1 +obj1[::50, 1::2] = 0 +obj2[0::2, ::50] = 1 +obj2[1::2, ::50] = 0 +obj2[::50, 0::2] = 1 +obj2[::50, 1::2] = 0 +intersection[0::2, ::50] = 1 +intersection[1::2, ::50] = 0 +intersection[::50, 0::2] = 1 +intersection[::50, 1::2] = 0 + +# Show image +obj1 = obj1.astype(np.float64) +obj2 = obj2.astype(np.float64) +intersection = intersection.astype(np.float64) + +cv2.imshow("obj1", obj1) +cv2.imshow("obj2", obj2) +cv2.imshow("intersection", intersection) + +cv2.waitKey(0) diff --git a/5_Bildanalyse/ü9/README.md b/5_Bildanalyse/ü9/README.md new file mode 100644 index 0000000..3961fca --- /dev/null +++ b/5_Bildanalyse/ü9/README.md @@ -0,0 +1,14 @@ +# Übung 9: Kantendetektion + +Sie möchten die Kanten des Kopfhörers in dem folgenden Bild detektieren: + ![](../../data/headphones.jpg) + + +## a) Morphologische Operationen + +Finden Sie die Kanten, indem Sie das Bild zuerst mit einem geeigneten Schwellwert binarisieren. Verwenden Sie +dann einer der beiden morphologischen Operationen Dilatation oder Erodieren. Wenden Sie dann auf das +Binärbild und morphologisch modifizierte Binärbild eine Subtraktion an und visualisieren Sie die so gefundenen +Kanten in dem originalen Bild. + +Die Lösung befindet sich in Datei [l_a.py](l_a.py). diff --git a/5_Bildanalyse/ü9/l_a.py b/5_Bildanalyse/ü9/l_a.py new file mode 100644 index 0000000..2aaa791 --- /dev/null +++ b/5_Bildanalyse/ü9/l_a.py @@ -0,0 +1,31 @@ +import numpy as np +import cv2 + +# Load image +original_img = cv2.imread("../../data/headphones.jpg") +original_img = cv2.resize(original_img, (int(original_img.shape[1]/ 2), int(original_img.shape[0] / 2))) + +img = cv2.cvtColor(original_img, cv2.COLOR_BGR2GRAY) +cv2.imshow("original_img", original_img) + +# Binary image +threshold = 80 +binary_mask = np.copy(img) +binary_mask[img < threshold] = 1 +binary_mask[img >= threshold] = 0 +cv2.imshow("binary_mask", binary_mask.astype(np.float32)) + +# Morphing +kernel = np.ones((9, 9)) +eroded_mask = cv2.erode(binary_mask, kernel, iterations=1) +cv2.imshow("eroded_mask", eroded_mask.astype(np.float32)) + +# Subtraction +edges = binary_mask - eroded_mask +cv2.imshow("edges", edges.astype(np.float32)) + +# Modify original image +original_img[:, :, 2] = np.maximum(original_img[:, :, 2], edges * 255) +cv2.imshow("modified_image", original_img) + +cv2.waitKey(0) diff --git a/Abgabe/DigBV_Aufgabe-1-7.pdf b/Abgabe/DigBV_Aufgabe-1-7.pdf new file mode 100644 index 0000000..af9e8dc Binary files /dev/null and b/Abgabe/DigBV_Aufgabe-1-7.pdf differ diff --git a/Abgabe/DigBV_Aufgabe.aux b/Abgabe/DigBV_Aufgabe.aux new file mode 100644 index 0000000..6601fce --- /dev/null +++ b/Abgabe/DigBV_Aufgabe.aux @@ -0,0 +1,45 @@ +\relax +\providecommand\hyper@newdestlabel[2]{} +\gdef\pagesLTS@loaded{p@gesLTSnotlo@ded} +\providecommand\HyperFirstAtBeginDocument{\AtBeginDocument} +\HyperFirstAtBeginDocument{\ifx\hyper@anchor\@undefined +\global\let\oldcontentsline\contentsline +\gdef\contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}} +\global\let\oldnewlabel\newlabel +\gdef\newlabel#1#2{\newlabelxx{#1}#2} +\gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}} +\AtEndDocument{\ifx\hyper@anchor\@undefined +\let\contentsline\oldcontentsline +\let\newlabel\oldnewlabel +\fi} +\fi} +\global\let\hyper@last\relax +\gdef\HyperFirstAtBeginDocument#1{#1} +\providecommand\HyField@AuxAddToFields[1]{} +\providecommand\HyField@AuxAddToCoFields[2]{} +\catcode `"\active +\newlabel{pagesLTS.0}{{}{1}{}{page.1}{}} +\newlabel{pagesLTS.0.local}{{}{1}{}{page.1}{}} +\providecommand \oddpage@label [2]{} +\reset@newl@bel +\select@language{ngerman} +\@writefile{toc}{\select@language{ngerman}} +\@writefile{lof}{\select@language{ngerman}} +\@writefile{lot}{\select@language{ngerman}} +\@input{sections/overview.aux} +\@input{sections/a.aux} +\@input{sections/a1.aux} +\@input{sections/a2.aux} +\@input{sections/a3.aux} +\@input{sections/conclusion.aux} +\newlabel{LastPage}{{}{17}{}{page.17}{}} +\pagesLTS@ifcounter{pagesLTS.arabic.1.local.cnt} +\setcounter{pagesLTS.arabic.1.local.cnt}{17} +\gdef\pagesLTS.lastpage{17} +\setcounter{pagesLTS.pagenr}{17} +\newlabel{VeryLastPage}{{}{17}{}{page.17}{}} +\newlabel{pagesLTS.arabic.1}{{}{17}{}{page.17}{}} +\newlabel{pagesLTS.arabic.1.local}{{}{17}{}{page.17}{}} +\newlabel{pagesLTS.arabic}{{}{17}{}{page.17}{}} +\newlabel{pagesLTS.arabic.local}{{}{17}{}{page.17}{}} +\newlabel{LastPages}{{}{17}{}{page.17}{}} diff --git a/Abgabe/DigBV_Aufgabe.log b/Abgabe/DigBV_Aufgabe.log new file mode 100644 index 0000000..bb8681f --- /dev/null +++ b/Abgabe/DigBV_Aufgabe.log @@ -0,0 +1,1031 @@ +This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/TeX Live for SUSE Linux) (preloaded format=pdflatex 2022.2.15) 15 JUN 2022 14:04 +entering extended mode + restricted \write18 enabled. + %&-line parsing enabled. +**DigBV_Aufgabe.tex +(./DigBV_Aufgabe.tex +LaTeX2e <2017-04-15> +Babel <3.10> and hyphenation patterns for 84 language(s) loaded. +(/usr/share/texmf/tex/latex/standalone/standalone.cls +Document Class: standalone 2015/07/15 v1.2 Class to compile TeX sub-files stand +alone +(/usr/share/texmf/tex/generic/oberdiek/ifluatex.sty +Package: ifluatex 2016/05/16 v1.4 Provides the ifluatex switch (HO) +Package ifluatex Info: LuaTeX not detected. +) +(/usr/share/texmf/tex/generic/oberdiek/ifpdf.sty +Package: ifpdf 2017/03/15 v3.2 Provides the ifpdf switch +) +(/usr/share/texmf/tex/generic/ifxetex/ifxetex.sty +Package: ifxetex 2010/09/12 v0.6 Provides ifxetex conditional +) +(/usr/share/texmf/tex/latex/xkeyval/xkeyval.sty +Package: xkeyval 2014/12/03 v2.7a package option processing (HA) + +(/usr/share/texmf/tex/generic/xkeyval/xkeyval.tex +(/usr/share/texmf/tex/generic/xkeyval/xkvutils.tex +\XKV@toks=\toks14 +\XKV@tempa@toks=\toks15 + +(/usr/share/texmf/tex/generic/xkeyval/keyval.tex)) +\XKV@depth=\count79 +File: xkeyval.tex 2014/12/03 v2.7a key=value parser (HA) +)) +\sa@internal=\count80 +\c@sapage=\count81 + +(/usr/share/texmf/tex/latex/standalone/standalone.cfg +File: standalone.cfg 2015/07/15 v1.2 Default configuration file for 'standalone +' class +) +(/usr/share/texmf/tex/latex/base/article.cls +Document Class: article 2014/09/29 v1.4h Standard LaTeX document class +(/usr/share/texmf/tex/latex/base/size10.clo +File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option) +) +\c@part=\count82 +\c@section=\count83 +\c@subsection=\count84 +\c@subsubsection=\count85 +\c@paragraph=\count86 +\c@subparagraph=\count87 +\c@figure=\count88 +\c@table=\count89 +\abovecaptionskip=\skip41 +\belowcaptionskip=\skip42 +\bibindent=\dimen102 +)) +(/usr/share/texmf/tex/latex/standalone/standalone.sty +Package: standalone 2015/07/15 v1.2 Package to include TeX sub-files with pream +bles + +(/usr/share/texmf/tex/latex/currfile/currfile.sty +Package: currfile 2015/04/23 v0.7c Provides the file path elements of the curre +nt input file + +(/usr/share/texmf/tex/latex/oberdiek/kvoptions.sty +Package: kvoptions 2016/05/16 v3.12 Key value format for package options (HO) + +(/usr/share/texmf/tex/generic/oberdiek/ltxcmds.sty +Package: ltxcmds 2016/05/16 v1.23 LaTeX kernel commands for general use (HO) +) +(/usr/share/texmf/tex/generic/oberdiek/kvsetkeys.sty +Package: kvsetkeys 2016/05/16 v1.17 Key value parser (HO) + +(/usr/share/texmf/tex/generic/oberdiek/infwarerr.sty +Package: infwarerr 2016/05/16 v1.4 Providing info/warning/error messages (HO) +) +(/usr/share/texmf/tex/generic/oberdiek/etexcmds.sty +Package: etexcmds 2016/05/16 v1.6 Avoid name clashes with e-TeX commands (HO) +Package etexcmds Info: Could not find \expanded. +(etexcmds) That can mean that you are not using pdfTeX 1.50 or +(etexcmds) that some package has redefined \expanded. +(etexcmds) In the latter case, load this package earlier. +))) +(/usr/share/texmf/tex/latex/filehook/filehook.sty +Package: filehook 2011/10/12 v0.5d Hooks for input files +) +\c@currfiledepth=\count90 +) +(/usr/share/texmf/tex/latex/gincltex/gincltex.sty +(/usr/share/texmf/tex/latex/svn-prov/svn-prov.sty +Package: svn-prov 2010/04/24 v3.1862 Package Date/Version from SVN Keywords +) +Package: gincltex 2011/09/04 v0.3 Include external LaTeX files like graphics + +(/usr/share/texmf/tex/latex/adjustbox/adjustbox.sty +Package: adjustbox 2012/05/21 v1.0 Adjusting TeX boxes (trim, clip, ...) + +(/usr/share/texmf/tex/latex/adjustbox/adjcalc.sty +Package: adjcalc 2012/05/16 v1.1 Provides advanced setlength with multiple back +-ends (calc, etex, pgfmath) +) +(/usr/share/texmf/tex/latex/adjustbox/trimclip.sty +Package: trimclip 2012/05/16 v1.0 Trim and clip general TeX material + +(/usr/share/texmf/tex/latex/graphics/graphicx.sty +Package: graphicx 2014/10/28 v1.0g Enhanced LaTeX Graphics (DPC,SPQR) + +(/usr/share/texmf/tex/latex/graphics/graphics.sty +Package: graphics 2017/04/14 v1.1b Standard LaTeX Graphics (DPC,SPQR) + +(/usr/share/texmf/tex/latex/graphics/trig.sty +Package: trig 2016/01/03 v1.10 sin cos tan (DPC) +) +(/usr/share/texmf/tex/latex/graphics-cfg/graphics.cfg +File: graphics.cfg 2016/06/04 v1.11 sample graphics configuration +) +Package graphics Info: Driver file: pdftex.def on input line 99. + +(/usr/share/texmf/tex/latex/graphics-def/pdftex.def +File: pdftex.def 2017/01/12 v0.06k Graphics/color for pdfTeX +\Gread@gobject=\count91 +)) +\Gin@req@height=\dimen103 +\Gin@req@width=\dimen104 +) +(/usr/share/texmf/tex/latex/collectbox/collectbox.sty +Package: collectbox 2012/05/17 v0.4b Collect macro arguments as boxes +\collectedbox=\box26 +) +\tc@llx=\dimen105 +\tc@lly=\dimen106 +\tc@urx=\dimen107 +\tc@ury=\dimen108 +Package trimclip Info: Using driver 'tc-pdftex.def'. + +(/usr/share/texmf/tex/latex/adjustbox/tc-pdftex.def +File: tc-pdftex.def 2012/05/13 v1.0 Clipping driver for pdftex +)) +\adjbox@Width=\dimen109 +\adjbox@Height=\dimen110 +\adjbox@Depth=\dimen111 +\adjbox@Totalheight=\dimen112 + +(/usr/share/texmf/tex/latex/ifoddpage/ifoddpage.sty +Package: ifoddpage 2016/04/23 v1.1 Conditionals for odd/even page detection +\c@checkoddpage=\count92 +) +(/usr/share/texmf/tex/latex/varwidth/varwidth.sty +Package: varwidth 2009/03/30 ver 0.92; Variable-width minipages +\@vwid@box=\box27 +\sift@deathcycles=\count93 +\@vwid@loff=\dimen113 +\@vwid@roff=\dimen114 +)) +\gincltex@box=\box28 +) +(/usr/share/texmf/tex/latex/filemod/filemod-expmin.sty +Package: filemod-expmin 2011/09/19 v1.2 Get and compare file modification times + (expandable; minimal) +)) (./labor.sty) +(/usr/share/texmf/tex/latex/pageslts/pageslts.sty +Package: pageslts 2015/12/21 v1.2f Refers to special pages' numbers/names (HMM) + + +(/usr/share/texmf/tex/latex/oberdiek/atveryend.sty +Package: atveryend 2016/05/16 v1.9 Hooks at the very end of document (HO) +) +(/usr/share/texmf/tex/latex/ms/everyshi.sty +Package: everyshi 2001/05/15 v3.00 EveryShipout Package (MS) +) +(/usr/share/texmf/tex/latex/oberdiek/letltxmacro.sty +Package: letltxmacro 2016/05/16 v1.5 Let assignment for LaTeX macros (HO) +) +(/usr/share/texmf/tex/latex/undolabl/undolabl.sty +Package: undolabl 2015/03/29 v1.0l Overriding labels (HMM) +) +(/usr/share/texmf/tex/latex/oberdiek/rerunfilecheck.sty +Package: rerunfilecheck 2016/05/16 v1.8 Rerun checks for auxiliary files (HO) + +(/usr/share/texmf/tex/generic/oberdiek/pdftexcmds.sty +Package: pdftexcmds 2017/03/19 v0.25 Utility functions of pdfTeX for LuaTeX (HO +) +Package pdftexcmds Info: LuaTeX not detected. +Package pdftexcmds Info: \pdf@primitive is available. +Package pdftexcmds Info: \pdf@ifprimitive is available. +Package pdftexcmds Info: \pdfdraftmode found. +) +(/usr/share/texmf/tex/generic/oberdiek/uniquecounter.sty +Package: uniquecounter 2016/05/16 v1.3 Provide unlimited unique counter (HO) + +(/usr/share/texmf/tex/generic/oberdiek/bigintcalc.sty +Package: bigintcalc 2016/05/16 v1.4 Expandable calculations on big integers (HO +) +)) +Package uniquecounter Info: New unique counter `rerunfilecheck' on input line 2 +82. +) +Package pageslts Info: Option pagecontinue enabled +(pageslts) (maybe by default): +(pageslts) The pageslts package will continue the page numbering, +(pageslts) when the same page numbering scheme is used twice. +(pageslts) If you do not want this, call pageslts with option +(pageslts) pagecontinue=false (or use \setcounter{page}=1). +(pageslts) on input line 179. + +(/usr/share/texmf/tex/generic/oberdiek/alphalph.sty +Package: alphalph 2016/05/16 v2.5 Convert numbers to letters (HO) + +(/usr/share/texmf/tex/generic/oberdiek/intcalc.sty +Package: intcalc 2016/05/16 v1.2 Expandable calculations with integers (HO) +)) +Package pageslts Info: Option romanMult enabled +(pageslts) (maybe by default): +(pageslts) The pageslts package will extend the page numbering +(pageslts) of the roman scheme below i with +(pageslts) 0, -i, -ii, -iii, -iv,... +(pageslts) If you do not want this, call pageslts with option +(pageslts) romanMult=false. +(pageslts) on input line 278. +Package pageslts Info: Option RomanMulti enabled +(pageslts) (maybe by default): +(pageslts) The pageslts package will extend the page numbering +(pageslts) of the Roman scheme below I with +(pageslts) 0, -I, -II, -III, -IV,... +(pageslts) If you do not want this, call pageslts with option +(pageslts) RomanMulti=false. +(pageslts) on input line 300. +Package pageslts Info: Option fnsymbolmult enabled +(pageslts) (maybe by default): +(pageslts) The pageslts package will extend the page numbering +(pageslts) of the footnotesymbol scheme using the alphalph +(pageslts) package. +(pageslts) If you do not want this, call pageslts with option +(pageslts) fnsymbolmult=false. +(pageslts) on input line 322. +\c@CurrentPage=\count94 +\c@pagesLTS.pagenr=\count95 +\c@pagesLTS.current.local.0=\count96 +\c@pagesLTS.pnc.0=\count97 +) +(/usr/share/texmf/tex/latex/hyperref/hyperref.sty +Package: hyperref 2017/03/14 v6.85a Hypertext links for LaTeX + +(/usr/share/texmf/tex/generic/oberdiek/hobsub-hyperref.sty +Package: hobsub-hyperref 2016/05/16 v1.14 Bundle oberdiek, subset hyperref (HO) + + +(/usr/share/texmf/tex/generic/oberdiek/hobsub-generic.sty +Package: hobsub-generic 2016/05/16 v1.14 Bundle oberdiek, subset generic (HO) +Package: hobsub 2016/05/16 v1.14 Construct package bundles (HO) +Package hobsub Info: Skipping package `infwarerr' (already loaded). +Package hobsub Info: Skipping package `ltxcmds' (already loaded). +Package hobsub Info: Skipping package `ifluatex' (already loaded). +Package: ifvtex 2016/05/16 v1.6 Detect VTeX and its facilities (HO) +Package ifvtex Info: VTeX not detected. +Package hobsub Info: Skipping package `intcalc' (already loaded). +Package hobsub Info: Skipping package `ifpdf' (already loaded). +Package hobsub Info: Skipping package `etexcmds' (already loaded). +Package hobsub Info: Skipping package `kvsetkeys' (already loaded). +Package: kvdefinekeys 2016/05/16 v1.4 Define keys (HO) +Package hobsub Info: Skipping package `pdftexcmds' (already loaded). +Package: pdfescape 2016/05/16 v1.14 Implements pdfTeX's escape features (HO) +Package hobsub Info: Skipping package `bigintcalc' (already loaded). +Package: bitset 2016/05/16 v1.2 Handle bit-vector datatype (HO) +Package hobsub Info: Skipping package `uniquecounter' (already loaded). +) +Package hobsub Info: Skipping package `hobsub' (already loaded). +Package hobsub Info: Skipping package `letltxmacro' (already loaded). +Package: hopatch 2016/05/16 v1.3 Wrapper for package hooks (HO) +Package: xcolor-patch 2016/05/16 xcolor patch +Package hobsub Info: Skipping package `atveryend' (already loaded). +Package: atbegshi 2016/06/09 v1.18 At begin shipout hook (HO) +Package: refcount 2016/05/16 v3.5 Data extraction from label references (HO) +Package: hycolor 2016/05/16 v1.8 Color options for hyperref/bookmark (HO) +) +(/usr/share/texmf/tex/latex/oberdiek/auxhook.sty +Package: auxhook 2016/05/16 v1.4 Hooks for auxiliary files (HO) +) +\@linkdim=\dimen115 +\Hy@linkcounter=\count98 +\Hy@pagecounter=\count99 + +(/usr/share/texmf/tex/latex/hyperref/pd1enc.def +File: pd1enc.def 2017/03/14 v6.85a Hyperref: PDFDocEncoding definition (HO) +) +\Hy@SavedSpaceFactor=\count100 + +(/usr/share/texmf/tex/latex/latexconfig/hyperref.cfg +File: hyperref.cfg 2002/06/06 v1.2 hyperref configuration of TeXLive +) +Package hyperref Info: Hyper figures OFF on input line 4498. +Package hyperref Info: Link nesting OFF on input line 4503. +Package hyperref Info: Hyper index ON on input line 4506. +Package hyperref Info: Plain pages OFF on input line 4513. +Package hyperref Info: Backreferencing OFF on input line 4518. +Package hyperref Info: Implicit mode ON; LaTeX internals redefined. +Package hyperref Info: Bookmarks ON on input line 4751. +\c@Hy@tempcnt=\count101 + +(/data/tex/texmf/tex/latex/html/url.sty +\Urlmuskip=\muskip10 +Package: url 2006/04/12 ver 3.3 Verb mode for urls, etc. +) +LaTeX Info: Redefining \url on input line 5104. +\XeTeXLinkMargin=\dimen116 +\Fld@menulength=\count102 +\Field@Width=\dimen117 +\Fld@charsize=\dimen118 +Package hyperref Info: Hyper figures OFF on input line 6358. +Package hyperref Info: Link nesting OFF on input line 6363. +Package hyperref Info: Hyper index ON on input line 6366. +Package hyperref Info: backreferencing OFF on input line 6373. +Package hyperref Info: Link coloring OFF on input line 6378. +Package hyperref Info: Link coloring with OCG OFF on input line 6383. +Package hyperref Info: PDF/A mode OFF on input line 6388. +LaTeX Info: Redefining \ref on input line 6428. +LaTeX Info: Redefining \pageref on input line 6432. +\Hy@abspage=\count103 +\c@Item=\count104 +\c@Hfootnote=\count105 +) + +Package hyperref Message: Driver (autodetected): hpdftex. + +(/usr/share/texmf/tex/latex/hyperref/hpdftex.def +File: hpdftex.def 2017/03/14 v6.85a Hyperref driver for pdfTeX +\Fld@listcount=\count106 +\c@bookmark@seq@number=\count107 +\Hy@SectionHShift=\skip43 +) +(/usr/share/texmf/tex/latex/booktabs/booktabs.sty +Package: booktabs 2016/04/27 v1.618033 publication quality tables +\heavyrulewidth=\dimen119 +\lightrulewidth=\dimen120 +\cmidrulewidth=\dimen121 +\belowrulesep=\dimen122 +\belowbottomsep=\dimen123 +\aboverulesep=\dimen124 +\abovetopsep=\dimen125 +\cmidrulesep=\dimen126 +\cmidrulekern=\dimen127 +\defaultaddspace=\dimen128 +\@cmidla=\count108 +\@cmidlb=\count109 +\@aboverulesep=\dimen129 +\@belowrulesep=\dimen130 +\@thisruleclass=\count110 +\@lastruleclass=\count111 +\@thisrulewidth=\dimen131 +) +(/usr/share/texmf/tex/latex/listings/listings.sty +\lst@mode=\count112 +\lst@gtempboxa=\box29 +\lst@token=\toks16 +\lst@length=\count113 +\lst@currlwidth=\dimen132 +\lst@column=\count114 +\lst@pos=\count115 +\lst@lostspace=\dimen133 +\lst@width=\dimen134 +\lst@newlines=\count116 +\lst@lineno=\count117 +\lst@maxwidth=\dimen135 + +(/usr/share/texmf/tex/latex/listings/lstmisc.sty +File: lstmisc.sty 2015/06/04 1.6 (Carsten Heinz) +\c@lstnumber=\count118 +\lst@skipnumbers=\count119 +\lst@framebox=\box30 +) +(/usr/share/texmf/tex/latex/listings/listings.cfg +File: listings.cfg 2015/06/04 1.6 listings configuration +)) +Package: listings 2015/06/04 1.6 (Carsten Heinz) + +(/usr/share/texmf/tex/latex/base/inputenc.sty +Package: inputenc 2015/03/17 v1.2c Input encoding file +\inpenc@prehook=\toks17 +\inpenc@posthook=\toks18 + +(/usr/share/texmf/tex/latex/base/latin1.def +File: latin1.def 2015/03/17 v1.2c Input encoding file +)) +(/usr/share/texmf/tex/latex/pgf/frontendlayer/tikz.sty +(/usr/share/texmf/tex/latex/pgf/basiclayer/pgf.sty +(/usr/share/texmf/tex/latex/pgf/utilities/pgfrcs.sty +(/data/tex/texmf/tex/generic/tex/generic/pgf/utilities/pgfutil-common.tex +\pgfutil@everybye=\toks19 +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/utilities/pgfutil-latex.def +\pgfutil@abb=\box31 +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/utilities/pgfrcs.code.tex +Package: pgfrcs 2010/11/07 v2.10-cvs (rcs-revision 1.25) +)) +Package: pgf 2015/08/07 v2.10-cvs (rcs-revision 1.15) + +(/usr/share/texmf/tex/latex/pgf/basiclayer/pgfcore.sty +(/usr/share/texmf/tex/latex/pgf/systemlayer/pgfsys.sty +(/data/tex/texmf/tex/generic/tex/generic/pgf/systemlayer/pgfsys.code.tex +Package: pgfsys 2012/03/30 v2.10-cvs (rcs-revision 1.38) + +(/data/tex/texmf/tex/generic/tex/generic/pgf/utilities/pgfkeys.code.tex +\pgfkeys@pathtoks=\toks20 +\pgfkeys@temptoks=\toks21 + +(/data/tex/texmf/tex/generic/tex/generic/pgf/utilities/pgfkeysfiltered.code.tex +\pgfkeys@tmptoks=\toks22 +)) +\pgf@x=\dimen136 +\pgf@y=\dimen137 +\pgf@xa=\dimen138 +\pgf@ya=\dimen139 +\pgf@xb=\dimen140 +\pgf@yb=\dimen141 +\pgf@xc=\dimen142 +\pgf@yc=\dimen143 +\w@pgf@writea=\write3 +\r@pgf@reada=\read1 +\c@pgf@counta=\count120 +\c@pgf@countb=\count121 +\c@pgf@countc=\count122 +\c@pgf@countd=\count123 + (/data/tex/texmf/tex/generic/tex/generic/pgf/systemlayer/pgf.cfg +File: pgf.cfg 2008/05/14 (rcs-revision 1.7) +) +Package pgfsys Info: Driver file for pgf: pgfsys-pdftex.def on input line 919. + +(/data/tex/texmf/tex/generic/tex/generic/pgf/systemlayer/pgfsys-pdftex.def +File: pgfsys-pdftex.def 2012/09/26 (rcs-revision 1.28) + +(/data/tex/texmf/tex/generic/tex/generic/pgf/systemlayer/pgfsys-common-pdf.def +File: pgfsys-common-pdf.def 2008/05/19 (rcs-revision 1.10) +))) +(/data/tex/texmf/tex/generic/tex/generic/pgf/systemlayer/pgfsyssoftpath.code.te +x +File: pgfsyssoftpath.code.tex 2008/07/18 (rcs-revision 1.7) +\pgfsyssoftpath@smallbuffer@items=\count124 +\pgfsyssoftpath@bigbuffer@items=\count125 +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/systemlayer/pgfsysprotocol.code.te +x +File: pgfsysprotocol.code.tex 2006/10/16 (rcs-revision 1.4) +)) (/usr/share/texmf/tex/latex/xcolor/xcolor.sty +Package: xcolor 2016/05/11 v2.12 LaTeX color extensions (UK) + +(/usr/share/texmf/tex/latex/graphics-cfg/color.cfg +File: color.cfg 2016/01/02 v1.6 sample color configuration +) +Package xcolor Info: Driver file: pdftex.def on input line 225. +Package xcolor Info: Model `cmy' substituted by `cmy0' on input line 1348. +Package xcolor Info: Model `hsb' substituted by `rgb' on input line 1352. +Package xcolor Info: Model `RGB' extended on input line 1364. +Package xcolor Info: Model `HTML' substituted by `rgb' on input line 1366. +Package xcolor Info: Model `Hsb' substituted by `hsb' on input line 1367. +Package xcolor Info: Model `tHsb' substituted by `hsb' on input line 1368. +Package xcolor Info: Model `HSB' substituted by `hsb' on input line 1369. +Package xcolor Info: Model `Gray' substituted by `gray' on input line 1370. +Package xcolor Info: Model `wave' substituted by `hsb' on input line 1371. +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcore.code.tex +Package: pgfcore 2010/04/11 v2.10-cvs (rcs-revision 1.7) + +(/data/tex/texmf/tex/generic/tex/generic/pgf/math/pgfmath.code.tex +(/data/tex/texmf/tex/generic/tex/generic/pgf/math/pgfmathcalc.code.tex +(/data/tex/texmf/tex/generic/tex/generic/pgf/math/pgfmathutil.code.tex) +(/data/tex/texmf/tex/generic/tex/generic/pgf/math/pgfmathparser.code.tex +\pgfmath@dimen=\dimen144 +\pgfmath@count=\count126 +\pgfmath@box=\box32 +\pgfmath@toks=\toks23 +\pgfmath@stack@operand=\toks24 +\pgfmath@stack@operation=\toks25 +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/math/pgfmathfunctions.code.tex +(/data/tex/texmf/tex/generic/tex/generic/pgf/math/pgfmathfunctions.basic.code.t +ex) +(/data/tex/texmf/tex/generic/tex/generic/pgf/math/pgfmathfunctions.trigonometri +c.code.tex) +(/data/tex/texmf/tex/generic/tex/generic/pgf/math/pgfmathfunctions.random.code. +tex) +(/data/tex/texmf/tex/generic/tex/generic/pgf/math/pgfmathfunctions.comparison.c +ode.tex) +(/data/tex/texmf/tex/generic/tex/generic/pgf/math/pgfmathfunctions.base.code.te +x) +(/data/tex/texmf/tex/generic/tex/generic/pgf/math/pgfmathfunctions.round.code.t +ex) +(/data/tex/texmf/tex/generic/tex/generic/pgf/math/pgfmathfunctions.misc.code.te +x) +(/data/tex/texmf/tex/generic/tex/generic/pgf/math/pgfmathfunctions.integerarith +metics.code.tex))) +(/data/tex/texmf/tex/generic/tex/generic/pgf/math/pgfmathfloat.code.tex +\c@pgfmathroundto@lastzeros=\count127 +)) +(/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcorepoints.code.tex +File: pgfcorepoints.code.tex 2012/01/06 (rcs-revision 1.21) +\pgf@picminx=\dimen145 +\pgf@picmaxx=\dimen146 +\pgf@picminy=\dimen147 +\pgf@picmaxy=\dimen148 +\pgf@pathminx=\dimen149 +\pgf@pathmaxx=\dimen150 +\pgf@pathminy=\dimen151 +\pgf@pathmaxy=\dimen152 +\pgf@xx=\dimen153 +\pgf@xy=\dimen154 +\pgf@yx=\dimen155 +\pgf@yy=\dimen156 +\pgf@zx=\dimen157 +\pgf@zy=\dimen158 +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcorepathconstruct.co +de.tex +File: pgfcorepathconstruct.code.tex 2011/04/17 (rcs-revision 1.25) +\pgf@path@lastx=\dimen159 +\pgf@path@lasty=\dimen160 +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcorepathusage.code.t +ex +File: pgfcorepathusage.code.tex 2008/04/22 (rcs-revision 1.12) +\pgf@shorten@end@additional=\dimen161 +\pgf@shorten@start@additional=\dimen162 +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcorescopes.code.tex +File: pgfcorescopes.code.tex 2011/10/01 (rcs-revision 1.37) +\pgfpic=\box33 +\pgf@hbox=\box34 +\pgf@layerbox@main=\box35 +\pgf@picture@serial@count=\count128 +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcoregraphicstate.cod +e.tex +File: pgfcoregraphicstate.code.tex 2008/04/22 (rcs-revision 1.9) +\pgflinewidth=\dimen163 +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcoretransformations. +code.tex +File: pgfcoretransformations.code.tex 2012/01/06 (rcs-revision 1.12) +\pgf@pt@x=\dimen164 +\pgf@pt@y=\dimen165 +\pgf@pt@temp=\dimen166 +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcorequick.code.tex +File: pgfcorequick.code.tex 2008/10/09 (rcs-revision 1.3) +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcoreobjects.code.tex +File: pgfcoreobjects.code.tex 2006/10/11 (rcs-revision 1.2) +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcorepathprocessing.c +ode.tex +File: pgfcorepathprocessing.code.tex 2008/10/09 (rcs-revision 1.8) +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcorearrows.code.tex +File: pgfcorearrows.code.tex 2011/06/07 (rcs-revision 1.12) +) (/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcoreshade.code.tex +File: pgfcoreshade.code.tex 2008/11/23 (rcs-revision 1.13) +\pgf@max=\dimen167 +\pgf@sys@shading@range@num=\count129 +) (/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcoreimage.code.tex +File: pgfcoreimage.code.tex 2010/03/25 (rcs-revision 1.16) + +(/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcoreexternal.code.te +x +File: pgfcoreexternal.code.tex 2012/06/18 (rcs-revision 1.19) +\pgfexternal@startupbox=\box36 +)) +(/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcorelayers.code.tex +File: pgfcorelayers.code.tex 2011/10/02 (rcs-revision 1.4) +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcoretransparency.cod +e.tex +File: pgfcoretransparency.code.tex 2008/01/17 (rcs-revision 1.2) +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/basiclayer/pgfcorepatterns.code.te +x +File: pgfcorepatterns.code.tex 2009/07/02 (rcs-revision 1.3) +))) +(/data/tex/texmf/tex/generic/tex/generic/pgf/modules/pgfmoduleshapes.code.tex +File: pgfmoduleshapes.code.tex 2012/08/29 (rcs-revision 1.22) +\pgfnodeparttextbox=\box37 +) +(/data/tex/texmf/tex/generic/tex/generic/pgf/modules/pgfmoduleplot.code.tex +File: pgfmoduleplot.code.tex 2011/10/22 (rcs-revision 1.10) +) +(/usr/share/texmf/tex/latex/pgf/compatibility/pgfcomp-version-0-65.sty +Package: pgfcomp-version-0-65 2007/07/03 v2.10-cvs (rcs-revision 1.7) +\pgf@nodesepstart=\dimen168 +\pgf@nodesepend=\dimen169 +) +(/usr/share/texmf/tex/latex/pgf/compatibility/pgfcomp-version-1-18.sty +Package: pgfcomp-version-1-18 2007/07/23 v2.10-cvs (rcs-revision 1.1) +)) +(/usr/share/texmf/tex/latex/pgf/utilities/pgffor.sty +(/usr/share/texmf/tex/latex/pgf/utilities/pgfkeys.sty +(/data/tex/texmf/tex/generic/tex/generic/pgf/utilities/pgfkeys.code.tex)) +(/usr/share/texmf/tex/latex/pgf/math/pgfmath.sty +(/data/tex/texmf/tex/generic/tex/generic/pgf/math/pgfmath.code.tex)) +(/data/tex/texmf/tex/generic/tex/generic/pgf/utilities/pgffor.code.tex +Package: pgffor 2012/08/27 v2.10-cvs (rcs-revision 1.22) + +(/data/tex/texmf/tex/generic/tex/generic/pgf/math/pgfmath.code.tex) +\pgffor@iter=\dimen170 +\pgffor@skip=\dimen171 +\pgffor@stack=\toks26 +\pgffor@toks=\toks27 +)) +(/data/tex/texmf/tex/generic/tex/generic/pgf/frontendlayer/tikz/tikz.code.tex +Package: tikz 2012/08/29 v2.10-cvs (rcs-revision 1.100) + +(/data/tex/texmf/tex/generic/tex/generic/pgf/libraries/pgflibraryplothandlers.c +ode.tex +File: pgflibraryplothandlers.code.tex 2012/09/11 v2.10-cvs (rcs-revision 1.17) +\pgf@plot@mark@count=\count130 +\pgfplotmarksize=\dimen172 +) +\tikz@lastx=\dimen173 +\tikz@lasty=\dimen174 +\tikz@lastxsaved=\dimen175 +\tikz@lastysaved=\dimen176 +\tikzleveldistance=\dimen177 +\tikzsiblingdistance=\dimen178 +\tikz@figbox=\box38 +\tikz@tempbox=\box39 +\tikztreelevel=\count131 +\tikznumberofchildren=\count132 +\tikznumberofcurrentchild=\count133 +\tikz@fig@count=\count134 + +(/data/tex/texmf/tex/generic/tex/generic/pgf/modules/pgfmodulematrix.code.tex +File: pgfmodulematrix.code.tex 2010/08/24 (rcs-revision 1.4) +\pgfmatrixcurrentrow=\count135 +\pgfmatrixcurrentcolumn=\count136 +\pgf@matrix@numberofcolumns=\count137 +) +\tikz@expandcount=\count138 + +(/data/tex/texmf/tex/generic/tex/generic/pgf/frontendlayer/tikz/libraries/tikzl +ibrarytopaths.code.tex +File: tikzlibrarytopaths.code.tex 2008/06/17 v2.10-cvs (rcs-revision 1.2) +))) +(/data/tex/texmf/tex/generic/tex/generic/pgf/frontendlayer/tikz/libraries/tikzl +ibraryshapes.code.tex +File: tikzlibraryshapes.code.tex 2008/01/09 v2.10-cvs (rcs-revision 1.1) + +(/data/tex/texmf/tex/generic/tex/generic/pgf/frontendlayer/tikz/libraries/tikzl +ibraryshapes.geometric.code.tex +File: tikzlibraryshapes.geometric.code.tex 2008/01/09 v2.10-cvs (rcs-revision 1 +.1) + +(/data/tex/texmf/tex/generic/tex/generic/pgf/libraries/shapes/pgflibraryshapes. +geometric.code.tex +File: pgflibraryshapes.geometric.code.tex 2008/06/26 v2.10-cvs (rcs-revision 1. +1) +)) +(/data/tex/texmf/tex/generic/tex/generic/pgf/frontendlayer/tikz/libraries/tikzl +ibraryshapes.misc.code.tex +File: tikzlibraryshapes.misc.code.tex 2008/01/09 v2.10-cvs (rcs-revision 1.1) + +(/data/tex/texmf/tex/generic/tex/generic/pgf/libraries/shapes/pgflibraryshapes. +misc.code.tex +File: pgflibraryshapes.misc.code.tex 2008/10/07 v2.10-cvs (rcs-revision 1.3) +)) +(/data/tex/texmf/tex/generic/tex/generic/pgf/frontendlayer/tikz/libraries/tikzl +ibraryshapes.symbols.code.tex +File: tikzlibraryshapes.symbols.code.tex 2008/01/09 v2.10-cvs (rcs-revision 1.1 +) + +(/data/tex/texmf/tex/generic/tex/generic/pgf/libraries/shapes/pgflibraryshapes. +symbols.code.tex +File: pgflibraryshapes.symbols.code.tex 2009/10/27 v2.10-cvs (rcs-revision 1.3) + +)) +(/data/tex/texmf/tex/generic/tex/generic/pgf/frontendlayer/tikz/libraries/tikzl +ibraryshapes.arrows.code.tex +File: tikzlibraryshapes.arrows.code.tex 2008/01/09 v2.10-cvs (rcs-revision 1.1) + + +(/data/tex/texmf/tex/generic/tex/generic/pgf/libraries/shapes/pgflibraryshapes. +arrows.code.tex +File: pgflibraryshapes.arrows.code.tex 2008/06/26 v2.10-cvs (rcs-revision 1.1) +)) +(/data/tex/texmf/tex/generic/tex/generic/pgf/frontendlayer/tikz/libraries/tikzl +ibraryshapes.callouts.code.tex +(/data/tex/texmf/tex/generic/tex/generic/pgf/libraries/shapes/pgflibraryshapes. +callouts.code.tex)) +(/data/tex/texmf/tex/generic/tex/generic/pgf/frontendlayer/tikz/libraries/tikzl +ibraryshapes.multipart.code.tex +File: tikzlibraryshapes.multipart.code.tex 2008/01/09 v2.10-cvs (rcs-revision 1 +.1) + +(/data/tex/texmf/tex/generic/tex/generic/pgf/libraries/shapes/pgflibraryshapes. +multipart.code.tex +File: pgflibraryshapes.multipart.code.tex 2010/01/07 v2.10-cvs (rcs-revision 1. +2) +\pgfnodepartlowerbox=\box40 +\pgfnodeparttwobox=\box41 +\pgfnodepartthreebox=\box42 +\pgfnodepartfourbox=\box43 +\pgfnodeparttwentybox=\box44 +\pgfnodepartnineteenbox=\box45 +\pgfnodeparteighteenbox=\box46 +\pgfnodepartseventeenbox=\box47 +\pgfnodepartsixteenbox=\box48 +\pgfnodepartfifteenbox=\box49 +\pgfnodepartfourteenbox=\box50 +\pgfnodepartthirteenbox=\box51 +\pgfnodeparttwelvebox=\box52 +\pgfnodepartelevenbox=\box53 +\pgfnodeparttenbox=\box54 +\pgfnodepartninebox=\box55 +\pgfnodeparteightbox=\box56 +\pgfnodepartsevenbox=\box57 +\pgfnodepartsixbox=\box58 +\pgfnodepartfivebox=\box59 +))) +(/data/tex/texmf/tex/generic/tex/generic/pgf/frontendlayer/tikz/libraries/tikzl +ibraryarrows.code.tex +File: tikzlibraryarrows.code.tex 2008/01/09 v2.10-cvs (rcs-revision 1.1) + +(/data/tex/texmf/tex/generic/tex/generic/pgf/libraries/pgflibraryarrows.code.te +x +File: pgflibraryarrows.code.tex 2008/10/27 v2.10-cvs (rcs-revision 1.9) +\arrowsize=\dimen179 +)) (/usr/share/texmf/tex/generic/babel/babel.sty +Package: babel 2017/05/19 3.10 The Babel package + +(/usr/share/texmf/tex/generic/babel-german/ngerman.ldf +Language: ngerman 2016/11/02 v2.9 German support for babel (new orthography) + +(/usr/share/texmf/tex/generic/babel-german/ngermanb.ldf +Language: ngermanb 2016/11/02 v2.9 German support for babel (new orthography) + +(/usr/share/texmf/tex/generic/babel/babel.def +File: babel.def 2017/05/19 3.10 Babel common definitions +\babel@savecnt=\count139 +\U@D=\dimen180 +) +Package babel Info: Making " an active character on input line 125. +))) +(/usr/share/texmf/tex/latex/listings/lstlang1.sty +File: lstlang1.sty 2015/06/04 1.6 listings language file +) (./DigBV_Aufgabe.aux +(./sections/overview.aux) (./sections/a.aux) (./sections/a1.aux + +LaTeX Warning: Label `lst:code1' multiply defined. + + +LaTeX Warning: Label `lst:code1' multiply defined. + +) (./sections/a2.aux + +LaTeX Warning: Label `lst:code1' multiply defined. + +) (./sections/a3.aux + +LaTeX Warning: Label `lst:code1' multiply defined. + + +LaTeX Warning: Label `lst:contours' multiply defined. + + +LaTeX Warning: Label `lst:contours' multiply defined. + +) (./sections/conclusion.aux) +\c@pagesLTS.arabic.1.local.cnt=\count140 +) +\openout1 = `DigBV_Aufgabe.aux'. + +LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 31. +LaTeX Font Info: ... okay on input line 31. +LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 31. +LaTeX Font Info: ... okay on input line 31. +LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 31. +LaTeX Font Info: ... okay on input line 31. +LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 31. +LaTeX Font Info: ... okay on input line 31. +LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 31. +LaTeX Font Info: ... okay on input line 31. +LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 31. +LaTeX Font Info: ... okay on input line 31. +LaTeX Font Info: Checking defaults for PD1/pdf/m/n on input line 31. +LaTeX Font Info: ... okay on input line 31. +LaTeX Font Info: Try loading font information for OT1+ptm on input line 31. + (/usr/share/texmf/tex/latex/psnfss/ot1ptm.fd +File: ot1ptm.fd 2001/06/04 font definitions for OT1/ptm. +) +(/usr/share/texmf/tex/context/base/mkii/supp-pdf.mkii +[Loading MPS to PDF converter (version 2006.09.02).] +\scratchcounter=\count141 +\scratchdimen=\dimen181 +\scratchbox=\box60 +\nofMPsegments=\count142 +\nofMParguments=\count143 +\everyMPshowfont=\toks28 +\MPscratchCnt=\count144 +\MPscratchDim=\dimen182 +\MPnumerator=\count145 +\makeMPintoPDFobject=\count146 +\everyMPtoPDFconversion=\toks29 +) (/usr/share/texmf/tex/latex/oberdiek/epstopdf-base.sty +Package: epstopdf-base 2016/05/15 v2.6 Base part for package epstopdf + +(/usr/share/texmf/tex/latex/oberdiek/grfext.sty +Package: grfext 2016/05/16 v1.2 Manage graphics extensions (HO) +) +Package epstopdf-base Info: Redefining graphics rule for `.eps' on input line 4 +38. +Package grfext Info: Graphics extension search list: +(grfext) [.png,.pdf,.jpg,.mps,.jpeg,.jbig2,.jb2,.PNG,.PDF,.JPG,.JPE +G,.JBIG2,.JB2,.eps] +(grfext) \AppendGraphicsExtensions on input line 456. + +(/usr/share/texmf/tex/latex/latexconfig/epstopdf-sys.cfg +File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv +e +)) +ABD: EveryShipout initializing macros +\AtBeginShipoutBox=\box61 +Package hyperref Info: Link coloring OFF on input line 31. + +(/usr/share/texmf/tex/latex/hyperref/nameref.sty +Package: nameref 2016/05/21 v2.44 Cross-referencing by name of section + +(/usr/share/texmf/tex/generic/oberdiek/gettitlestring.sty +Package: gettitlestring 2016/05/16 v1.5 Cleanup title references (HO) +) +\c@section@level=\count147 +) +LaTeX Info: Redefining \ref on input line 31. +LaTeX Info: Redefining \pageref on input line 31. +LaTeX Info: Redefining \nameref on input line 31. + +(./DigBV_Aufgabe.out) (./DigBV_Aufgabe.out) +\@outlinefile=\write4 +\openout4 = `DigBV_Aufgabe.out'. + +\c@lstlisting=\count148 +\c@pagesLTS.pnc.arabic=\count149 +\c@pagesLTS.double.arabic=\count150 +\c@pagesLTS.current.local.arabic=\count151 +LaTeX Font Info: Try loading font information for OT1+phv on input line 38. + +(/usr/share/texmf/tex/latex/psnfss/ot1phv.fd +File: ot1phv.fd 2001/06/04 scalable font definitions for OT1/phv. +) +LaTeX Font Info: External font `cmex10' loaded for size +(Font) <7> on input line 39. +LaTeX Font Info: External font `cmex10' loaded for size +(Font) <5> on input line 39. +LaTeX Font Info: Font shape `OT1/ptm/bx/n' in size <14.4> not available +(Font) Font shape `OT1/ptm/b/n' tried instead on input line 48. +LaTeX Font Info: Font shape `OT1/ptm/bx/n' in size <10> not available +(Font) Font shape `OT1/ptm/b/n' tried instead on input line 66. + +Overfull \hbox (28.45276pt too wide) in paragraph at lines 67--67 +[]$[]$ + [] + + +Overfull \hbox (28.45276pt too wide) in paragraph at lines 68--68 +[]$[]$ + [] + + +Overfull \hbox (28.45276pt too wide) in paragraph at lines 69--69 +[]$[]$ + [] + +(./DigBV_Aufgabe.toc [1 + +{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}]) +\tf@toc=\write5 +\openout5 = `DigBV_Aufgabe.toc'. + + +[2] +\openout2 = `sections/overview.aux'. + + (./sections/overview.tex +File: fig/harry1.jpg Graphic file (type jpg) + + +Package pdftex.def Info: fig/harry1.jpg used on input line 9. +(pdftex.def) Requested size: 93.15031pt x 103.86438pt. + +File: fig/harry2.jpg Graphic file (type jpg) + + +Package pdftex.def Info: fig/harry2.jpg used on input line 16. +(pdftex.def) Requested size: 93.15031pt x 102.24596pt. +LaTeX Font Info: External font `cmex10' loaded for size +(Font) <8> on input line 23. +LaTeX Font Info: External font `cmex10' loaded for size +(Font) <6> on input line 23. +LaTeX Font Info: Try loading font information for OT1+pcr on input line 23. + (/usr/share/texmf/tex/latex/psnfss/ot1pcr.fd +File: ot1pcr.fd 2001/06/04 font definitions for OT1/pcr. +) +Overfull \hbox (149.40033pt too wide) in paragraph at lines 23--23 +[][][][]$\OT1/pcr/m/n/8 https : / / assets . cdn . moviepilot . de / files / 8a +2cc0d2eb31c41136fb2be242540606dcd50821980e830481404b276065 / + [] + + +Underfull \hbox (badness 10000) in paragraph at lines 24--24 +[][][][]$\OT1/pcr/m/n/8 https : / / www . tres-[]click . com / wp-[]content / u +ploads / 2019 / 06 / + [] + +LaTeX Font Info: Try loading font information for OMS+ptm on input line 28. +(/usr/share/texmf/tex/latex/psnfss/omsptm.fd +File: omsptm.fd +) +LaTeX Font Info: Font shape `OMS/ptm/m/n' in size <10> not available +(Font) Font shape `OMS/cmsy/m/n' tried instead on input line 28. + [3 + + <./fig/harry1.jpg> <./fig/harry2.jpg>] +LaTeX Font Info: Font shape `OT1/ptm/bx/n' in size <12> not available +(Font) Font shape `OT1/ptm/b/n' tried instead on input line 38. + +File: fig/pycharm.png Graphic file (type png) + + +Package pdftex.def Info: fig/pycharm.png used on input line 49. +(pdftex.def) Requested size: 345.0pt x 191.2606pt. + [4 <./fig/pycharm.png (PNG copy)>] + +File: fig/Run-Configs.png Graphic file (type png) + + +Package pdftex.def Info: fig/Run-Configs.png used on input line 79. +(pdftex.def) Requested size: 224.2479pt x 241.29944pt. + [5 <./fig/Run-Configs.png>] +Underfull \hbox (badness 1675) in paragraph at lines 87--88 + []\OT1/ptm/b/n/10 Eigene Al-go-rith-men ein-bin-den. \OT1/ptm/m/n/10 F[]ur Sie + sind nur die Da-tei-en im Da-teipfad + [] + +Package hyperref Info: bookmark level for unknown lstlisting defaults to 0 on i +nput line 94. +LaTeX Font Info: Font shape `OT1/pcr/bx/n' in size <8> not available +(Font) Font shape `OT1/pcr/b/n' tried instead on input line 95. +[6]) [7] +\openout2 = `sections/a.aux'. + + (./sections/a.tex [8 + + +]) [9] +\openout2 = `sections/a1.aux'. + + (./sections/a1.tex +LaTeX Font Info: Font shape `OT1/pcr/m/it' in size <8> not available +(Font) Font shape `OT1/pcr/m/sl' tried instead on input line 33. + [10 + + +]) [11] +\openout2 = `sections/a2.aux'. + + +(./sections/a2.tex [12 + + +]) [13] +\openout2 = `sections/a3.aux'. + + (./sections/a3.tex [14 + + +] [15]) [16] +\openout2 = `sections/conclusion.aux'. + + +(./sections/conclusion.tex) [17 + + +] +AED: pageslts setting LastPage +Package atveryend Info: Empty hook `BeforeClearDocument' on input line 86. +Package atveryend Info: Executing hook `AfterLastShipout' on input line 86. +\c@pagesLTS.arabic.1.local.count=\count152 + +AED: pageslts setting VeryLastPage via AfterLastShipout + +AED: pageslts setting LastPages via AfterLastShipout + + +Package pageslts Info: Total number of pages is odd. + + +(./DigBV_Aufgabe.aux (./sections/overview.aux) (./sections/a.aux) +(./sections/a1.aux) (./sections/a2.aux) (./sections/a3.aux) +(./sections/conclusion.aux)) +Package atveryend Info: Executing hook `AtVeryEndDocument' on input line 86. +Package atveryend Info: Executing hook `AtEndAfterFileList' on input line 86. +Package rerunfilecheck Info: File `DigBV_Aufgabe.out' has not changed. +(rerunfilecheck) Checksum: A6ADFE0CE58667BB4633B2797149341F;995. + + +LaTeX Warning: There were multiply-defined labels. + + ) +Here is how much of TeX's memory you used: + 20007 strings out of 492995 + 370654 string characters out of 6141053 + 515114 words of memory out of 5000000 + 22934 multiletter control sequences out of 15000+600000 + 26139 words of font info for 51 fonts, out of 8000000 for 9000 + 1141 hyphenation exceptions out of 8191 + 67i,10n,72p,883b,1246s stack positions out of 5000i,500n,10000p,200000b,80000s +{/usr/share/texmf/fonts/enc/dvips/base/8r.enc} +Output written on DigBV_Aufgabe.pdf (17 pages, 901146 bytes). +PDF statistics: + 377 PDF objects out of 1000 (max. 8388607) + 335 compressed objects within 4 object streams + 134 named destinations out of 1000 (max. 500000) + 153 words of extra memory for PDF output out of 10000 (max. 10000000) + diff --git a/Abgabe/DigBV_Aufgabe.out b/Abgabe/DigBV_Aufgabe.out new file mode 100644 index 0000000..d2e50b3 --- /dev/null +++ b/Abgabe/DigBV_Aufgabe.out @@ -0,0 +1,15 @@ +\BOOKMARK [1][-]{section.1}{Einleitung}{}% 1 +\BOOKMARK [2][-]{subsection.1.1}{Vorbereitung}{section.1}% 2 +\BOOKMARK [2][-]{subsection.1.2}{Programmierumgebung}{section.1}% 3 +\BOOKMARK [1][-]{section.2}{Aufgabe}{}% 4 +\BOOKMARK [2][-]{subsection.2.1}{Vorverarbeitung}{section.2}% 5 +\BOOKMARK [3][-]{subsubsection.2.1.1}{Rauschreduktion}{subsection.2.1}% 6 +\BOOKMARK [3][-]{subsubsection.2.1.2}{Histogramm Spreizung}{subsection.2.1}% 7 +\BOOKMARK [2][-]{subsection.2.2}{Farbanalyse}{section.2}% 8 +\BOOKMARK [3][-]{subsubsection.2.2.1}{RGB}{subsection.2.2}% 9 +\BOOKMARK [3][-]{subsubsection.2.2.2}{HSV}{subsection.2.2}% 10 +\BOOKMARK [2][-]{subsection.2.3}{Segmentierung und Bildmodifizierung}{section.2}% 11 +\BOOKMARK [3][-]{subsubsection.2.3.1}{Statisches Schwellwertverfahren}{subsection.2.3}% 12 +\BOOKMARK [3][-]{subsubsection.2.3.2}{Bin\344rmaske}{subsection.2.3}% 13 +\BOOKMARK [3][-]{subsubsection.2.3.3}{Bildmodifizierung}{subsection.2.3}% 14 +\BOOKMARK [1][-]{section.3}{Zusammenfassung}{}% 15 diff --git a/Abgabe/DigBV_Aufgabe.pdf b/Abgabe/DigBV_Aufgabe.pdf new file mode 100644 index 0000000..2f74e27 Binary files /dev/null and b/Abgabe/DigBV_Aufgabe.pdf differ diff --git a/Abgabe/DigBV_Aufgabe.synctex.gz b/Abgabe/DigBV_Aufgabe.synctex.gz new file mode 100644 index 0000000..b21e0a0 Binary files /dev/null and b/Abgabe/DigBV_Aufgabe.synctex.gz differ diff --git a/Abgabe/DigBV_Aufgabe.tex b/Abgabe/DigBV_Aufgabe.tex new file mode 100644 index 0000000..cfaa73a --- /dev/null +++ b/Abgabe/DigBV_Aufgabe.tex @@ -0,0 +1,87 @@ +\documentclass[class=article, crop=false]{standalone} +\usepackage{standalone} +\usepackage{labor} +\usepackage{pageslts} +\usepackage{hyperref} +\usepackage{booktabs} +\usepackage{listings} +\usepackage[latin1]{inputenc} +\usepackage{tikz} +\usetikzlibrary{shapes,arrows} + +% Verwendung von Umlauten +\usepackage[ngerman]{babel} +% Auf Windows folgendes Paket verwenden +%\usepackage[ansinew]{inputenc} +% Auf Mac folgendes Paket verwenden +%\usepackage[applemac]{inputenc} + +\lstset{ + language=python, + basicstyle=\footnotesize\ttfamily, + %basicstyle=\ttfamily + numbers=left, + stepnumber=1, + tabsize=4, + frame=lines, +} + +\renewcommand{\lstlistingname}{Code}% Listing -> Algorithm + +\begin{document} + + \pagenumbering{arabic} + \newpage + \thispagestyle{empty} + + \begin{center} + \normalfont \sffamily + \begin{tabular*}{\textwidth}{@{\extracolsep{\fill}}lr@{}} + {INSTITUT F\"{U}R } & {\small Appelstra\ss e 9A} \\ + {INFORMATIONSVERARBEITUNG} & {\small 30167 Hannover} \\ + {\small LEIBNIZ UNIVERSIT\"{A}T HANNOVER} & + \end{tabular*} + \end{center} + + \vspace{1.5cm} + \begin{center} + {\Large Labor zur Vorlesung\\[.2cm] {\normalfont\bfseries Digitale Bildverarbeitung}} + \end{center} + + + %\addcontentsline{toc}{}{Titelblatt} + + \vspace{2cm} + + \begin{tabular}{@{}p{4cm}l} + Datum: & XX.XX.XXXX \\ + Uhrzeit: & XX:XX \\ + Anzahl der Bl\"{a}tter: & \lastpageref*{LastPages} (einschlie\ss{}lich Deckblatt) + + \end{tabular} + + \vspace{3cm} + + \begin{tabular}{@{}p{4cm} l } + {\normalfont\bfseries Name:} & {\normalfont\bfseries Matrikelnummer:}\\ + $\underline{\hspace{5cm}}$ \hspace{0.5cm}& $\underline{\hspace{5cm}}$ \\ + $\underline{\hspace{5cm}}$ \hspace{0.5cm}& $\underline{\hspace{5cm}}$\\ + $\underline{\hspace{5cm}}$ \hspace{0.5cm}& $\underline{\hspace{5cm}}$\\ + \end{tabular} + + \vspace{2.0cm} + + Die Bearbeitung der Aufgaben erfolgt selbststndig in Kleingruppen. Alle Gruppenmitglieder sollen Arbeitsaufwand in gleicher Grenordnung einbringen. Betrugsversuche werden geahndet. + + +\tableofcontents + +\include{sections/overview} +\include{sections/a} +\include{sections/a1} +\include{sections/a2} +\include{sections/a3} +\include{sections/conclusion} + +\end{document} + diff --git a/Abgabe/DigBV_Aufgabe.toc b/Abgabe/DigBV_Aufgabe.toc new file mode 100644 index 0000000..d2d8fe1 --- /dev/null +++ b/Abgabe/DigBV_Aufgabe.toc @@ -0,0 +1,16 @@ +\select@language {ngerman} +\contentsline {section}{\numberline {1}Einleitung}{3}{section.1} +\contentsline {subsection}{\numberline {1.1}Vorbereitung}{4}{subsection.1.1} +\contentsline {subsection}{\numberline {1.2}Programmierumgebung}{5}{subsection.1.2} +\contentsline {section}{\numberline {2}Aufgabe}{8}{section.2} +\contentsline {subsection}{\numberline {2.1}Vorverarbeitung}{10}{subsection.2.1} +\contentsline {subsubsection}{\numberline {2.1.1}Rauschreduktion}{10}{subsubsection.2.1.1} +\contentsline {subsubsection}{\numberline {2.1.2}Histogramm Spreizung}{11}{subsubsection.2.1.2} +\contentsline {subsection}{\numberline {2.2}Farbanalyse}{12}{subsection.2.2} +\contentsline {subsubsection}{\numberline {2.2.1}RGB}{12}{subsubsection.2.2.1} +\contentsline {subsubsection}{\numberline {2.2.2}HSV}{13}{subsubsection.2.2.2} +\contentsline {subsection}{\numberline {2.3}Segmentierung und Bildmodifizierung}{14}{subsection.2.3} +\contentsline {subsubsection}{\numberline {2.3.1}Statisches Schwellwertverfahren}{14}{subsubsection.2.3.1} +\contentsline {subsubsection}{\numberline {2.3.2}Bin\"armaske}{15}{subsubsection.2.3.2} +\contentsline {subsubsection}{\numberline {2.3.3}Bildmodifizierung}{15}{subsubsection.2.3.3} +\contentsline {section}{\numberline {3}Zusammenfassung}{17}{section.3} diff --git a/Abgabe/Versionen/V1_20210407_DigBV_Aufgabe.pdf b/Abgabe/Versionen/V1_20210407_DigBV_Aufgabe.pdf new file mode 100644 index 0000000..8cd73e7 Binary files /dev/null and b/Abgabe/Versionen/V1_20210407_DigBV_Aufgabe.pdf differ diff --git a/Abgabe/Versionen/V2_20210423_DigBV_Aufgabe - Kopie.pdf b/Abgabe/Versionen/V2_20210423_DigBV_Aufgabe - Kopie.pdf new file mode 100644 index 0000000..8bb2822 Binary files /dev/null and b/Abgabe/Versionen/V2_20210423_DigBV_Aufgabe - Kopie.pdf differ diff --git a/Abgabe/Versionen/V2_20210423_DigBV_Aufgabe.pdf b/Abgabe/Versionen/V2_20210423_DigBV_Aufgabe.pdf new file mode 100644 index 0000000..8bb2822 Binary files /dev/null and b/Abgabe/Versionen/V2_20210423_DigBV_Aufgabe.pdf differ diff --git a/Abgabe/Versionen/V3_20210517_DigBV_Aufgabe - Kopie.pdf b/Abgabe/Versionen/V3_20210517_DigBV_Aufgabe - Kopie.pdf new file mode 100644 index 0000000..1b0d077 Binary files /dev/null and b/Abgabe/Versionen/V3_20210517_DigBV_Aufgabe - Kopie.pdf differ diff --git a/Abgabe/Versionen/V3_20210517_DigBV_Aufgabe.pdf b/Abgabe/Versionen/V3_20210517_DigBV_Aufgabe.pdf new file mode 100644 index 0000000..1b0d077 Binary files /dev/null and b/Abgabe/Versionen/V3_20210517_DigBV_Aufgabe.pdf differ diff --git a/Abgabe/Versionen/V4_20210608_DigBV_Aufgabe.pdf b/Abgabe/Versionen/V4_20210608_DigBV_Aufgabe.pdf new file mode 100644 index 0000000..1d5c9c3 Binary files /dev/null and b/Abgabe/Versionen/V4_20210608_DigBV_Aufgabe.pdf differ diff --git a/Abgabe/fig/Run-Configs.png b/Abgabe/fig/Run-Configs.png new file mode 100644 index 0000000..3803b81 Binary files /dev/null and b/Abgabe/fig/Run-Configs.png differ diff --git a/Abgabe/fig/harry1.jpg b/Abgabe/fig/harry1.jpg new file mode 100644 index 0000000..cbe3e72 Binary files /dev/null and b/Abgabe/fig/harry1.jpg differ diff --git a/Abgabe/fig/harry2.gif b/Abgabe/fig/harry2.gif new file mode 100644 index 0000000..42f80ec Binary files /dev/null and b/Abgabe/fig/harry2.gif differ diff --git a/Abgabe/fig/harry2.jpg b/Abgabe/fig/harry2.jpg new file mode 100644 index 0000000..819db2a Binary files /dev/null and b/Abgabe/fig/harry2.jpg differ diff --git a/Abgabe/fig/pycharm.png b/Abgabe/fig/pycharm.png new file mode 100644 index 0000000..4f2225c Binary files /dev/null and b/Abgabe/fig/pycharm.png differ diff --git a/Abgabe/labor.sty b/Abgabe/labor.sty new file mode 100644 index 0000000..d10a65f --- /dev/null +++ b/Abgabe/labor.sty @@ -0,0 +1,20 @@ +\renewcommand{\sfdefault}{phv} +\renewcommand{\rmdefault}{ptm} +\renewcommand{\ttdefault}{pcr} +% +% Abstand zwischen den Absaetzen auf 1.5 Zeilen setzen +% +\setlength{\parskip}{1.5ex} +% +% Einzug am Absatzanfang auf 0 setzen. +% +\setlength{\parindent}{0em} + +% Umbruch +\tolerance=2000 +\emergencystretch=20pt +\renewcommand{\floatpagefraction}{1.0} +\renewcommand{\topfraction}{1.0} +\renewcommand{\bottomfraction}{1.0} +\addtocounter{secnumdepth}{1} +\addtocounter{tocdepth}{1} diff --git a/Abgabe/sections/a.aux b/Abgabe/sections/a.aux new file mode 100644 index 0000000..c9a6fb1 --- /dev/null +++ b/Abgabe/sections/a.aux @@ -0,0 +1,39 @@ +\relax +\providecommand\hyper@newdestlabel[2]{} +\@writefile{toc}{\contentsline {section}{\numberline {2}Aufgabe}{8}{section.2}} +\@writefile{lof}{\contentsline {figure}{\numberline {5}{\ignorespaces Bildverarbeitungs-Pipeline}}{8}{figure.5}} +\newlabel{fig:skizzepipeline}{{5}{8}{Bildverarbeitungs-Pipeline}{figure.5}{}} +\@setckpt{sections/a}{ +\setcounter{page}{10} +\setcounter{equation}{0} +\setcounter{enumi}{0} +\setcounter{enumii}{0} +\setcounter{enumiii}{0} +\setcounter{enumiv}{0} +\setcounter{footnote}{2} +\setcounter{mpfootnote}{0} +\setcounter{sapage}{0} +\setcounter{part}{0} +\setcounter{section}{2} +\setcounter{subsection}{0} +\setcounter{subsubsection}{0} +\setcounter{paragraph}{0} +\setcounter{subparagraph}{0} +\setcounter{figure}{5} +\setcounter{table}{1} +\setcounter{currfiledepth}{0} +\setcounter{CurrentPage}{10} +\setcounter{pagesLTS.pagenr}{17} +\setcounter{pagesLTS.current.local.0}{1} +\setcounter{pagesLTS.pnc.0}{0} +\setcounter{Item}{0} +\setcounter{Hfootnote}{2} +\setcounter{bookmark@seq@number}{4} +\setcounter{lstnumber}{10} +\setcounter{pagesLTS.arabic.1.local.cnt}{17} +\setcounter{section@level}{1} +\setcounter{lstlisting}{2} +\setcounter{pagesLTS.pnc.arabic}{1} +\setcounter{pagesLTS.double.arabic}{1} +\setcounter{pagesLTS.current.local.arabic}{10} +} diff --git a/Abgabe/sections/a.log b/Abgabe/sections/a.log new file mode 100644 index 0000000..0abed2c --- /dev/null +++ b/Abgabe/sections/a.log @@ -0,0 +1,648 @@ +This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/TeX Live for SUSE Linux) (preloaded format=pdflatex 2020.8.24) 6 APR 2021 11:25 +entering extended mode + restricted \write18 enabled. + %&-line parsing enabled. +**a.tex +(./a.tex +LaTeX2e <2017-04-15> +Babel <3.10> and hyphenation patterns for 84 language(s) loaded. +! Undefined control sequence. +l.2 \section + {Aufgabe} +The control sequence at the end of the top line +of your error message was never \def'ed. If you have +misspelled it (e.g., `\hobx'), type `I' and the correct +spelling (e.g., `I\hbox'). Otherwise just continue, +and I'll forget about whatever was undefined. + + +! LaTeX Error: Missing \begin{document}. + +See the LaTeX manual or LaTeX Companion for explanation. +Type H for immediate help. + ... + +l.2 \section{A + ufgabe} +You're in trouble here. Try typing to proceed. +If that doesn't work, type X to quit. + +Missing character: There is no A in font nullfont! +Missing character: There is no u in font nullfont! +Missing character: There is no f in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no D in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no Z in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no l in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no D in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no k in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no o in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no s in font nullfont! +! Undefined control sequence. +l.3 Das Ziel ist die Detektion des \glqq + magischen Umhangs\grqq\ sowie das k... +The control sequence at the end of the top line +of your error message was never \def'ed. If you have +misspelled it (e.g., `\hobx'), type `I' and the correct +spelling (e.g., `I\hbox'). Otherwise just continue, +and I'll forget about whatever was undefined. + +Missing character: There is no m in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no c in font nullfont! +Missing character: There is no h in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no U in font nullfont! +Missing character: There is no m in font nullfont! +Missing character: There is no h in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no s in font nullfont! +! Undefined control sequence. +l.3 ... Detektion des \glqq magischen Umhangs\grqq + \ sowie das künstliche En... +The control sequence at the end of the top line +of your error message was never \def'ed. If you have +misspelled it (e.g., `\hobx'), type `I' and the correct +spelling (e.g., `I\hbox'). Otherwise just continue, +and I'll forget about whatever was undefined. + +Missing character: There is no s in font nullfont! +Missing character: There is no o in font nullfont! +Missing character: There is no w in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no k in font nullfont! +Missing character: There is no in font nullfont! +Missing character: There is no in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no l in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no c in font nullfont! +Missing character: There is no h in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no E in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no f in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no O in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no j in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no k in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no m in font nullfont! +Missing character: There is no V in font nullfont! +Missing character: There is no o in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no u in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no . in font nullfont! +Missing character: There is no D in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no f in font nullfont! +Missing character: There is no in font nullfont! +Missing character: There is no in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no w in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no m in font nullfont! +Missing character: There is no L in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no o in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no A in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no p in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no k in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no : in font nullfont! +Missing character: There is no D in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no V in font nullfont! +Missing character: There is no o in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no v in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no u in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no , in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no F in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no l in font nullfont! +Missing character: There is no y in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no S in font nullfont! +Missing character: There is no z in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no u in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no S in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no m in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no u in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no U in font nullfont! +Missing character: There is no m in font nullfont! +Missing character: There is no h in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no . in font nullfont! +Missing character: There is no E in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no S in font nullfont! +Missing character: There is no k in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no z in font nullfont! +Missing character: There is no z in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no B in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no l in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no v in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no u in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no - in font nullfont! +Missing character: There is no P in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no p in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no l in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no A in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no l in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no u in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no g in font nullfont! +! Undefined control sequence. + ... `fig:skizzepipeline' on page \thepage + \space undefined\on@line . +l.3 ...e ist in Abbildung \ref{fig:skizzepipeline} + dargestellt. +The control sequence at the end of the top line +of your error message was never \def'ed. If you have +misspelled it (e.g., `\hobx'), type `I' and the correct +spelling (e.g., `I\hbox'). Otherwise just continue, +and I'll forget about whatever was undefined. + + +LaTeX Warning: Reference `fig:skizzepipeline' on page undefined on input line +3. + +Missing character: There is no d in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no l in font nullfont! +Missing character: There is no l in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no . in font nullfont! + +Overfull \hbox (20.0pt too wide) in paragraph at lines 2--4 +[] + [] + + +Overfull \hbox (10.86105pt too wide) in paragraph at lines 2--4 +[] + [] + + +! LaTeX Error: Missing \begin{document}. + +See the LaTeX manual or LaTeX Companion for explanation. +Type H for immediate help. + ... + +l.8 I + m folgenden finden Sie detaillierte Beschreibungen der Arbeitspakete. B... + +You're in trouble here. Try typing to proceed. +If that doesn't work, type X to quit. + +Missing character: There is no I in font nullfont! +Missing character: There is no m in font nullfont! +Missing character: There is no f in font nullfont! +Missing character: There is no o in font nullfont! +Missing character: There is no l in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no f in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no S in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no l in font nullfont! +Missing character: There is no l in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no B in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no c in font nullfont! +Missing character: There is no h in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no u in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no A in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no p in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no k in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no . in font nullfont! +Missing character: There is no B in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no w in font nullfont! +Missing character: There is no o in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no S in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no v in font nullfont! +Missing character: There is no o in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no h in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no F in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no u in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no l in font nullfont! +Missing character: There is no l in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no S in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no f in font nullfont! +Missing character: There is no . in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no f in font nullfont! +Missing character: There is no o in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no C in font nullfont! +Missing character: There is no o in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no o in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no A in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no l in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no u in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no . in font nullfont! +Missing character: There is no D in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no B in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no b in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no u in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no F in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no k in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no w in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no m in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no h in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no l in font nullfont! +Missing character: There is no f in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no L in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no x in font nullfont! +Missing character: There is no D in font nullfont! +Missing character: There is no o in font nullfont! +Missing character: There is no k in font nullfont! +Missing character: There is no u in font nullfont! +Missing character: There is no m in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no , in font nullfont! +Missing character: There is no o in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no i in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no m in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no p in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no r in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no t in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no m in font nullfont! +Missing character: There is no P in font nullfont! +Missing character: There is no D in font nullfont! +Missing character: There is no F in font nullfont! +Missing character: There is no g in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no c in font nullfont! +Missing character: There is no h in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no h in font nullfont! +Missing character: There is no e in font nullfont! +Missing character: There is no n in font nullfont! +Missing character: There is no . in font nullfont! + +Overfull \hbox (20.0pt too wide) in paragraph at lines 8--9 +[] + [] + +) +! Emergency stop. +<*> a.tex + +*** (job aborted, no legal \end found) + + +Here is how much of TeX's memory you used: + 9 strings out of 492995 + 172 string characters out of 6141053 + 54074 words of memory out of 5000000 + 3661 multiletter control sequences out of 15000+600000 + 3948 words of font info for 15 fonts, out of 8000000 for 9000 + 1141 hyphenation exceptions out of 8191 + 19i,2n,19p,393b,89s stack positions out of 5000i,500n,10000p,200000b,80000s +! ==> Fatal error occurred, no output PDF file produced! diff --git a/Abgabe/sections/a.tex b/Abgabe/sections/a.tex new file mode 100644 index 0000000..84773d5 --- /dev/null +++ b/Abgabe/sections/a.tex @@ -0,0 +1,65 @@ +\newpage +\section{Aufgabe} +Das Ziel ist die Detektion des \glqq magischen Umhangs\grqq\ sowie das k\"unstliche Entfernen eines Objektes im Vordergrund. Daf\"ur werden in diesem Labor drei Arbeitspakete bearbeitet: Die Vorverarbeitung, die Farbanalyse der Szene und die Segmentierung des Umhangs. Eine Skizze der Bildverarbeitungs-Pipeline ist in Abbildung \ref{fig:skizzepipeline} dargestellt. + +\begin{figure} +\centering + +\tikzstyle{decision} = [diamond, draw, fill=blue!20, text width=4.5em, text badly centered, node distance=3cm, inner sep=0pt] +\tikzstyle{block} = [rectangle, draw, fill=blue!20, text width=8em, text centered, rounded corners, minimum height=4em] +\tikzstyle{line} = [draw, -latex'] +\tikzstyle{cloud} = [draw, ellipse,fill=red!20, node distance=4cm, minimum height=2em] +\begin{tikzpicture}[node distance = 2cm, auto] + % Place nodes + + +\node [block, fill=green!20] (Rauschreduktion) {Rauschreduktion}; +\node [block, fill=green!20, below of=Rauschreduktion] (Histogramm) {Histogramm Spreizung}; +\node [block, fill=yellow!20, below of=Histogramm] (Farbanalyse) {Farbanalyse}; +\node [block, fill=blue!20, below of=Farbanalyse] (Schwellwertverfahren) {Schwellwert-verfahren}; +\node [block, fill=blue!20, below of=Schwellwertverfahren] (Maske) {Bin\"armasken-Optimierung}; +\node [block, fill=blue!20, below of=Maske] (Bildmodifizierung) {Bildmodifizierung}; +\node [cloud, left of=Rauschreduktion] (Webcam) {Webcam}; +\node [cloud,right of=Bildmodifizierung] (Output1) {Screen}; +\node [cloud,below of=Output1, node distance=1.5cm] (Output2) {Virtuelle Kamera}; +\node [cloud,left of=Bildmodifizierung] (Input2) {Maus-Events}; +%\node [cloud, left of=init] (expert) {expert}; +%\node [cloud, right of=init] (system) {system}; +%\node [block, below of=init] (identify) {identify candidate models}; +%\node [block, below of=identify] (evaluate) {evaluate candidate models}; +%\node [block, left of=evaluate, node distance=3cm] (update) {update model}; +%\node [decision, below of=evaluate] (decide) {is best candidate better?}; +%\node [block, below of=decide, node distance=3cm] (stop) {stop}; + + +% Draw edges +\path [line] (Webcam) -- (Rauschreduktion); +\path [line] (Rauschreduktion) -- (Histogramm); +\path [line] (Histogramm) -- (Farbanalyse); +\path [line] (Farbanalyse) -- (Schwellwertverfahren); +\path [line] (Schwellwertverfahren) -- (Maske); +\path [line] (Maske) -- (Bildmodifizierung); +\path [line] (Bildmodifizierung) -- (Output1); +\path [line,dashed] (Bildmodifizierung) -- (Output2); +\path [line] (Input2) -- (Bildmodifizierung); +%\path [line] (identify) -- (evaluate); +%\path [line] (evaluate) -- (decide); +%\path [line] (decide) -| node [near start] {yes} (update); +%\path [line] (update) |- (identify); +%\path [line] (decide) -- node {no}(stop); +%\path [line,dashed] (expert) -- (init); +%path [line,dashed] (system) -- (init); +%\path [line,dashed] (system) |- (evaluate); + +\end{tikzpicture} +\caption{Bildverarbeitungs-Pipeline} +\label{fig:skizzepipeline} +\end{figure} + +Die Szene f\"ur diesen Versuch wird durch Sie definiert: W"ahlen Sie sich eine eint"onige, m"oglichst monotone Umgebung als Szene f\"ur diesen Versuch. Der \glqq magische Umhang\grqq\ wird dann durch einen einfarbigen Gegenstand (es muss kein Umhang sein!) realisiert. Achten Sie darauf, dass sich der Umhang farblich von der Szene unterscheidet. Je st"arker der Kontrast zwischen \glqq Umhang\grqq\ und Szene ist, desto besser l"asst sich dieser Versuch durchf"uhren. + + +Im folgenden finden Sie detaillierte Beschreibungen der Arbeitspakete. Bitte beantworten Sie die vorhandenen Fragen und erstellen Sie ggf.\ geforderten Code oder Abbildungen. Die Bearbeitung der Fragen kann entweder innerhalb dieses Latex Dokuments, oder in einem separatem PDF geschehen. + + + diff --git a/Abgabe/sections/a1.aux b/Abgabe/sections/a1.aux new file mode 100644 index 0000000..41e347a --- /dev/null +++ b/Abgabe/sections/a1.aux @@ -0,0 +1,44 @@ +\relax +\providecommand\hyper@newdestlabel[2]{} +\@writefile{toc}{\contentsline {subsection}{\numberline {2.1}Vorverarbeitung}{10}{subsection.2.1}} +\@writefile{toc}{\contentsline {subsubsection}{\numberline {2.1.1}Rauschreduktion}{10}{subsubsection.2.1.1}} +\newlabel{lst:code1}{{3}{10}{Vorverarbeitung, Aufgabe 1}{lstlisting.3}{}} +\@writefile{lol}{\contentsline {lstlisting}{\numberline {3}Vorverarbeitung, Aufgabe 1}{10}{lstlisting.3}} +\@writefile{toc}{\contentsline {subsubsection}{\numberline {2.1.2}Histogramm Spreizung}{11}{subsubsection.2.1.2}} +\newlabel{equ:histogramm-equalization}{{3}{11}{Histogramm Spreizung}{equation.2.3}{}} +\newlabel{lst:code1}{{4}{11}{Vorverarbeitung, Aufgabe 4}{lstlisting.4}{}} +\@writefile{lol}{\contentsline {lstlisting}{\numberline {4}Vorverarbeitung, Aufgabe 4}{11}{lstlisting.4}} +\@setckpt{sections/a1}{ +\setcounter{page}{12} +\setcounter{equation}{3} +\setcounter{enumi}{0} +\setcounter{enumii}{0} +\setcounter{enumiii}{0} +\setcounter{enumiv}{0} +\setcounter{footnote}{2} +\setcounter{mpfootnote}{0} +\setcounter{sapage}{0} +\setcounter{part}{0} +\setcounter{section}{2} +\setcounter{subsection}{1} +\setcounter{subsubsection}{2} +\setcounter{paragraph}{0} +\setcounter{subparagraph}{0} +\setcounter{figure}{5} +\setcounter{table}{1} +\setcounter{currfiledepth}{0} +\setcounter{CurrentPage}{12} +\setcounter{pagesLTS.pagenr}{17} +\setcounter{pagesLTS.current.local.0}{1} +\setcounter{pagesLTS.pnc.0}{0} +\setcounter{Item}{0} +\setcounter{Hfootnote}{2} +\setcounter{bookmark@seq@number}{7} +\setcounter{lstnumber}{2} +\setcounter{pagesLTS.arabic.1.local.cnt}{17} +\setcounter{section@level}{3} +\setcounter{lstlisting}{4} +\setcounter{pagesLTS.pnc.arabic}{1} +\setcounter{pagesLTS.double.arabic}{1} +\setcounter{pagesLTS.current.local.arabic}{12} +} diff --git a/Abgabe/sections/a1.tex b/Abgabe/sections/a1.tex new file mode 100644 index 0000000..8694c7d --- /dev/null +++ b/Abgabe/sections/a1.tex @@ -0,0 +1,63 @@ +\newpage +\subsection{Vorverarbeitung} +Um die folgende Verarbeitung der Bilder zu vereinfachen und robuster zu gestalten, sollen Sie den Videostream mit einem Preprocessing vorverarbeiten. +Binden Sie dafr die Datei \textit{./CV-App/algorithms/invis\_cloak.py} in den Algorithmus ein, wie in der Einleitung beschrieben. +Die folgenden Aufgabenstellungen sind in den dafr vorgesehenen Funktionen zu bearbeiten. +%Erstellen Sie dafr einen neuen Algorithmus, wie in der Einleitung beschrieben. + +\subsubsection{Rauschreduktion} +Jeder Farbwert eines Pixels $I_k(x, y) \in \{0, \ldots, 255 \}$ mit $k\in \{R, G, B\}$ wird auf dem Kamerasensor durch einen elektrischen Halbleiter physikalisch gemessen. Je nach Sensorqualitt und Lichtbedingungen wirkt dabei ein unterschiedlich ausgeprgtes Rauschen auf die Farbwerte ein, sodass der zur Verfgung stehende Farbwert als Summe + +\begin{equation} +I_k(x, y) = I^*_k(x, y) + r(x, y) +\end{equation} + +aus realem Farbwert $I^*_k(x, y) $ und statistischem Rauschen $r(x,y)$ modelliert werden kann. Das Rauschen $r$ kann als normalverteilt um den Mittelwert $0$ angenommen werden. Unter den Annahmen, dass die Kamera statisch montiert ist und in der aufgenommenen Szene keine Vernderung passiert, kann der Zusammenhang + +\begin{equation} + \overline{I}_{k,t}(x, y) = \lim_{N\rightarrow \infty} \frac{1}{N + 1} \sum_{n=0}^N I^*_{k,t-n}(x, y) + r_{t-n}(x, y) \stackrel{!}{=} I^*_{k,t} +\end{equation} + +fr die Mittelwertbildung ber lange Zeitrume formuliert werden. Dabei beschreibt $t$ den Zeitpunkt, zu dem der entsprechende Wert gemessen wurde. + +Um die Bildqualitt zu erhhen, soll der Einfluss von $r$ reduziert werden. Es soll dafr angenommen werden, dass die Kamera statisch ist und kaum Bewegung in zwei aufeinander folgenden Bildern vorhanden ist. +Implementieren Sie die Mittelwertbildung mit einer variablem Bildreihe $N$ (default: $N=1$) und geben Sie das Bild aus. \\ +Um zu prfen wie das Bild auf Pixelebene arbeitet, kann die Variable \textit{plotNoise} in der Funktion \textit{process()} auf \textit{True} gesetzt werden. +Es werden zwei zustzliche Plots ausgegeben, in der ein Bildausschnitt des Zentrums vor- und nach der Rauschunterdrckung vergrert dargestellt werden. + + +\paragraph*{Aufgabe 1} +Geben Sie Ihren Code an und beschreiben Sie ihn. Geben Sie nur relevante Code Bereiche an! + \lstset{caption={Vorverarbeitung, Aufgabe 1}} +\begin{lstlisting} +# Your code! +\end{lstlisting} + +\paragraph*{Aufgabe 2} +Nennen Sie Vor und Nachteile, wenn $N$ vergrert werden wrde. Sollte $N$ in dieser Anwendung vergrert werden? + +\paragraph*{Aufgabe 3} +Beschreiben Sie eine weitere Methode zur Rauschreduktion. Diskutieren Sie dabei Vor- oder Nachteile! + +\subsubsection{Histogramm Spreizung} +Pixel knnen in unserer Anwendung Werte von $I_k(x,y) \in \{ 0, \ldots , 255 \}$ annehmen. Dieser Wertebereich wird nicht zwangslufig ausgenutzt. Um das zu ndern, soll eine Histogramm Spreizung auf den Helligkeitsinformationen der Pixel durchgefhrt werden. + +Implementieren Sie zustzlich zur Rauschreduktion eine Histogramm Spreizung, indem sie (1) das Rausch-reduzierte Eingangsbild in den HSV-Farbbereich transformieren und (2) die Rechenvorschrift~\ref{equ:histogramm-equalization} auf den V-Kanal anwenden. Transformieren Sie das Bild dann (3) wieder in den RGB Farbraum. + +\begin{equation} +\label{equ:histogramm-equalization} +I_V^{\textnormal{new}}(x,y) = \frac{I_{V}(x,y) - \min I_{V}}{\max I_{V} - \min I_{V}} \cdot 255 +\end{equation} + +\textbf{Hinweis:} Nutzen Sie die Befehle \textit{cv2.cvtColor(img, cv2.COLOR\_BGR2HSV)} beziehungsweise \textit{cv2.cvtColor(img, cv2.COLOR\_HSV2BGR)}. + + +\paragraph*{Aufgabe 4} +Geben Sie Ihren Code an und beschreiben Sie ihn. Geben Sie nur relevante Code Bereiche an! +\lstset{caption={Vorverarbeitung, Aufgabe 4}} +\begin{lstlisting} +# Your code! +\end{lstlisting} + +\paragraph*{Aufgabe 5} +Warum ist es sinnvoll, den gesamten Wertebereich fr die Darstellung von Videos in Multimedia-Anwendungen auszunutzen? \ No newline at end of file diff --git a/Abgabe/sections/a1.tex.aux b/Abgabe/sections/a1.tex.aux new file mode 100644 index 0000000..499f287 --- /dev/null +++ b/Abgabe/sections/a1.tex.aux @@ -0,0 +1,29 @@ +\relax +\@setckpt{sections/a1.tex}{ +\setcounter{page}{4} +\setcounter{equation}{0} +\setcounter{enumi}{0} +\setcounter{enumii}{0} +\setcounter{enumiii}{0} +\setcounter{enumiv}{0} +\setcounter{footnote}{0} +\setcounter{mpfootnote}{0} +\setcounter{sapage}{0} +\setcounter{part}{0} +\setcounter{section}{1} +\setcounter{subsection}{0} +\setcounter{subsubsection}{0} +\setcounter{paragraph}{0} +\setcounter{subparagraph}{0} +\setcounter{figure}{0} +\setcounter{table}{0} +\setcounter{currfiledepth}{0} +\setcounter{CurrentPage}{4} +\setcounter{pagesLTS.pagenr}{3} +\setcounter{pagesLTS.current.local.0}{1} +\setcounter{pagesLTS.pnc.0}{0} +\setcounter{pagesLTS.arabic.1.local.cnt}{3} +\setcounter{pagesLTS.pnc.arabic}{1} +\setcounter{pagesLTS.double.arabic}{1} +\setcounter{pagesLTS.current.local.arabic}{4} +} diff --git a/Abgabe/sections/a2.aux b/Abgabe/sections/a2.aux new file mode 100644 index 0000000..df50241 --- /dev/null +++ b/Abgabe/sections/a2.aux @@ -0,0 +1,44 @@ +\relax +\providecommand\hyper@newdestlabel[2]{} +\@writefile{toc}{\contentsline {subsection}{\numberline {2.2}Farbanalyse}{12}{subsection.2.2}} +\@writefile{toc}{\contentsline {subsubsection}{\numberline {2.2.1}RGB}{12}{subsubsection.2.2.1}} +\newlabel{lst:Histogramm}{{5}{12}{Histogrammberechnung mit \textit {matplotlib}}{lstlisting.5}{}} +\@writefile{lol}{\contentsline {lstlisting}{\numberline {5}Histogrammberechnung mit \textit {matplotlib}}{12}{lstlisting.5}} +\newlabel{lst:code1}{{6}{13}{Farbanalyse, Aufgabe 1}{lstlisting.6}{}} +\@writefile{lol}{\contentsline {lstlisting}{\numberline {6}Farbanalyse, Aufgabe 1}{13}{lstlisting.6}} +\@writefile{toc}{\contentsline {subsubsection}{\numberline {2.2.2}HSV}{13}{subsubsection.2.2.2}} +\newlabel{equ:segrule}{{5}{13}{Aufgabe 5}{equation.2.5}{}} +\@setckpt{sections/a2}{ +\setcounter{page}{14} +\setcounter{equation}{5} +\setcounter{enumi}{0} +\setcounter{enumii}{0} +\setcounter{enumiii}{0} +\setcounter{enumiv}{0} +\setcounter{footnote}{2} +\setcounter{mpfootnote}{0} +\setcounter{sapage}{0} +\setcounter{part}{0} +\setcounter{section}{2} +\setcounter{subsection}{2} +\setcounter{subsubsection}{2} +\setcounter{paragraph}{0} +\setcounter{subparagraph}{0} +\setcounter{figure}{5} +\setcounter{table}{1} +\setcounter{currfiledepth}{0} +\setcounter{CurrentPage}{14} +\setcounter{pagesLTS.pagenr}{17} +\setcounter{pagesLTS.current.local.0}{1} +\setcounter{pagesLTS.pnc.0}{0} +\setcounter{Item}{0} +\setcounter{Hfootnote}{2} +\setcounter{bookmark@seq@number}{10} +\setcounter{lstnumber}{2} +\setcounter{pagesLTS.arabic.1.local.cnt}{17} +\setcounter{section@level}{3} +\setcounter{lstlisting}{6} +\setcounter{pagesLTS.pnc.arabic}{1} +\setcounter{pagesLTS.double.arabic}{1} +\setcounter{pagesLTS.current.local.arabic}{14} +} diff --git a/Abgabe/sections/a2.tex b/Abgabe/sections/a2.tex new file mode 100644 index 0000000..c61bf5e --- /dev/null +++ b/Abgabe/sections/a2.tex @@ -0,0 +1,64 @@ +\newpage +\subsection{Farbanalyse} +Die Zugrundeliegende Aufgabe ist die Detektion des \glqq magischen Umhangs\grqq , der Objekte verschwinden lassen kann. Der Umhang kann durch eine einfarbige Decke modelliert werden. Sollte keine einfarbige Decke vorhanden sein, kann ebenfalls ein einfarbiges Blatt Papier zur Hilfe genommen werden. + +Das Ziel des Arbeitspakets \glqq Farbanalyse\grqq\ ist es, die farblichen Eigenschaften der Szene, sowie des \glqq magischen Umhangs\grqq\ zu untersuchen. Dafr sollen die Histogramme einzelner Farbkanle mit und ohne Umhang erstellt und analysiert werden. + +\textbf{Hinweis:} Versuchen Sie von nun an die Position der Kamera nicht mehr zu verndern! + +\subsubsection{RGB} +Einzelne Pixel werden durch drei Werte reprsentiert. Jeweils ein Wert $I_k(x, y) \in \{0, \ldots, 255 \}$ mit $k\in \{R, G, B\}$ beschreibt die einfallende Lichtmenge fr die Farben Rot, Grn und Blau. In OpenCV werden Bilder im BGR Format reprsentiert. Die Verteilung der Farbwerte kann durch ein Histogramm dargestellt werden. Ein Histogramm +\begin{equation} +h(v) = |I_v| +\end{equation} +beschreibt die Anzahl der Menge Pixel $I_v$ im Bild, welche den Wert $v$ haben. In OpenCV kann das Histogramm mit der Funktion \textit{cv2.calcHist(image, [Kanal], None, [histSize], histRange, False)} berechnet werden. Dabei gibt \textit{histSize} die Anzahl der Intervalle und $\textit{histRange} = (0, 256)$ die obere und untere Schrank fr den zu betrachtenden Wertebereich an. + +Implementieren Sie in Ihren Algorithmus eine Funktion, mit dem Sie per Mausklick das aktuelle Bild speichern knnen. Des Weiteren soll bei Bettigung des Mausklicks ein Histogramm fr jeden Farbkanal des RGB-Bilder erstellt und abgespeichert werden. Mit Hilfe des Code-Schnipsel in Code \ref{lst:Histogramm} kann ein Histogramm angezeigt oder gespeichert werden! + +\begin{lstlisting}[caption={Histogrammberechnung mit \textit{matplotlib}},label={lst:Histogramm}] +import cv2 +from matplotlib import pyplot as plt + +channel = 0 #[0:B, 1:G, 2:R] +hist_size = 256 +hist_range = [0,256] +histr = cv2.calcHist([img], [channel], None, [hist_size], hist_range) +plt.plot(histr, color = "b") +plt.xlim([0,256]) +plt.savefig('the_path_to_store.png') +plt.show() +\end{lstlisting} + +Nehmen Sie mit dem fertig implementierten Code ein Bild und die Histogramme in der von Ihnen prferierten Szene auf. Nehmen Sie sich darauf den \glqq magischen Umhang\grqq zur Seite und halten ihn sehr gut sichtbar vor die Kamera. Nehmen Sie auch jetzt ein Bild mit den Histogrammen auf. Die Kamera sollte sich zwischen den beiden Bildern nicht bewegen. + + +\paragraph*{Aufgabe 1} +Geben Sie Ihren Code an und beschreiben Sie ihn. Geben Sie nur relevante Code Bereiche an! Geben sie zustzlich die aufgenommenen Bilder und die erstellten Histogramme an. + +\lstset{caption={Farbanalyse, Aufgabe 1}} +\begin{lstlisting} +# Your code! +\end{lstlisting} + +\paragraph*{Aufgabe 2} +Interpretieren Sie die Vernderungen zwischen den Histogrammen mit und ohne \glqq magischen Umhang\grqq . Verhalten sich die einzelnen Kanle gleich? Lassen sich Bereiche in den Histogrammen herausstellen, die dem Umhang zuzuordnen sind? Diskutieren Sie Ihre Beobachtungen. + +\subsubsection{HSV} +Erweitern Sie ihren vorherigen Code um eine Farbkonvertierung in den HSV-Farbraum. Fhren Sie die Konvertierung vor Erstellung der Histogramme durch und wiederholen Sie die Schritte aus dem vorherigen Aufgabenteil. + +\paragraph*{Aufgabe 3} +Geben sie die aufgenommenen Bilder und die erstellten Histogramme an. + +\paragraph*{Aufgabe 4} +Interpretieren Sie die Vernderungen zwischen den Histogrammen mit und ohne \glqq magischen Umhang\grqq . Verhalten sich die einzelnen Kanle gleich? Lassen sich Bereiche in den Histogrammen herausstellen, die dem Umhang zuzuordnen sind? Diskutieren Sie Ihre Beobachtungen. + +\paragraph*{Aufgabe 5} +Versuchen Sie mit den gegebenen Histogrammen Wertebereiche zu finden, mit denen Sie den \glqq magischen Umhang\grqq\ segmentieren knnten. Formulieren Sie eine Regel in dem Format +\begin{equation} +\label{equ:segrule} + S_\textnormal{Umhang} = \{ I(x, y)\ |\ \\ R_\textnormal{min} < I_R(x, y) < R_\textnormal{max} \ \ \textnormal{und} \ \ \ldots \} \quad , +\end{equation} +wobei $S_\textnormal{Umhang}$ die Binrmaske beschreibt und $R_\textnormal{min}$ und $R_\textnormal{max}$ beispielhafte Schwellwerte fr den Rot-Kanal sind. + +\paragraph*{Aufgabe 6} +Worauf muss geachtet werden, wenn mit dem H-Kanal des HSV-Farbraums gearbeitet wird? \ No newline at end of file diff --git a/Abgabe/sections/a2.tex.aux b/Abgabe/sections/a2.tex.aux new file mode 100644 index 0000000..4bee5bb --- /dev/null +++ b/Abgabe/sections/a2.tex.aux @@ -0,0 +1,29 @@ +\relax +\@setckpt{sections/a2.tex}{ +\setcounter{page}{4} +\setcounter{equation}{0} +\setcounter{enumi}{0} +\setcounter{enumii}{0} +\setcounter{enumiii}{0} +\setcounter{enumiv}{0} +\setcounter{footnote}{0} +\setcounter{mpfootnote}{0} +\setcounter{sapage}{0} +\setcounter{part}{0} +\setcounter{section}{1} +\setcounter{subsection}{0} +\setcounter{subsubsection}{0} +\setcounter{paragraph}{0} +\setcounter{subparagraph}{0} +\setcounter{figure}{0} +\setcounter{table}{0} +\setcounter{currfiledepth}{0} +\setcounter{CurrentPage}{4} +\setcounter{pagesLTS.pagenr}{3} +\setcounter{pagesLTS.current.local.0}{1} +\setcounter{pagesLTS.pnc.0}{0} +\setcounter{pagesLTS.arabic.1.local.cnt}{3} +\setcounter{pagesLTS.pnc.arabic}{1} +\setcounter{pagesLTS.double.arabic}{1} +\setcounter{pagesLTS.current.local.arabic}{4} +} diff --git a/Abgabe/sections/a3.aux b/Abgabe/sections/a3.aux new file mode 100644 index 0000000..d189d3f --- /dev/null +++ b/Abgabe/sections/a3.aux @@ -0,0 +1,50 @@ +\relax +\providecommand\hyper@newdestlabel[2]{} +\@writefile{toc}{\contentsline {subsection}{\numberline {2.3}Segmentierung und Bildmodifizierung}{14}{subsection.2.3}} +\@writefile{toc}{\contentsline {subsubsection}{\numberline {2.3.1}Statisches Schwellwertverfahren}{14}{subsubsection.2.3.1}} +\newlabel{lst:conditions}{{7}{14}{Benutzung von Randbedingungen mit \textit {numpy}}{lstlisting.7}{}} +\@writefile{lol}{\contentsline {lstlisting}{\numberline {7}Benutzung von Randbedingungen mit \textit {numpy}}{14}{lstlisting.7}} +\newlabel{lst:code1}{{8}{14}{Segmentierung und Bildmodifizierung, Aufgabe 1}{lstlisting.8}{}} +\@writefile{lol}{\contentsline {lstlisting}{\numberline {8}Segmentierung und Bildmodifizierung, Aufgabe 1}{14}{lstlisting.8}} +\@writefile{toc}{\contentsline {subsubsection}{\numberline {2.3.2}Bin\"armaske}{15}{subsubsection.2.3.2}} +\newlabel{lst:contours}{{9}{15}{Konturfindung}{lstlisting.9}{}} +\@writefile{lol}{\contentsline {lstlisting}{\numberline {9}Konturfindung}{15}{lstlisting.9}} +\newlabel{lst:contours}{{10}{15}{Segmentierung und Bildmodifizierung, Aufgabe 2}{lstlisting.10}{}} +\@writefile{lol}{\contentsline {lstlisting}{\numberline {10}Segmentierung und Bildmodifizierung, Aufgabe 2}{15}{lstlisting.10}} +\@writefile{toc}{\contentsline {subsubsection}{\numberline {2.3.3}Bildmodifizierung}{15}{subsubsection.2.3.3}} +\newlabel{lst:contours}{{11}{16}{Segmentierung und Bildmodifizierung, Aufgabe 4}{lstlisting.11}{}} +\@writefile{lol}{\contentsline {lstlisting}{\numberline {11}Segmentierung und Bildmodifizierung, Aufgabe 4}{16}{lstlisting.11}} +\@setckpt{sections/a3}{ +\setcounter{page}{17} +\setcounter{equation}{5} +\setcounter{enumi}{0} +\setcounter{enumii}{0} +\setcounter{enumiii}{0} +\setcounter{enumiv}{0} +\setcounter{footnote}{2} +\setcounter{mpfootnote}{0} +\setcounter{sapage}{0} +\setcounter{part}{0} +\setcounter{section}{2} +\setcounter{subsection}{3} +\setcounter{subsubsection}{3} +\setcounter{paragraph}{0} +\setcounter{subparagraph}{0} +\setcounter{figure}{5} +\setcounter{table}{1} +\setcounter{currfiledepth}{0} +\setcounter{CurrentPage}{17} +\setcounter{pagesLTS.pagenr}{17} +\setcounter{pagesLTS.current.local.0}{1} +\setcounter{pagesLTS.pnc.0}{0} +\setcounter{Item}{0} +\setcounter{Hfootnote}{2} +\setcounter{bookmark@seq@number}{14} +\setcounter{lstnumber}{2} +\setcounter{pagesLTS.arabic.1.local.cnt}{17} +\setcounter{section@level}{3} +\setcounter{lstlisting}{11} +\setcounter{pagesLTS.pnc.arabic}{1} +\setcounter{pagesLTS.double.arabic}{1} +\setcounter{pagesLTS.current.local.arabic}{17} +} diff --git a/Abgabe/sections/a3.tex b/Abgabe/sections/a3.tex new file mode 100644 index 0000000..5f5106b --- /dev/null +++ b/Abgabe/sections/a3.tex @@ -0,0 +1,81 @@ +\newpage +\subsection{Segmentierung und Bildmodifizierung} +In diesem Arbeitspaket werden Sie auf Grundlage der vorherigen Analysen eine Segmentierung des magischen Umhangs realisieren. Anschlieend werden Sie den segmentierten Bereich \glqq verschwinden\grqq\ lassen, indem sie ein statisches Bild des Hintergrunds auf diese Flchen einfgen. + + +\subsubsection{Statisches Schwellwertverfahren} +Implementieren Sie die von Ihnen gefundene Regel nach Gleichung~\ref{equ:segrule}, um eine Binrmaske zu erhalten. Sie knnen die Randbedingungen wie im folgenden Code-Schnipsel \ref{lst:conditions} implementieren. + +\begin{lstlisting}[caption={Benutzung von Randbedingungen mit \textit{numpy}}, label={lst:conditions}] +import cv2 +import numpy as np + +channel1 = 0 +lower_bound1, upper_bound1 = 15, 100 +is_condition_1_true = (lower_bound1 < img[:, :, channel1]) * \ + (img[:, :, channel1] < upper_bound1) +channel2 = 1 +lower_bound2, upper_bound2 = 65, 172 +is_condition_2_true = (lower_bound2 < img[:, :, channel2]) * \ +(img[:, :, channel2] < upper_bound2) + +binary_mask = is_condition_1_true * is_condition_2_true +\end{lstlisting} + +Geben Sie die gefundene Binrmaske als Ausgangsbild auf dem Bildschirm aus. Sollten die gefundenen Wertebereich zu keinen sinnvollen Segmentierungen fhren, drfen Sie Gleichung~\ref{equ:segrule} selbstverstndlich anpassen! + +Implementieren Sie ebenfalls eine Mausklick-Funktion, mit der Sie das aktuelle Bild und die dazugehrige Binrmaske abspeichern knnen. Fr das Abspeichern von Bildern knnen Sie die Funktion \textit{cv2.imwrite(img, "path\_to\_store.png")} verwenden. + +\paragraph*{Aufgabe 1} +Geben Sie Ihren Code an und beschreiben Sie ihn. Geben Sie nur relevante Code Bereiche an! Geben Sie ebenfalls das aufgenommene Bild sowie die dazugehrige Binrmaske an. + +\lstset{caption={Segmentierung und Bildmodifizierung, Aufgabe 1}} +\begin{lstlisting} +# Your code! +\end{lstlisting} + +\subsubsection{Binrmaske} +Die in der vorherigen Aufgabe erhaltene Binrmaske ist ggf.\ ungeeignet fr eine zufriedenstellende Segmentierung. Sie sollen die Maske nun optimieren. Wenden Sie dafr das \textit{Opening} und \textit{Closing} auf die Binrmaske an. Nutzen Sie die Funktionen \textit{cv2.erode(img, kernel)} und \textit{cv2.dilate(img, kernel)}. + +Whlen Sie zum Schluss die grte zusammenhnge Region segmentierter Pixel aus, und lschen alle anderen Segmente. Folgender Code-Schnipsel~\ref{lst:contours} soll als Hilfestellung dienen. Recherchieren Sie ggf.\ im Internet. + +\lstset{caption={Konturfindung}} +\lstset{label={lst:contours}} +\begin{lstlisting} +(cnts, _) = cv2.findContours( + binary_mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) +c = max(cnts, key = cv2.contourArea) +img = cv2.drawContours(img, [c], -1, color=255, -1) +\end{lstlisting} + +\paragraph*{Aufgabe 2} +Geben Sie Ihren Code an und beschreiben Sie ihn. Geben Sie nur relevante Code Bereiche an! +\lstset{caption={Segmentierung und Bildmodifizierung, Aufgabe 2}} +\begin{lstlisting} +# Your code! +\end{lstlisting} + +\paragraph*{Aufgabe 3} +Welche Probleme oder Fehler knnen in der Binrmaske vorkommen, die mit den Manahmen beseitigt werden sollen? + +\subsubsection{Bildmodifizierung} +Nach dem Fertigstellen der vorherigen Aufgabenstellungen sollten Sie nun eine Binrmaske erhalten, welche den \glqq magischen Umhang\grqq\ segmentiert. Die letzte Aufgabe befasst sich mit der Bildmodifizierung, welche den Eindruck verschwindender Objekte vermittelt. + +Sie sollen nun folgende Funktionen implementieren: + +Erstellen Sie eine Member-Variable (z.B. \textit{self.variable}) in die Algorithmus Funktion \textit{\_\_init\_\_()}. Initiieren Sie die Variable mit dem Wert \textit{None}. +Modifizieren Sie den Algorithmus, sodass Sie mit einem Mausklick ein Bild in die Variable speichern knnen. Dieses Bild wird als Hintergrund definiert. Mausklick-Funktionen aus vorherigen Aufgaben knnen berschrieben werden! + +Solange kein Bild in der Variable gespeichert ist, soll das Eingangsbild direkt wieder ausgegeben werden. Sobald ein Hintergrund vorhanden ist soll folgendes passieren: Modifizieren Sie das Bild, indem Sie das Ausgangsbild aus dem derzeitigen Kamera-Stream und dem Hintergrund zusammenfgen. Die durch die Binrmaske segmentierte Flche soll aus dem Hintergrund entnommen werden, die unsegmentierte Flche aus dem derzeitigen Videostream. + +\textbf{Hinweis:} Verlassen Sie das Sichtfeld der Kamera, whrend Sie die Hintergrund Aufnahme aufnehmen. + +\paragraph*{Aufgabe 4} +Geben Sie Ihren Code an und beschreiben Sie ihn. Geben Sie nur relevante Code Bereiche an! +\lstset{caption={Segmentierung und Bildmodifizierung, Aufgabe 4}} +\begin{lstlisting} +# Your code! +\end{lstlisting} + +\paragraph*{Aufgabe 5} +Geben Sie ein Bild (z.B. Screenshot) an, in dem die Funktion Ihres \glqq magischen Umhangs\grqq\ gezeigt wird! \ No newline at end of file diff --git a/Abgabe/sections/a3.tex.aux b/Abgabe/sections/a3.tex.aux new file mode 100644 index 0000000..ad9e6dd --- /dev/null +++ b/Abgabe/sections/a3.tex.aux @@ -0,0 +1,29 @@ +\relax +\@setckpt{sections/a3.tex}{ +\setcounter{page}{4} +\setcounter{equation}{0} +\setcounter{enumi}{0} +\setcounter{enumii}{0} +\setcounter{enumiii}{0} +\setcounter{enumiv}{0} +\setcounter{footnote}{0} +\setcounter{mpfootnote}{0} +\setcounter{sapage}{0} +\setcounter{part}{0} +\setcounter{section}{1} +\setcounter{subsection}{0} +\setcounter{subsubsection}{0} +\setcounter{paragraph}{0} +\setcounter{subparagraph}{0} +\setcounter{figure}{0} +\setcounter{table}{0} +\setcounter{currfiledepth}{0} +\setcounter{CurrentPage}{4} +\setcounter{pagesLTS.pagenr}{3} +\setcounter{pagesLTS.current.local.0}{1} +\setcounter{pagesLTS.pnc.0}{0} +\setcounter{pagesLTS.arabic.1.local.cnt}{3} +\setcounter{pagesLTS.pnc.arabic}{1} +\setcounter{pagesLTS.double.arabic}{1} +\setcounter{pagesLTS.current.local.arabic}{4} +} diff --git a/Abgabe/sections/conclusion.aux b/Abgabe/sections/conclusion.aux new file mode 100644 index 0000000..d0a30f6 --- /dev/null +++ b/Abgabe/sections/conclusion.aux @@ -0,0 +1,37 @@ +\relax +\providecommand\hyper@newdestlabel[2]{} +\@writefile{toc}{\contentsline {section}{\numberline {3}Zusammenfassung}{17}{section.3}} +\@setckpt{sections/conclusion}{ +\setcounter{page}{18} +\setcounter{equation}{5} +\setcounter{enumi}{0} +\setcounter{enumii}{0} +\setcounter{enumiii}{0} +\setcounter{enumiv}{0} +\setcounter{footnote}{2} +\setcounter{mpfootnote}{0} +\setcounter{sapage}{0} +\setcounter{part}{0} +\setcounter{section}{3} +\setcounter{subsection}{0} +\setcounter{subsubsection}{0} +\setcounter{paragraph}{0} +\setcounter{subparagraph}{0} +\setcounter{figure}{5} +\setcounter{table}{1} +\setcounter{currfiledepth}{0} +\setcounter{CurrentPage}{18} +\setcounter{pagesLTS.pagenr}{17} +\setcounter{pagesLTS.current.local.0}{1} +\setcounter{pagesLTS.pnc.0}{0} +\setcounter{Item}{0} +\setcounter{Hfootnote}{2} +\setcounter{bookmark@seq@number}{15} +\setcounter{lstnumber}{2} +\setcounter{pagesLTS.arabic.1.local.cnt}{17} +\setcounter{section@level}{1} +\setcounter{lstlisting}{11} +\setcounter{pagesLTS.pnc.arabic}{1} +\setcounter{pagesLTS.double.arabic}{1} +\setcounter{pagesLTS.current.local.arabic}{18} +} diff --git a/Abgabe/sections/conclusion.log b/Abgabe/sections/conclusion.log new file mode 100644 index 0000000..d21ba3c --- /dev/null +++ b/Abgabe/sections/conclusion.log @@ -0,0 +1,42 @@ +This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/TeX Live for SUSE Linux) (preloaded format=pdflatex 2020.8.24) 31 MAR 2021 16:10 +entering extended mode + restricted \write18 enabled. + %&-line parsing enabled. +**conclusion.tex +(./conclusion.tex +LaTeX2e <2017-04-15> +Babel <3.10> and hyphenation patterns for 84 language(s) loaded. + +! LaTeX Error: Missing \begin{document}. + +See the LaTeX manual or LaTeX Companion for explanation. +Type H for immediate help. + ... + +l.3 s + adsad +You're in trouble here. Try typing to proceed. +If that doesn't work, type X to quit. + +Missing character: There is no s in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no d in font nullfont! +Missing character: There is no s in font nullfont! +Missing character: There is no a in font nullfont! +Missing character: There is no d in font nullfont! +) +! Emergency stop. +<*> conclusion.tex + +*** (job aborted, no legal \end found) + + +Here is how much of TeX's memory you used: + 5 strings out of 492995 + 163 string characters out of 6141053 + 54074 words of memory out of 5000000 + 3658 multiletter control sequences out of 15000+600000 + 3640 words of font info for 14 fonts, out of 8000000 for 9000 + 1141 hyphenation exceptions out of 8191 + 5i,0n,4p,43b,14s stack positions out of 5000i,500n,10000p,200000b,80000s +! ==> Fatal error occurred, no output PDF file produced! diff --git a/Abgabe/sections/conclusion.tex b/Abgabe/sections/conclusion.tex new file mode 100644 index 0000000..2ce126d --- /dev/null +++ b/Abgabe/sections/conclusion.tex @@ -0,0 +1,3 @@ +\newpage +\section{Zusammenfassung} +Herzlichen Gl\"uckwunsch! Sie haben in diesem Labor eine Bildverarbeitungs-Pipeline erfolgreich implementiert. Bitte fassen Sie die genutzten Methoden und Erkenntnisse kurz zusammen. \ No newline at end of file diff --git a/Abgabe/sections/overview.aux b/Abgabe/sections/overview.aux new file mode 100644 index 0000000..63fef42 --- /dev/null +++ b/Abgabe/sections/overview.aux @@ -0,0 +1,54 @@ +\relax +\providecommand\hyper@newdestlabel[2]{} +\@writefile{toc}{\contentsline {section}{\numberline {1}Einleitung}{3}{section.1}} +\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Harry Potter ohne magischen Tarnumhang}}{3}{figure.1}} +\newlabel{fig:harry1}{{1}{3}{Harry Potter ohne magischen Tarnumhang}{figure.1}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces Harry Potter mit magischem Tarnumhang}}{3}{figure.2}} +\newlabel{fig:harry2}{{2}{3}{Harry Potter mit magischem Tarnumhang}{figure.2}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {1.1}Vorbereitung}{4}{subsection.1.1}} +\@writefile{lof}{\contentsline {figure}{\numberline {3}{\ignorespaces Programmierumgebung in PyCharm}}{4}{figure.3}} +\newlabel{fig:pycharm}{{3}{4}{Programmierumgebung in PyCharm}{figure.3}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {1.2}Programmierumgebung}{5}{subsection.1.2}} +\newlabel{sec:Programmierumgebung}{{1.2}{5}{Programmierumgebung}{subsection.1.2}{}} +\@writefile{lot}{\contentsline {table}{\numberline {1}{\ignorespaces Argumente f\"ur die Programmausf\"uhrung}}{5}{table.1}} +\newlabel{tab:parameter}{{1}{5}{Argumente fr die Programmausfhrung}{table.1}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {4}{\ignorespaces Run Configuration in PyCharm}}{5}{figure.4}} +\newlabel{fig:run_config}{{4}{6}{Run Configuration in PyCharm}{figure.4}{}} +\newlabel{lst:code2}{{1}{6}{Eigener Algorithmus in \textit {your\_algorithm.py}}{lstlisting.1}{}} +\@writefile{lol}{\contentsline {lstlisting}{\numberline {1}Eigener Algorithmus in \textit {your\_algorithm.py}}{6}{lstlisting.1}} +\newlabel{lst:code1}{{2}{7}{Verlinkung der Algorithmen in \textit {\_\_init\_\_.py}}{lstlisting.2}{}} +\@writefile{lol}{\contentsline {lstlisting}{\numberline {2}Verlinkung der Algorithmen in \textit {\_\_init\_\_.py}}{7}{lstlisting.2}} +\@setckpt{sections/overview}{ +\setcounter{page}{8} +\setcounter{equation}{0} +\setcounter{enumi}{0} +\setcounter{enumii}{0} +\setcounter{enumiii}{0} +\setcounter{enumiv}{0} +\setcounter{footnote}{2} +\setcounter{mpfootnote}{0} +\setcounter{sapage}{0} +\setcounter{part}{0} +\setcounter{section}{1} +\setcounter{subsection}{2} +\setcounter{subsubsection}{0} +\setcounter{paragraph}{0} +\setcounter{subparagraph}{0} +\setcounter{figure}{4} +\setcounter{table}{1} +\setcounter{currfiledepth}{0} +\setcounter{CurrentPage}{8} +\setcounter{pagesLTS.pagenr}{17} +\setcounter{pagesLTS.current.local.0}{1} +\setcounter{pagesLTS.pnc.0}{0} +\setcounter{Item}{0} +\setcounter{Hfootnote}{2} +\setcounter{bookmark@seq@number}{3} +\setcounter{lstnumber}{10} +\setcounter{pagesLTS.arabic.1.local.cnt}{17} +\setcounter{section@level}{2} +\setcounter{lstlisting}{2} +\setcounter{pagesLTS.pnc.arabic}{1} +\setcounter{pagesLTS.double.arabic}{1} +\setcounter{pagesLTS.current.local.arabic}{8} +} diff --git a/Abgabe/sections/overview.tex b/Abgabe/sections/overview.tex new file mode 100644 index 0000000..422c6e2 --- /dev/null +++ b/Abgabe/sections/overview.tex @@ -0,0 +1,130 @@ +\newpage +\section{Einleitung} +Digitale Bildverarbeitung wird unter anderem in industriellen Prozessen, medizinischen Verfahren oder in Multimedia-Produkten angewandt. In diesem Labor soll eine beispielhafte Multimedia-Anwendung entwickelt werden, die ber das Labor hinaus als erheiterndes Demonstrationsobjekt fr Bildverarbeitung in Videokonferenzen genutzt werden kann. Als Inspiration dient ein Effekt aus der Filmreihe \glqq Harry Potter\grqq . + +\begin{figure} + \centering + \begin{minipage}{.45\textwidth} + \centering + \includegraphics[width=.6\linewidth]{fig/harry1.jpg} + \caption{Harry Potter ohne magischen Tarnumhang} + \label{fig:harry1} + \end{minipage}% + \hspace{0.5cm} + \begin{minipage}{.45\textwidth} + \centering + \includegraphics[width=.6\linewidth]{fig/harry2.jpg} + \caption{Harry Potter mit magischem Tarnumhang} + \label{fig:harry2} + \end{minipage} +\end{figure} + +Die Abbildungen \ref{fig:harry1} und \ref{fig:harry2} zeigen Harry Potter ohne +\footnote{\url{https://assets.cdn.moviepilot.de/files/8a2cc0d2eb31c41136fb2be242540606dcd50821980e830481404b276065/fill/1280/614/Harry\%20Potter\%20Tarnumhang.jpg}} +und mit\footnote{\url{https://www.tres-click.com/wp-content/uploads/2019/06/harry-potter-tarnumhang.gif}} +verzauberten Tarnumhang, welchen den Trger des Umhangs verschwinden lassen kann. In diesem Labor entwickeln Sie eine Bildverarbeitungs-Pipeline, mit welcher dieser Effekt mit einer einfachen Webcam simuliert werden kann. Sie festigen den Umgang mit + +\begin{itemize} + \item Rauschunterdrckung + \item Histogrammen + \item verschiedenen Farbrumen + \item Erosion und Dilatation + \item Schwellwertverfahren +\end{itemize} + +und ben gleichzeitig den Umgang mit der Programmiersprache Python. + +\newpage +\subsection{Vorbereitung} +Fr das Labor wird ein Rechner mit Betriebssystem Windows, Linux-Ubuntu oder Mac bentigt. Zustzlich muss eine Webcam vorhanden sein (im Laptop integriert oder extern). +Melden Sie sich \textbf{vorab} bei dem Betreuer des Labors, sollte Ihnen eines der bentigten Mittel nicht zur Verfgung stehen. + + +Um an dem Labor erfolgreich teilnehmen zu knnen, muss die zu nutzende Programmierumgebung vorbereitet werden. Sollten Sie an der praktischen bung zur Vorlesung \textit{Digitale Bildverarbeitung} teilgenommen haben, ist die erforderliche Programmierumgebung sowie der Programmcode wahrscheinlich bereits installiert und eingerichtet. Ansonsten befolgen Sie die Installationsanweisungen auf \url{https://github.com/TimoK93/Digitale-Bildverarbeitung} im Bereich \textit{0\_Einfhrung}. Die Installation des Streaming Programms zur Erstellung einer virtuellen Kamera ist dabei optional und nicht verpflichtend. + +Nachdem Sie die Installation vollendet haben, ffnen Sie die Programmierumgebung, sodass Ihr Bildschirm hnliches zu Abbildung \ref{fig:pycharm} anzeigt. + +\begin{figure} + \centering + \includegraphics[width=\linewidth]{fig/pycharm.png} + \caption{Programmierumgebung in PyCharm} + \label{fig:pycharm} +\end{figure} + +Machen Sie sich als nchstes mithilfe der Beschreibung in Kapitel \ref{sec:Programmierumgebung} mit der Programmierumgebung vertraut. + + + +\newpage +\subsection{Programmierumgebung} +\label{sec:Programmierumgebung} +In der Programmierumgebung ist das Hauptprogramm bereits soweit vorbereitet, sodass Sie einen Videostream aus Ihrer Kamera auslesen, darauf einen vorbereiteten Beispielalgorithmus anwenden und diesen anzeigen knnen. In diesem Kapitel wird kurz erlutert, wie Sie diese Bildverarbeitungs-Pipeline starten und eigene Algorithmen integrieren knnen. + +\paragraph*{Starten der Bildverarbeitungs-Pipeline.} ffnen Sie die Datei \mbox{\textit{./CV-App/main.py}} in PyCharm und klicken Sie mit der rechten Maustaste in den Programmcode. ffnen Sie dann das Fenster \textit{Modify Run Configuration...} wie in Abbildung \ref{fig:run_config} dargestellt. In dem Feld \textit{Parameter} knnen Sie zustzliche Argumente in die Umgebung eingeben. Argumente werden dabei im Schema \textit{--Argument1 Value1 --Argument2 Value2} eingegeben. Die einzustellenden Parameter knnen Sie aus der Tabelle \ref{tab:parameter} entnehmen. Wenn Sie keine Argumente whlen, werden die Standard Einstellungen gewhlt. + +\begin{table} + \centering + \caption{Argumente fr die Programmausfhrung} + \begin{tabular}[h]{c | l| c} + Argument & Werte & Default-Wert \\ \toprule + \textit{camera} & -1, 0, 1, \ldots (-1 ffnet ein Video) & 0 \\ + \textit{mode} & \textit{virtual\_cam} (virtuelle Kamera), \textit{screen} (nur Fenster)& \textit{virtual\_cam} \\ + \textit{video} & Pfad zu Video, wenn \textit{camera} den Wert $-1$ hat. & - \\ + \end{tabular} + \label{tab:parameter} +\end{table} + +\begin{figure} + \centering + \includegraphics[width=0.65\linewidth]{fig/Run-Configs.png} + \caption{Run Configuration in PyCharm} + \label{fig:run_config} +\end{figure} + + Sie knnen das Programm nun mit \textit{Run} starten. Kurz nach dem Start sollten Sie ein Fenster mit dem Videostream aus Ihrer Kamera sehen. Durch das Bettigen verschiedener Tasten auf der Tastatur (z.B.\ Taste 1 oder 2) knnen Sie verschiedene Algorithmen aktivieren. Sie sehen das Ergebnis direkt in dem ausgegebenem Videostream. Wichtig: Das Programm reagiert nur auf Tastendrcke, wenn das Videostream-Fenster im Vordergrund ihres Bildschirms ist. + + + \paragraph*{Eigene Algorithmen einbinden.} Fr Sie sind nur die Dateien im Dateipfad \mbox{ \textit{./CV-App/algorithms}} relevant. Beispielhaft erstellen Sie im Folgenden den Algorithmus \textit{YourAlgorithm}. + + Erstellen Sie eine Datei \textit{your\_algorithm.py} und kopieren Sie den Inhalt aus dem Code \ref{lst:code2}. In der Funktion \textit{\_\_init\_\_(self)} knnen Sie dauerhafte Variablen definieren. Die Funktion \textit{process(self, img)} verarbeitet das Eingangsbild \textit{img} und gibt es am Ende modifiziert wieder aus (Hinweis: Ein und Ausgangsbild mssen gleich gro sein!). Die Funktion \textit{mouse\_callback(self, ...)} reagiert auf Aktionen der Maus, wie zum Beispiel einem Mausklick an der Position x und y. So knnen Sie mit ihrem Algorithmus interagieren. Sie knnen sich einige Beispielalgorithmen in dem Ordner \textit{./CV-App/algorithms} zur Veranschaulichung ansehen. Der Algorithmus in \textit{white\_balancing.py} veranschaulicht alle Funktionen mit Algorithmen der Klasse \textit{Algorithm}. + + % Settings for listings + \lstset{caption={Eigener Algorithmus in \textit{your\_algorithm.py}}} + \lstset{label={lst:code2}} + \begin{lstlisting} +import cv2 +import numpy as np +from . import Algorithm + +class YourAlgorithm(Algorithm): + def __init__(self): + self.some_persistent_value = "i_am_alwys_existing" + + def process(self, img): + print(self.some_persistent_value) + return img + + def mouse_callback(self, event, x, y, flags, param): + if event == cv2.EVENT_LBUTTONUP: + print("A Mouse click happend! at position", x, y) + \end{lstlisting} + + \newpage + Um Ihren Algorithmus nun mit einer Aktivierungstaste-Taste zu verlinken, ffnen Sie die Datei \textit{\_\_init\_\_.py}. Am Ende der Datei ist eine Verlinkung der Algorithmen zu bestimmten Tasten zu sehen (siehe Code \ref{lst:code1}).. In dem Beispiel in Code \ref{lst:code1} ist Ihr neuer Algorithmus \textit{YourAlgorithm} importiert und an die Taste 3 verlinkt. + + % Settings for listings + \lstset{caption={Verlinkung der Algorithmen in \textit{\_\_init\_\_.py}}} + \lstset{label={lst:code1}} + \begin{lstlisting} +from .image_to_gray import ImageToGray +from .image_to_hue import ImageToHue +from .your_algorithm import YourAlgorithm + +algorithms = dict() +algorithms["0"] = Algorithm +algorithms["1"] = ImageToGray +algorithms["2"] = ImageToHue +algorithms["3"] = YourAlgorithm + \end{lstlisting} + + Nach Neustart des Programms durch erneute Bettigung der \textit{Run} Funktion, ist Ihr Algorithmus durch bettigen der Taste 3 zugnglich. \ No newline at end of file diff --git a/Abgabe/sections/overview.tex.aux b/Abgabe/sections/overview.tex.aux new file mode 100644 index 0000000..aa9d720 --- /dev/null +++ b/Abgabe/sections/overview.tex.aux @@ -0,0 +1,29 @@ +\relax +\@setckpt{sections/overview.tex}{ +\setcounter{page}{3} +\setcounter{equation}{0} +\setcounter{enumi}{0} +\setcounter{enumii}{0} +\setcounter{enumiii}{0} +\setcounter{enumiv}{0} +\setcounter{footnote}{0} +\setcounter{mpfootnote}{0} +\setcounter{sapage}{0} +\setcounter{part}{0} +\setcounter{section}{0} +\setcounter{subsection}{0} +\setcounter{subsubsection}{0} +\setcounter{paragraph}{0} +\setcounter{subparagraph}{0} +\setcounter{figure}{0} +\setcounter{table}{0} +\setcounter{currfiledepth}{0} +\setcounter{CurrentPage}{3} +\setcounter{pagesLTS.pagenr}{2} +\setcounter{pagesLTS.current.local.0}{1} +\setcounter{pagesLTS.pnc.0}{0} +\setcounter{pagesLTS.arabic.1.local.cnt}{2} +\setcounter{pagesLTS.pnc.arabic}{1} +\setcounter{pagesLTS.double.arabic}{1} +\setcounter{pagesLTS.current.local.arabic}{3} +} diff --git a/CV-App/README.md b/CV-App/README.md new file mode 100644 index 0000000..035b46d --- /dev/null +++ b/CV-App/README.md @@ -0,0 +1,144 @@ +# CV-Application +Original | Geom. Transformation | Chrominanz +:-------------------------:|:-------------------------:|:-------------------------: +![](./data/cv1.png) | ![](./data/cv2.png) | ![](./data/cv3.png) + +Die CV-App ist eine Applikation, mit der eine Bildverarbeitungs-Pipeline generiert werden kann. Die Pipeline ließt eine +vorhandene Webcam aus. Der Inhalt dieses Videostreams wird dann durch CV-Algorithmen be- und/oder verarbeitet und angezeigt. +Optional kann der so erzeugte Videostream an eine virtuelle Kamera weitergeleitet werden. Diese virtuelle Kamera kann +dann von anderen Programmen (z.B. für Videokonferenzen) wie eine normale Webcam ausgelesen werden. + +Zwei einfache Algorithmen wie die geometrische Transformation oder die Entfernung der Luminanz sind in oberen +Abbildungen dargestellt. + + +## Anleitung +### Treiber virtuelle Kamera +Die Grundfunktion der CV-App ist einsatzbereit, sobald dieses Repository erfolgreich installiert ist. Sie können Ihre +Webcam einlesen und CV-Algorithmen auf den Videostream anwenden. +Für die Nutzung der virtuellen Kamera ist ein zusätzlicher Treiber notwendig. Je nachdem welches Betriebssystem Sie +nutzen, kann dieser variieren. Die nötige Treiber Installation finden Sie unter + [https://github.com/letmaik/pyvirtualcam](https://github.com/letmaik/pyvirtualcam). + +### Bedienung des Programms +Führen Sie das Skript `main.py` aus diesem Verzeichnis mit dem Befehl + +```bash +python main.py --camera=0 --mode=virtual_cam --video=PFAD_ZU_EINEM_VIDEO +``` + +im Terminal aus. Dabei stehen Ihnen einige optionale Parameter zur Verfügung. Wenn Sie die Parameter nicht angeben, +werden die Default-Werte verwendet. Die Bedeutung der Parameter sowie die Default-Werte finden Sie in der folgenden +Tabelle. + +**Parameter** | **Default-Wert** | **Beschreibung** +:---:|:---:|:---:| +--camera| 0 | OpenCV ID der Kamera. Wenn -1 angegeben ist, wird anstelle einer Kamera ein Video in Dauserschleife gespielt. +--mode| *virtual_cam* | Entweder *virtual_cam* (mit virtueller Kamera und Bildschirmausgabe) oder *screen* (nur Bildschirmausgabe) +--video | - | Gibt den Pfad zum Video an, wenn --camera=-1 ist + +**Hinweise:** +- Sollten Sie keine Kamera zur Verfügung haben, können Sie *--camera=-1* wählen, um ein Video zu verwenden +- Die Default-Werte sind in `main.py` definiert und können dort angepasst werden + +Nachdem Sie das Programm erfolgreich gestartet haben, sollten Sie das Bild der Kamera in einem neu geöffneten Fenster +sehen. Zu Beginn der Programmausführung wird kein CV-Algorithmus auf das Bild angewendet (Eingangsbild=Ausgangsbild). +Sie können verschiedene Funktionen bzw. Algorithmen durch betätigen verschiedener Tasten aktivieren. Als Standard sind +einige Funktionen auf den Tasten *1* bis *10* vorprogrammiert. Es ist ebenfalls möglich, mit Maus-Aktionen mit der +Pipeline zu interagieren. + +Mit den Tasten **f** und **e** können Sie den Auto**f**okus bzw. Auto**e**xposure aktivieren oder deaktivieren. + +**Hinweise:** +- Sie können nur mit der App interagieren, wenn das Programmfenster im Vordergrund ist! +- Autofokus und Autoexposure sind für viele Webcams nicht supported! + +## Eigene CV Algorithmen +Für die Implementierung eigener Algorithmen sind nur Dateien in dem Unterverzeichnis *algorithms* notwendig. Öffnen +Sie sich in das Verzeichnis und lesen die folgenden Abschnitte. Nachdem Sie die Abschnitte gelesen haben können Sie die Übungsaufgabe +in der Datei [exercise.md](./exercise.md) bearbeiten. + +### Eigenen "Algorithm" erstellen +Sie können einen eigenen Algorithmus erstellen, in dem Sie ein neues Skript in dem Ordner *algorithms* erstellen. Das +folgende Skript *algorithms/your_algorithm.py* zeigt einen beispielhaften Algorithmus, der einen Weißabgleich implementiert. + +```python +import cv2 +import numpy as np + +from . import Algorithm + + +class YourAlgorithm(Algorithm): + """ The implementation of your algorithm """ + + def __init__(self): + """ Inititation of your algorithm. You can store member variables here! """ + self.max_b, self.max_g, self.max_r = 255, 255, 255 + self.last_image = None + + def process(self, img): + """ Here the input image (img) is processed and returned """ + self.last_image = img + img = img.astype(np.float32) + img[:, :, 0] = np.clip(img[:, :, 0], 0, self.max_b) * 255 / max(1, self.max_b) + img[:, :, 1] = np.clip(img[:, :, 1], 0, self.max_g) * 255 / max(1, self.max_g) + img[:, :, 2] = np.clip(img[:, :, 2], 0, self.max_r) * 255 / max(1, self.max_r) + img = img.astype(np.uint8) + return img + + def mouse_callback(self, event, x, y, flags, param): + """ The mouse callback react on mouse events """ + if self.last_image is None: + return + if event == cv2.EVENT_LBUTTONUP: + self.max_b, self.max_g, self.max_r = \ + self.last_image[y, x, 0], self.last_image[y, x, 1], self.last_image[y, x, 2] +``` + +Die Funktion *\_\_init\_\_(self)* wird bei der Erstellung des Algorithmus aufgerufen. Sie können dort Variablen definieren, +die während der gesamten Laufzeit gespeichert bleiben. So können Sie z.B. Daten zwischen der Eingabe mehrerer Bilder +speichern. +Die Funktion *process.py(self, img)* verarbeitet jedes ausgelesene Bild. Am Ende der Funktion **muss** ein Bild mit selber Höhe und +Breite ausgegben werden. +Die Funktion *mouse_callback(self, event, x, y, flags, param)* wird bei Maus-Events ausgeführt. Für weitere Information +lesen Sie z.B. [hier](https://techtutorialsx.com/2020/12/08/python-opencv-mouse-events/). + +In dem Ordner *algorithms* sind mehrere Beispiele für Algorithmen gegeben. + +### Verlinken des eigenen Algorithmus zu einer Taste +Ihr Algorithmus *YourAlgorithm* kann nun zu einer Taste verlinkt werden. Der folgende Code entspricht in etwa dem Inhalt +der Datei *\_\_init\_\_.py*. Ihr Algorithmus ist in dem Beispiel an die Taste *3* verlinkt. Um weitere Algorithmen zu +verlinken müssen Sie lediglich einen weiteren Import und einen Eintrag in das algorithmus-dictionary hinzufügen. + +```python +class Algorithm: + + def process(self, img): + return img + + def mouse_callback(self, event, x, y, flags, param): + return + +from .image_to_gray import ImageToGray +from .image_to_hue import ImageToHue +from .your_algorithm import YourAlgorithm + +algorithms = dict() +algorithms["0"] = Algorithm +algorithms["1"] = ImageToGray +algorithms["2"] = ImageToHue +algorithms["3"] = YourAlgorithm +``` + +## Anforderungen +Hardware: + - Webcam, die von OpenCV eingelesen werden kann + +Getestet mit Python Versionen: + - 3.6 + +Getestet auf Betriebssystemen: + - Windows 10 + - OpenSuse (pyvirtualcam funktioniert nicht!) + diff --git a/CV-App/algorithms/__init__.py b/CV-App/algorithms/__init__.py new file mode 100644 index 0000000..4877221 --- /dev/null +++ b/CV-App/algorithms/__init__.py @@ -0,0 +1,38 @@ + + +class Algorithm: + """ An abstract class to create custom algorithms """ + def process(self, img): + """ Processes the input image""" + return img + + def mouse_callback(self, event, x, y, flags, param): + """ Reacts on mouse callbacks """ + return + + +''' Import algorithms to use''' +from .image_to_gray import ImageToGray +from .image_to_hue import ImageToHue +from .motion_detector import MotionDetector +from .white_balancing import WhiteBalancing +from .spin import Spin +from .segmentation_tracker import SegmentationTracker +#from .object_detection import ObjectDetector +#from .bottle_detection import BottleDetector +from .invis_cloak import InvisCloak +from .canny_edges import CannyEdgeDetector + +''' Link Algorithms to keys ''' +algorithms = dict() +algorithms["0"] = Algorithm +algorithms["1"] = ImageToGray +algorithms["2"] = ImageToHue +algorithms["3"] = MotionDetector +algorithms["4"] = WhiteBalancing +algorithms["5"] = Spin +algorithms["6"] = SegmentationTracker +algorithms["7"] = InvisCloak +#algorithms["7"] = ObjectDetector +#algorithms["8"] = BottleDetector +algorithms["9"] = CannyEdgeDetector diff --git a/CV-App/algorithms/bottle_detection.py b/CV-App/algorithms/bottle_detection.py new file mode 100644 index 0000000..e0bd842 --- /dev/null +++ b/CV-App/algorithms/bottle_detection.py @@ -0,0 +1,69 @@ +""" +Many thanks to https://github.com/vardanagarwal/Proctoring-AI/blob/master/coco models/tflite mobnetv1 ssd +""" + + +import cv2 +import numpy as np +import threading +from copy import copy +from time import sleep + +from . object_detection import Detector +from . import Algorithm + + +class BottleDetector(Algorithm): + """ Detects objects """ + + def __init__(self): + """ Init some values and set seed point to None """ + self.objects = dict() + self.detection_image = None + self.lock = threading.Lock() + self.thread = threading.Thread(target=self._detect, args=[], daemon=True) + self.thread.start() + + def process(self, img): + """ + Tries to segment a region around the seed point and calculates a new seed point by finding the segments center + """ + with self.lock: + if self.detection_image is None: + self.detection_image = np.copy(img) + with self.lock: + objects = copy(self.objects) + h, w, c = img.shape + + if "detection_classes_name" in objects.keys(): + for i, cls in enumerate(objects["detection_classes_name"]): + name = cls["name"] + if name in ["bottle", "cup"]: + box = objects["detection_boxes"][i] + score = objects["detection_scores"][i] + y1, x1, y2, x2 = \ + max(round(box[0] * h) - 20, 0), round(box[1] * w) - 20 ,\ + max(round(box[2] * h) + 20, 0), round(box[3] * w) + 20 + if img[y1:y2, x1:x2].size > 0: + img[y1:y2, x1:x2] = cv2.medianBlur(img[y1:y2, x1:x2], 31) + + return img.astype(np.uint8) + + def _detect(self): + detector = Detector() + while True: + with self.lock: + img = self.detection_image + if img is None: + sleep(.033) + continue + objects = detector.make_inference(img, score_thresh=0.1) + with self.lock: + self.objects = objects + self.detection_image = None + + def mouse_callback(self, event, x, y, flags, param): + """ Selects a new seed point""" + if event == cv2.EVENT_LBUTTONUP: + pass + diff --git a/CV-App/algorithms/canny_edges.py b/CV-App/algorithms/canny_edges.py new file mode 100644 index 0000000..97a13b1 --- /dev/null +++ b/CV-App/algorithms/canny_edges.py @@ -0,0 +1,40 @@ +import cv2 +import numpy as np + + +from . import Algorithm + + +class CannyEdgeDetector(Algorithm): + """ Converts a BGR image to grayscale""" + def __init__(self): + self.image_count = 0 + self.background = None + self.background_update_rate = 0.2 + self.threshold = 15 + + def process(self, img): + img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + h, w = img_gray.shape + resized_image = cv2.resize(img_gray, (int(w/2), int(h/2)), interpolation=cv2.INTER_NEAREST) + blurred_img = cv2.GaussianBlur(resized_image, (15, 15), 0) + + if self.background is None: + self.background = blurred_img + self.background = (1 - self.background_update_rate) * self.background + self.background_update_rate * blurred_img + + diff = blurred_img - self.background + diff_abs = np.abs(diff) + binary_image = diff_abs > self.threshold + + canny_edges = canny(resized_image, 50, 100) + + canny_edges = canny_edges * binary_image + canny_edges = cv2.resize(canny_edges, (int(w), int(h)), interpolation=cv2.INTER_NEAREST) + + return canny_edges + + +def canny(img, thresh1, thresh2): + img = cv2.Canny(img, thresh1, thresh2) + return img \ No newline at end of file diff --git a/CV-App/algorithms/image_to_gray.py b/CV-App/algorithms/image_to_gray.py new file mode 100644 index 0000000..b83c194 --- /dev/null +++ b/CV-App/algorithms/image_to_gray.py @@ -0,0 +1,10 @@ +import cv2 + +from . import Algorithm + + +class ImageToGray(Algorithm): + """ Converts a BGR image to grayscale""" + def process(self, img): + img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + return img diff --git a/CV-App/algorithms/image_to_hue.py b/CV-App/algorithms/image_to_hue.py new file mode 100644 index 0000000..6f6a9eb --- /dev/null +++ b/CV-App/algorithms/image_to_hue.py @@ -0,0 +1,13 @@ +import cv2 +import numpy as np + +from . import Algorithm + + +class ImageToHue(Algorithm): + """ Normalizes a BGR image with color information""" + def process(self, img): + channel_sum = np.sum(img.astype(np.float32), axis=2, keepdims=True) + img_normalized = img.astype(np.float32) * 255 / channel_sum + img_normalized = img_normalized.astype(np.uint8()) + return img_normalized diff --git a/CV-App/algorithms/invis_cloak.py b/CV-App/algorithms/invis_cloak.py new file mode 100644 index 0000000..a7ecb25 --- /dev/null +++ b/CV-App/algorithms/invis_cloak.py @@ -0,0 +1,118 @@ +import cv2 +import numpy as np +from copy import deepcopy +from matplotlib import pyplot as plt + +from . import Algorithm + + +class InvisCloak (Algorithm): + + """ init function """ + def __init__(self): + pass + + """ Processes the input image""" + def process(self, img): + + """ 2.1 Vorverarbeitung """ + """ 2.1.1 Rauschreduktion """ + plotNoise = False # Schaltet die Rauschvisualisierung ein + if plotNoise: + self._plotNoise(img, "Rauschen vor Korrektur") + img = self._211_Rauschreduktion(img) + if plotNoise: + self._plotNoise(img, "Rauschen nach Korrektur") + """ 2.1.2 HistogrammSpreizung """ + img = self._212_HistogrammSpreizung(img) + + + """ 2.2 Farbanalyse """ + """ 2.2.1 RGB """ + self._221_RGB(img) + """ 2.2.2 HSV """ + self._222_HSV(img) + + + """ 2.3 Segmentierung und Bildmdifikation """ + img = self._23_SegmentUndBildmodifizierung(img) + + return img + + """ Reacts on mouse callbacks """ + def mouse_callback(self, event, x, y, flags, param): + if event == cv2.EVENT_LBUTTONUP: + print("A Mouse click happend! at position", x, y) + + def _plotNoise(self, img, name:str): + height, width = np.array(img.shape[:2]) + centY = (height / 2).astype(int) + centX = (width / 2).astype(int) + + cutOut = 5 + tmpImg = deepcopy(img) + tmpImg = tmpImg[centY - cutOut:centY + cutOut, centX - cutOut:centX + cutOut, :] + + outSize = 500 + tmpImg = cv2.resize(tmpImg, (outSize, outSize), interpolation=cv2.INTER_NEAREST) + + cv2.imshow(name, tmpImg) + cv2.waitKey(1) + + def _211_Rauschreduktion(self, img): + """ + Hier steht Ihr Code zu Aufgabe 2.1.1 (Rauschunterdrückung) + - Implementierung Mittelwertbildung über N Frames + """ + + + return img + + def _212_HistogrammSpreizung(self, img): + """ + Hier steht Ihr Code zu Aufgabe 2.1.2 (Histogrammspreizung) + - Transformation HSV + - Histogrammspreizung berechnen + - Transformation BGR + """ + + return img + + def _221_RGB(self, img): + """ + Hier steht Ihr Code zu Aufgabe 2.2.1 (RGB) + - Histogrammberechnung und Analyse + """ + pass + + + def _222_HSV(self, img): + """ + Hier steht Ihr Code zu Aufgabe 2.2.2 (HSV) + - Histogrammberechnung und Analyse im HSV-Raum + """ + pass + + + def _23_SegmentUndBildmodifizierung (self, img): + """ + Hier steht Ihr Code zu Aufgabe 2.3.1 (StatischesSchwellwertverfahren) + - Binärmaske erstellen + """ + + + """ + Hier steht Ihr Code zu Aufgabe 2.3.2 (Binärmaske) + - Binärmaske optimieren mit Opening/Closing + - Wahl größte zusammenhängende Region + """ + + + """ + Hier steht Ihr Code zu Aufgabe 2.3.1 (Bildmodifizerung) + - Hintergrund mit Mausklick definieren + - Ersetzen des Hintergrundes + """ + + + return img \ No newline at end of file diff --git a/CV-App/algorithms/motion_detector.py b/CV-App/algorithms/motion_detector.py new file mode 100644 index 0000000..3b39a6b --- /dev/null +++ b/CV-App/algorithms/motion_detector.py @@ -0,0 +1,45 @@ +import cv2 +import numpy as np + + +from . import Algorithm + + +class MotionDetector(Algorithm): + """ Converts a BGR image to grayscale""" + def __init__(self): + self.image_count = 0 + self.background = None + self.motion_field = None + self.background_update_rate = 0.5 + self.motion_update_rate = 0.3 + self.threshold = 50 + + def process(self, img): + img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + h, w = img_gray.shape + blurred_img = cv2.resize(img_gray, (int(w/2), int(h/2)), interpolation=cv2.INTER_NEAREST) + blurred_img = cv2.GaussianBlur(blurred_img, (15, 15), 0) + + if self.background is None: + self.background = blurred_img + self.motion_field = np.zeros_like(blurred_img) + + self.background = (1 - self.background_update_rate) * self.background + self.background_update_rate * blurred_img + + diff = blurred_img - self.background + diff_abs = np.abs(diff) + diff_rel = np.clip(diff_abs, 0, self.threshold) / self.threshold + self.motion_field = (1 - self.motion_update_rate) * self.motion_field + self.motion_update_rate * diff_rel + + motion_field = cv2.resize(self.motion_field, (w, h), interpolation=cv2.INTER_NEAREST) + motion_field = np.expand_dims(motion_field, 2) + + colormap = cv2.applyColorMap((motion_field * 255).astype(np.uint8), cv2.COLORMAP_HOT) + img_gray = np.stack([img_gray, img_gray, img_gray], axis=2) + final_image = 0.5 * img_gray * (1 - motion_field) + colormap * motion_field + final_image = final_image.astype(np.uint8) + + self.image_count += 1 + + return final_image diff --git a/CV-App/algorithms/object_detection.py b/CV-App/algorithms/object_detection.py new file mode 100644 index 0000000..11a9f38 --- /dev/null +++ b/CV-App/algorithms/object_detection.py @@ -0,0 +1,179 @@ +""" +Many thanks to https://github.com/vardanagarwal/Proctoring-AI/blob/master/coco models/tflite mobnetv1 ssd +""" + + +import cv2 +import numpy as np +import multiprocessing +import threading +import os +from copy import copy +from time import sleep + +from . import Algorithm + +""" Check if neural network accelerator is existing """ +try_edgetpu = True +try: + if not try_edgetpu: + raise Exception() + from pycoral.adapters import common + from pycoral.adapters import detect + from pycoral.utils.dataset import read_label_file + from pycoral.utils.edgetpu import make_interpreter, list_edge_tpus + if len(list_edge_tpus()) == 0: + raise Exception() + engine = "edgetpu" +except Exception as e: + import tensorflow as tf + engine = "tflite" + + +class Detector: + def __init__(self): + self.category_index = self.create_category_index() + if engine == "tflite": + self.num_threads = int(multiprocessing.cpu_count()) + print("Self using %s threads for object detection" % self.num_threads) + self.interpreter = tf.lite.Interpreter( + model_path="data" + os.sep + "ssd_mobilenet_v2_coco_quant_postprocess.tflite", num_threads=self.num_threads + ) + self.interpreter.allocate_tensors() + # Get input and output tensors. + self.input_details = self.interpreter.get_input_details() + self.output_details = self.interpreter.get_output_details() + elif engine == "edgetpu": + print("Running with edge tpu") + self.interpreter = make_interpreter("data" + os.sep + "ssd_mobilenet_v2_coco_quant_postprocess_edgetpu.tflite") + self.interpreter.allocate_tensors() + # Get input and output tensors. + self.input_details = self.interpreter.get_input_details() + self.output_details = self.interpreter.get_output_details() + + def create_category_index(self, label_path='data' + os.sep + 'labelmap.txt'): + f = open(label_path) + category_index = {} + for i, val in enumerate(f): + if i != 0: + val = val[:-1] + category_index.update({(i - 1): {'id': (i - 1), 'name': val}}) + f.close() + return category_index + + def get_output_dict(self, nms=True, iou_thresh=0.5, score_thresh=0.5): + output_dict = { + 'detection_boxes': self.interpreter.get_tensor(self.output_details[0]['index'])[0], + 'detection_classes': self.interpreter.get_tensor(self.output_details[1]['index'])[0], + 'detection_scores': self.interpreter.get_tensor(self.output_details[2]['index'])[0], + 'num_detections': self.interpreter.get_tensor(self.output_details[3]['index'])[0] + } + output_dict['detection_classes'] = output_dict['detection_classes'].astype(np.int64) + output_dict["detection_classes_name"] = [self.category_index[x] for x in output_dict["detection_classes"]] + if nms and engine == "tflite": + output_dict = self.apply_nms(output_dict, iou_thresh, score_thresh) + if nms and engine == "edgetpu": + valid = np.where(output_dict["detection_scores"] >= score_thresh)[0] + if valid.size == 0: + output_dict = {} + elif valid.size == 1: + output_dict = { + 'detection_boxes': output_dict["detection_boxes"][valid[0]:valid[0] + 1], + 'detection_classes': output_dict["detection_classes"][valid[0]:valid[0] + 1], + 'detection_scores': output_dict["detection_scores"][valid[0]:valid[0] + 1], + 'detection_classes_name': output_dict["detection_classes_name"][valid[0]:valid[0] + 1], + 'num_detections': 1, + } + else: + output_dict = { + 'detection_boxes': output_dict["detection_boxes"][valid], + 'detection_classes': output_dict["detection_classes"][valid], + 'detection_scores': output_dict["detection_scores"][valid], + 'detection_classes_name': [x for i,x in enumerate(output_dict["detection_classes_name"]) if i in valid], + 'num_detections': valid.size, + } + return output_dict + + def apply_nms(self, output_dict, iou_thresh=0.5, score_thresh=0.5): + q = 90 # no of classes + num = int(output_dict['num_detections']) + boxes = np.zeros([1, num, q, 4]) + scores = np.zeros([1, num, q]) + # val = [0]*q + for i in range(num): + # indices = np.where(classes == output_dict['detection_classes'][i])[0][0] + boxes[0, i, output_dict['detection_classes'][i], :] = output_dict['detection_boxes'][i] + scores[0, i, output_dict['detection_classes'][i]] = output_dict['detection_scores'][i] + nmsd = tf.image.combined_non_max_suppression( + boxes=boxes, scores=scores, max_output_size_per_class=num, max_total_size=num, iou_threshold=iou_thresh, + score_threshold=score_thresh, pad_per_class=False, clip_boxes=False + ) + valid = nmsd.valid_detections[0].numpy() + output_dict = { + 'detection_boxes': nmsd.nmsed_boxes[0].numpy()[:valid], + 'detection_classes': nmsd.nmsed_classes[0].numpy().astype(np.int64)[:valid], + 'detection_scores': nmsd.nmsed_scores[0].numpy()[:valid], + 'detection_classes_name': output_dict["detection_classes_name"][:valid] + } + return output_dict + + def make_inference(self, img, nms=True, score_thresh=0.5, iou_thresh=0.5): + img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + img_rgb = cv2.resize(img_rgb, (300, 300), cv2.INTER_AREA) + img_rgb = img_rgb.reshape([1, 300, 300, 3]) + self.interpreter.set_tensor(self.input_details[0]['index'], img_rgb) + self.interpreter.invoke() + output_dict = self.get_output_dict(nms, iou_thresh, score_thresh) + return output_dict + + +class ObjectDetector(Algorithm): + """ Detects objects """ + + def __init__(self): + """ Init some values and set seed point to None """ + self.objects = dict() + self.detection_image = None + self.lock = threading.Lock() + self.thread = threading.Thread(target=self._detect, args=[], daemon=True) + self.thread.start() + + def process(self, img): + """ + Tries to segment a region around the seed point and calculates a new seed point by finding the segments center + """ + with self.lock: + if self.detection_image is None: + self.detection_image = np.copy(img) + with self.lock: + objects = copy(self.objects) + h, w, c = img.shape + if "detection_classes_name" in objects.keys(): + for i, cls in enumerate(objects["detection_classes_name"]): + box = objects["detection_boxes"][i] + score = objects["detection_scores"][i] + name = cls["name"] + y1, x1, y2, x2 = round(box[0] * h), round(box[1] * w), round(box[2] * h), round(box[3] * w) + img = cv2.rectangle(img, (x1, y1), (x2, y2), color=(0, 0, 0), thickness=2) + img = cv2.putText(img, "%s: %.2f" % (name, score), (x1, y1), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=1, color=(0, 0, 0)) + + return img + + def _detect(self): + detector = Detector() + while True: + with self.lock: + img = self.detection_image + if img is None: + sleep(.033) + continue + objects = detector.make_inference(img) + with self.lock: + self.objects = objects + self.detection_image = None + + def mouse_callback(self, event, x, y, flags, param): + """ Selects a new seed point""" + if event == cv2.EVENT_LBUTTONUP: + pass + diff --git a/CV-App/algorithms/segmentation_tracker.py b/CV-App/algorithms/segmentation_tracker.py new file mode 100644 index 0000000..ea47ab7 --- /dev/null +++ b/CV-App/algorithms/segmentation_tracker.py @@ -0,0 +1,71 @@ +import cv2 +import numpy as np + +from . import Algorithm + + +class SegmentationTracker(Algorithm): + """ Tracks a point by re-identify a suitable segmentation """ + + def __init__(self): + """ Init some values and set seed point to None """ + self.pos = None + self.distance_threshold = 80 + self.reference_pixel = None + + def process(self, img): + """ + Tries to segment a region around the seed point and calculates a new seed point by finding the segments center + """ + if self.pos is None: + result = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + result = np.stack([result, result, result], axis=2) + return result + h, w, c = img.shape + + if self.reference_pixel is None: + self.reference_pixel = np.copy(img[self.pos[1], self.pos[0]]) + pixel_low, pixel_high = \ + np.maximum(0, self.reference_pixel-self.distance_threshold),\ + np.minimum(255, self.reference_pixel+self.distance_threshold) + binary = cv2.inRange(img, pixel_low, pixel_high) + + element = np.ones((5, 5), dtype=np.uint8) + binary = cv2.erode(binary, element) + binary = cv2.dilate(binary, element) + sure_background = binary + sure_foreground = np.zeros_like(sure_background) + x, y = max(2, self.pos[0]), max(2, self.pos[1]) + sure_foreground[y-2:y+2, x-5:x+2] = 1 + unknown = np.maximum(0, sure_background - sure_foreground) + + ret, markers = cv2.connectedComponents(sure_foreground) + # Add one to all labels so that sure background is not 0, but 1 + markers = markers + 1 + # Now, mark the region of unknown with zero + markers[unknown == 255] = 0 + markers = cv2.watershed(img, markers) + + try: + contours, hierarchy = cv2.findContours(((markers == 2) * 1).astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) + c = contours[0] + M = cv2.moments(c) + cX = int(M["m10"] / M["m00"]) + cY = int(M["m01"] / M["m00"]) + self.pos = (min(cX, w-1), min(cY, h-1)) + except: + pass + + result = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + result = np.stack([result, result, result], axis=2) + random_noise = np.random.randint(0, 255, (h, w), dtype=np.uint8) + random_noise = cv2.applyColorMap(random_noise, colormap=cv2.COLORMAP_INFERNO) + result[markers == 2] = random_noise[markers == 2] + return result + + def mouse_callback(self, event, x, y, flags, param): + """ Selects a new seed point""" + if event == cv2.EVENT_LBUTTONUP: + self.pos = (x, y) + self.reference_pixel = None + diff --git a/CV-App/algorithms/silhouette_ghost.py b/CV-App/algorithms/silhouette_ghost.py new file mode 100644 index 0000000..67c4c3b --- /dev/null +++ b/CV-App/algorithms/silhouette_ghost.py @@ -0,0 +1,131 @@ +import cv2 +import numpy as np +from copy import deepcopy +from matplotlib import pyplot as plt + +from . import Algorithm + + +class SilhouetteGhost (Algorithm): + + """ init function """ + def __init__(self): + self.image_count = 0 + self.background = None + self.background_update_rate = 0.2 + self.threshold = 15 + + """ Processes the input image""" + def process(self, img): + + """ 2.1 Vorverarbeitung """ + """ 2.1.1 Rauschreduktion """ + plotNoise = False # Schaltet die Rauschvisualisierung ein + if plotNoise: + self._plotNoise(img, "Rauschen vor Korrektur") + img = self._211_Rauschreduktion(img) + if plotNoise: + self._plotNoise(img, "Rauschen nach Korrektur") + """ 2.1.2 HistogrammSpreizung """ + img = self._212_HistogrammSpreizung(img) + + + """ 2.2 Vordergrund-Detektion """ + img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + h, w = img_gray.shape + resized_img_gray = cv2.resize(img_gray, (int(w/2), int(h/2)), interpolation=cv2.INTER_NEAREST) + blurred_img = cv2.GaussianBlur(resized_img_gray, (15, 15), 0) + + if self.background is None: + self.background = blurred_img + self.background = (1 - self.background_update_rate) * self.background + self.background_update_rate * blurred_img + + diff = blurred_img - self.background + diff_abs = np.abs(diff) + binary_image = diff_abs > self.threshold + + """ 2.2.1 Opening und Closing """ + binary_image = self._221_OpeningClosing(binary_image) + + """ 2.3 Canny-Edge und Bildmodifizierung """ + canny_edges = self._231_CannyEdge(resized_img_gray) + + canny_edges = canny_edges * binary_image + canny_edges = cv2.resize(canny_edges, (int(w), int(h)), interpolation=cv2.INTER_NEAREST) + + return canny_edges + + """ Reacts on mouse callbacks """ + def mouse_callback(self, event, x, y, flags, param): + if event == cv2.EVENT_LBUTTONUP: + print("A Mouse click happend! at position", x, y) + + + def _plotNoise(self, img, name:str): + height, width = np.array(img.shape[:2]) + centY = (height / 2).astype(int) + centX = (width / 2).astype(int) + + cutOut = 5 + tmpImg = deepcopy(img) + tmpImg = tmpImg[centY - cutOut:centY + cutOut, centX - cutOut:centX + cutOut, :] + + outSize = 500 + tmpImg = cv2.resize(tmpImg, (outSize, outSize), interpolation=cv2.INTER_NEAREST) + + cv2.imshow(name, tmpImg) + cv2.waitKey(1) + + def _211_Rauschreduktion(self, img): + """ + Hier steht Ihr Code zu Aufgabe 2.1.1 (Rauschunterdrückung) + - Implementierung Mittelwertbildung über N Frames + """ + + + return img + + def _212_HistogrammSpreizung(self, img): + """ + Hier steht Ihr Code zu Aufgabe 2.1.2 (Histogrammspreizung) + - Transformation HSV + - Histogrammspreizung berechnen + - Transformation BGR + """ + + return img + + def _221_OpeningClosing(self, binary_image): + """ + Hier steht Ihr Code zu Aufgabe 2.2.1 (Opening and Closing) + - Implementieren Sie das Closing + - Speichern Sie das aktuelle Bild vor und nach der Funktion beim Mausklick + """ + + return binary_image + + def _231_CannyEdge (self, img_gray): + """ + Hier steht Ihr Code zu Aufgabe 2.3.1 (Manuelle Canny Edge Implementierung) + - Glättung + - Gradienten berechnen + - Nicht-Maximum Unterdrückung + - Hysterese Unterdrückung + """ + + """ 1. Glättung """ + + + """ 2. Gradienten berechnen """ + + + """ 3. Nicht-Maximum Unterdrückung """ + + + """ 4. Hysterese Unterdrückung """ + #parameter: + thresh1 = 50 + thresh2 = 100 + + + return np.ones_like(img_gray) * 255 # hier eigenes Edge-Bild ausgeben \ No newline at end of file diff --git a/CV-App/algorithms/spin.py b/CV-App/algorithms/spin.py new file mode 100644 index 0000000..f337e32 --- /dev/null +++ b/CV-App/algorithms/spin.py @@ -0,0 +1,21 @@ +import cv2 +import numpy as np + +from . import Algorithm + + +class Spin(Algorithm): + """ Rotates an image """ + + def __init__(self): + self.current_angle = 0 # between 0 and 2 pi + self.anlge_per_image = 360 / 100 + + def process(self, img): + self.current_angle = (self.current_angle + self.anlge_per_image) % 360 + w, h = img.shape[1], img.shape[0] + image_center = (w / 2, h / 2) + rot_mat = cv2.getRotationMatrix2D(image_center, self.current_angle, 1.0) + img = cv2.warpAffine(img, rot_mat, (w, h), flags=cv2.INTER_LINEAR) + return img + diff --git a/CV-App/algorithms/tutorial_algorithm.py b/CV-App/algorithms/tutorial_algorithm.py new file mode 100644 index 0000000..d80f98a --- /dev/null +++ b/CV-App/algorithms/tutorial_algorithm.py @@ -0,0 +1,30 @@ +import cv2 + +from . import Algorithm + + +class TutorialAlgorithm(Algorithm): + """ Writes the RGB values of an pixel to the output image """ + + def __init__(self): + """ Init reference point with None value """ + + def process(self, img): + """ + Reads out the RGB values of the reference point and writes it to the output image + """ + if self.pos is not None: + pixel = img[self.pos[1], self.pos[0]] + text = "x:%s y:%s R:%s G:%s B:%s" % (self.pos[0], self.pos[1], pixel[2], pixel[1], pixel[0]) + else: + text = "Click on the image!" + font, org, font_scale, color, thickness = cv2.FONT_HERSHEY_SIMPLEX, (50, 50), 1, (0, 0, 0), 2 + image = cv2.putText(img, text, org, font, font_scale, color, thickness, cv2.LINE_AA) + + return image + + def mouse_callback(self, event, x, y, flags, param): + """ Selects a new reference position""" + if event == cv2.EVENT_LBUTTONUP: + # Store x and y to the member value self.pos + pass diff --git a/CV-App/algorithms/tutorial_algorithm_solution.py b/CV-App/algorithms/tutorial_algorithm_solution.py new file mode 100644 index 0000000..4f009af --- /dev/null +++ b/CV-App/algorithms/tutorial_algorithm_solution.py @@ -0,0 +1,31 @@ +import cv2 + +from . import Algorithm + + +class TutorialAlgorithm(Algorithm): + """ Writes the RGB values of an pixel to the output image """ + + def __init__(self): + """ Init reference point with None value """ + self.pos = None + + def process(self, img): + """ + Reads out the RGB values of the reference point and writes it to the output image + """ + if self.pos is not None: + pixel = img[self.pos[1], self.pos[0]] + text = "x:%s y:%s R:%s G:%s B:%s" % (self.pos[0], self.pos[1], pixel[2], pixel[1], pixel[0]) + else: + text = "Click on the image!" + font, org, font_scale, color, thickness = cv2.FONT_HERSHEY_SIMPLEX, (50, 50), 1, (0, 0, 0), 2 + image = cv2.putText(img, text, org, font, font_scale, color, thickness, cv2.LINE_AA) + + return image + + def mouse_callback(self, event, x, y, flags, param): + """ Selects a new reference position""" + if event == cv2.EVENT_LBUTTONUP: + self.pos = (x, y) + diff --git a/CV-App/algorithms/white_balancing.py b/CV-App/algorithms/white_balancing.py new file mode 100644 index 0000000..2c30479 --- /dev/null +++ b/CV-App/algorithms/white_balancing.py @@ -0,0 +1,31 @@ +import cv2 +import numpy as np + +from . import Algorithm + + +class WhiteBalancing(Algorithm): + """ White Balancing """ + + def __init__(self): + """ Define Reference RGB values to (255, 255, 255) """ + self.max_b, self.max_g, self.max_r = 255, 255, 255 + self.last_image = None + + def process(self, img): + """ Performs white balancing based on the reference RGB values """ + self.last_image = img + img = img.astype(np.float32) + img[:, :, 0] = np.clip(img[:, :, 0], 0, self.max_b) * 255 / max(1, self.max_b) + img[:, :, 1] = np.clip(img[:, :, 1], 0, self.max_g) * 255 / max(1, self.max_g) + img[:, :, 2] = np.clip(img[:, :, 2], 0, self.max_r) * 255 / max(1, self.max_r) + img = img.astype(np.uint8) + return img + + def mouse_callback(self, event, x, y, flags, param): + """ Selects new reference RGB values, if left mouse button is clicked and self.last_image is defined """ + if self.last_image is None: + return + if event == cv2.EVENT_LBUTTONUP: + self.max_b, self.max_g, self.max_r = \ + self.last_image[y, x, 0], self.last_image[y, x, 1], self.last_image[y, x, 2] diff --git a/CV-App/data/cv1.png b/CV-App/data/cv1.png new file mode 100644 index 0000000..29f40e8 Binary files /dev/null and b/CV-App/data/cv1.png differ diff --git a/CV-App/data/cv2.png b/CV-App/data/cv2.png new file mode 100644 index 0000000..0081ab8 Binary files /dev/null and b/CV-App/data/cv2.png differ diff --git a/CV-App/data/cv3.png b/CV-App/data/cv3.png new file mode 100644 index 0000000..341424a Binary files /dev/null and b/CV-App/data/cv3.png differ diff --git a/CV-App/data/labelmap.txt b/CV-App/data/labelmap.txt new file mode 100644 index 0000000..c634db4 --- /dev/null +++ b/CV-App/data/labelmap.txt @@ -0,0 +1,91 @@ +??? +person +bicycle +car +motorcycle +airplane +bus +train +truck +boat +traffic light +fire hydrant +??? +stop sign +parking meter +bench +bird +cat +dog +horse +sheep +cow +elephant +bear +zebra +giraffe +??? +backpack +umbrella +??? +??? +handbag +tie +suitcase +frisbee +skis +snowboard +sports ball +kite +baseball bat +baseball glove +skateboard +surfboard +tennis racket +bottle +??? +wine glass +cup +fork +knife +spoon +bowl +banana +apple +sandwich +orange +broccoli +carrot +hot dog +pizza +donut +cake +chair +couch +potted plant +bed +??? +dining table +??? +??? +toilet +??? +tv +laptop +mouse +remote +keyboard +cell phone +microwave +oven +toaster +sink +refrigerator +??? +book +clock +vase +scissors +teddy bear +hair drier +toothbrush \ No newline at end of file diff --git a/CV-App/data/tutorial1.png b/CV-App/data/tutorial1.png new file mode 100644 index 0000000..ef2b481 Binary files /dev/null and b/CV-App/data/tutorial1.png differ diff --git a/CV-App/data/tutorial2.png b/CV-App/data/tutorial2.png new file mode 100644 index 0000000..506d2eb Binary files /dev/null and b/CV-App/data/tutorial2.png differ diff --git a/CV-App/data/tutorial3.png b/CV-App/data/tutorial3.png new file mode 100644 index 0000000..df7647a Binary files /dev/null and b/CV-App/data/tutorial3.png differ diff --git a/CV-App/exercise.md b/CV-App/exercise.md new file mode 100644 index 0000000..066c1a3 --- /dev/null +++ b/CV-App/exercise.md @@ -0,0 +1,117 @@ +# Übung: CV-Application +Um diese Übung lösen zu können, lesen Sie das [README.md](README.md). + +In dieser Übung vollenden Sie ein Skript, mit dem ein bestimmtes Pixel eines Bildes ausgewählt und dessen RGB-Werte angezeigt +werden können. Für diese Übung werden die Dateien [algorithms/tutorial_algorithm.py](./algorithms/tutorial_algorithm.py) und + [algorithms/\_\_init\_\_.py](./algorithms/__init__.py) modifiziert. Die Musterlösung für die Übung findet sich in der Datei + [algorithms/tutorial_algorithm_solution.py](./algorithms/tutorial_algorithm_solution.py). + + +## a) Einbinden des Algorithmus +Öffnen Sie die Datei [algorithms/\_\_init\_\_.py](./algorithms/__init__.py). Der Inhalt wird ungefähr wie der folgende +Code-Snippet aussehen: + +```python +class Algorithm: + """ An abstract class to create custom algorithms """ + def process(self, img): + """ Processes the input image""" + return img + + def mouse_callback(self, event, x, y, flags, param): + """ Reacts on mouse callbacks """ + return + + +''' Import algorithms to use''' +from .image_to_gray import ImageToGray +from .image_to_hue import ImageToHue +from .motion_detector import MotionDetector +from .white_balancing import WhiteBalancing +from .spin import Spin +from .segmentation_tracker import SegmentationTracker + +''' Link Algorithms to keys ''' +algorithms = dict() +algorithms["0"] = Algorithm +algorithms["1"] = ImageToGray +algorithms["2"] = ImageToHue +algorithms["3"] = MotionDetector +algorithms["4"] = WhiteBalancing +algorithms["5"] = Spin +algorithms["6"] = SegmentationTracker +``` + +Ihre Aufgabe ist es nun, den Algorithmus ``TutorialAlgorithm`` zu importieren und der Taste **7** zuzuordnen. + +## b) Vervollständigen des Scripts +Öffnen Sie das Skript [algorithms/tutorial_algorithm.py](./algorithms/tutorial_algorithm.py). Der Inhalt der Datei ähnelt dem +folgenden Code-Snippet: + +```python +import cv2 + +from . import Algorithm + + +class TutorialAlgorithm(Algorithm): + """ Writes the RGB values of an pixel to the output image """ + + def __init__(self): + """ Init reference point with None value """ + ### 1) INSERT self.pos ### + + def process(self, img): + """ + Reads out the RGB values of the reference point and writes it to the output image + """ + if self.pos is not None: + pixel = img[self.pos[1], self.pos[0]] + text = "x:%s y:%s R:%s G:%s B:%s" % (self.pos[0], self.pos[1], pixel[2], pixel[1], pixel[0]) + else: + text = "Click on the image!" + font, org, font_scale, color, thickness = cv2.FONT_HERSHEY_SIMPLEX, (50, 50), 1, (0, 0, 0), 2 + image = cv2.putText(img, text, org, font, font_scale, color, thickness, cv2.LINE_AA) + + return image + + def mouse_callback(self, event, x, y, flags, param): + """ Selects a new reference position""" + if event == cv2.EVENT_LBUTTONUP: + # Store x and y to the member value self.pos + ### 2) UPDATE self.pos ### + +``` + +Zu sehen ist eine Klasse Namens ``TutorialAlgorithm``, welche aus der Klasse ``Algorithm`` abgeleitet wurde. Zu sehen sind +die drei vordefinierten Funktionen ``__init__(self)``, ``process(self, img)`` und +``def mouse_callback(self, event, x, y, flags, param)`` (siehe [README.md](README.md)) + +Die Funktion ``process(self, img)`` ist bereits fertig implementiert und schreibt einen Text auf das Eingangsbild. Sie +greift auf die Variable ``self.pos`` zu, die bisher noch nicht definiert ist. + +Definieren Sie die Member-Variable ``self.pos`` in der Funktion ``__init__(self)`` und weisen Sie ihr den initialen Wert +*None* zu. Dafür vorgesehen ist die Zeile mit dem Inhalt ```### 1) INSERT self.pos ###```. + +Nun soll die Variable bei jedem Mausklick mit einem neuen Wert überschrieben werden. Speichern Sie bei jedem Mausklick +die x und y Werte als Tupel ``(x, y)`` in die Variable ``self.None``. Dafür vorgesehen ist die Zeile mit dem Inhalt +``### 2) UPDATE self.pos ###``. + +Das Programm ist nun einsatzbereit. + +## c) Ausführen des Skripts + +Führen Sie das Skript `main.py` aus diesem Verzeichnis mit dem Befehl + +```bash +python main.py --mode=screen +``` +aus. Nach dem das Skript gestartet wurde, drücken Sie die Taste **7**, um Ihren Algorithmus zu aktivieren. Klicken Sie +dann mit der Maustaste auf eine beliebige Stelle des Bildes. Nach dem Klick sollten die RGB-Werte der gewählten Position +ausgegeben werden. + +Die folgenden Abbildungen visualisieren einen beispielhaften Output aus dem Skript. + +Nach Start des Programms | Nach Betätigen der Taste **7** | Nach dem Klick auf das Bild +:-------------------------:|:-------------------------:|:-------------------------: +![](./data/tutorial1.png) | ![](./data/tutorial2.png) | ![](./data/tutorial3.png) \ No newline at end of file diff --git a/CV-App/main.py b/CV-App/main.py new file mode 100644 index 0000000..0084ed9 --- /dev/null +++ b/CV-App/main.py @@ -0,0 +1,131 @@ +""" +Main file for starting the CV-Application +More infos in the README.md file +""" + +import argparse +import cv2 +import platform +import numpy as np +import datetime + +DEFAULT_CAMERA = 0 +DEFAULT_MODE = "screen" # "screen", "virtual_cam" +DEFAULT_VIDEO = "DEFAULT VIDEO TO SHOW" +WINDOW_NAME = "Output" +FRAMERATE = 30 + +''' +The following code is to setup the framework +''' +print("=== INITIALIZE FRAMEWORK === ") + +# Read input arguments +parser = argparse.ArgumentParser(description='CV-App to demonstrate basic CV algorithms in a usefull application') +parser.add_argument( + '--camera', type=int, default=DEFAULT_CAMERA, help='The camera to be opened by the app') +parser.add_argument( + '--mode', type=str, default=DEFAULT_MODE, help="Either 'virtual_cam' for camera emulation or 'screen' for testing") +parser.add_argument( + '--video', type=str, default=DEFAULT_VIDEO, help="The video to use if no camera is available") + +args = parser.parse_args() + +# Check if arguments are valid +available_cameras = list() +print("Availlable cameras:") +for i in range(3): + temp = cv2.VideoCapture(i) + is_opened = temp.isOpened() + if is_opened: + available_cameras.append(i) + print(" camera with id", i) + temp.release() +assert args.mode in ["screen", "virtual_cam"], "Wrong mode selected! '%s' is not existing!" % args.mode +assert args.camera in available_cameras or args.camera == -1, "Wrong cam selected! '%s' is not existing!" % args.camera + +# Get current OS and import camera emulator software (skip if mode=='screen' is used) +current_os = platform.system() +print("Working on ", current_os) +if args.mode == "screen": + def show(img): + cv2.imshow(WINDOW_NAME, img) +elif current_os == "Darwin": + raise NotImplementedError +elif current_os == "Linux": + raise NotImplementedError +elif current_os == "Windows": + import pyvirtualcam + cam = None + + def show(img): + global cam + if cam is None: + h, w, c = img.shape + cam = pyvirtualcam.Camera(width=w, height=h, fps=20) + if len(img.shape) == 2: + img = np.stack([img, img, img], axis=2) + cv2.imshow(WINDOW_NAME, img) + img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + cam.send(img) + cam.sleep_until_next_frame() + +else: + raise Exception("OS %s not known!" % current_os) + +# Define CV algorithms you want to use in the application +from algorithms import algorithms + +current_algorithm_id = sorted(algorithms.keys())[0] +current_algorithm = algorithms[current_algorithm_id]() +cv2.namedWindow(WINDOW_NAME) +cv2.setMouseCallback(WINDOW_NAME, current_algorithm.mouse_callback) + +print("=== FINISHED INITIALIZING FRAMEWORK === \n\n") + + +''' +Following code runs the processing loop +''' +print("=== RUN PROCESSING LOOP === ") +input_source = args.camera if args.camera != -1 else args.video +print("Using input source", input_source) +cap = cv2.VideoCapture(input_source) +last_read = datetime.datetime.now() +auto_focus = True +auto_exposure = True +while True: + # Measure time to last read out to avoid to fast readout in videos + if datetime.datetime.now() - last_read < datetime.timedelta(milliseconds=int(1000 / FRAMERATE)): + continue + last_read = datetime.datetime.now() + # Read, process and show image + ret, img = cap.read() + if not ret and type(input_source) == str: + cap = cv2.VideoCapture(input_source) + ret, img = cap.read() + img = current_algorithm.process(img) + show(img) + # Check if a new + key = cv2.waitKey(1) + if key == -1: + continue + elif key == 27: + cap.release() + break + elif chr(key) in algorithms.keys(): + current_algorithm_id = chr(key) + current_algorithm = algorithms[current_algorithm_id]() + print("Set algorithm to %s selected by key '%s'" % (type(current_algorithm), chr(key))) + cv2.setMouseCallback(WINDOW_NAME, current_algorithm.mouse_callback) + elif chr(key) == "e" and type(input_source) == int: + auto_exposure = not auto_exposure + print("Set auto exposure to", int(auto_exposure)) + cap.set(propId=cv2.CAP_PROP_AUTO_EXPOSURE, value=int(auto_exposure)) + elif chr(key) == "f" and type(input_source) == int: + auto_focus = not auto_focus + print("Set auto focus to", int(auto_focus)) + cap.set(propId=cv2.CAP_PROP_AUTOFOCUS, value=int(auto_focus)) + +print("=== FINISHED PROCESSING LOOP AND STOP APPLICATION === ") + diff --git a/LICENCE b/LICENCE new file mode 100644 index 0000000..e69de29 diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..1542c5a --- /dev/null +++ b/Pipfile @@ -0,0 +1,18 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +"opencv.python" = "*" +numpy = "*" +matplotlib = "*" +scipy = "*" +opencv-python = "*" +pyvirtualcam = "*" +tensorflow = "*" + +[dev-packages] + +[requires] +python_version = "3" diff --git a/README.md b/README.md new file mode 100644 index 0000000..326a4f5 --- /dev/null +++ b/README.md @@ -0,0 +1,141 @@ +![alt text](./data/tnt_banner.svg) + +# Digitale Bildverarbeitung + +Sehr geehrte Studierende, + +dieses Github-Repository bietet Ihnen praktische Übungsmaterialien zur +Vorlesung "Digitale Bildverarbeitung" des [Instituts für Informationsverarbeitung](https://www.tnt.uni-hannover.de/en/) +an der [Leibniz Universität Hannover](https://www.uni-hannover.de/). + +Die Übungsmaterialien sollen die erlernten theoretischen Grundlagen +festigen und zusätzlich einen Einblick in die angewandte Praxis +moderner Bildverarbeitung geben. Den Studierenden wird mit +Programmierübungen gezeigt, wie einfache, aber auch komplexe Aufgaben +mithilfe von Grundlagen der Digitalen Bildverarbeitung gelößt werden +können. In den nächsten Abschnitten wird ein kurzer Überblick über +die Struktur und Inhalte dieses Online-Kurses gegeben. + +Die Autoren dieser Übungen würden sich freuen, wenn dieses Repository +das Interesse von Studierenden an der Bildverarbeitung wecken könnte, +dass über den Erwerb von Leistungspunkten hinaus geht. + +Gez. die Autoren + +--- + +## Struktur +Dieses Repository ist unterteilt in die Themenbereiche + + 0. Einführung + 1. Grundlagen + 2. Bildbearbeitung + 3. Signalorientierte Bildverarbeitung + 4. Farbrepäsentationen + 5. Bildanalyse + +welche jeweils mit Übungsaufgaben, Lösungen sowie begleitendem Material +ausgestattet sind. + +Zusätzlich sind die Ordnerstrukturen + - *CV-App*: + Pipeline für die Anwendung von BV Videokonferenzen + - *data*: Daten für die Verarbeitung, z.B. Bilder + - *utilities*: Allgemeine Hilfsskripte und Tools + - *Sandkasten*: Ort, um eigene Dinge auszuprobieren + +vorhanden. Die **CV-App** nimmt dabei eine besondere Position ein, da +den Studierenden hier mit einer Interaktiven Appliaktion der praktische +Nutzen von Bildverarbeitung demonstriert wird und ebenfalls Material +für fortgeschrittene Programmierübungen gegeben wird, welche hier nicht +explizit behandelt werden. + +--- + +Das Erlernen der Fertigkeiten aus der Vorlesung wird mit Übungen unterstützt. +Eine herkömmliche Übung bietet den Studierenden eine oder mehrere zu lösende +Aufgaben. Übungen sind in einem eigenen Unterordner wie z.B. **ü1** angelegt. Die Aufgaben sind in +der **README.md** beschrieben und sollen in der entsprechenden Datei mit Dateinamen wie `a.py` gelößt werden. +Zu jeder Übung gibt es eine Lösungsdatei mit einer +(von möglicherweise vielen!) Musterlösung. Die Lösungen sind mit der +Bennenung von z.B. `l_a.py` gekennzeichnet. + +--- + +Im folgenden werden die Themenschwerpunkte des Kurses kurz erläutert. + +### 0. Einführung +Der Themenbereich **Einführung** hilft den Studierenden bei der Installation, +Einrichtung und der ersten Nutzung der Arbeitsumgebungumgebung für diesen +Kurs. Es wird noch nicht auf den Themenkomplex Bildverarbeitung +eingegangen. + +Das Kapitel ist für Neulinge in den folgenden Bereichen zu empfehlen: + + - **Installation Python und/oder PyCharm** + - **Programmierung Python** + - **OpenCV und Numpy** + +### 1. 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. + +### 2. 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** + +### 3. 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** + +### 4. Farbrepäsentationen +Die Wahrnehmung von "Farbe" wird in technischen Anwendungen in verschiedenen Formen dargestellt und codiert. Zu +den Grundlagen der Farbrepräsentationen werden in diesem Kapitel Aufgaben und Beispiele bereitgestellt. +Die Aufgaben behandeln die Themengebiete + +- **Additive Subtraktive Farbmischung** +- **Farbempfinden und technische Repräsentation von Farbe** +- **Farbmodelle/Farbräume und Konvertierung** +- **Weißabgleich** + +### 5. Bildanalyse +Ein Ziel der Digitalen Bildverarbeitung ist die Extrahierung von Informationen aus Bilddaten, um nachfolgende Aufgaben +zu lösen. In diesem Kapitel werden einige Beispiele und Aufgaben zur Bildanalyse bereitgestellt. Dabei werden die Themen + +- **Diskrete Geometrie und Analyse von Binärbildern** +- **Bildsegmentierung** +- **Template-Matching und Korrelation** +- **Hough** + +behandelt. + +--- + +## FAQ, Kommentare und Hinweise + - Dieses Repository hat keinen Anspruch auf Vollständigkeit + - Hauptsprache der Kurses ist Deutsch + - Interessierte dürfen eigene Übungen erstellen und per Pull-Request + in das Repository einpflegen. Vielen Dank für das Engagement! + - Viel Spaß beim Lernen! diff --git a/Sandkasten/fft.py b/Sandkasten/fft.py new file mode 100644 index 0000000..6e47053 --- /dev/null +++ b/Sandkasten/fft.py @@ -0,0 +1,40 @@ +import cv2 +import numpy as np +from matplotlib import pyplot as plt + + +images = ["data/1.png", "data/2.png", "data/3.png", "data/4.png", "data/5.png"] + +lena = cv2.imread(images[0]) + +lena = cv2.cvtColor(lena, cv2.COLOR_BGR2GRAY) + +grauwerte, beugungen = list(), list() +for image in images: + image = cv2.imread(image) + gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) + grauwerte.append(gray) + f = np.fft.fft2(gray) # Fouriertransformation + fshift = np.fft.fftshift(f) # Umsortieren + FT = np.abs(fshift) + FT = np.log(np.abs(fshift)) # mit log() wird der Kontrast angehoben + beugungen.append(FT) + +i = 0 +for gray, FT in zip(grauwerte, beugungen): + i += 1 + plt.figure(figsize=(12, 12)) + plt.subplot(121) + plt.xticks([]), plt.yticks([]) + plt.imshow(gray, cmap = 'gray') + plt.title('Lena') + + plt.subplot(122) + plt.xticks([]), plt.yticks([]) + plt.imshow(FT, cmap=plt.cm.gray) + plt.title('Fouriertransformierte von Lena') + #plt.show() + FT = np.round( 255 * (FT + np.min(FT)) / (np.abs(np.max(FT)) + np.abs(np.min(FT)))) + cv2.imwrite(f"/home/kaiser/Schreibtisch/ownCloud/Vorlesung/DigitaleBildverarbeitung/Klausuren/Klausur_WS2021/images/fft/{i}_grau.png", gray) + cv2.imwrite(f"/home/kaiser/Schreibtisch/ownCloud/Vorlesung/DigitaleBildverarbeitung/Klausuren/Klausur_WS2021/images/fft/{i}_fft.png", FT) + #print(np.max(FT), np.min(FT)) \ No newline at end of file diff --git a/Sandkasten/flaschen_transformation.py b/Sandkasten/flaschen_transformation.py new file mode 100644 index 0000000..19ccaea --- /dev/null +++ b/Sandkasten/flaschen_transformation.py @@ -0,0 +1,29 @@ +import cv2 +import numpy as np +import math + + +img = cv2.imread("data/flasche.jpeg") +img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) +x, y = 300, 270 +img = img[y:y+900, x:x+900] +img = cv2.resize(img, (300, 300)) +rows, cols = img.shape +print(rows, cols) +alpha = np.pi / 4 +M1 = np.float32([ + [np.cos(alpha), -np.sin(alpha), 150], + [np.sin(alpha), np.cos(alpha), 0] +]) + + +dst1 = cv2.warpAffine(img, M1 ,(cols,rows)) + + +cv2.imshow("A", img) +cv2.imshow("1", dst1) + +cv2.waitKey(0) + +#cv2.imwrite("/home/kaiser/Schreibtisch/ownCloud/Vorlesung/DigitaleBildverarbeitung/Klausuren/Klausur_WS2021/images/flasche_original.png", img) +#cv2.imwrite("/home/kaiser/Schreibtisch/ownCloud/Vorlesung/DigitaleBildverarbeitung/Klausuren/Klausur_WS2021/images/flasche_rotated.png", dst1) diff --git a/Sandkasten/gray_image.py b/Sandkasten/gray_image.py new file mode 100644 index 0000000..22bc20b --- /dev/null +++ b/Sandkasten/gray_image.py @@ -0,0 +1,35 @@ +import cv2 +import numpy as np +from matplotlib import pyplot as plt + + +a = [ + [220, 0, 150, 3, 100, 0], + [0, 250, 3, 160, 0, 100], + [150, 0, 203, 0, 165, 5], + [2, 145, 5, 205, 0, 150], + [99, 0, 150, 0, 255, 2], + [1, 105, 0, 160, 0, 250], +] + +b = [ + [0, 1, 0, 0, 0, 0], + [1, 0, 1, 0, 0, 0], + [0, 1, 0, 1, 0, 0], + [0, 0, 1, 0, 1, 0], + [0, 0, 0, 1, 0, 1], + [0, 0, 0, 0, 1, 0], +] + + +a = np.array(a, dtype=np.uint8) +a = cv2.resize(a, (200,200), interpolation=cv2.INTER_NEAREST) +b = np.array(b, dtype=np.uint8) +b = 255 * b +b = cv2.resize(b, (200,200), interpolation=cv2.INTER_NEAREST) + +cv2.imshow("A", b) +cv2.waitKey(0) + +cv2.imwrite("/home/kaiser/Schreibtisch/ownCloud/Vorlesung/DigitaleBildverarbeitung/Klausuren/Klausur_WS2021/images/filter_chess.png", a) +cv2.imwrite("/home/kaiser/Schreibtisch/ownCloud/Vorlesung/DigitaleBildverarbeitung/Klausuren/Klausur_WS2021/images/filter_chess_final.png", b) \ No newline at end of file diff --git a/Sandkasten/transformations.py b/Sandkasten/transformations.py new file mode 100644 index 0000000..d2b8a18 --- /dev/null +++ b/Sandkasten/transformations.py @@ -0,0 +1,40 @@ +import cv2 +import numpy as np + + +img = cv2.imread("data/flower.jpeg") +img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) +rows, cols = img.shape + +M1 = np.float32([ + [1, 0, 0], + [0, -1, rows] +]) + +M2 = np.float32([ + [-1, 0, cols], + [0, 1, 0] +]) + +M3 = np.float32([ + [2, 0, -int(cols/2)], + [0, 2, -int(rows/2)] +]) + + +dst1 = cv2.warpAffine(img, M1 ,(cols,rows)) +dst2 = cv2.warpAffine(img, M2 ,(cols,rows)) +dst3 = cv2.warpAffine(img, M3 ,(cols,rows)) + + +cv2.imshow("A", img) +cv2.imshow("1", dst1) +cv2.imshow("2", dst2) +cv2.imshow("3", dst3) + +cv2.waitKey(0) + +cv2.imwrite("/home/kaiser/Schreibtisch/ownCloud/Vorlesung/DigitaleBildverarbeitung/Klausuren/Klausur_WS2021/images/flower_original.png", img) +cv2.imwrite("/home/kaiser/Schreibtisch/ownCloud/Vorlesung/DigitaleBildverarbeitung/Klausuren/Klausur_WS2021/images/flower_1.png", dst1) +cv2.imwrite("/home/kaiser/Schreibtisch/ownCloud/Vorlesung/DigitaleBildverarbeitung/Klausuren/Klausur_WS2021/images/flower_2.png", dst2) +cv2.imwrite("/home/kaiser/Schreibtisch/ownCloud/Vorlesung/DigitaleBildverarbeitung/Klausuren/Klausur_WS2021/images/flower_3.png", dst3) diff --git a/data/airfresher.png b/data/airfresher.png new file mode 100644 index 0000000..8079a3c Binary files /dev/null and b/data/airfresher.png differ diff --git a/data/balls.png b/data/balls.png new file mode 100644 index 0000000..0b95941 Binary files /dev/null and b/data/balls.png differ diff --git a/data/cameraman.png b/data/cameraman.png new file mode 100644 index 0000000..82380a4 Binary files /dev/null and b/data/cameraman.png differ diff --git a/data/car.png b/data/car.png new file mode 100644 index 0000000..6d49355 Binary files /dev/null and b/data/car.png differ diff --git a/data/car2.png b/data/car2.png new file mode 100644 index 0000000..132273b Binary files /dev/null and b/data/car2.png differ diff --git a/data/dog.png b/data/dog.png new file mode 100644 index 0000000..bbb7d17 Binary files /dev/null and b/data/dog.png differ diff --git a/data/eth_blurred.png b/data/eth_blurred.png new file mode 100644 index 0000000..494fa12 Binary files /dev/null and b/data/eth_blurred.png differ diff --git a/data/flasche.jpeg b/data/flasche.jpeg new file mode 100644 index 0000000..811428d Binary files /dev/null and b/data/flasche.jpeg differ diff --git a/data/flasche_rechteckig.png b/data/flasche_rechteckig.png new file mode 100644 index 0000000..98627fd Binary files /dev/null and b/data/flasche_rechteckig.png differ diff --git a/data/flower.jpeg b/data/flower.jpeg new file mode 100644 index 0000000..2337a4a Binary files /dev/null and b/data/flower.jpeg differ diff --git a/data/hazard.png b/data/hazard.png new file mode 100644 index 0000000..c2f3ac9 Binary files /dev/null and b/data/hazard.png differ diff --git a/data/headphones.jpg b/data/headphones.jpg new file mode 100644 index 0000000..cddef37 Binary files /dev/null and b/data/headphones.jpg differ diff --git a/data/karo.png b/data/karo.png new file mode 100644 index 0000000..3d45c89 Binary files /dev/null and b/data/karo.png differ diff --git a/data/lena.png b/data/lena.png new file mode 100644 index 0000000..59ef68a Binary files /dev/null and b/data/lena.png differ diff --git a/data/lena_raster.png b/data/lena_raster.png new file mode 100644 index 0000000..6949510 Binary files /dev/null and b/data/lena_raster.png differ diff --git a/data/model.png b/data/model.png new file mode 100644 index 0000000..dd3e8db Binary files /dev/null and b/data/model.png differ diff --git a/data/obst.png b/data/obst.png new file mode 100644 index 0000000..db08a52 Binary files /dev/null and b/data/obst.png differ diff --git a/data/surv_01.png b/data/surv_01.png new file mode 100644 index 0000000..cee3e03 Binary files /dev/null and b/data/surv_01.png differ diff --git a/data/surv_02.png b/data/surv_02.png new file mode 100644 index 0000000..e10954c Binary files /dev/null and b/data/surv_02.png differ diff --git a/data/teardrop.png b/data/teardrop.png new file mode 100644 index 0000000..812c38c Binary files /dev/null and b/data/teardrop.png differ diff --git a/data/teppich.png b/data/teppich.png new file mode 100644 index 0000000..3c589b7 Binary files /dev/null and b/data/teppich.png differ diff --git a/data/text_1.jpg b/data/text_1.jpg new file mode 100644 index 0000000..1d68754 Binary files /dev/null and b/data/text_1.jpg differ diff --git a/data/text_2.jpg b/data/text_2.jpg new file mode 100644 index 0000000..0aab5e9 Binary files /dev/null and b/data/text_2.jpg differ diff --git a/data/text_3.jpg b/data/text_3.jpg new file mode 100644 index 0000000..f30b90f Binary files /dev/null and b/data/text_3.jpg differ diff --git a/data/tnt_banner.svg b/data/tnt_banner.svg new file mode 100644 index 0000000..f6c14ef --- /dev/null +++ b/data/tnt_banner.svg @@ -0,0 +1,125 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/yellowlilly.jpg b/data/yellowlilly.jpg new file mode 100644 index 0000000..692fb00 Binary files /dev/null and b/data/yellowlilly.jpg differ diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..e69de29