Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Mayer
CircularGreenSimCity
Commits
28a37ce3
Commit
28a37ce3
authored
Sep 20, 2024
by
Mayer
Browse files
Add new file
parent
e199074d
Changes
1
Hide whitespace changes
Inline
Side-by-side
python_scripts/DLM_Tree_Classification/Labelling_script
0 → 100644
View file @
28a37ce3
# Labelling 2.0 (ohne Skala 0-200 und weißen Hintergrund) ACHTUNG - Es wurden mehrere Verarbeitungsmöglichkeiten implementiert mit minimalen Unterschieden. Ungewollte Verarbeitung sollte auskommentiert werden:
# Möglichkeit 1:
import pandas as pd
import geopandas as gpd
import os
import rasterio
import numpy as np
from shapely.geometry import box
import matplotlib.pyplot as plt
import matplotlib.patches as patches
city_name = 'konstanz'
gdf = gpd.read_file('baumkataster_stadt_' + city_name + '.geojson')
gdf.loc[:, 'id'] = list(gdf.index)
gdf = gdf.to_crs('EPSG:31468')
df = pd.read_csv('baumkataster_classified_' + city_name + '.csv')
tree_class = df.Klasse
# Importverzeichnis für die rgbi Bilder
datadir = city_name + '_aerial_images_rgbi'
# Exportverzeichnis für die rgb Bilder
rgbdir = city_name + '_aerial_images_rgb'
# Exportverzeichnis für die gelabelten Bilder
labeldir = city_name + '_labeled'
# Verzeichnisse erstellen, falls noch nicht existent
if not os.path.exists(labeldir):
os.makedirs(labeldir)
if not os.path.exists(rgbdir):
os.makedirs(rgbdir)
filenames = os.listdir(datadir)
# Distanz pro Pixel festlegen
gsd = 0.2 # m/px
# Klassifizierungssystem und Farbgebung definieren
class_id = {'Großer Laubbaum': 0,
'Kleiner Laubbaum': 1,
'Großer Nadelbaum': 2,
'Kleiner Nadelbaum': 3,
'Busch/Hecke (Laub/Hartlaub)': 4,
'Busch/Hecke (Nadel)': 5,
'Unbekannt': 6}
class_colors = {'Großer Laubbaum': 'red',
'Kleiner Laubbaum': 'orange',
'Großer Nadelbaum': 'darkgreen',
'Kleiner Nadelbaum': 'lightgreen',
'Busch/Hecke (Laub/Hartlaub)': 'purple',
'Busch/Hecke (Nadel)': 'cornflowerblue',
'Unbekannt': 'white'}
# Liste zum Speichern problematischer Dateien
problematic_files = []
# Schleife für gesamten Ordner
for filename in filenames:
try:
# Überprüfen, ob die Datei eine Bilddatei ist (z.B. .tif oder .png)
if filename.endswith('.tif') or filename.endswith('.png'):
# Öffnet Bilddatei
dataset = rasterio.open(os.path.join(datadir, filename))
# Erstellung BBox für Bildgrenzen
geom = box(*dataset.bounds)
# Filtern der Bäume aus dem GeoDataFrame, die sich innerhalb der Bildgrenzen befinden
trees = gdf[gdf.intersects(geom)]
# Vorbereitung der Bilddarstellung
f, ax = plt.subplots()
ax.axis('off') # Skalen und Achsen ausblenden
# Erstellen eines RGB-Bildes für die Visualisierung
img = np.dstack(dataset.read()[:3])
ax.imshow(img)
# Speichern des Originalbilds ohne Bounding-Boxen
plt.savefig(os.path.join(rgbdir, filename.replace('.tif', '.png')))
# Erstellen und Speichern der Bounding-Boxen, wenn Bäume im Bild gefunden wurden
if len(trees) > 0:
for i, tree in trees.iterrows():
if not np.isnan(tree.kronenbrei):
# Berechnen der Pixelkoordinaten des Baumes im Bild
xy = dataset.index(tree.geometry.x, tree.geometry.y)
# Bestimmen der oberen linken Ecke der Bounding-Box basierend auf der Baumkrone
xy_center = (xy[0] - int(tree.kronenbrei/gsd/2), xy[1] - int(tree.kronenbrei/gsd/2))
# Speichern der Bounding-Box-Koordinaten und der Klassen-ID in einer .txt-Datei
with open(os.path.join(labeldir, filename.replace('.tif', '.txt')), 'a') as bboxf:
bboxf.write('{:d} {} {} {} {}\n'.format(class_id[tree_class.iloc[tree.id]], # Klassen-ID basierend auf dem Baumtyp
xy[1]/img.shape[1], # Normalisierte x-Koordinate
(xy[1] + int(tree.kronenbrei/gsd/2))/img.shape[1], # Normalisierte Breite
xy[0]/img.shape[0], # Normalisierte y-Koordinate
(xy[0] + int(tree.kronenbrei/gsd/2))/img.shape[1])) # Normalisierte Höhe
# Erstellen eines Rechtecks (Bounding-Box) zur Visualisierung im Bild
rect = patches.Rectangle(np.array(xy_center)[::-1], # Position der Bounding-Box
tree.kronenbrei/gsd, # Breite der Bounding-Box
tree.kronenbrei/gsd, # Höhe der Bounding-Box
linewidth=1, # Linienstärke der BBox
edgecolor=class_colors[tree_class.iloc[tree.id]], facecolor='none') # Farbe der Bounding-Box basierend auf der Klasse
ax.add_patch(rect)
# Speichern des Bildes mit den Bounding-Boxen als PNG-Datei
plt.savefig(os.path.join(labeldir, filename.replace('.tif', '_bbox.png')))
plt.close()
print(f"Processed: {filename}")
except Exception as e:
print(f"Error processing {filename}: {e}")
problematic_files.append(filename)
# Problematische Dateien anzeigen
if problematic_files:
print("\nProblematic files:")
for problem_file in problematic_files:
print(problem_file)
# Möglichkeit 2: (Bilder unskaliert lassen)
import pandas as pd
import geopandas as gpd
import os
import rasterio
import numpy as np
from shapely.geometry import box
import matplotlib.pyplot as plt
import matplotlib.patches as patches
city_name = 'wuerzburg'
gdf = gpd.read_file('baumkataster_stadt_' + city_name + '.geojson')
gdf.loc[:, 'id'] = list(gdf.index)
gdf = gdf.to_crs('EPSG:31468')
df = pd.read_csv('baumkataster_classified_' + city_name + '.csv')
tree_class = df.Klasse
# Importverzeichnis für die rgbi Bilder
datadir = city_name + '_aerial_images_rgbi'
# Exportverzeichnis für die rgb Bilder (ohne Bounding-Boxen)
rgbdir = city_name + '_aerial_images_rgb'
# Exportverzeichnis für die gelabelten Bilder (mit oder ohne Bounding-Boxen)
labeldir = city_name + '_labeled'
# Verzeichnisse erstellen, falls noch nicht existent
if not os.path.exists(labeldir):
os.makedirs(labeldir)
if not os.path.exists(rgbdir):
os.makedirs(rgbdir)
filenames = os.listdir(datadir)
# Distanz pro Pixel festlegen
gsd = 0.2 # m/px
# Klassifizierungssystem und Farbgebung definieren
class_id = {'Großer Laubbaum': 0,
'Kleiner Laubbaum': 1,
'Großer Nadelbaum': 2,
'Kleiner Nadelbaum': 3,
'Busch/Hecke (Laub/Hartlaub)': 4,
'Busch/Hecke (Nadel)': 5,
'Unbekannt': 6}
class_colors = {'Großer Laubbaum': 'red',
'Kleiner Laubbaum': 'orange',
'Großer Nadelbaum': 'darkgreen',
'Kleiner Nadelbaum': 'lightgreen',
'Busch/Hecke (Laub/Hartlaub)': 'purple',
'Busch/Hecke (Nadel)': 'cornflowerblue',
'Unbekannt': 'white'}
# Liste zum Speichern problematischer Dateien
problematic_files = []
# Schleife für gesamten Ordner
for filename in filenames:
try:
# Überprüfen, ob die Datei eine Bilddatei ist (z.B. .tif oder .png)
if filename.endswith('.tif') or filename.endswith('.png'):
# Öffnet Bilddatei
dataset = rasterio.open(os.path.join(datadir, filename))
# Erstellung BBox für Bildgrenzen
geom = box(*dataset.bounds)
# Filtern der Bäume aus dem GeoDataFrame, die sich innerhalb der Bildgrenzen befinden
trees = gdf[gdf.intersects(geom)]
# Erstellen eines RGB-Bildes für die Visualisierung
img = np.dstack(dataset.read()[:3]) # Verwende nur die RGB-Kanäle
# Speichern des Originalbilds im 'rgbdir'-Ordner (ohne Bounding-Boxen)
plt.imsave(os.path.join(rgbdir, filename.replace('.tif', '.png')), img)
# Falls keine Bäume gefunden wurden, speichere das Bild dennoch im 'labeldir'-Ordner mit der Endung '_bbox.png'
if len(trees) == 0:
plt.imsave(os.path.join(labeldir, filename.replace('.tif', '_bbox.png')), img)
continue # Keine Bounding-Boxen, also überspringe den Rest des Loops
# Bild und Achsen für Bounding-Box vorbereiten
fig, ax = plt.subplots(figsize=(img.shape[1] / 100, img.shape[0] / 100), dpi=100) # Bildgröße exakt festlegen
ax.imshow(img)
ax.axis('off') # Skalen und Achsen ausblenden
# Erstellen und Speichern der Bounding-Boxen, wenn Bäume im Bild gefunden wurden
for i, tree in trees.iterrows():
if not np.isnan(tree.kronenbrei):
# Berechnen der Pixelkoordinaten des Baumes im Bild
xy = dataset.index(tree.geometry.x, tree.geometry.y)
# Bestimmen der oberen linken Ecke der Bounding-Box basierend auf der Baumkrone
xy_center = (xy[0] - int(tree.kronenbrei/gsd/2), xy[1] - int(tree.kronenbrei/gsd/2))
# Speichern der Bounding-Box-Koordinaten und der Klassen-ID in einer .txt-Datei
with open(os.path.join(labeldir, filename.replace('.tif', '.txt')), 'a') as bboxf:
bboxf.write('{:d} {} {} {} {}\n'.format(class_id[tree_class.iloc[tree.id]], # Klassen-ID basierend auf dem Baumtyp
xy[1]/img.shape[1], # Normalisierte x-Koordinate
(xy[1] + int(tree.kronenbrei/gsd/2))/img.shape[1], # Normalisierte Breite
xy[0]/img.shape[0], # Normalisierte y-Koordinate
(xy[0] + int(tree.kronenbrei/gsd/2))/img.shape[1])) # Normalisierte Höhe
# Erstellen eines Rechtecks (Bounding-Box) zur Visualisierung im Bild
rect = patches.Rectangle(np.array(xy_center)[::-1], # Position der Bounding-Box
tree.kronenbrei/gsd, # Breite der Bounding-Box
tree.kronenbrei/gsd, # Höhe der Bounding-Box
linewidth=1, # Linienstärke der BBox
edgecolor=class_colors[tree_class.iloc[tree.id]], facecolor='none') # Farbe der Bounding-Box basierend auf der Klasse
ax.add_patch(rect)
# Speichern des Bildes mit den Bounding-Boxen als PNG-Datei
plt.savefig(os.path.join(labeldir, filename.replace('.tif', '_bbox.png')), bbox_inches='tight', pad_inches=0)
plt.close()
print(f"Processed: {filename}")
except Exception as e:
print(f"Error processing {filename}: {e}")
problematic_files.append(filename)
# Problematische Dateien anzeigen
if problematic_files:
print("\nProblematic files:")
for problem_file in problematic_files:
print(problem_file)
# Möglichkeit 3: (Das Gleiche noch einmal aber mittels Pillow)
import pandas as pd
import geopandas as gpd
import os
import rasterio
import numpy as np
from shapely.geometry import box
from PIL import Image, ImageDraw
city_name = 'memmingen'
gdf = gpd.read_file('baumkataster_stadt_' + city_name + '.geojson')
gdf.loc[:, 'id'] = list(gdf.index)
gdf = gdf.to_crs('EPSG:31468')
df = pd.read_csv('baumkataster_classified_' + city_name + '.csv')
tree_class = df.Klasse
# Importverzeichnis für die rgbi Bilder
datadir = city_name + '_aerial_images_rgbi'
# Exportverzeichnis für die rgb Bilder (ohne Bounding-Boxen)
rgbdir = city_name + '_aerial_images_rgb'
# Exportverzeichnis für die gelabelten Bilder (mit oder ohne Bounding-Boxen)
labeldir = city_name + '_labeled'
# Verzeichnisse erstellen, falls noch nicht existent
if not os.path.exists(labeldir):
os.makedirs(labeldir)
if not os.path.exists(rgbdir):
os.makedirs(rgbdir)
filenames = os.listdir(datadir)
# Distanz pro Pixel festlegen
gsd = 0.2 # m/px
# Klassifizierungssystem und Farbgebung definieren
class_id = {'Großer Laubbaum': 0,
'Kleiner Laubbaum': 1,
'Großer Nadelbaum': 2,
'Kleiner Nadelbaum': 3,
'Busch/Hecke (Laub/Hartlaub)': 4,
'Busch/Hecke (Nadel)': 5,
'Unbekannt': 6}
class_colors = {'Großer Laubbaum': 'red',
'Kleiner Laubbaum': 'orange',
'Großer Nadelbaum': 'darkgreen',
'Kleiner Nadelbaum': 'lightgreen',
'Busch/Hecke (Laub/Hartlaub)': 'purple',
'Busch/Hecke (Nadel)': 'cornflowerblue',
'Unbekannt': 'white'}
# Liste zum Speichern problematischer Dateien
problematic_files = []
# Schleife für gesamten Ordner
for filename in filenames:
try:
# Überprüfen, ob die Datei eine Bilddatei ist (z.B. .tif oder .png)
if filename.endswith('.tif') or filename.endswith('.png'):
# Öffnet Bilddatei
dataset = rasterio.open(os.path.join(datadir, filename))
# Erstellung BBox für Bildgrenzen
geom = box(*dataset.bounds)
# Filtern der Bäume aus dem GeoDataFrame, die sich innerhalb der Bildgrenzen befinden
trees = gdf[gdf.intersects(geom)]
# Erstellen eines RGB-Bildes für die Visualisierung
img = np.dstack(dataset.read()[:3]) # Verwende nur die RGB-Kanäle
img_pil = Image.fromarray(img.astype(np.uint8))
# Speichern des Originalbilds im 'rgbdir'-Ordner (ohne Bounding-Boxen)
img_pil.save(os.path.join(rgbdir, filename.replace('.tif', '.png')))
# Falls keine Bäume gefunden wurden, speichere das Bild dennoch im 'labeldir'-Ordner mit der Endung '_bbox.png'
if len(trees) == 0:
img_pil.save(os.path.join(labeldir, filename.replace('.tif', '_bbox.png')))
continue # Keine Bounding-Boxen, also überspringe den Rest des Loops
# Erstellen des Zeichenwerkzeugs für Bounding-Boxen
draw = ImageDraw.Draw(img_pil)
# Erstellen und Speichern der Bounding-Boxen, wenn Bäume im Bild gefunden wurden
for i, tree in trees.iterrows():
if not np.isnan(tree.kronenbrei):
# Berechnen der Pixelkoordinaten des Baumes im Bild
xy = dataset.index(tree.geometry.x, tree.geometry.y)
# Bestimmen der oberen linken Ecke der Bounding-Box basierend auf der Baumkrone
xy_center = (xy[0] - int(tree.kronenbrei/gsd/2), xy[1] - int(tree.kronenbrei/gsd/2))
# Speichern der Bounding-Box-Koordinaten und der Klassen-ID in einer .txt-Datei
with open(os.path.join(labeldir, filename.replace('.tif', '.txt')), 'a') as bboxf:
bboxf.write('{:d} {} {} {} {}\n'.format(class_id[tree_class.iloc[tree.id]], # Klassen-ID basierend auf dem Baumtyp
xy[1] / img.shape[1], # Normalisierte x-Koordinate
(xy[1] + int(tree.kronenbrei / gsd / 2)) / img.shape[1], # Normalisierte Breite
xy[0] / img.shape[0], # Normalisierte y-Koordinate
(xy[0] + int(tree.kronenbrei / gsd / 2)) / img.shape[0])) # Normalisierte Höhe
# Zeichnen der Bounding-Box
rect_xy = [xy_center[1], xy_center[0], xy_center[1] + tree.kronenbrei / gsd, xy_center[0] + tree.kronenbrei / gsd]
draw.rectangle(rect_xy, outline=class_colors[tree_class.iloc[tree.id]], width=2)
# Speichern des Bildes mit den Bounding-Boxen als PNG-Datei
img_pil.save(os.path.join(labeldir, filename.replace('.tif', '_bbox.png')))
print(f"Processed: {filename}")
except Exception as e:
print(f"Error processing {filename}: {e}")
problematic_files.append(filename)
# Problematische Dateien anzeigen
if problematic_files:
print("\nProblematic files:")
for problem_file in problematic_files:
print(problem_file)
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment