Objekterkennung (Teil 2)

Potenzialanalyse für Dachflächen-Photovoltaik

Im zweiten Teil geht es um die automatisierte Erkennung bereits installierter Photovoltaikanlagen auf Dachflächen. Dazu wird ein KI-Modell zur Objekterkennung verwendet, das Solaranlagen auf Luftaufnahmen (Orthofotos) identifiziert. Die Vorhersagen des Modells werden anschließend unter Verwendung geeigneter Metriken evaluiert.

Autor:in
Zugehörigkeit

Sören Sparmann

Universität Paderborn

Veröffentlichungsdatum

14. September 2025

Im letzten Arbeitsblatt wurden geeignete Dachflächen für den Einsatz von Photovoltaikanlagen (PV-Anlagen) identifiziert.

In diesem interaktiven Arbeitsblatt sollen nun bereits vorhandene PV-Anlagen mithilfe von künstlicher Intelligenz auf Luftbildern erkannt werden. So können noch ungenutzte Dachflächen mit hohem Potenzial ermittelt werden.

Ziel dieses Arbeitsblatts ist es, eine Liste potenzieller Standorte zu erstellen. Diese Liste kann dazu beitragen, Eigentümer von geeigneten Dächern zu motivieren, PV-Anlagen auf ihren Dächern zu installieren.

1 Orthophoto herunterladen

Ein Orthophoto ist ein verzerrungsfreies und maßstabsgetreues Luftbild, das aus einem Flugzeug aufgenommen wurde.

Zunächst werden die Koordinaten (WGS 84) für unseren Untersuchungsbereich bestimmt.

from cdec import get_lat_lon_for

# Adresse festlegen
adresse = 'Upsprunger Str. 67, 33154 Salzkotten'

# Breiten- und Längengrad bestimmen
coords = get_lat_lon_for(adresse)
coords
(51.6604721, 8.6024081)

Mit dem Befehl download_orthophoto kann ein Luftbild (Orthophoto) der Umgebung heruntergeladen werden.

Hinweis

Das Herunterladen und Anzeigen des Fotos kann einige Sekunden dauern. Die Vorschau hat eine geringere Auflösung (2500 x 2500 px) als das Original (10000 x 10000 px).

from cdec import download_orthophoto

# Lade Orthophoto herunter und zeige Vorschau
image = download_orthophoto(coords)
https://www.opengeodata.nrw.de/produkte/geobasis/lusat/akt/dop/dop_jp2_f10/dop10rgbi_32_472_5723_1_nw_2024.jp2
Lade Vorschau ...

Aufgabe 1

  • Ändere die Adresse zu jener aus dem letzten Arbeitsblatt.
  • Lade das dazugehörige Orthophoto herunter, indem du die entsprechenden Zellen erneut ausführst.

(5 Minuten)

Die Angaben aus Aufgabe 2 in Kapitel 3 müssen in die erste Zelle dieses Kapitels übertragen werden.

# Adresse festlegen
adresse = 'Paulinenstraße 67, 32756 Detmold'

Im weiteren Verlauf wird auf die Adresse Paulinenstraße 67, 32756 Detmold mit den Koordinaten (51.93866553853838, 8.874417255128995) Bezug genommen.

2 Objekterkennung mit künstlicher Intelligenz

Für die Erkennung von PV-Anlagen wird ein Modell des maschinellen Lernens eingesetzt.

Das Modell wurde darauf trainiert, PV-Anlagen auf Orthofotos zu identifizieren und zu markieren (siehe ). Dafür wurden dem Modell eine Auswahl an Orthophotos präsentiert, auf denen PV-Anlagen bereits manuell markiert wurden. Anhand dieser Beispiele (Trainingsdaten) hat das Modell gelernt, wie eine PV-Anlage aussieht, und kann diese nun automatisch erkennen.

Abbildung 1: Trainingsdaten zur Erkennung von PV-Anlagen

