Initial commit with project files
9
2_Bildbearbeitung/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Einführung in die Bildbearbeitung
|
||||
|
||||
In diesem Kapitel werden Ihnen verschiedene Klassen von Operationen und Methoden erläutert und mit Beispielen
|
||||
exemplarisch dargestellt. Die Übungen zeigen Beispiele zu den Themen
|
||||
- **Punktoperationen (Intensitätstransformationen)**
|
||||
- **Lokale Operationen (Filterung)**
|
||||
- **Globale Operationen**
|
||||
- **Geometrische Transformationen**
|
||||
|
||||
19
2_Bildbearbeitung/ü1/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Übung 1: Helligkeitsausgleich
|
||||
|
||||
In dieser Übung wird ein Helligkeitsausgleich durchgeführt. Gegeben sind drei Bilder von Texten wie exemplarisch unten
|
||||
dargestellt. Zu sehen ist, dass die mittlere Beleuchtung des Bildes lokal stark variiert. Auf Algorithmen, die beispielweise
|
||||
Schwellwerte auf Gurndlage der Helligkeit nutzen, können diese Unterschiede störend wirken. Im folgenden soll daher ein
|
||||
Helligkeitsausgleich durchgeführt werden, nachdem die mittlere lokale Helligkeit in jedem Bildsegment gleich ist.
|
||||
|
||||

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

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

|
||||

|
||||

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

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

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