Satellitendaten-Explorer und -Downloader mit SentinelHub
Dieses Notebook zeigt, wie man Datensätze von Sentinel Hub herunterlädt, einer Plattform zur Verwaltung und zum Zugriff auf Satellitenbilder und geospatiale Daten. Mit der robusten API von Sentinel Hub können Benutzer Satellitenbilder abrufen, verarbeiten und analysieren, die auf spezifische Bedürfnisse zugeschnitten sind. Dies ist besonders wertvoll für Anwendungen wie Umweltüberwachung, geospatiale Analysen und Forschung.
Hauptmerkmale dieses Notebooks:
Zweck: Zugriff auf Satellitenbilder und deren Download über Sentinel Hub.
Anwendungsfälle: Unterstützung bei der Datenfilterung und der Generierung verschiedener Indizes.
Informationen zum Datensatz:
Python Library: Sentinelhub
Author: str.ucture GmbH
Notebook-Version: 1.1 (Aktualisiert: 21. Januar 2025)
1. Festlegen der Pfade und Arbeitsverzeichnisse
import os
''' ---- Verzeichnisse hier angeben ---- '''
download_folder = r".\data\sentinelhub\download"
images_folder = r".\data\sentinelhub\images"
''' ----- Ende der Angaben ---- '''
os.makedirs(download_folder, exist_ok=True)
os.makedirs(images_folder, exist_ok=True)
2. Filtern und Abrufen von Metadaten für Satellitenbilder
2.1 API und Authentifizierung
Die Sentinel Hub API ist eine leistungsstarke RESTful-Schnittstelle, die Zugriff auf Satellitenbilder aus verschiedenen Quellen wie Sentinel, Landsat und anderen Erdbeobachtungsmissionen bietet. Mit dieser API können Benutzer:
Rohdaten von Satelliten abrufen
Statistische Analysen durchführen
Gerenderte Bilder visualisieren
Diese API wird häufig für Anwendungen in Bereichen wie Landwirtschaft, Forstwirtschaft, Umweltüberwachung und mehr verwendet.
a. Authentifizierung mit OAuth2
Um mit der Sentinel Hub API zu interagieren, ist eine OAuth2-Authentifizierung erforderlich. Befolgen Sie diese Schritte, um Ihre Anmeldeinformationen einzurichten und sich zu authentifizieren:
Konto registrieren
Besuchen Sie das Copernicus Data Space Ecosystem und erstellen Sie ein Konto.
Nach der Registrierung melden Sie sich bei Ihrem Konto an.
OAuth-Client erstellen
Befolgen Sie die OAuth Client Registrierungsanleitung.
Erstellen Sie eine
Client-ID
und einClient-Secret
für Ihre Anwendung.
Alternativ gehen Sie zu Dashboard > Benutzereinstellungen > Unter OAuth-Clients wählen Sie + Erstellen. > Füllen Sie die Informationen aus und erstellen Sie. Dies gibt Ihnen Ihre Client-ID
und Client Secret
.
Verwendung der Anmeldeinformationen für Zugriffstoken
Verwenden Sie die
Client-ID
und dasClient-Secret
, um Zugriffstoken anzufordern, die zur Authentifizierung und Autorisierung Ihrer API-Anfragen erforderlich sind.Ersetzen Sie die Platzhalter
Client-ID
undClient-Secret
Werte im folgenden Code durch Ihre tatsächlichen Anmeldeinformationen.
Einmalige Authentifizierung
Die Authentifizierung ist nur einmal pro Computersystem erforderlich. Nachdem Sie Ihre Anmeldeinformationen eingerichtet und authentifiziert haben, können Sie mit den nächsten Schritten fortfahren, ohne den Prozess zu wiederholen.
b. Schnellzugriffslinks:
Konto registrieren: Copernicus Data Space Ecosystem
OAuth-Client einrichten: OAuth Client Anleitung
# # Entkommentieren und führen Sie diese Zelle nur aus, wenn:
# # - Sie diesen Code zum ersten Mal ausführen UND
# # - Sie noch keine Konfiguration erstellt haben.
# from sentinelhub import SHConfig
# # Initialisieren der Sentinel Hub-Konfiguration
# config = SHConfig()
# # Ersetzen Sie die Platzhalter unten mit Ihrer tatsächlichen Client-ID und Client-Secret
# config.sh_client_id = 'your-client-id-here' # Beispiel: '1234abcd-5678-efgh-ijkl-9876mnopqrst'
# config.sh_client_secret = 'your-client-secret-here' # Beispiel: 'a1b2c3d4e5f6g7h8i9j0klmnopqrst'
# # Setzen Sie die Basis-URL und Token-URL für das Copernicus Data Space Ecosystem
# config.sh_base_url = 'https://sh.dataspace.copernicus.eu'
# config.sh_token_url = 'https://identity.dataspace.copernicus.eu/auth/realms/CDSE/protocol/openid-connect/token'
# # Speichern Sie die Konfiguration in einer Datei namens "cdse"
# config.save("cdse")
# Import required modules from sentinelhub
from sentinelhub import (
SHConfig,
DataCollection,
SentinelHubCatalog,
SentinelHubRequest,
BBox,
bbox_to_dimensions,
CRS,
MimeType,
MosaickingOrder,
)
# Load the configuration from the "cdse" file
config = SHConfig("cdse")
# Check if the configuration has loaded properly
if not config.sh_client_id or not config.sh_client_secret:
raise ValueError(
"The configuration file 'cdse' is missing or incomplete. "
"Ensure that you have created it with valid 'client ID' and 'client secret'."
)
2.2 Definieren der Abfrageparameter für Daten
Sie können Satellitendaten mit verschiedenen Parametern filtern, um die Ergebnisse basierend auf Ihrem Interessensgebiet und spezifischen Analysebedürfnissen einzugrenzen. Einige der wichtigsten Parameter sind:
Bounding Box Ausdehnungen: Definieren Sie ein geografisches Interessensgebiet, indem Sie Koordinaten angeben.
Datenbereich: Filtern Sie die Daten, indem Sie ein Start- und Enddatum angeben.
Wolkenbedeckung: Beschränken Sie den Datensatz auf Bilder mit einer bestimmten Wolkenbedeckung.
Evaluierungsskripte: Verwenden Sie benutzerdefinierte Skripte, um bestimmte Bänder zu filtern oder zu verarbeiten, nützlich für fortgeschrittene Anwendungsfälle. (Siehe Abschnitt 3.1 für Details.)
2.2.1. Definieren der Bounding Box Ausdehnungen, Bounding Box und Größe
Die Koordinaten können mit dem Tool BBox Extractor ermittelt werden.
Der BBox Extractor ist ein webbasiertes Tool, das Benutzern hilft, interaktiv eine Bounding Box auszuwählen und deren Koordinaten im WGS84-Format (Breite/Länge) zu generieren. Dies ist besonders nützlich, wenn man mit APIs oder Datensätzen arbeitet, die eine geografische Bereichseingabe erfordern.
# Definieren Sie die Ausdehnungen der Bounding Box im CRS: WGS84-Format [lon_min, lat_min, lon_max, lat_max]
bbox_wgs84 = [9.1170, 47.6330, 9.2180, 47.7160] # Bounding Box für Konstanz, Deutschland
resolution = 10 # Die primären Bänder von Sentinel-2 haben eine räumliche Auflösung von 10m
# Erstellen Sie ein BBox-Objekt und berechnen Sie die Dimensionen der Bounding Box basierend auf der Auflösung
aoi_bbox = BBox(bbox=bbox_wgs84, crs=CRS.WGS84)
aoi_size = bbox_to_dimensions(aoi_bbox, resolution=resolution)
# Referenzdokumentation für Sentinel-2-Bänder und Auflösung
# Weitere Informationen: https://docs.sentinel-hub.com/api/latest/data/sentinel-2-l1c/
2.2.2 Definieren des Datumsbereichs für die Suche nach Satellitendaten
import ipywidgets as widgets
import datetime
# Erstellen eines DatePicker-Widgets zur Auswahl des Startdatums
initial_date = widgets.DatePicker(
description="Startdatum auswählen: ",
style=dict(description_width='initial'),
disabled=False,
value=datetime.date(2024,1,1)
)
# Anzeigen des DatePicker-Widgets
display(initial_date)
# Erstellen eines DatePicker-Widgets zur Auswahl des Enddatums
final_date = widgets.DatePicker(
description="Enddatum auswählen: ",
style=dict(description_width='initial'),
disabled=False,
value=datetime.date.today()
)
# Anzeigen des DatePicker-Widgets
display(final_date)
# Stellen Sie sicher, dass das Zeitintervall nur festgelegt wird, wenn beide Datumswerte gültig sind
if initial_date.value and final_date.value:
# Erstellen eines Tupels für das Zeitintervall mit dem ausgewählten Start- und Enddatum
time_interval = (str(initial_date.value), str(final_date.value))
print(f"Zeitintervall erfolgreich festgelegt: {time_interval}")
else:
# Fehler auslösen, wenn ein Datum fehlt
raise ValueError("Sowohl das Start- als auch das Enddatum müssen ausgewählt werden, um das Zeitintervall festzulegen.")
Zeitintervall erfolgreich festgelegt: ('2024-01-01', '2025-04-02')
2.2.3 Maximale Wolkenbedeckung in Prozent festlegen
# Erstellen eines BoundedIntText-Widgets zur Angabe des Prozentsatzes der Wolkenbedeckung
cloud_cover_input = widgets.BoundedIntText(
value=20,
min=0,
max=100,
step=10,
description="Wolkenbedeckung (%):",
style={"description_width": "initial"},
)
# Anzeigen des Eingabe-Widgets für die Wolkenbedeckung
display(cloud_cover_input)
2.3 Gefilterten Datensatz mit SentinelHubCatalog abrufen
Der SentinelHubCatalog ist ein leistungsstarkes Tool innerhalb der Sentinel Hub API, das Benutzern ermöglicht, nach Metadaten für Satellitenbild-Datensätze zu suchen und diese abzurufen. Es bietet erweiterte Filterfunktionen basierend auf verschiedenen Parametern, wie:
Zeitraum: Filtern nach bestimmten Daten oder Zeitintervallen.
Interessensgebiet (AoI): Definieren der geografischen Region für den Datensatz.
Wolkenbedeckung: Filtern von Bildern basierend auf dem Prozentsatz der Wolkenbedeckung.
Datensammlungen: Auswahl verschiedener Datensätze (z. B. Sentinel-2, Landsat).
Dieses Tool vereinfacht den Prozess der Identifizierung und des Abrufs relevanter Bilder, indem es eine effiziente Filterung anhand dieser Kriterien ermöglicht.
import pandas as pd
# Initialisieren des SentinelHubCatalog mit der Konfiguration
catalog = SentinelHubCatalog(config=config)
# Durchsuchen der Sentinel-2 L2A-Datensammlung mit den definierten Parametern
search_iterator = catalog.search(
DataCollection.SENTINEL2_L2A,
bbox=aoi_bbox,
time=time_interval,
filter=f"eo:cloud_cover <= {cloud_cover_input.value}",
)
# Konvertieren der Suchergebnisse in eine Liste
results = list(search_iterator)
print("Gesamtanzahl der Ergebnisse:", len(results))
# Verarbeitung der Ergebnisse in eine strukturierte Liste von Dictionaries
data = []
for entry in results:
id = entry['id']
dt = entry['properties']['datetime']
date, time = dt.split('T')
time = time.replace('Z', '')
cloud_cover = entry['properties']['eo:cloud_cover']
data.append({
'Datum': date,
'Uhrzeit': time,
'Wolkenbedeckung (%)': cloud_cover,
'Id': id,
}),
# Konvertieren der Liste in ein Pandas DataFrame und Anzeigen der ersten 8 Zeilen
df = pd.DataFrame(data).sort_values(by='Wolkenbedeckung (%)').reset_index(drop=True)
df.head(8)
---------------------------------------------------------------------------
InvalidClientError Traceback (most recent call last)
Cell In[9], line 15
7 search_iterator = catalog.search(
8 DataCollection.SENTINEL2_L2A,
9 bbox=aoi_bbox,
10 time=time_interval,
11 filter=f"eo:cloud_cover <= {cloud_cover_input.value}",
12 )
14 # Konvertieren der Suchergebnisse in eine Liste
---> 15 results = list(search_iterator)
16 print("Gesamtanzahl der Ergebnisse:", len(results))
18 # Verarbeitung der Ergebnisse in eine strukturierte Liste von Dictionaries
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\base.py:277, in FeatureIterator.__next__(self)
272 """Method called to provide the next feature in iteration
273
274 :return: the next feature
275 """
276 while self.index >= len(self.features) and not self.finished:
--> 277 new_features = self._fetch_features()
278 self.features.extend(new_features)
280 if self.index < len(self.features):
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\api\catalog.py:245, in CatalogSearchIterator._fetch_features(self)
242 """Collects more results from the service"""
243 payload = remove_undefined({**self.params, "next": self.next})
--> 245 results = self.client.get_json_dict(self.url, post_values=payload, use_session=True)
247 self.next = results["context"].get("next")
248 new_features = results["features"]
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\client.py:248, in DownloadClient.get_json_dict(self, url, extract_key, *args, **kwargs)
240 def get_json_dict(self, url: str, *args: Any, extract_key: str | None = None, **kwargs: Any) -> JsonDict:
241 """Download request as JSON data type, failing if the result is not a dictionary
242
243 For other parameters see `get_json` method.
(...)
246 :param extract_key: If provided, the field is automatically extracted, checked, and returned
247 """
--> 248 response = self.get_json(url, *args, **kwargs)
250 if not isinstance(response, dict):
251 raise MissingDataInRequestException(
252 f"Response from {url} was expected to be a dictionary, but got {type(response)}."
253 )
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\client.py:238, in DownloadClient.get_json(self, url, post_values, headers, request_type, **kwargs)
227 json_headers = {"Content-Type": MimeType.JSON.get_string(), **json_headers}
229 request = DownloadRequest(
230 url=url,
231 headers=json_headers,
(...)
235 **kwargs,
236 )
--> 238 return self._single_download_decoded(request)
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\client.py:116, in DownloadClient._single_download_decoded(self, request)
114 def _single_download_decoded(self, request: DownloadRequest) -> Any:
115 """Downloads a response and decodes it into data. By decoding a single response"""
--> 116 response = self._single_download(request)
117 return None if response is None else response.decode()
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\client.py:129, in DownloadClient._single_download(self, request)
127 no_local_data = self.redownload or response_path is None or not os.path.exists(response_path)
128 if no_local_data:
--> 129 response = self._execute_download(request)
130 else:
131 if not request.return_data or response_path is None:
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\handlers.py:67, in retry_temporary_errors.<locals>.new_download_func(self, request)
65 for attempt_idx in range(download_attempts):
66 try:
---> 67 return download_func(self, request)
69 except requests.RequestException as exception: # noqa: PERF203
70 attempts_left = download_attempts - (attempt_idx + 1)
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\handlers.py:40, in fail_user_errors.<locals>.new_download_func(self, request)
37 @functools.wraps(download_func)
38 def new_download_func(self: Self, request: DownloadRequest) -> T:
39 try:
---> 40 return download_func(self, request)
41 except requests.HTTPError as exception:
42 if (
43 exception.response.status_code < requests.status_codes.codes.INTERNAL_SERVER_ERROR
44 and exception.response.status_code != requests.status_codes.codes.TOO_MANY_REQUESTS
45 ):
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\sentinelhub_client.py:90, in SentinelHubDownloadClient._execute_download(self, request)
83 download_attempts += 1
84 LOGGER.debug(
85 "Sending %s request to %s. Hash of sent request is %s",
86 request.request_type.value,
87 request.url,
88 request.get_hashed_name(),
89 )
---> 90 response = self._do_download(request)
92 if response.status_code == requests.status_codes.codes.TOO_MANY_REQUESTS:
93 warnings.warn("Download rate limit hit", category=SHRateLimitWarning)
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\sentinelhub_client.py:125, in SentinelHubDownloadClient._do_download(self, request)
118 if request.url is None:
119 raise ValueError(f"Faulty request {request}, no URL specified.")
121 return requests.request(
122 request.request_type.value,
123 url=request.url,
124 json=request.post_values,
--> 125 headers=self._prepare_headers(request),
126 timeout=self.config.download_timeout_seconds,
127 )
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\sentinelhub_client.py:136, in SentinelHubDownloadClient._prepare_headers(self, request)
134 session_headers: JsonDict = {}
135 if request.use_session:
--> 136 session_headers = self._execute_thread_safe(self._get_session_headers)
138 return {**SHConstants.HEADERS, **session_headers, **request.headers}
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\sentinelhub_client.py:111, in SentinelHubDownloadClient._execute_thread_safe(self, thread_unsafe_function, *args, **kwargs)
109 """Executes a function inside a thread lock and handles potential errors"""
110 if self.lock is None:
--> 111 return thread_unsafe_function(*args, **kwargs)
113 with self.lock:
114 return thread_unsafe_function(*args, **kwargs)
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\sentinelhub_client.py:146, in SentinelHubDownloadClient._get_session_headers(self)
140 def _get_session_headers(self) -> JsonDict:
141 """Provides up-to-date session headers
142
143 Note that calling session_headers property triggers update if session has expired therefore this has to be
144 called in a thread-safe way
145 """
--> 146 return self.get_session().session_headers
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\sentinelhub_client.py:162, in SentinelHubDownloadClient.get_session(self)
160 session = SentinelHubDownloadClient._CACHED_SESSIONS[SentinelHubDownloadClient._UNIVERSAL_CACHE_KEY]
161 else:
--> 162 session = SentinelHubSession(config=self.config)
163 SentinelHubDownloadClient._CACHED_SESSIONS[cache_key] = session
165 return session
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\session.py:73, in SentinelHubSession.__init__(self, config, refresh_before_expiry, _token)
66 if token_fetching_required and not (self.config.sh_client_id and self.config.sh_client_secret):
67 raise ValueError(
68 "Configuration parameters 'sh_client_id' and 'sh_client_secret' have to be set in order "
69 "to authenticate with Sentinel Hub service. Check "
70 "https://sentinelhub-py.readthedocs.io/en/latest/configure.html for more info."
71 )
---> 73 self._token = self._collect_new_token() if _token is None else _token
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\session.py:127, in SentinelHubSession._collect_new_token(self)
121 """Creates a download request and fetches a token from the service.
122
123 Note that the `DownloadRequest` object is created only because retry decorators of `_fetch_token` method
124 require it.
125 """
126 request = DownloadRequest(url=f"{self.config.sh_token_url}")
--> 127 return self._fetch_token(request)
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\handlers.py:67, in retry_temporary_errors.<locals>.new_download_func(self, request)
65 for attempt_idx in range(download_attempts):
66 try:
---> 67 return download_func(self, request)
69 except requests.RequestException as exception: # noqa: PERF203
70 attempts_left = download_attempts - (attempt_idx + 1)
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\handlers.py:40, in fail_user_errors.<locals>.new_download_func(self, request)
37 @functools.wraps(download_func)
38 def new_download_func(self: Self, request: DownloadRequest) -> T:
39 try:
---> 40 return download_func(self, request)
41 except requests.HTTPError as exception:
42 if (
43 exception.response.status_code < requests.status_codes.codes.INTERNAL_SERVER_ERROR
44 and exception.response.status_code != requests.status_codes.codes.TOO_MANY_REQUESTS
45 ):
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\sentinelhub\download\session.py:139, in SentinelHubSession._fetch_token(self, request)
136 with OAuth2Session(client=oauth_client) as oauth_session:
137 oauth_session.register_compliance_hook("access_token_response", self._compliance_hook)
--> 139 return oauth_session.fetch_token(
140 token_url=request.url,
141 client_id=self.config.sh_client_id,
142 client_secret=self.config.sh_client_secret,
143 headers={**self.DEFAULT_HEADERS, **SHConstants.HEADERS},
144 include_client_id=True,
145 )
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\requests_oauthlib\oauth2_session.py:406, in OAuth2Session.fetch_token(self, token_url, code, authorization_response, body, auth, username, password, method, force_querystring, timeout, headers, verify, proxies, include_client_id, client_secret, cert, **kwargs)
403 log.debug("Invoking hook %s.", hook)
404 r = hook(r)
--> 406 self._client.parse_request_body_response(r.text, scope=self.scope)
407 self.token = self._client.token
408 log.debug("Obtained token %s.", self.token)
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\oauthlib\oauth2\rfc6749\clients\base.py:427, in Client.parse_request_body_response(self, body, scope, **kwargs)
379 """Parse the JSON response body.
380
381 If the access token request is valid and authorized, the
(...)
424 .. _`Section 7.1`: https://tools.ietf.org/html/rfc6749#section-7.1
425 """
426 scope = self.scope if scope is None else scope
--> 427 self.token = parse_token_response(body, scope=scope)
428 self.populate_token_attributes(self.token)
429 return self.token
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\oauthlib\oauth2\rfc6749\parameters.py:441, in parse_token_response(body, scope)
438 params['expires_at'] = time.time() + int(params['expires_in'])
440 params = OAuth2Token(params, old_scope=scope)
--> 441 validate_token_parameters(params)
442 return params
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\oauthlib\oauth2\rfc6749\parameters.py:448, in validate_token_parameters(params)
446 """Ensures token presence, token type, expiration and scope in params."""
447 if 'error' in params:
--> 448 raise_from_error(params.get('error'), params)
450 if not 'access_token' in params:
451 raise MissingTokenError(description="Missing access token parameter.")
File F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\oauthlib\oauth2\rfc6749\errors.py:399, in raise_from_error(error, params)
397 for _, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass):
398 if cls.error == error:
--> 399 raise cls(**kwargs)
400 raise CustomOAuth2Error(error=error, **kwargs)
InvalidClientError: (invalid_client) Invalid client or Invalid client credentials
# Zusätzliche Filterung, um nur Bilder aus den Sommermonaten (Juni, Juli und August) auszuwählen
df['Datum'] = pd.to_datetime(df['Datum'])
filtered_df = df[df['Datum'].dt.month.isin([6, 7, 8])].reset_index(drop=True)
filtered_df.head(3)
Datum | Uhrzeit | Wolkenbedeckung (%) | Id | |
---|---|---|---|---|
0 | 2024-08-23 | 10:27:45.974 | 0.08 | S2B_MSIL2A_20240823T101559_N0511_R065_T32TMT_2... |
1 | 2024-08-23 | 10:27:44.048 | 0.37 | S2B_MSIL2A_20240823T101559_N0511_R065_T32TNT_2... |
2 | 2024-08-11 | 10:37:42.547 | 0.87 | S2A_MSIL2A_20240811T103031_N0511_R108_T32TNT_2... |
3. Herunterladen und Visualisieren von Satellitendaten
3.1 Evaluierungsskripte für die Verarbeitung von Satellitendaten
Evaluierungsskripte (evalscript) in der Sentinel Hub API werden verwendet, um die Verarbeitung und Visualisierung von Satellitenbilddaten anzupassen. Mit diesen Skripten können Sie Bänder auswählen, Indizes berechnen (z. B. NDVI), benutzerdefinierte Visualisierungen anwenden sowie Daten filtern oder maskieren. Sie werden serverseitig ausgeführt, um verarbeitete Ausgaben wie Bilder oder numerische Werte bereitzustellen, die auf die spezifischen Bedürfnisse des Benutzers zugeschnitten sind. Durch die Verwendung von Evaluierungsskripten können Sie die Datenverarbeitung optimieren und sich auf die präzisen Informationen konzentrieren, die für Fernerkundungsanalysen oder Anwendungen erforderlich sind.
Warnung!!: Ändern Sie die Evaluierungsskripte nur, wenn Sie sich Ihrer Änderungen sicher sind.
Für eine umfassende Sammlung von Evaluierungsskripten und eine detaillierte Anleitung zur Nutzung besuchen Sie die offizielle Dokumentation von Sentinel Hub, Sentinelhub Evalscript Dokumentation. Diese Ressource bietet tiefgehende Erklärungen, Syntaxrichtlinien und praktische Beispiele, die Ihnen helfen, Evaluierungsskripte zur effizienten Verarbeitung von Satellitenbildern zu erstellen und anzupassen.
evalscript_sentinel2_all_bands = """
//VERSION=3
function setup() {
return {
input: [{
bands: ["B01","B02","B03","B04","B05","B06","B07","B08","B8A","B09","B10","B11","B12"],
units: "DN"
}],
output: {
bands: 13,
sampleType: "INT16"
}
};
}
function evaluatePixel(sample) {
return [sample.B01,
sample.B02,
sample.B03,
sample.B04,
sample.B05,
sample.B06,
sample.B07,
sample.B08,
sample.B8A,
sample.B09,
sample.B10,
sample.B11,
sample.B12];
}
"""
3.2 Satellitendaten anfordern und Visualisieren
3.2.1 Anforderung der Datensammlung und Abruf des Satellitenbildes mit der geringsten Wolkenbedeckung (Least_CC)
Hinweis: Die Methode Least_CC hilft, die Datenqualität zu optimieren, insbesondere wenn die Wolkenbedeckung die Klarheit des Bildes beeinträchtigen kann. Stellen Sie sicher, dass Sie dies in Ihrer Anfrage angeben, um die Chancen auf klare Bilder zu maximieren.
# Definieren Sie eine Anfrage, um alle Sentinel-2-Bänder herunterzuladen
request_all_bands = SentinelHubRequest(
data_folder = download_folder,
evalscript=evalscript_sentinel2_all_bands,
input_data=[
SentinelHubRequest.input_data(
data_collection=DataCollection.SENTINEL2_L1C.define_from(
"s2l1c",
service_url=config.sh_base_url
),
time_interval=time_interval,
mosaicking_order=MosaickingOrder.LEAST_CC,
)
],
responses=[SentinelHubRequest.output_response("default", MimeType.TIFF)],
bbox=aoi_bbox,
size=aoi_size,
config=config,
)
# Anfordern und Abrufen der Daten (ohne sie lokal zu speichern)
all_bands_response = request_all_bands.get_data(save_data=False)
3.2.2 Definieren eine Funktion zur Darstellung der Satellitendaten
import matplotlib.pyplot as plt
import numpy as np
from typing import Any, Optional, Tuple
def plot_image(
image: np.ndarray,
factor: float = 1.0,
clip_range: Optional[Tuple[float, float]] = None,
figsize: Tuple[float, float] = (15, 15),
show_axis: bool = False, # Hinzugefügte Option zum Anzeigen der Achsen
**kwargs: Any
) -> None:
"""
Hilfsfunktion zum Plotten von RGB-Bildern.
Parameter:
image (np.ndarray): Das Bildarray, das geplottet werden soll. Erwartete Form ist (Höhe, Breite, Kanäle).
factor (float, optional): Skalierungsfaktor zur Anpassung der Bildintensität. Der Standardwert ist 1.0.
clip_range (Tuple[float, float], optional): Bereich für das Zuschneiden der Bildintensitätswerte.
Wenn angegeben, werden die Bildwerte auf diesen Bereich begrenzt.
figsize (Tuple[float, float], optional): Größe der Abbildung in Zoll. Der Standardwert ist (15, 15).
show_axis (bool, optional): Ob die Achsenmarkierungen angezeigt werden sollen. Der Standardwert ist False.
**kwargs (Any): Weitere Schlüsselwortargumente, die an plt.imshow übergeben werden.
Rückgabewert:
None: Die Funktion zeigt das Bild mit matplotlib an.
"""
# Erstellen einer Figur und Achse zum Plotten
fig, ax = plt.subplots(figsize=figsize)
# Anwendung der Skalierung und optionales Zuschneiden des Bildes
image_to_display = np.clip(image * factor, *clip_range) if clip_range is not None else image * factor
# Bild anzeigen
ax.imshow(image_to_display, **kwargs)
# Bedingtes Entfernen der Achsenmarkierungen für eine sauberere Bildanzeige
if not show_axis:
ax.set_xticks([])
ax.set_yticks([])
ax.axis('off')
3.2.3 Visualisierung des Satellitenbildes in Echtfarbe (RGB)
# Holen Sie sich das erste Bild aus all_bands_response
image = all_bands_response[0]
# Berechnen Sie den Intensitätsbereich für Skalierung und Zuschneiden
min_val = np.percentile(image, 2) # 2. Perzentil für die untere Grenze
max_val = np.percentile(image, 98) # 98. Perzentil für die obere Grenze
# Berechnen Sie den Skalierungsfaktor basierend auf dem maximalen Wert
factor = 1.0 / max_val
# Wenden Sie einen Multiplikator an, um die Intensität weiter anzupassen
factor_multiplier = 1.4
# Plotten Sie das Bild in echten Farben (RGB) unter Verwendung des berechneten Skalierungsfaktors
plot_image(
image[:, :, [3, 2, 1]], # Bandindizes für Rot, Grün und Blau (B04, B03, B02)
factor=factor * factor_multiplier, # Wenden Sie den Faktor und den Multiplikator an, um die Intensität zu skalieren
clip_range=(0, 1), # Begrenzen Sie die Intensität auf den Bereich [0, 1]
figsize=(8, 8)
)
# Setzen Sie den Titel für das Diagramm
plt.title("Echtes Farb-Bild (True Color (RGB))", fontsize=14, fontweight='bold')
plt.show()

Manchmal können die Anforderungsparameter—wie der Zeitraum und mosaicking_order
—zu minderwertigen oder unerwünschten Mosaik-Satellitendaten führen. In solchen Fällen kann es notwendig sein, das Zeitintervall manuell anzupassen, um sicherzustellen, dass die gewünschten Satellitenbilder abgerufen werden. Weitere Details dazu, wie man den Zeitraum ändert, finden Sie in Abschnitt 2.3.
Zusätzlich ist die Möglichkeit, direkt auf Satellitendaten anhand einer bestimmten Bild-ID zuzugreifen, eine wertvolle Funktion mit großem Potenzial. Diese Funktion sollte weiter untersucht werden, um ihre Möglichkeiten vollständig zu verstehen und effektiv umzusetzen.
# Beispiel: Anfordern von Daten für die angegebenen Parameter in der Tabelle "df"
# Definieren des Zeitintervalls (ändern je nach spezifischen Anforderungen)
time_interval = '2024-08-23' # Passen Sie diesen Wert an, um nach dem gewünschten Zeitraum zu filtern
# Anfordern von Satellitendaten basierend auf den bereitgestellten Parametern
request_all_bands = SentinelHubRequest(
data_folder=download_folder,
evalscript=evalscript_sentinel2_all_bands,
input_data=[
SentinelHubRequest.input_data(
data_collection=DataCollection.SENTINEL2_L1C.define_from(
"s2l1c", service_url=config.sh_base_url
),
time_interval=time_interval,
)
],
responses=[SentinelHubRequest.output_response("default", MimeType.TIFF)],
bbox=aoi_bbox,
size=aoi_size,
config=config,
)
# Abrufen der Satellitendaten
all_bands_response_v2 = request_all_bands.get_data(save_data=False)
# Ändern Sie save_data=True, um die Daten lokal zu speichern
# all_bands_response_v3 = request_all_bands.get_data(save_data=True)
3.2.4 Visualisierung des aktualisierten Satellitenbildes in Echtfarbe (RGB)
# Abrufen des ersten Bildes aus den Antwortdaten
image = all_bands_response_v2[0]
# Berechnung des Intensitätsbereichs, Skalierungsfaktors und Anpassung der Gesamthelligkeit
min_val = np.percentile(image, 2)
max_val = np.percentile(image, 98)
factor = 1.0 / max_val
factor_multiplier = 1.6
# Plotten des Bildes in echten Farben (RGB) unter Verwendung des angegebenen Skalierungs- und Clipping-Bereichs
plot_image(
image[:, :, [3, 2, 1]],
factor=factor * factor_multiplier,
clip_range=(0, 1),
figsize=(8, 8)
)
# Festlegen des Titels für das Diagramm
plt.title("Echtes Farb-Bild (True Color (RGB))", fontsize=14, fontweight='bold')
plt.show()

4. Speichern das Bild als GeoTIFF-Raster und PNG
Eine effektive Möglichkeit, Sentinel-2-Datensätze zu visualisieren und die Integrität zu bewahren, besteht darin, sie lokal als GeoTIFF-Datei zu speichern. GeoTIFF ist ein weit verbreitetes Format, das nicht nur die Bilddaten, sondern auch wichtige geospatiale Metadaten wie geografische Koordinaten, Projektionsinformationen und andere Eigenschaften beibehält. Dies macht es ideal für weitere Analysen in GIS-Software wie QGIS, ArcGIS oder anderen geospatialen Tools.
Das Speichern Ihres Bildes in diesem Format stellt sicher, dass Sie die Bilddaten einfach laden, manipulieren und visualisieren können, während die räumliche Referenz beibehalten wird.
import rasterio
from rasterio.transform import from_bounds
from PIL import Image
# Definieren Sie die Form und die Transformationsparameter basierend auf den Bildabmessungen
höhe, breite, bänder = image.shape
transform = from_bounds(*bbox_wgs84, width=breite, height=höhe)
# Extrahieren Sie die RGB-Bänder (Rot, Grün, Blau) und verarbeiten Sie das Bild vor
rgb_image = image[:, :, [3, 2, 1]]
clipped_image = np.clip(rgb_image * factor * factor_multiplier, 0, 1)
uint8_image = (clipped_image * 255).astype(np.uint8)
# Definieren Sie die Pfade zum Speichern der Bilder
temp_tif = os.path.join(images_folder, f"sentinel2_all_bands_{time_interval}.tif")
temp_png = os.path.join(images_folder, f"sentinel2_rgb_{time_interval}.png")
# Stellen Sie sicher, dass der Download-Ordner existiert
os.makedirs(images_folder, exist_ok=True)
# Speichern Sie das Bild als GeoTIFF, wenn es noch nicht existiert
if not os.path.isfile(temp_tif):
with rasterio.open(
temp_tif,
"w",
driver="GTiff",
height=höhe,
width=breite,
count=3, # Nur 3 Bänder für RGB
dtype=uint8_image.dtype,
crs="EPSG:4326", # WGS84-Koordinatenreferenzsystem
transform=transform,
) as dst:
for i in range(3): # Schleife durch die RGB-Bänder
dst.write(uint8_image[:, :, i], i + 1)
print(f"GeoTIFF gespeichert unter: {temp_tif}")
else:
print(f"GeoTIFF-Datei existiert bereits unter: {temp_tif}")
# Speichern Sie das Bild als PNG-Datei
if not os.path.isfile(temp_png):
# Konvertieren Sie das RGB-Array in das PIL Image-Format und speichern Sie es als PNG
pil_image = Image.fromarray(uint8_image, mode="RGB")
pil_image.save(temp_png)
print(f"PNG gespeichert unter: {temp_png}")
else:
print(f"PNG-Datei existiert bereits unter: {temp_png}")
GeoTIFF-Datei existiert bereits unter: .\data\sentinelhub\images\sentinel2_all_bands_2024-08-23.tif
PNG-Datei existiert bereits unter: .\data\sentinelhub\images\sentinel2_rgb_2024-08-23.png
5. Visualisieren True-Color-Raster mit einer interaktiven Karte
Sobald das True-Color-Raster als GeoTIFF-Datei gespeichert wurde, kann es einfach mit Folium visualisiert werden.
import folium
from folium.plugins import MiniMap, Fullscreen
# Erstellen Sie eine Folium-Karte, die um die Bounding Box zentriert ist
m = folium.Map(
location=[(bbox_wgs84[1] + bbox_wgs84[3])/2, (bbox_wgs84[0] + bbox_wgs84[2])/2],
zoom_start=12,
scrollWheelZoom=False
)
# Definieren Sie die Grenzen des Bildes in Breitengrad/Längengrad
bounds_latlon = [[bbox_wgs84[1], bbox_wgs84[0]], [bbox_wgs84[3], bbox_wgs84[2]]]
# Fügen Sie eine Rasterüberlagerung für das gespeicherte PNG-Bild hinzu (alternativ kann auch GeoTIFF verwendet werden)
temp_png_filename = (os.path.basename(temp_png).split(".")[0])
folium.raster_layers.ImageOverlay(
name=f"{temp_png_filename}",
image=temp_png,
bounds=bounds_latlon,
opacity=1.0,
).add_to(m)
# Fügen Sie eine Layer-Steuerung hinzu (zum Umschalten zwischen den Layern)
folium.LayerControl().add_to(m)
# Fügen Sie MiniMap und Fullscreen-Steuerelemente hinzu
MiniMap(toggle_display=True, minimized=True).add_to(m)
Fullscreen().add_to(m)
# Zeigen Sie die Karte an
m
6. Analyse und Visualisierung von Satellitenbildern
6.1 Falschfarbenkomposit: Vegetationsanalyse
Falschfarbenkomposits heben spezifische Merkmale in Satellitenbildern hervor, wie z. B. Vegetation, Gewässer und städtische Gebiete, indem verschiedenen Farben unsichtbare spektrale Bänder zugewiesen werden. Diese Methode ist besonders nützlich für die Analyse der Landnutzung, der Vegetationsgesundheit (mit Bändern wie NIR und Red Edge) und anderer Umweltfaktoren.
Mehr über benutzerdefinierte Komposit-Skripte und deren Anwendungsfälle können Sie im offiziellen Sentinel Hub Custom Scripts Repository erfahren.
import textwrap
# Erstellen Sie eine Falschfarbenkompositdarstellung unter Verwendung spezifischer Bänder:
# Band 7 (NIR), Band 3 (Rot), Band 2 (Grün) für die Vegetationsanalyse
# Dies wird oft verwendet, um Vegetation hervorzuheben, da das NIR-Band (Nahinfrarot) die Vegetation stark reflektiert.
plot_image(
image[:, :, [7, 3, 2]], # NIR (Band 7), Rot (Band 3), Grün (Band 2)
factor=factor*factor_multiplier,
clip_range=(0, 1),
figsize=(8, 8)
)
# Setzen Sie den Titel für das Diagramm
plt.title("Falschfarbenkomposit - Vegetationsanalyse", fontsize=14, fontweight='bold')
# Beschreibungstext definieren
text = (
"Das Falschfarbenkomposit verwendet das Nahinfrarot (Band 7), Rot (Band 3) und Grün (Band 2), um Vegetation hervorzuheben. Vegetation erscheint in leuchtendem Rot, da sie das NIR stark reflektiert."
)
wrapped_text = textwrap.fill(text, width=80)
# Beschreibung hinzufügen
plt.figtext(
0.2,
0.07,
wrapped_text,
ha='left',
va='center',
fontsize=8,
# wrap=True,
backgroundcolor='w',
)
# Zeigen Sie das Diagramm an
plt.show()

