Initial commit with project files

This commit is contained in:
2025-06-27 14:34:11 +02:00
commit 7ea3207e63
310 changed files with 9331 additions and 0 deletions

11
5_Bildanalyse/README.md Normal file
View File

@@ -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.

View File

@@ -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:
<p align="center">
<img src="../../data/surv_01.png" />
</p>
<p align="center">
<img src="../../data/surv_02.png" />
</p>
## 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).

13
5_Bildanalyse/ü1/a.py Normal file
View 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
5_Bildanalyse/ü1/l_a.py Normal file
View File

@@ -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

View File

@@ -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).

31
5_Bildanalyse/ü10/a.py Normal file
View File

@@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

44
5_Bildanalyse/ü10/l_a.py Normal file
View File

@@ -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)

View File

@@ -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).

20
5_Bildanalyse/ü11/a.py Normal file
View File

@@ -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 =", ...)

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 782 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

60
5_Bildanalyse/ü11/l_a.py Normal file
View File

@@ -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)

60
5_Bildanalyse/ü11/l_b.md Normal file
View File

@@ -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.

View File

@@ -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
<p align="center">
<img src="https://latex.codecogs.com/svg.image?n_1(s)=\sum_{k=0}^sh(k)" title="\sum_1" />
<p>
<p align="center">
<img src="https://latex.codecogs.com/svg.image?n_2(s)=\sum_{k=s+1}^{255}h(k)" title="\sum_1" />
<p>
<p align="center">
<img src="https://latex.codecogs.com/svg.image?\mu_1(s)=\frac{1}{n_1}\sum_{k=0}^sh(k)k" title="\sum_1" />
<p>
<p align="center">
<img src="https://latex.codecogs.com/svg.image?\mu_2(s)=\frac{1}{n_2}\sum_{k=s+1}^{255}h(k)k" title="\sum_1" />
<p>
<p align="center">
<img src="https://latex.codecogs.com/svg.image?\sigma_1(s)=\sqrt{\frac{1}{n_1}\sum_{k=0}^sh(k)(k-\mu_1)^2}" title="\sum_1" />
<p>
<p align="center">
<img src="https://latex.codecogs.com/svg.image?\sigma_2(s)=\sqrt{\frac{1}{n_2}\sum_{k=s+1}^{255}h(k)(k-\mu_2)^2}" title="\sum_1" />
<p>
und maximieren Sie den Quotienten
<p align="center">
<img src="https://latex.codecogs.com/svg.image?Q(s)=\frac{\sigma(s)_{zw}^2}{\sigma(s)_{in}^2}=\frac{n_1(s)(\mu_1(s)-\mu)^2+n_2(s)(\mu_2(s)-\mu)^2}{n_1(s)\sigma_1(s)^2+n_2(s)\sigma_2(s)^2}" title="\sum_1" />
<p>
mit dem Mittelwert des Grauwertbildes
<p align="center">
<img src="https://latex.codecogs.com/svg.image?\mu=\frac{1}{n_1(255)}\sum_{k=0}^{255}h(k)k," title="\sum_1" />
<p>
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).

41
5_Bildanalyse/ü12/a.py Normal file
View File

@@ -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)

77
5_Bildanalyse/ü12/l_a.py Normal file
View File

@@ -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)

View File

@@ -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).

9
5_Bildanalyse/ü13/a.py Normal file
View File

@@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

61
5_Bildanalyse/ü13/l_a.py Normal file
View File

@@ -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)

91
5_Bildanalyse/ü13/l_b.py Normal file
View File

@@ -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)

View File

@@ -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).

22
5_Bildanalyse/ü2/d.py Normal file
View File

@@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

20
5_Bildanalyse/ü2/l_a.md Normal file
View File

@@ -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)

26
5_Bildanalyse/ü2/l_b.md Normal file
View File

@@ -0,0 +1,26 @@
# Musterlösung Aufgabe b)
**Erosion:**
<p align="center">
<img src="https://latex.codecogs.com/svg.image?A&space;\ominus&space;b" title="A \ominus b" />
</p>
**Dilatation:**
<p align="center">
<img src="https://latex.codecogs.com/svg.image?A&space;\oplus&space;b" title="A \oplus b" />
</p>
**Opening:**
<p align="center">
<img src="https://latex.codecogs.com/svg.image?(A&space;\ominus&space;b)\oplus&space;b" title="(A \ominus b)\oplus b" />
</p>
**Closing:**
<p align="center">
<img src="https://latex.codecogs.com/svg.image?(A&space;\oplus&space;b)\ominus&space;b" title="(A \oplus b)\ominus b" />
</p>

10
5_Bildanalyse/ü2/l_c.md Normal file
View File

@@ -0,0 +1,10 @@
# Musterlösung Aufgabe c)
Antwort: Nein!
Beweis:
Verwendet man als Strukturelement zum Beispiel
<p align="center">
<img src="https://latex.codecogs.com/svg.image?\begin{bmatrix}&space;0&&space;1&space;&&space;0&space;\\&space;1&&space;0&space;&&space;1&space;\\&space;0&&space;1&space;&&space;0&space;\\\end{bmatrix}" title="\begin{bmatrix} 0& 1 & 0 \\ 1& 0 & 1 \\ 0& 1 & 0 \\\end{bmatrix}" />
</p>
so kann die Erosion zusätzliche
Binärpixel erzeugen, welche nicht im Ursprungsbild waren.

35
5_Bildanalyse/ü2/l_d.py Normal file
View File

@@ -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)

View File

@@ -0,0 +1,25 @@
# Übung 3: Split and Merge
Sie haben folgendes Grauwertbild gegeben:
![](data/splitmerge.png)
Dabei gilt die Homogenitätsbedingung:
<p align="center">
<img src="https://latex.codecogs.com/svg.image?y&space;=&space;\left\{\begin{matrix}&space;1,&space;\&space;\max(R_i)&space;-&space;\min(R_i)&space;<&space;3&space;\\&space;0,&space;sonst&space;\end{matrix}\right." title="y = \left\{\begin{matrix} 1, \ \max(R_i) - \min(R_i) < 3 \\ 0, sonst \end{matrix}\right." />
</p>
## 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?

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

12
5_Bildanalyse/ü3/l_ac.md Normal file
View File

@@ -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)

4
5_Bildanalyse/ü3/l_b.md Normal file
View File

@@ -0,0 +1,4 @@
# Lösung Aufgabe b)
![](data/l_b.png)

3
5_Bildanalyse/ü3/l_d.md Normal file
View File

@@ -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.

View File

@@ -0,0 +1,15 @@
# Übung 4: Region Growing
Gegeben ist der folgende Bildausschnitt:
<p align="center">
<img src="data/a.png">
</p>
<p align="center">
<img src="https://latex.codecogs.com/svg.image?\begin{bmatrix}64&space;&179&space;&54&space;&164&space;&248&space;&94&space;&77&space;&55&space;\\208&space;&170&space;&233&space;&134&space;&222&space;&179&space;&178&space;&77&space;\\34&space;&154&space;&182&space;&69&space;&10&space;&228&space;&172&space;&178&space;\\224&space;&112&space;&89&space;&118&space;&202&space;&219&space;&63&space;&102&space;\\78&space;&251&space;&65&space;&255&space;&249&space;&79&space;&72&space;&150&space;\\160&space;&164&space;&202&space;&252&space;&56&space;&178&space;&208&space;&200&space;\\208&space;&0&space;&83&space;&172&space;&30&space;&210&space;&97&space;&255&space;\\100&space;&20&space;&187&space;&235&space;&40&space;&156&space;&92&space;&54&space;\end{bmatrix}&space;" title="\begin{bmatrix}64 &179 &54 &164 &248 &94 &77 &55 \\208 &170 &233 &134 &222 &179 &178 &77 \\34 &154 &182 &69 &10 &228 &172 &178 \\224 &112 &89 &118 &202 &219 &63 &102 \\78 &251 &65 &255 &249 &79 &72 &150 \\160 &164 &202 &252 &56 &178 &208 &200 \\208 &0 &83 &172 &30 &210 &97 &255 \\100 &20 &187 &235 &40 &156 &92 &54 \end{bmatrix} " />
</p>
## 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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

11
5_Bildanalyse/ü4/l_a.md Normal file
View File

@@ -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?

View File

@@ -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).

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

6
5_Bildanalyse/ü5/l_a.md Normal file
View File

@@ -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)

View File

@@ -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).

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

10
5_Bildanalyse/ü6/l_a.py Normal file
View File

@@ -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)

6
5_Bildanalyse/ü6/l_b.py Normal file
View File

@@ -0,0 +1,6 @@
import numpy as np
n = 4
m = -1
print("%s * x + %s" % (m, n))

View File

@@ -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).

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

44
5_Bildanalyse/ü7/l_a.py Normal file
View File

@@ -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)

View File

@@ -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).

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

66
5_Bildanalyse/ü8/l_a.py Normal file
View File

@@ -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)

63
5_Bildanalyse/ü8/l_b.py Normal file
View File

@@ -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)

View File

@@ -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).

31
5_Bildanalyse/ü9/l_a.py Normal file
View File

@@ -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)