Zunächst wird das Modell in den Arbeitsspeicher geladen.

from cdec import ObjectDetection

# Modell laden
model = ObjectDetection()
WARNING ⚠️ no model scale passed. Assuming scale='n'.

                   from  n    params  module                                       arguments                     
  0                  -1  1       464  ultralytics.nn.modules.conv.Conv             [3, 16, 3, 2]                 
  1                  -1  1      4672  ultralytics.nn.modules.conv.Conv             [16, 32, 3, 2]                
  2                  -1  1      7360  ultralytics.nn.modules.block.C2f             [32, 32, 1, True]             
  3                  -1  1     18560  ultralytics.nn.modules.conv.Conv             [32, 64, 3, 2]                
  4                  -1  2     49664  ultralytics.nn.modules.block.C2f             [64, 64, 2, True]             
  5                  -1  1     73984  ultralytics.nn.modules.conv.Conv             [64, 128, 3, 2]               
  6                  -1  2    197632  ultralytics.nn.modules.block.C2f             [128, 128, 2, True]           
  7                  -1  1    295424  ultralytics.nn.modules.conv.Conv             [128, 256, 3, 2]              
  8                  -1  1    460288  ultralytics.nn.modules.block.C2f             [256, 256, 1, True]           
  9                  -1  1    164608  ultralytics.nn.modules.block.SPPF            [256, 256, 5]                 
 10                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          
 11             [-1, 6]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 12                  -1  1    148224  ultralytics.nn.modules.block.C2f             [384, 128, 1]                 
 13                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          
 14             [-1, 4]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 15                  -1  1     37248  ultralytics.nn.modules.block.C2f             [192, 64, 1]                  
 16                  -1  1     36992  ultralytics.nn.modules.conv.Conv             [64, 64, 3, 2]                
 17            [-1, 12]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 18                  -1  1    123648  ultralytics.nn.modules.block.C2f             [192, 128, 1]                 
 19                  -1  1    147712  ultralytics.nn.modules.conv.Conv             [128, 128, 3, 2]              
 20             [-1, 9]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 21                  -1  1    493056  ultralytics.nn.modules.block.C2f             [384, 256, 1]                 
 22        [15, 18, 21]  1    751507  ultralytics.nn.modules.head.Detect           [1, [64, 128, 256]]           
model summary: 129 layers, 3,011,043 parameters, 3,011,027 gradients, 8.2 GFLOPs

Transferred 355/355 items from pretrained weights

Mit dem Methode predict lässt nun sich eine Vorhersage des Modell für das entsprechende Bild erzeugen.

Hinweis

Im Bereich des maschinellen Lernens wird häufig der Begriff “Vorhersage” (Prediction) verwendet. Damit ist jedoch nicht zwangsläufig eine Aussage über die Zukunft gemeint. In diesem Fall ist damit das Ergebnis der Objekterkennung gemeint.

# Vorhersage erstellen
result = model.predict(image)
Anzahl gefundener PV-Anlagen: 256

Aufgabe 2

Schau dir das Ergebnis der Objekterkennung genauer an und suche nach Fehlern:

  • Finde ein Beispiel, bei dem das Modell eine PV-Anlage übersehen hat (False Negative).
  • Finde ein Beispiel, bei dem das Modell fälschlicherweise eine PV-Anlage erkannt hat, obwohl dort keine vorhanden ist (False Positive).

Welcher der beiden Fehlerarten ist deiner Meinung nach schwerwiegender? Begründe deine Antwort!

(15 Minuten)

result.explore(height=800)
Make this Notebook Trusted to load map: File -> Trust Notebook

TODO

3 Evaluation des Modells

Um zu überprüfen, wie gut ein Modell zur Objekterkennung geeignet ist, wird es evaluiert.
Dabei wird gemessen, wie genau und zuverlässig das Modell die Objekte erkennt. Zwei wichtige Maße (Metriken), die dabei oft verwendet werden, sind Precision (Genauigkeit) und Recall (Trefferquote).