6.2 Fernerkundungsindizes (Remote Sensing Indices)
Fernerkundungsindizes wie der Normalized Difference Vegetation Index (NDVI), Normalized Difference Water Index (NDWI) und andere werden häufig verwendet, um verschiedene Umweltfaktoren wie die Gesundheit der Vegetation, Gewässer und die Landbedeckung zu analysieren.
Weitere Informationen zur Berechnung und Nutzung dieser Indizes finden Sie im offiziellen Sentinel Hub Custom Scripts Repositiry
6.2.1 Normalized Difference Vegetation Index (NDVI)
Der Normalized Difference Vegetation Index (NDVI) misst die Pflanzen-gesundheit und Biomasse. Er wird häufig verwendet, um das Wachstum und die Gesundheit der Vegetation zu überwachen sowie Gebiete mit Stress oder Schäden zu identifizieren.
# Extrahieren Sie die NIR (Band 8) und Rot (Band 4) Bänder aus den Satellitendaten
nir = all_bands_response_v2[0][:, :, 7] # Band 8 (NIR)
rot = all_bands_response_v2[0][:, :, 3] # Band 4 (Rot)
# Berechnen Sie den NDVI (Fügen Sie eine kleine Zahl zum Nenner hinzu, um Division durch null zu vermeiden)
ndvi = (nir - rot) / (nir + rot + 1e-10)
# NDVI plotten
plt.figure(figsize=(10, 10))
cmap = plt.get_cmap('RdYlGn', 8)
plt.imshow(ndvi, cmap=cmap, vmin=-1, vmax=1)
# Fügen Sie eine Farbskala hinzu
plt.colorbar(label='NDVI')
# Setzen Sie den Titel für das Diagramm
plt.title('NDVI', fontsize=14, fontweight='bold')
# Definieren Sie den Beschreibungstext
text = (
"NDVI (Normalized Difference Vegetation Index) wird unter Verwendung des Nahinfrarot (Band 8) und Rot (Band 4) Bändern berechnet. "
"NDVI-Werte reichen von -1 bis 1, wobei höhere Werte (näher bei 1) auf gesunde Vegetation hinweisen, und niedrigere Werte (näher bei -1) "
"auf nicht-vegetierte Oberflächen wie Wasser, nackten Boden oder städtische Gebiete hinweisen."
)
wrapped_text = textwrap.fill(text, width=100)
# Beschreibung hinzufügen
plt.figtext(
0.13,
0.07,
wrapped_text,
ha='left',
va='center',
fontsize=8,
backgroundcolor='w',
)
# Entfernen Sie die Achsenmarkierungen für eine sauberere Anzeige
plt.axis('off')
# Zeigen Sie das Diagramm an
plt.show()

