Vertdure commited on
Commit
cb00c19
•
1 Parent(s): 0dd9e26

Update pages/12_🌲_VertXtractor.py

Browse files
Files changed (1) hide show
  1. pages/12_🌲_VertXtractor.py +162 -74
pages/12_🌲_VertXtractor.py CHANGED
@@ -2,28 +2,33 @@ import streamlit as st
2
  import geopandas as gpd
3
  import folium
4
  from streamlit_folium import folium_static
5
- from shapely.geometry import box
 
 
6
  import requests
7
  import json
8
  from io import BytesIO
9
- import zipfile
10
  from PIL import Image
11
  import numpy as np
 
 
12
 
13
- # Liste des couches de données Swisstopo
14
  LAYERS = {
15
- "Bâtiments": "ch.swisstopo.vec25-gebaeude",
16
- "Bâtiments 3D": "ch.swisstopo.swissbuildings3d_2",
17
- "RĂ©seau hydrographique": "ch.swisstopo.vec25-gewaessernetz",
18
- "RĂ©seau routier": "ch.swisstopo.vec25-strassen",
19
- "Couverture du sol": "ch.swisstopo.vec25-landesbedeckung",
20
- "Limites administratives": "ch.swisstopo.swissboundaries3d",
21
- "Modèle numérique de terrain": "ch.swisstopo.swissalti3d",
22
- "Carte nationale 1:25'000": "ch.swisstopo.pixelkarte-farbe-pk25.noscale",
23
- "Carte nationale 1:50'000": "ch.swisstopo.pixelkarte-farbe-pk50.noscale",
24
- "Carte nationale 1:100'000": "ch.swisstopo.pixelkarte-farbe-pk100.noscale",
25
- "Orthophoto SWISSIMAGE": "ch.swisstopo.swissimage-product",
26
- "Noms géographiques": "ch.swisstopo.swissnames3d",
 
 
27
  }
28
 
29
  def extract_swisstopo_data(min_x, min_y, max_x, max_y, layer):
@@ -55,7 +60,6 @@ def download_swissimage(min_x, min_y, max_x, max_y):
55
 
56
  params = {
57
  "bbox": f"{min_x},{min_y},{max_x},{max_y}",
58
- "datetime": "2022-01-01T00:00:00Z/..",
59
  "limit": 1
60
  }
61
 
@@ -68,69 +72,153 @@ def download_swissimage(min_x, min_y, max_x, max_y):
68
  image_response = requests.get(asset_url)
69
  image_response.raise_for_status()
70
 
71
- with zipfile.ZipFile(BytesIO(image_response.content)) as zf:
72
- image_file = [f for f in zf.namelist() if f.endswith('.tif')][0]
73
- with zf.open(image_file) as file:
74
- image = Image.open(file)
75
- return np.array(image)
76
  return None
77
 
78
- # Interface utilisateur Streamlit
79
- st.title("Extracteur de données Swisstopo")
 
 
 
 
 
 
 
 
 
 
80
 
81
- # SĂ©lection de la couche
82
- selected_layer_name = st.selectbox(
83
- "Sélectionnez la couche de données",
84
- list(LAYERS.keys())
85
- )
86
- layer = LAYERS[selected_layer_name]
 
 
 
 
 
 
 
 
 
87
 
88
- # Entrée des coordonnées
89
- col1, col2 = st.columns(2)
90
- with col1:
91
- min_x = st.number_input("Coordonnée X minimale", value=2600000)
92
- min_y = st.number_input("Coordonnée Y minimale", value=1200000)
93
- with col2:
94
- max_x = st.number_input("Coordonnée X maximale", value=2601000)
95
- max_y = st.number_input("Coordonnée Y maximale", value=1201000)
96
 
97
- if st.button("Extraire les données"):
98
- try:
99
- # Extraction des données Swisstopo
100
- gdf = extract_swisstopo_data(min_x, min_y, max_x, max_y, layer)
101
-
102
- # Affichage des données
103
- st.subheader("Aperçu des données")
104
- st.write(gdf.head())
105
-
106
- # Visualisation sur une carte
107
- st.subheader("Visualisation des données")
108
- m = folium.Map(location=[gdf.geometry.centroid.y.mean(), gdf.geometry.centroid.x.mean()], zoom_start=14)
109
- folium.GeoJson(gdf).add_to(m)
110
- folium_static(m)
111
-
112
- # Téléchargement des données
113
- st.download_button(
114
- label="Télécharger les données (GeoJSON)",
115
- data=gdf.to_json(),
116
- file_name=f"{selected_layer_name.lower().replace(' ', '_')}.geojson",
117
- mime="application/json"
118
- )
 
 
 
119
 