3.1 Genauigkeit (Precision)

Die Genauigkeit (Precision) gibt an, wie viele der vom Modell erkannten Objekte tatsächlich richtig erkannt wurden.

Precision=Anzahl der richtig erkannten ObjekteAnzahl aller erkannten Objekte

Beispiel: Angenommen, ein Objekterkennungsmodell identifiziert 50 Objekte auf Dachflächen als PV-Anlagen. Davon sind tatsächlich 45 PV-Anlagen (True Positives) und 5 Objekte sind keine PV-Anlagen, wurden aber fälschlicherweise als solche erkannt (False Positives).

Precision=4550=0.9=90%

Eine hohe Precision bedeutet, dass das Modell sehr genau darin ist, PV-Anlagen zu identifizieren, und nur wenige falsche Positive (Nicht-PV-Anlagen, die fälschlicherweise als PV-Anlagen erkannt wurden) erzeugt.

3.2 Trefferquote (Recall)

Die Trefferquote (Recall) gibt, wie viele der tatsächlich vorhandenen Objekte vom Modell erkannt wurden.

Recall=Anzahl der richtig erkannten ObjekteAnzahl aller tatsächlich vorhandenen Objekte

Beispiel: Angenommen, auf den analysierten Hausdächern befinden sich insgesamt 60 PV-Anlagen. Das Modell erkennt davon 45 korrekt (True Positives), übersieht jedoch 15 Anlagen (False Negatives), die tatsächlich existieren. Der Recall wäre dann:

Recall=4560=0.75=75%

Ein hoher Recall bedeutet, dass das Modell in der Lage ist, die meisten vorhandenen PV-Anlagen zu erkennen, also nur wenige davon übersieht.

Aufgabe 3

Dem Modell wurden Orthophotos mit insgesamt 400 PV-Anlagen gezeigt. Davon hat das Modell 309 korrekt erkannt. In 108 Fällen erkannte das Modell fälschlicherweise eine PV-Anlage.

Vorhersage: PV-Anlage Vorhersage: Hintergrund
PV-Anlage. 309 (TP) 91 (FN)
Hintergrund 108 (FP)

Berechne Precision und Recall für das Modell!

(10 Minuten)

Berechnung der Genauigkeit (Precision):

309 / (309 + 108)   
0.7410071942446043

Berechnung der Trefferquote (Recall):

309 / 400 
0.7725

Interpretation: Somit besitzt das Modell eine Genauigkeit von 74% und eine Trefferquote von 77%

Hinweis

In der Praxis ist es oft eine Herausforderung, ein Modell zu entwickeln, das sowohl eine hohe Precision als auch einen hohen Recall erreicht. Es kommt daher meist zu einen Kompromiss:

  • Hohe Precision kann bedeuten, dass das Modell sehr selektiv ist und nur dann eine PV-Anlage identifiziert, wenn es sich sehr sicher ist. Dies führt zu wenigen False Positives, aber es könnte viele tatsächliche PV-Anlagen übersehen (niedriger Recall).
  • Hoher Recall kann bedeuten, dass das Modell sehr sensitiv ist und versucht, möglichst alle PV-Anlagen zu erkennen. Dies führt zu wenigen False Negatives, aber es könnte auch viele Objekte fälschlicherweise als PV-Anlagen identifizieren (niedrige Precision).

4 Solarkatasterdaten laden

Nachdem nun erkannt wurde, wo bereits PV-Anlagen vorhanden sind, können diese Standorte von der bisher erstellten Liste entfernt werden.

Dazu wird zunächst das Zwischenergebnis aus dem letzten Arbeitsblatt geladen.

from cdec import read_file