6.2.2 Normalized Difference Moisture Index (NDMI)
Der Normalized Difference Moisture Index (NDMI) ist ein wichtiger Indikator zur Überwachung des Wassergehalts von Pflanzen. Er hilft dabei, die Pflanzen gesund zu bewerten, Trockenstress zu erkennen und die Effizienz der Bewässerung zu beurteilen.
# Extrahiere die NIR (Band 8) und SWIR (Band 12) Bänder aus den Satellitendaten
nir = all_bands_response_v2[0][:, :, 7] # Band 8 (NIR)
swir = all_bands_response_v2[0][:, :, 11] # Band 12 (SWIR)
# Berechne den NDMI (Füge eine kleine Zahl zum Nenner hinzu, um eine Division durch null zu vermeiden)
ndmi = (nir - swir) / (nir + swir + 1e-10)
# Plotte den NDMI
plt.figure(figsize=(10, 10))
cmap = plt.get_cmap('BrBG', 8) # Angepasste Farbkarte für NDMI
plt.imshow(ndmi, cmap=cmap, vmin=-1, vmax=1)
# Füge eine Farbskala hinzu
plt.colorbar(label='NDMI')
# Setze den Titel für das Diagramm
plt.title('NDMI', fontsize=14, fontweight='bold')
# Definiere die Textbeschreibung
text = (
"NDMI (Normalized Difference Moisture Index) wird unter Verwendung des Nahinfrarot (Band 8) und des Kurzwelligen Infrarots (Band 12) berechnet. "
"Die NDMI-Werte reichen von -1 bis 1, wobei höhere Werte einen höheren Feuchtigkeitsgehalt anzeigen und niedrigere Werte trockene Bereiche anzeigen."
)
wrapped_text = textwrap.fill(text, width=100)
# Füge die Beschreibung hinzu
plt.figtext(
0.13,
0.07,
wrapped_text,
ha='left',
va='center',
fontsize=8,
backgroundcolor='w',
)
# Entferne die Achsenmarkierungen für eine sauberere Anzeige
plt.axis('off')
# Zeige das Diagramm an
plt.show()

