Spaces:
Sleeping
Sleeping
Update pages/v2.py
Browse files- pages/v2.py +48 -22
pages/v2.py
CHANGED
|
@@ -18,6 +18,7 @@ from concurrent.futures import ThreadPoolExecutor
|
|
| 18 |
from functools import lru_cache
|
| 19 |
import numpy as np
|
| 20 |
|
|
|
|
| 21 |
@st.cache_data
|
| 22 |
def uploaded_file_to_gdf(data):
|
| 23 |
import tempfile
|
|
@@ -38,6 +39,7 @@ def uploaded_file_to_gdf(data):
|
|
| 38 |
|
| 39 |
return gdf
|
| 40 |
|
|
|
|
| 41 |
@lru_cache(maxsize=128)
|
| 42 |
def get_wms_url(bbox, width, height, time):
|
| 43 |
url = "https://wms.geo.admin.ch/"
|
|
@@ -57,10 +59,11 @@ def get_wms_url(bbox, width, height, time):
|
|
| 57 |
}
|
| 58 |
return url + "?" + "&".join(f"{k}={v}" for k, v in params.items())
|
| 59 |
|
|
|
|
| 60 |
def add_date_to_image(image, date):
|
| 61 |
draw = ImageDraw.Draw(image)
|
| 62 |
font = ImageFont.load_default()
|
| 63 |
-
text = str(date // 10000)
|
| 64 |
|
| 65 |
bbox = draw.textbbox((0, 0), text, font=font)
|
| 66 |
textwidth = bbox[2] - bbox[0]
|
|
@@ -73,6 +76,7 @@ def add_date_to_image(image, date):
|
|
| 73 |
draw.text((x, y), text, font=font, fill="white")
|
| 74 |
return image
|
| 75 |
|
|
|
|
| 76 |
async def fetch_image(session, url, date, semaphore):
|
| 77 |
async with semaphore:
|
| 78 |
try:
|
|
@@ -85,12 +89,14 @@ async def fetch_image(session, url, date, semaphore):
|
|
| 85 |
print(f"Erreur lors de la récupération de l'image pour la date {date}: {str(e)}")
|
| 86 |
return None
|
| 87 |
|
|
|
|
| 88 |
async def download_images(bbox, width, height, available_years):
|
| 89 |
semaphore = asyncio.Semaphore(20) # Limité à 20 requêtes simultanées
|
| 90 |
async with aiohttp.ClientSession() as session:
|
| 91 |
tasks = [fetch_image(session, get_wms_url(bbox, width, height, date), date, semaphore) for date in available_years]
|
| 92 |
return await asyncio.gather(*tasks)
|
| 93 |
|
|
|
|
| 94 |
def process_images_stream(images, format_option, speed, temp_dir, batch_size=20):
|
| 95 |
results = {}
|
| 96 |
|
|
@@ -112,7 +118,7 @@ def process_images_stream(images, format_option, speed, temp_dir, batch_size=20)
|
|
| 112 |
|
| 113 |
if "Images individuelles (ZIP)" in format_option:
|
| 114 |
zip_paths = []
|
| 115 |
-
num_batches = (len(images) + batch_size - 1) // batch_size
|
| 116 |
for batch_index in range(num_batches):
|
| 117 |
batch_zip_path = os.path.join(temp_dir, f"images_batch_{batch_index + 1}.zip")
|
| 118 |
with zipfile.ZipFile(batch_zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
|
@@ -124,10 +130,11 @@ def process_images_stream(images, format_option, speed, temp_dir, batch_size=20)
|
|
| 124 |
zipf.write(img_path, os.path.basename(img_path))
|
| 125 |
os.remove(img_path)
|
| 126 |
zip_paths.append(batch_zip_path)
|
| 127 |
-
results["ZIP"] = zip_paths
|
| 128 |
|
| 129 |
return results
|
| 130 |
|
|
|
|
| 131 |
def get_binary_file_downloader_html(bin_file, file_label='File'):
|
| 132 |
with open(bin_file, 'rb') as f:
|
| 133 |
data = f.read()
|
|
@@ -135,27 +142,46 @@ def get_binary_file_downloader_html(bin_file, file_label='File'):
|
|
| 135 |
href = f'<a href="data:application/octet-stream;base64,{bin_str}" download="{os.path.basename(bin_file)}">Télécharger {file_label}</a>'
|
| 136 |
return href
|
| 137 |
|
|
|
|
| 138 |
def app():
|
| 139 |
st.title("Générateur de Timelapse Historique Suisse")
|
| 140 |
|
| 141 |
-
# Interface de
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
|
| 160 |
if submitted:
|
| 161 |
if data:
|
|
@@ -172,7 +198,7 @@ def app():
|
|
| 172 |
for format, paths in results.items():
|
| 173 |
if format == "ZIP":
|
| 174 |
for path in paths:
|
| 175 |
-
batch_number = path.split("_")[-1].split(".")[0]
|
| 176 |
st.success(f"Images individuelles (ZIP) - Lot {batch_number} créé avec succès!")
|
| 177 |
st.markdown(get_binary_file_downloader_html(path, f'Images individuelles (ZIP) - Lot {batch_number}'), unsafe_allow_html=True)
|
| 178 |
else:
|
|
|
|
| 18 |
from functools import lru_cache
|
| 19 |
import numpy as np
|
| 20 |
|
| 21 |
+
# Fonction pour charger les données de fichiers GeoJSON/KML
|
| 22 |
@st.cache_data
|
| 23 |
def uploaded_file_to_gdf(data):
|
| 24 |
import tempfile
|
|
|
|
| 39 |
|
| 40 |
return gdf
|
| 41 |
|
| 42 |
+
# Fonction pour construire l'URL de requête WMS
|
| 43 |
@lru_cache(maxsize=128)
|
| 44 |
def get_wms_url(bbox, width, height, time):
|
| 45 |
url = "https://wms.geo.admin.ch/"
|
|
|
|
| 59 |
}
|
| 60 |
return url + "?" + "&".join(f"{k}={v}" for k, v in params.items())
|
| 61 |
|
| 62 |
+
# Fonction pour ajouter une date à l'image
|
| 63 |
def add_date_to_image(image, date):
|
| 64 |
draw = ImageDraw.Draw(image)
|
| 65 |
font = ImageFont.load_default()
|
| 66 |
+
text = str(date // 10000)
|
| 67 |
|
| 68 |
bbox = draw.textbbox((0, 0), text, font=font)
|
| 69 |
textwidth = bbox[2] - bbox[0]
|
|
|
|
| 76 |
draw.text((x, y), text, font=font, fill="white")
|
| 77 |
return image
|
| 78 |
|
| 79 |
+
# Fonction asynchrone pour télécharger une image
|
| 80 |
async def fetch_image(session, url, date, semaphore):
|
| 81 |
async with semaphore:
|
| 82 |
try:
|
|
|
|
| 89 |
print(f"Erreur lors de la récupération de l'image pour la date {date}: {str(e)}")
|
| 90 |
return None
|
| 91 |
|
| 92 |
+
# Téléchargement des images en fonction des années disponibles
|
| 93 |
async def download_images(bbox, width, height, available_years):
|
| 94 |
semaphore = asyncio.Semaphore(20) # Limité à 20 requêtes simultanées
|
| 95 |
async with aiohttp.ClientSession() as session:
|
| 96 |
tasks = [fetch_image(session, get_wms_url(bbox, width, height, date), date, semaphore) for date in available_years]
|
| 97 |
return await asyncio.gather(*tasks)
|
| 98 |
|
| 99 |
+
# Traitement des images et génération des fichiers ZIP par lots
|
| 100 |
def process_images_stream(images, format_option, speed, temp_dir, batch_size=20):
|
| 101 |
results = {}
|
| 102 |
|
|
|
|
| 118 |
|
| 119 |
if "Images individuelles (ZIP)" in format_option:
|
| 120 |
zip_paths = []
|
| 121 |
+
num_batches = (len(images) + batch_size - 1) // batch_size
|
| 122 |
for batch_index in range(num_batches):
|
| 123 |
batch_zip_path = os.path.join(temp_dir, f"images_batch_{batch_index + 1}.zip")
|
| 124 |
with zipfile.ZipFile(batch_zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
|
|
|
| 130 |
zipf.write(img_path, os.path.basename(img_path))
|
| 131 |
os.remove(img_path)
|
| 132 |
zip_paths.append(batch_zip_path)
|
| 133 |
+
results["ZIP"] = zip_paths
|
| 134 |
|
| 135 |
return results
|
| 136 |
|
| 137 |
+
# Générer un lien de téléchargement pour les fichiers ZIP
|
| 138 |
def get_binary_file_downloader_html(bin_file, file_label='File'):
|
| 139 |
with open(bin_file, 'rb') as f:
|
| 140 |
data = f.read()
|
|
|
|
| 142 |
href = f'<a href="data:application/octet-stream;base64,{bin_str}" download="{os.path.basename(bin_file)}">Télécharger {file_label}</a>'
|
| 143 |
return href
|
| 144 |
|
| 145 |
+
# Application Streamlit principale
|
| 146 |
def app():
|
| 147 |
st.title("Générateur de Timelapse Historique Suisse")
|
| 148 |
|
| 149 |
+
# Interface de la carte interactive
|
| 150 |
+
row1_col1, row1_col2 = st.columns([2, 1])
|
| 151 |
+
|
| 152 |
+
with row1_col1:
|
| 153 |
+
m = folium.Map(location=[46.8182, 8.2275], zoom_start=8)
|
| 154 |
+
folium.TileLayer(
|
| 155 |
+
tiles="https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.pixelkarte-farbe/default/current/3857/{z}/{x}/{y}.jpeg",
|
| 156 |
+
attr="© swisstopo",
|
| 157 |
+
name="swisstopo",
|
| 158 |
+
overlay=False,
|
| 159 |
+
control=True
|
| 160 |
+
).add_to(m)
|
| 161 |
+
|
| 162 |
+
draw = plugins.Draw(export=True)
|
| 163 |
+
draw.add_to(m)
|
| 164 |
+
folium.LayerControl().add_to(m)
|
| 165 |
+
folium_static(m, height=400)
|
| 166 |
+
|
| 167 |
+
with row1_col2:
|
| 168 |
+
data = st.file_uploader(
|
| 169 |
+
"Téléchargez un fichier GeoJSON à utiliser comme ROI. Personnalisez les paramètres du timelapse puis cliquez sur le bouton Soumettre 😇👇",
|
| 170 |
+
type=["geojson", "kml", "zip"],
|
| 171 |
+
)
|
| 172 |
+
|
| 173 |
+
with st.form("submit_form"):
|
| 174 |
+
start_year = st.selectbox("Sélectionnez l'année de début:", [1864, 2021])
|
| 175 |
+
end_year = st.selectbox("Sélectionnez l'année de fin:", [1864, 2021], index=len([1864, 2021]) - 1)
|
| 176 |
+
|
| 177 |
+
# Options de taille d'image
|
| 178 |
+
size_choice = st.selectbox("Choisissez la taille de l'image:", ["HD (720p)", "Full HD (1080p)"])
|
| 179 |
+
width, height = (1280, 720) if size_choice == "HD (720p)" else (1920, 1080)
|
| 180 |
+
|
| 181 |
+
speed = st.slider("Images par seconde:", 1, 30, 5)
|
| 182 |
+
format_option = st.multiselect("Choisissez le(s) format(s) de sortie:", ["GIF", "MP4", "Images individuelles (ZIP)"], default=["GIF", "MP4", "Images individuelles (ZIP)"])
|
| 183 |
+
|
| 184 |
+
submitted = st.form_submit_button("Générer le Timelapse")
|
| 185 |
|
| 186 |
if submitted:
|
| 187 |
if data:
|
|
|
|
| 198 |
for format, paths in results.items():
|
| 199 |
if format == "ZIP":
|
| 200 |
for path in paths:
|
| 201 |
+
batch_number = path.split("_")[-1].split(".")[0]
|
| 202 |
st.success(f"Images individuelles (ZIP) - Lot {batch_number} créé avec succès!")
|
| 203 |
st.markdown(get_binary_file_downloader_html(path, f'Images individuelles (ZIP) - Lot {batch_number}'), unsafe_allow_html=True)
|
| 204 |
else:
|