solarkataster = read_file('data/solarkataster.json').set_index('id')
solarkataster
geb_id richtung neigung dachtyp himmel_kat flaecheninhalt total_energy_per_square_metre total_energy geometry
id
0 Geb64596ln0403_c 269 15 geneigt West 7.411919 1.500811e+06 1.112389e+07 MULTIPOLYGON (((472254 5723718, 472254 5723720...
1 Geb77493ln0403_c -1 0 flach Flach 7.500000 1.526328e+06 1.144746e+07 MULTIPOLYGON (((472548 5723151.5, 472546.5 572...
2 Geb67252ln0403_c 263 44 geneigt West 36.716183 1.444865e+06 5.304994e+07 MULTIPOLYGON (((472177.5 5723508, 472177.5 572...
3 Geb68143ln0403_c 175 51 geneigt Süd 12.497905 2.077114e+06 2.595957e+07 MULTIPOLYGON (((472206 5723548, 472207 5723548...
4 Geb73711ln0403_c 82 21 geneigt Ost 36.641219 1.413035e+06 5.177533e+07 MULTIPOLYGON (((472698.5 5723757.5, 472698.5 5...
... ... ... ... ... ... ... ... ... ...
2552 Geb62779ln0403_c 176 50 geneigt Süd 12.903848 2.079983e+06 2.683979e+07 MULTIPOLYGON (((472358.906 5723561.578, 472359...
2553 Geb63299ln0403_c 246 34 geneigt West 32.292786 1.662412e+06 5.368391e+07 MULTIPOLYGON (((472215 5723774.5, 472214.5 572...
2554 Geb76249ln0403_c 178 26 geneigt Süd 11.989565 1.961843e+06 2.352165e+07 MULTIPOLYGON (((472931.5 5723834, 472931.5 572...
2555 Geb70353ln0403_c 82 36 geneigt Ost 88.135948 1.315017e+06 1.159003e+08 MULTIPOLYGON (((472099 5723372.5, 472099 57233...
2556 Geb58712ln0403_c 265 33 geneigt West 60.672663 1.471228e+06 8.926334e+07 MULTIPOLYGON (((472263 5723281, 472263 5723277...

2557 rows × 9 columns

5 Daten zusammenführen

Nun können die Ergebnisse zusammenführt werden: Der folgende Code entfernt alle Dachflächen von Gebäuden aus dem Solarkataster, auf denen sich bereits eine PV-Anlage befindet.

Hinweis

Der folgenden Programmcode enthält einige Funktionen, die nicht ausführlich erklärt werden. Es ist nicht notwendig, dass du jeden Befehl nachvollziehen kannst.

import geopandas as gpd

# Schnittmenge zwischen den Daten bilden
intersection = gpd.sjoin(solarkataster, result, how='inner', predicate='intersects')
# Gebaeude IDs aus der Schnittmenge bestimmen
geb_ids = intersection['geb_id'].unique()
# Solarkatasterdaten anhand der Gebauede IDs filtern
solarkataster = solarkataster[~solarkataster['geb_id'].isin(geb_ids)]
# Daten visualiseren
solarkataster.explore(width=800, height=600)
Make this Notebook Trusted to load map: File -> Trust Notebook

6 Daten sortieren

Zuletzt sortieren werden die Daten absteigend nach der Bestrahlungsenergie pro Quadratmeter sortiert.

# Dachflächen nach Bestrahlungsenergie pro Quadratmeter sortieren
sorted_df = solarkataster.sort_values('total_energy_per_square_metre', ascending=False)
sorted_df
geb_id richtung neigung dachtyp himmel_kat flaecheninhalt total_energy_per_square_metre total_energy geometry
id
13 Geb71192ln0403_c 180 47 geneigt Süd 15.741250 2.083685e+06 3.279980e+07 MULTIPOLYGON (((472498 5723301.5, 472498 57233...
193 Geb72502ln0403_c 178 48 geneigt Süd 38.898535 2.083154e+06 8.103162e+07 MULTIPOLYGON (((472559 5723631, 472560 5723631...
229 Geb80497ln0403_c 179 46 geneigt Süd 12.616012 2.082779e+06 2.627636e+07 MULTIPOLYGON (((472510 5723627.5, 472510.5 572...
1810 Geb74557ln0403_c 177 48 geneigt Süd 37.394520 2.082365e+06 7.786903e+07 MULTIPOLYGON (((472492.5 5723627.5, 472493 572...
1406 Geb79875ln0403_c 177 48 geneigt Süd 53.928732 2.082365e+06 1.122993e+08 MULTIPOLYGON (((472489 5723834, 472489 5723834...
... ... ... ... ... ... ... ... ... ...
1481 Geb64117ln0403_c 345 51 geneigt Nord 8.750000 5.642711e+05 4.937372e+06 MULTIPOLYGON (((472306.5 5723720, 472307 57237...
669 Geb65166ln0403_c 354 50 geneigt Nord 14.831913 5.544158e+05 8.223047e+06 MULTIPOLYGON (((472392 5723454, 472392 5723454...
921 Geb65145ln0403_c 354 50 geneigt Nord 12.118879 5.544158e+05 6.718898e+06 MULTIPOLYGON (((472396 5723454, 472396 5723454...
918 Geb65145ln0403_c 355 50 geneigt Nord 38.964160 5.531547e+05 2.155321e+07 MULTIPOLYGON (((472399 5723454, 472399 5723454...
1748 Geb73538ln0403_c 352 51 geneigt Nord 8.500000 5.455292e+05 4.636998e+06 MULTIPOLYGON (((472417.5 5723231, 472417.5 572...

2062 rows × 9 columns

Mit Hilfe der Methode iloc[] können die Einträge anhand der Reihenfolge der Daten ausgewählt werden.

# Die ersten 100 Dachflächen auswählen
sorted_df.iloc[:100]
geb_id richtung neigung dachtyp himmel_kat flaecheninhalt total_energy_per_square_metre total_energy geometry
id
13 Geb71192ln0403_c 180 47 geneigt Süd 15.741250 2.083685e+06 3.279980e+07 MULTIPOLYGON (((472498 5723301.5, 472498 57233...
193 Geb72502ln0403_c 178 48 geneigt Süd 38.898535 2.083154e+06 8.103162e+07 MULTIPOLYGON (((472559 5723631, 472560 5723631...
229 Geb80497ln0403_c 179 46 geneigt Süd 12.616012 2.082779e+06 2.627636e+07 MULTIPOLYGON (((472510 5723627.5, 472510.5 572...
1810 Geb74557ln0403_c 177 48 geneigt Süd 37.394520 2.082365e+06 7.786903e+07 MULTIPOLYGON (((472492.5 5723627.5, 472493 572...
1406 Geb79875ln0403_c 177 48 geneigt Süd 53.928732 2.082365e+06 1.122993e+08 MULTIPOLYGON (((472489 5723834, 472489 5723834...
... ... ... ... ... ... ... ... ... ...
474 Geb76275ln0403_c 165 47 geneigt Süd 38.859698 2.056823e+06 7.992752e+07 MULTIPOLYGON (((472176.5 5723690.5, 472177 572...
156 Geb66901ln0403_c 180 58 geneigt Süd 14.489619 2.056763e+06 2.980171e+07 MULTIPOLYGON (((472415 5723903, 472416.5 57239...
1173 Geb58849ln0403_c 175 38 geneigt Süd 45.011800 2.055992e+06 9.254389e+07 MULTIPOLYGON (((472397 5723504.5, 472398.5 572...
1030 Geb61773ln0403_c 175 38 geneigt Süd 27.128010 2.055992e+06 5.577496e+07 MULTIPOLYGON (((472334.41 5723544.5, 472334.5 ...
1253 Geb60563ln0403_c 175 38 geneigt Süd 19.252148 2.055992e+06 3.958226e+07 MULTIPOLYGON (((472370 5723354.5, 472369 57233...

100 rows × 9 columns

Aufgabe 4

  • Erstelle eine Liste mit 10 Dachflächen, auf denen deiner Meinung nach der Einsatz von PV-Anlagen sinnvoll wäre.

(10 Minuten)

sorted_df = solarkataster.sort_values('total_energy_per_square_metre', ascending=False)  
sorted_df.iloc[:10]
geb_id richtung neigung dachtyp himmel_kat flaecheninhalt total_energy_per_square_metre total_energy geometry
id
13 Geb71192ln0403_c 180 47 geneigt Süd 15.741250 2.083685e+06 3.279980e+07 MULTIPOLYGON (((472498 5723301.5, 472498 57233...
193 Geb72502ln0403_c 178 48 geneigt Süd 38.898535 2.083154e+06 8.103162e+07 MULTIPOLYGON (((472559 5723631, 472560 5723631...
229 Geb80497ln0403_c 179 46 geneigt Süd 12.616012 2.082779e+06 2.627636e+07 MULTIPOLYGON (((472510 5723627.5, 472510.5 572...
1810 Geb74557ln0403_c 177 48 geneigt Süd 37.394520 2.082365e+06 7.786903e+07 MULTIPOLYGON (((472492.5 5723627.5, 472493 572...
1406 Geb79875ln0403_c 177 48 geneigt Süd 53.928732 2.082365e+06 1.122993e+08 MULTIPOLYGON (((472489 5723834, 472489 5723834...
926 Geb65145ln0403_c 177 48 geneigt Süd 42.108134 2.082365e+06 8.768450e+07 MULTIPOLYGON (((472399.5 5723450, 472400.5 572...
2540 Geb72885ln0403_c 177 48 geneigt Süd 10.420916 2.082365e+06 2.170015e+07 MULTIPOLYGON (((472455.5 5723613.5, 472458.5 5...
2413 Geb70313ln0403_c 177 49 geneigt Süd 37.711134 2.081993e+06 7.851430e+07 MULTIPOLYGON (((472533.5 5723629.5, 472539.5 5...
672 Geb65166ln0403_c 177 49 geneigt Süd 18.167287 2.081993e+06 3.782415e+07 MULTIPOLYGON (((472389 5723451.5, 472395.162 5...
333 Geb73278ln0403_c 177 49 geneigt Süd 36.689935 2.081993e+06 7.638817e+07 MULTIPOLYGON (((472417.5 5723246, 472421 57232...

Der Algorithmus listet die Zehn besten Dachflächen hinsichtlich des durchschnittlichen Kwh-Outputs auf.

7 Zusammenfassung – Objekterkennung

In diesem Notebook hast du gelernt, wie du:

  • mit einem KI-gestützten Objekterkennungsmodell bereits installierte PV-Anlagen auf Luftbildern (Orthofotos) identifizierst,
  • Luftbilddaten (Orthofotos) als Input für eine Objekterkennung aufbereitest,
  • die Vorhersagen des Modells mit geeigneten Metriken evaluierst, z. B. Präzision, Recall oder F1-Score,
  • die Bedeutung der Erkennung vorhandener Anlagen für die Planung neuer Installationen verstehst,
  • eine Liste potenzieller neuer Standorte erstellst, die für Eigentümer interessant sein könnten,
  • den Gesamtzusammenhang zwischen technischer Analyse, KI und Klimaschutz erkennst.

Wiederverwendung

Zitat

Mit BibTeX zitieren:
@online{sparmann2025,
  author = {Sparmann, Sören},
  title = {Objekterkennung (Teil 2)},
  date = {2025-09-14},
  url = {https://material.cdec.io/modul_2/submodules/03_photovoltaik/02_objekterkennung.html},
  langid = {de}
}
Bitte zitieren Sie diese Arbeit als:
Sparmann, Sören. 2025. “Objekterkennung (Teil 2).” September 14, 2025. https://material.cdec.io/modul_2/submodules/03_photovoltaik/02_objekterkennung.html.
close all nutshells