6.2.3 Oberflächenalbedo
Albedo ist ein Maß für die Reflektivität einer Oberfläche, das angibt, wie viel Sonnenlicht von einer Oberfläche reflektiert wird im Vergleich dazu, wie viel absorbiert wird. Es ist entscheidend für das Verständnis des Energiehaushalts der Oberfläche, der Wärmeverteilung und der Eigenschaften der Landbedeckung. In der Fernerkundung wird Albedo häufig verwendet, um Veränderungen in den Oberflächenmerkmalen wie Schneebedeckung, Vegetation oder Urbanisierung zu untersuchen.
Albedo-Werte reichen von 0 (keine Reflektion, vollständige Absorption) bis 1 (vollständige Reflektion), wobei ein höheres Albedo reflektierendere Oberflächen (wie Schnee oder Eis) und ein niedrigeres Albedo dunklere Oberflächen (wie Wälder oder Ozeane) anzeigt.
Regerenz: Albedo-Retrieval von Sentinel-2
# Extrahiere die Bänder und konvertiere DN in Reflektivität (DN = 10000 * REFLEKTANZ)
B02 = all_bands_response_v2[0][:, :, 1] / 10000.0 # Blau
B03 = all_bands_response_v2[0][:, :, 2] / 10000.0 # Grün
B04 = all_bands_response_v2[0][:, :, 3] / 10000.0 # Rot
B08 = all_bands_response_v2[0][:, :, 7] / 10000.0 # NIR
B11 = all_bands_response_v2[0][:, :, 11] / 10000.0 # SWIR1
B12 = all_bands_response_v2[0][:, :, 12] / 10000.0 # SWIR2
# Berechne Albedo unter Verwendung der Gewichtungen für jedes Band
albedo = (B02 * 0.2266) + (B03 * 0.1236) + (B04 * 0.1573) + \
(B08 * 0.3417) + (B11 * 0.1170) + (B12 * 0.0338)
# Setze den Albedo-Bereich für die Visualisierung
vmin = 0.05
vmax = 0.35
interval = 0.025
# Plotte das Albedo
plt.figure(figsize=(10, 10))
cmap = plt.get_cmap('turbo', int((vmax-vmin)/interval)+1)
plt.imshow(albedo, cmap=cmap, vmin=vmin, vmax=vmax)
# Füge eine Farbskala hinzu
plt.colorbar(label='Albedo')
# Setze den Titel für das Diagramm
plt.title('Oberflächen-Albedo', fontsize=14, fontweight='bold')
# Definiere die Textbeschreibung
text = (
"Albedo ist das Maß für die Reflektivität der Erdoberfläche, berechnet mit mehreren Spektralbändern. "
"Es wird von verschiedenen Faktoren beeinflusst, einschließlich Vegetation, Bodentyp und Oberflächenfeuchtigkeit. Albedo-Werte reichen typischerweise "
"von 0 (keine Reflektion) bis 1 (vollständige Reflektion), wobei höhere Werte auf reflektierendere Oberflächen hinweisen."
)
wrapped_text = textwrap.fill(text, width=100)
# Füge die Beschreibung hinzu
plt.figtext(
0.13,
0.07,
wrapped_text,
ha='left',
va='center',
fontsize=8,
backgroundcolor='w',
)
# Entferne Achsenmarkierungen für eine sauberere Anzeige
plt.axis('off')
# Zeige das Diagramm an
plt.show()