120
- # Téléchargement et affichage de l'image SWISSIMAGE
121
- if layer == "ch.swisstopo.swissimage-product":
122
- st.subheader("Image SWISSIMAGE")
123
- image = download_swissimage(min_x, min_y, max_x, max_y)
124
- if image is not None:
125
- st.image(image, caption="Image SWISSIMAGE", use_column_width=True)
126
- else:
127
- st.warning("Aucune image SWISSIMAGE disponible pour cette zone.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
- except Exception as e:
130
- st.error(f"Une erreur s'est produite : {str(e)}")
 
 
 
 
 
131
 
132
- # Informations supplémentaires
133
- st.sidebar.markdown("## À propos")
134
- st.sidebar.markdown("Cet outil permet d'extraire des données géospatiales de Swisstopo.")
135
- st.sidebar.markdown("Développé par Vertdure")
136
- st.sidebar.markdown("[Code source](https://huggingface.co/spaces/Vertdure/Streamlit/tree/main)")
 
2
  import geopandas as gpd
3
  import folium
4
  from streamlit_folium import folium_static
5
+ from folium.plugins import Draw
6
+ from streamlit_folium import st_folium
7
+ from shapely.geometry import box, shape
8
  import requests
9
  import json
10
  from io import BytesIO
 
11
  from PIL import Image
12
  import numpy as np
13
+ import rasterio
14
+ from rasterio.io import MemoryFile
15
 
16
+ # Liste des couches de données Swisstopo et ESRI
17
  LAYERS = {
18
+ "Swisstopo - Bâtiments": "ch.swisstopo.vec25-gebaeude",
19
+ "Swisstopo - Bâtiments 3D": "ch.swisstopo.swissbuildings3d_2",
20
+ "Swisstopo - RĂ©seau hydrographique": "ch.swisstopo.vec25-gewaessernetz",
21
+ "Swisstopo - RĂ©seau routier": "ch.swisstopo.vec25-strassen",
22
+ "Swisstopo - Couverture du sol": "ch.swisstopo.vec25-landesbedeckung",
23
+ "Swisstopo - Limites administratives": "ch.swisstopo.swissboundaries3d",
24
+ "Swisstopo - Modèle numérique de terrain": "ch.swisstopo.swissalti3d",
25
+ "Swisstopo - Carte nationale 1:25'000": "ch.swisstopo.pixelkarte-farbe-pk25.noscale",
26
+ "Swisstopo - Carte nationale 1:50'000": "ch.swisstopo.pixelkarte-farbe-pk50.noscale",
27
+ "Swisstopo - Carte nationale 1:100'000": "ch.swisstopo.pixelkarte-farbe-pk100.noscale",
28
+ "Swisstopo - Orthophoto SWISSIMAGE": "ch.swisstopo.swissimage-product",
29
+ "Swisstopo - Noms géographiques": "ch.swisstopo.swissnames3d",
30
+ "ESRI - World Imagery": "esri_world_imagery",
31
+ "ESRI - World Elevation": "esri_world_elevation",
32
  }
33
 
34
  def extract_swisstopo_data(min_x, min_y, max_x, max_y, layer):
 
60
 
61
  params = {
62
  "bbox": f"{min_x},{min_y},{max_x},{max_y}",
 
63
  "limit": 1
64
  }
65
 
 
72
  image_response = requests.get(asset_url)
73
  image_response.raise_for_status()
74
 
75
+ with MemoryFile(image_response.content) as memfile:
76
+ with memfile.open() as dataset:
77
+ image_array = dataset.read()
78
+ image = Image.fromarray(np.transpose(image_array, (1, 2, 0)))
79
+ return image
80
  return None
81
 
82
+ def download_esri_imagery(min_x, min_y, max_x, max_y):
83
+ api_url = "https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/export"
84
+ params = {
85
+ "bbox": f"{min_x},{min_y},{max_x},{max_y}",
86
+ "bboxSR": "2056",
87
+ "size": "1000,1000",
88
+ "format": "png",
89
+ "f": "image"
90
+ }
91
+ response = requests.get(api_url, params=params)
92
+ response.raise_for_status()
93
+ return Image.open(BytesIO(response.content))
94
 
95
+ def download_esri_elevation(min_x, min_y, max_x, max_y):
96
+ api_url = "https://elevation.arcgis.com/arcgis/rest/services/WorldElevation/Terrain/ImageServer/exportImage"
97
+ params = {
98
+ "bbox": f"{min_x},{min_y},{max_x},{max_y}",
99
+ "bboxSR": "2056",
100
+ "size": "1000,1000",
101
+ "format": "tiff",
102
+ "pixelType": "F32",
103
+ "noDataInterpretation": "esriNoDataMatchAny",
104
+ "interpolation": "RSP_BilinearInterpolation",
105
+ "f": "image"
106
+ }
107
+ response = requests.get(api_url, params=params)
108
+ response.raise_for_status()
109
+ return Image.open(BytesIO(response.content))
110
 
111
+ def main():
112
+ st.title("Extracteur de données Swisstopo et ESRI")
 
 
 
 
 
 
113
 
114
+ # Sélection de la méthode d'entrée
115
+ input_method = st.radio("Choisissez la méthode d'entrée",
116
+ ["Coordonnées manuelles", "Charger un GeoJSON", "Dessiner sur la carte"])
117
+
118
+ if input_method == "Coordonnées manuelles":
119
+ col1, col2 = st.columns(2)
120
+ with col1:
121
+ min_x = st.number_input("Coordonnée X minimale", value=2600000)
122
+ min_y = st.number_input("Coordonnée Y minimale", value=1200000)
123
+ with col2:
124
+ max_x = st.number_input("Coordonnée X maximale", value=2601000)
125
+ max_y = st.number_input("Coordonnée Y maximale", value=1201000)
126
+ bbox = box(min_x, min_y, max_x, max_y)
127
+
128
+ elif input_method == "Charger un GeoJSON":
129
+ uploaded_file = st.file_uploader("Choisissez un fichier GeoJSON", type="geojson")
130
+ if uploaded_file is not None:
131
+ gdf = gpd.read_file(uploaded_file)
132
+ bbox = gdf.total_bounds
133
+ min_x, min_y, max_x, max_y = bbox
134
+
135
+ elif input_method == "Dessiner sur la carte":
136
+ m = folium.Map(location=[46.8, 8.2], zoom_start=8)
137
+ Draw(export=True).add_to(m)
138
+ output = st_folium(m, width=700, height=500)
139
 
140
+ if output["last_active_drawing"]:
141
+ geom = shape(output["last_active_drawing"]["geometry"])
142
+ bbox = geom.bounds
143
+ min_x, min_y, max_x, max_y = bbox
144
+
145
+ # SĂ©lection de la couche
146
+ selected_layer_name = st.selectbox("Sélectionnez la couche de données", list(LAYERS.keys()))
147
+ layer = LAYERS[selected_layer_name]
148
+
149
+ if st.button("Extraire les données"):
150
+ try:
151
+ if "Swisstopo" in selected_layer_name:
152
+ if layer == "ch.swisstopo.swissimage-product":
153
+ st.subheader("Image SWISSIMAGE")
154
+ image = download_swissimage(min_x, min_y, max_x, max_y)
155
+ if image is not None:
156
+ st.image(image, caption="Image SWISSIMAGE", use_column_width=True)
157
+
158
+ buf = BytesIO()
159
+ image.save(buf, format="PNG")
160
+ st.download_button(
161
+ label="Télécharger l'image SWISSIMAGE (PNG)",
162
+ data=buf.getvalue(),
163
+ file_name="swissimage.png",
164
+ mime="image/png"
165
+ )
166
+ else:
167
+ st.warning("Aucune image SWISSIMAGE disponible pour cette zone.")
168
+ else:
169
+ gdf = extract_swisstopo_data(min_x, min_y, max_x, max_y, layer)
170
+
171
+ st.subheader("Aperçu des données")
172
+ st.write(gdf.head())
173
+
174
+ st.subheader("Visualisation des données")
175
+ m = folium.Map(location=[gdf.geometry.centroid.y.mean(), gdf.geometry.centroid.x.mean()], zoom_start=14)
176
+ folium.GeoJson(gdf).add_to(m)
177
+ folium_static(m)
178
+
179
+ st.download_button(
180
+ label="Télécharger les données (GeoJSON)",
181
+ data=gdf.to_json(),
182
+ file_name=f"{selected_layer_name.lower().replace(' ', '_')}.geojson",
183
+ mime="application/json"
184
+ )
185
+
186
+ elif "ESRI" in selected_layer_name:
187
+ if layer == "esri_world_imagery":
188
+ st.subheader("Image ESRI World Imagery")
189
+ image = download_esri_imagery(min_x, min_y, max_x, max_y)
190
+ st.image(image, caption="ESRI World Imagery", use_column_width=True)
191
+
192
+ buf = BytesIO()
193
+ image.save(buf, format="PNG")
194
+ st.download_button(
195
+ label="Télécharger l'image (PNG)",
196
+ data=buf.getvalue(),
197
+ file_name="esri_world_imagery.png",
198
+ mime="image/png"
199
+ )
200
+
201
+ elif layer == "esri_world_elevation":
202
+ st.subheader("Modèle numérique de terrain ESRI")
203
+ image = download_esri_elevation(min_x, min_y, max_x, max_y)
204
+ st.image(image, caption="ESRI World Elevation", use_column_width=True, clamp=True)
205
+
206
+ buf = BytesIO()
207
+ image.save(buf, format="TIFF")
208
+ st.download_button(
209
+ label="Télécharger le MNT (TIFF)",
210
+ data=buf.getvalue(),
211
+ file_name="esri_world_elevation.tiff",
212
+ mime="image/tiff"
213
+ )
214
 
215
+ except Exception as e:
216
+ st.error(f"Une erreur s'est produite : {str(e)}")
217
+
218
+ st.sidebar.markdown("## À propos")
219
+ st.sidebar.markdown("Cet outil permet d'extraire des données géospatiales de Swisstopo et ESRI.")
220
+ st.sidebar.markdown("Développé par Vertdure")
221
+ st.sidebar.markdown("[Code source](https://huggingface.co/spaces/Vertdure/Streamlit/tree/main)")
222
 
223
+ if __name__ == "__main__":
224
+ main()