Update pages/5_đ_VertXtractor.py
Browse files- pages/5_đ_VertXtractor.py +149 -87
pages/5_đ_VertXtractor.py
CHANGED
@@ -1,110 +1,172 @@
|
|
1 |
import streamlit as st
|
2 |
-
import requests
|
3 |
import folium
|
4 |
from streamlit_folium import folium_static
|
5 |
-
|
|
|
6 |
import rasterio
|
7 |
from rasterio.merge import merge
|
8 |
-
import os
|
9 |
import tempfile
|
10 |
-
import
|
11 |
from io import BytesIO
|
|
|
|
|
|
|
12 |
|
13 |
-
#
|
14 |
-
|
15 |
-
|
16 |
-
'Photo aérienne 10cm': 'ch.swisstopo.swissimage-dop10',
|
17 |
-
'Carte nationale 1:10 000': 'ch.swisstopo.landeskarte-farbe-10',
|
18 |
-
'Carte nationale 1:25 000': 'ch.swisstopo.pixelkarte-farbe-pk25.noscale',
|
19 |
-
'Carte nationale 1:50 000': 'ch.swisstopo.pixelkarte-farbe-pk50.noscale',
|
20 |
-
'Carte nationale 1:100 000': 'ch.swisstopo.pixelkarte-farbe-pk100.noscale',
|
21 |
-
'Carte nationale 1:200 000': 'ch.swisstopo.pixelkarte-farbe-pk200.noscale',
|
22 |
-
'ModÚle numérique de terrain': 'ch.swisstopo.swissalti3d',
|
23 |
-
}
|
24 |
|
25 |
-
|
26 |
-
def
|
27 |
-
"""RĂ©cupĂšre les Ă©lĂ©ments pour une zone d'intĂ©rĂȘt (AOI)."""
|
28 |
-
url = f"{STAC_API_URL}{product_name}/items?bbox={bbox}"
|
29 |
response = requests.get(url)
|
30 |
if response.status_code == 200:
|
31 |
-
|
32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
else:
|
34 |
-
st.error(f"Erreur lors de la
|
35 |
return []
|
36 |
|
37 |
-
|
38 |
-
|
39 |
-
with tempfile.TemporaryDirectory() as tmpdir:
|
40 |
-
files = []
|
41 |
-
for url in urls:
|
42 |
-
response = requests.get(url)
|
43 |
-
if response.status_code == 200:
|
44 |
-
file_path = os.path.join(tmpdir, os.path.basename(url))
|
45 |
-
with open(file_path, 'wb') as f:
|
46 |
-
f.write(response.content)
|
47 |
-
files.append(file_path)
|
48 |
-
|
49 |
-
if files:
|
50 |
-
src_files_to_mosaic = [rasterio.open(fp) for fp in files]
|
51 |
-
mosaic, out_trans = merge(src_files_to_mosaic)
|
52 |
-
|
53 |
-
out_meta = src_files_to_mosaic[0].meta.copy()
|
54 |
-
out_meta.update({
|
55 |
-
"driver": "GTiff",
|
56 |
-
"height": mosaic.shape[1],
|
57 |
-
"width": mosaic.shape[2],
|
58 |
-
"transform": out_trans
|
59 |
-
})
|
60 |
-
|
61 |
-
merged_file = BytesIO()
|
62 |
-
with rasterio.MemoryFile(merged_file) as memfile:
|
63 |
-
with memfile.open(**out_meta) as dest:
|
64 |
-
dest.write(mosaic)
|
65 |
-
|
66 |
-
merged_file.seek(0)
|
67 |
-
return merged_file
|
68 |
-
return None
|
69 |
|
70 |
-
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
|
73 |
-
|
74 |
-
|
75 |
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
|
|
81 |
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
|
89 |
-
if st.button("Télécharger")
|
90 |
-
with st.spinner("
|
91 |
-
urls =
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
mime="image/tiff"
|
101 |
)
|
102 |
-
else:
|
103 |
-
st.error("Erreur lors de la fusion des fichiers.")
|
104 |
else:
|
105 |
-
st.
|
106 |
-
|
107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
108 |
|
109 |
-
|
110 |
-
|
|
|
|
|
|
1 |
import streamlit as st
|
|
|
2 |
import folium
|
3 |
from streamlit_folium import folium_static
|
4 |
+
from folium.plugins import Draw
|
5 |
+
import requests
|
6 |
import rasterio
|
7 |
from rasterio.merge import merge
|
|
|
8 |
import tempfile
|
9 |
+
import os
|
10 |
from io import BytesIO
|
11 |
+
import json
|
12 |
+
from shapely.geometry import box
|
13 |
+
import geopandas as gpd
|
14 |
|
15 |
+
# Configuration de la page Streamlit
|
16 |
+
st.set_page_config(layout="wide", page_title="SwissTopoBatchNMerge")
|
17 |
+
st.title("SwissTopoBatchNMerge Streamlit")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
+
# Fonction pour télécharger les données depuis une URL
|
20 |
+
def download_data(url):
|
|
|
|
|
21 |
response = requests.get(url)
|
22 |
if response.status_code == 200:
|
23 |
+
return BytesIO(response.content)
|
24 |
+
else:
|
25 |
+
st.error(f"Erreur lors du téléchargement: {response.status_code}")
|
26 |
+
return None
|
27 |
+
|
28 |
+
# Fonction pour fusionner les tuiles raster
|
29 |
+
def merge_tiles(files):
|
30 |
+
src_files_to_mosaic = []
|
31 |
+
for file in files:
|
32 |
+
src = rasterio.open(file)
|
33 |
+
src_files_to_mosaic.append(src)
|
34 |
+
mosaic, out_trans = merge(src_files_to_mosaic)
|
35 |
+
return mosaic, out_trans
|
36 |
+
|
37 |
+
# Fonction pour obtenir les liens de téléchargement des tuiles de l'API swisstopo
|
38 |
+
def get_swisstopo_tiles(bbox, product):
|
39 |
+
# URL de l'API d'identification de swisstopo
|
40 |
+
api_url = "https://api3.geo.admin.ch/rest/services/api/MapServer/identify"
|
41 |
+
|
42 |
+
# ParamĂštres de la requĂȘte
|
43 |
+
params = {
|
44 |
+
'geometry': f"{bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]}",
|
45 |
+
'geometryType': 'esriGeometryEnvelope',
|
46 |
+
'imageDisplay': '1000,1000,96',
|
47 |
+
'mapExtent': f"{bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]}",
|
48 |
+
'tolerance': '0',
|
49 |
+
'layers': 'all:' + product,
|
50 |
+
'sr': '4326'
|
51 |
+
}
|
52 |
+
|
53 |
+
# Envoi de la requĂȘte Ă l'API
|
54 |
+
response = requests.get(api_url, params=params)
|
55 |
+
|
56 |
+
if response.status_code == 200:
|
57 |
+
data = response.json()
|
58 |
+
# Extraction des liens de téléchargement des résultats
|
59 |
+
return [result['attributes']['download'] for result in data['results'] if 'download' in result['attributes']]
|
60 |
else:
|
61 |
+
st.error(f"Erreur lors de la requĂȘte Ă l'API: {response.status_code}")
|
62 |
return []
|
63 |
|
64 |
+
# Création de la carte Folium centrée sur la Suisse
|
65 |
+
m = folium.Map(location=[46.8182, 8.2275], zoom_start=8)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
|
67 |
+
# Ajout d'un contrĂŽle de dessin Ă la carte
|
68 |
+
draw = Draw(
|
69 |
+
draw_options={
|
70 |
+
'rectangle': True,
|
71 |
+
'polygon': False,
|
72 |
+
'polyline': False,
|
73 |
+
'circle': False,
|
74 |
+
'marker': False,
|
75 |
+
'circlemarker': False,
|
76 |
+
},
|
77 |
+
edit_options={'edit': False}
|
78 |
+
)
|
79 |
+
m.add_child(draw)
|
80 |
|
81 |
+
# Affichage de la carte dans Streamlit
|
82 |
+
map_data = folium_static(m, width=700, height=500)
|
83 |
|
84 |
+
# SĂ©lection du produit swisstopo
|
85 |
+
product = st.selectbox(
|
86 |
+
"Choisissez un produit",
|
87 |
+
["ch.swisstopo.swissimage-dop10", "ch.swisstopo.swissalti3d"],
|
88 |
+
help="Sélectionnez le type de données que vous souhaitez télécharger"
|
89 |
+
)
|
90 |
|
91 |
+
# Vérification si une boßte de sélection a été dessinée
|
92 |
+
if 'last_active_drawing' in st.session_state:
|
93 |
+
# Extraction des coordonnées de la boßte de sélection
|
94 |
+
bbox = st.session_state.last_active_drawing['geometry']['coordinates'][0]
|
95 |
+
bbox = [coord for sublist in bbox[:-1] for coord in sublist]
|
96 |
+
st.write(f"Boßte de sélection : {bbox}")
|
97 |
|
98 |
+
if st.button("Télécharger et fusionner"):
|
99 |
+
with st.spinner("Récupération des liens de téléchargement..."):
|
100 |
+
urls = get_swisstopo_tiles(bbox, product)
|
101 |
+
|
102 |
+
if urls:
|
103 |
+
with st.spinner("Téléchargement des tuiles..."):
|
104 |
+
temp_dir = tempfile.mkdtemp()
|
105 |
+
files = []
|
106 |
+
for i, url in enumerate(urls):
|
107 |
+
file = download_data(url)
|
108 |
+
if file:
|
109 |
+
file_path = os.path.join(temp_dir, f"tile_{i}.tif")
|
110 |
+
with open(file_path, "wb") as f:
|
111 |
+
f.write(file.getvalue())
|
112 |
+
files.append(file_path)
|
113 |
+
|
114 |
+
if files:
|
115 |
+
with st.spinner("Fusion des tuiles..."):
|
116 |
+
mosaic, out_trans = merge_tiles(files)
|
117 |
+
|
118 |
+
st.success("Traitement terminé !")
|
119 |
+
|
120 |
+
# Sauvegarde du résultat fusionné
|
121 |
+
output_path = os.path.join(temp_dir, "result.tif")
|
122 |
+
with rasterio.open(output_path, 'w', **mosaic.profile) as dst:
|
123 |
+
dst.write(mosaic)
|
124 |
+
|
125 |
+
# Proposition de téléchargement du résultat
|
126 |
+
with open(output_path, "rb") as file:
|
127 |
+
btn = st.download_button(
|
128 |
+
label="Télécharger le résultat",
|
129 |
+
data=file,
|
130 |
+
file_name="merged_result.tif",
|
131 |
mime="image/tiff"
|
132 |
)
|
|
|
|
|
133 |
else:
|
134 |
+
st.error("Ăchec du tĂ©lĂ©chargement des tuiles.")
|
135 |
+
else:
|
136 |
+
st.error("Aucune tuile trouvée pour la zone sélectionnée.")
|
137 |
+
else:
|
138 |
+
st.write("Veuillez dessiner une boßte de sélection sur la carte.")
|
139 |
+
|
140 |
+
# JavaScript pour récupérer les coordonnées de la boßte dessinée
|
141 |
+
st.components.v1.html(
|
142 |
+
"""
|
143 |
+
<script>
|
144 |
+
const map = document.getElementsByClassName('folium-map')[0];
|
145 |
+
map.addEventListener('draw:created', function(e) {
|
146 |
+
const type = e.layerType;
|
147 |
+
const layer = e.layer;
|
148 |
+
if (type === 'rectangle') {
|
149 |
+
const bounds = layer.getBounds();
|
150 |
+
const coordinates = [
|
151 |
+
bounds.getSouthWest().lng, bounds.getSouthWest().lat,
|
152 |
+
bounds.getNorthEast().lng, bounds.getNorthEast().lat
|
153 |
+
];
|
154 |
+
window.parent.postMessage({
|
155 |
+
type: 'drawing',
|
156 |
+
coordinates: coordinates
|
157 |
+
}, '*');
|
158 |
+
}
|
159 |
+
});
|
160 |
+
</script>
|
161 |
+
""",
|
162 |
+
height=0,
|
163 |
+
)
|
164 |
+
|
165 |
+
# Gestion des événements de dessin
|
166 |
+
if 'last_active_drawing' not in st.session_state:
|
167 |
+
st.session_state.last_active_drawing = None
|
168 |
|
169 |
+
for event in st.session_state.get("events", []):
|
170 |
+
if event.type == 'drawing':
|
171 |
+
st.session_state.last_active_drawing = event.data
|
172 |
+
st.experimental_rerun()
|