7. Ergänzungen
In der Fernerkundungsanalyse können verschiedene ergänzende Indizes oder Techniken angewendet werden, um aussagekräftige Informationen aus Satellitenbildern zu extrahieren. Diese Indizes können primäre Analysen (wie Albedo oder NDVI) ergänzen, um Einblicke in die Landbedeckung, die Gesundheit der Vegetation, den Wasserstress und andere Umweltparameter zu bieten.
Zusätzliche Indizes finden Sie in der Sentinel-2 Index-Datenbank
Für ein besseres Verständnis der Sentinel-2-Bandmerkmale können Sie auf die folgende Quelle zugreifen, um detailliertere Informationen zu erhalten: Sentinel-2 Bandmerkmale
# Daten für Sentinel-2 Bänder
data = {
"Bandname": ["B01", "B02", "B03", "B04", "B05", "B06", "B07", "B08", "B8A", "B09", "B10", "B11", "B12"],
"Wellenlänge (nm)": [443, 490, 560, 665, 705, 740, 783, 842, 865, 945, 1375, 1610, 2190],
"Auflösung (m)": [60, 10, 10, 10, 20, 20, 20, 10, 20, 60, 60, 20, 20],
"Beschreibung": [
"Aerosol",
"Blue",
"Green",
"Red",
"Red Edge 1",
"Red Edge 2",
"Red Edge 3",
"Near Infrared (NIR)",
"Narrow NIR",
"Water vapor",
"Cirrus",
"Shortwave Infrared (SWIR) - 1",
"Shortwave Infrared (SWIR) - 2"
],
"Alternative Beschreibung": [
"Coastal aerosol",
"Blue",
"Green",
"Red",
"Vegetation red edge",
"Vegetation red edge",
"Vegetation red edge",
"NIR",
"Vegetation red edge",
"Water vapour",
"SWIR - Cirrius",
"SWIR",
"SWIR"
]
}
# Erstelle ein DataFrame
bands_table = pd.DataFrame(data)
# Zeige die Tabelle an
bands_table
Bandname | Wellenlänge (nm) | Auflösung (m) | Beschreibung | Alternative Beschreibung | |
---|---|---|---|---|---|
0 | B01 | 443 | 60 | Aerosol | Coastal aerosol |
1 | B02 | 490 | 10 | Blue | Blue |
2 | B03 | 560 | 10 | Green | Green |
3 | B04 | 665 | 10 | Red | Red |
4 | B05 | 705 | 20 | Red Edge 1 | Vegetation red edge |
5 | B06 | 740 | 20 | Red Edge 2 | Vegetation red edge |
6 | B07 | 783 | 20 | Red Edge 3 | Vegetation red edge |
7 | B08 | 842 | 10 | Near Infrared (NIR) | NIR |
8 | B8A | 865 | 20 | Narrow NIR | Vegetation red edge |
9 | B09 | 945 | 60 | Water vapor | Water vapour |
10 | B10 | 1375 | 60 | Cirrus | SWIR - Cirrius |
11 | B11 | 1610 | 20 | Shortwave Infrared (SWIR) - 1 | SWIR |
12 | B12 | 2190 | 20 | Shortwave Infrared (SWIR) - 2 | SWIR |