Vertdure commited on
Commit
d15d5fe
·
verified ·
1 Parent(s): d6319a8

Update pages/v4.py

Browse files
Files changed (1) hide show
  1. pages/v4.py +81 -58
pages/v4.py CHANGED
@@ -24,7 +24,7 @@ logger = logging.getLogger(__name__)
24
  # Configuration de la page Streamlit
25
  st.set_page_config(layout="wide")
26
 
27
- # Récupération des clés AWS à partir des secrets
28
  aws_access_key = os.environ.get("AWS_ACCESS_KEY_ID")
29
  aws_secret_key = os.environ.get("AWS_SECRET_ACCESS_KEY")
30
 
@@ -32,7 +32,7 @@ aws_secret_key = os.environ.get("AWS_SECRET_ACCESS_KEY")
32
  s3_client = boto3.client(
33
  "s3",
34
  aws_access_key_id=aws_access_key,
35
- aws_secret_access_key=aws_secret_key
36
  )
37
 
38
  # Fonction pour télécharger un fichier sur AWS S3
@@ -45,12 +45,8 @@ def upload_to_s3(file_path, bucket_name, object_name):
45
  logger.error(f"Erreur lors du téléchargement vers S3 : {str(e)}")
46
  return None
47
 
48
- # Liste des dates disponibles
49
- AVAILABLE_DATES = [
50
- 18641231, 18701231, 18801231, 18901231, 18941231, 18951231, 18961231,
51
- # ... (ajoutez toutes les autres dates ici)
52
- 20201231, 20211231
53
- ]
54
 
55
  @st.cache_data
56
  def uploaded_file_to_gdf(data):
@@ -83,8 +79,20 @@ def get_wms_url(bbox, width, height, time):
83
  def add_date_to_image(image, date):
84
  draw = ImageDraw.Draw(image)
85
  font = ImageFont.load_default()
86
- text = str(date // 10000)
87
- draw.text((10, 10), text, font=font, fill="white")
 
 
 
 
 
 
 
 
 
 
 
 
88
  return image
89
 
90
  async def fetch_image(session, url, date, semaphore):
@@ -94,116 +102,131 @@ async def fetch_image(session, url, date, semaphore):
94
  if response.status == 200:
95
  data = await response.read()
96
  img = Image.open(BytesIO(data))
 
 
 
 
 
 
97
  logger.info(f"Image pour {date} téléchargée avec succès")
98
  return add_date_to_image(img, date)
99
  else:
100
  logger.error(f"Échec de la récupération de l'image pour {date} : {response.status}")
101
  except Exception as e:
102
  logger.error(f"Erreur lors de la récupération de l'image pour {date} : {str(e)}")
103
- return None
104
 
105
  async def download_images(bbox, width, height, available_years):
106
- semaphore = asyncio.Semaphore(20)
107
  async with aiohttp.ClientSession() as session:
108
  tasks = [fetch_image(session, get_wms_url(bbox, width, height, date), date, semaphore) for date in available_years]
109
  images = await asyncio.gather(*tasks)
 
110
  # Filtrer les images qui ne sont pas None
111
  images = [img for img in images if img is not None]
 
112
  logger.info(f"{len(images)} images téléchargées avec succès")
113
  return images
114
 
115
  def process_images_stream(images, format_option, speed, temp_dir):
116
  results = {}
117
-
118
  if "GIF" in format_option and images:
119
  gif_path = os.path.join(temp_dir, "timelapse.gif")
120
- with imageio.get_writer(gif_path, mode='I', fps=speed, loop=0) as writer:
121
  for img in images:
122
  writer.append_data(np.array(img))
123
  results["GIF"] = gif_path
124
-
125
  if "MP4" in format_option and images:
126
  mp4_path = os.path.join(temp_dir, "timelapse.mp4")
127
- with imageio.get_writer(mp4_path, fps=speed, quality=9) as writer:
128
  for img in images:
129
  writer.append_data(np.array(img))
130
  results["MP4"] = mp4_path
131
-
132
  if "Images individuelles (ZIP)" in format_option and images:
133
  zip_path = os.path.join(temp_dir, "images.zip")
134
  with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
135
  for i, img in enumerate(images):
136
  img_path = os.path.join(temp_dir, f"image_{i}.png")
137
  img.save(img_path)
138
- zipf.write(img_path, os.path.basename(img_path))
139
  os.remove(img_path)
140
  results["ZIP"] = zip_path
141
-
142
  return results
143
 
144
  def app():
145
  st.title("Générateur de Timelapse Historique Suisse")
146
-
147
  st.markdown("Une application web interactive pour créer des timelapses historiques de la Suisse en utilisant WMS-Time.")
148
-
149
  row1_col1, row1_col2 = st.columns([2, 1])
150
-
151
  with row1_col1:
152
  m = folium.Map(location=[46.8182, 8.2275], zoom_start=8)
 
153
  folium.TileLayer(
154
  tiles="https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.pixelkarte-farbe/default/current/3857/{z}/{x}/{y}.jpeg",
155
- attr="© swisstopo",
156
- name="swisstopo"
157
  ).add_to(m)
 
158
  plugins.Draw(export=True).add_to(m)
 
159
  folium.LayerControl().add_to(m)
160
- folium_static(m, height=400)
 
161
 
162
  with row1_col2:
163
  data = st.file_uploader("Téléchargez un fichier GeoJSON à utiliser comme ROI.", type=["geojson", "kml", "zip"])
 
164
  start_year = st.selectbox("Sélectionnez l'année de début:", [date // 10000 for date in AVAILABLE_DATES])
 
165
  end_year = st.selectbox("Sélectionnez l'année de fin:", [date // 10000 for date in AVAILABLE_DATES])
166
-
167
- size_options = {
168
- "HD (720p)": (1280, 720),
169
- "Full HD (1080p)": (1920, 1080),
170
- "2K": (2560, 1440),
171
- "4K": (3840, 2160)
172
- }
173
  size_choice = st.selectbox("Choisissez la taille de l'image:", list(size_options.keys()))
 
174
  width, height = size_options[size_choice]
175
-
176
- speed = st.slider("Images par seconde:", 1, 30, 5)
 
177
  format_option = st.multiselect(
178
- "Choisissez le(s) format(s) de sortie:",
179
- ["GIF", "MP4", "Images individuelles (ZIP)"],
180
  default=["GIF"]
181
  )
182
-
183
  submitted = st.button("Générer le Timelapse")
184
 
185
- if submitted:
186
- if data is None:
187
- st.warning("Veuillez télécharger un fichier GeoJSON.")
 
 
 
 
 
 
 
 
 
 
 
 
188
  else:
189
- gdf = uploaded_file_to_gdf(data)
190
- bbox = tuple(gdf.total_bounds)
191
- available_years = [date for date in AVAILABLE_DATES if start_year <= date // 10000 <= end_year]
192
- images = asyncio.run(download_images(bbox, width, height, available_years))
193
-
194
- if not images:
195
- st.error("Aucune image n'a été téléchargée. Veuillez vérifier votre sélection ou réessayer.")
196
- else:
197
- with tempfile.TemporaryDirectory() as temp_dir:
198
- results = process_images_stream(images, format_option, speed, temp_dir)
199
-
200
- # Téléchargement des fichiers sur S3 et génération des liens
201
- for format, path in results.items():
202
- s3_url = upload_to_s3(path, "timelapse-storage-vertgis", os.path.basename(path))
203
- if s3_url:
204
- st.markdown(f"[Télécharger le timelapse {format}]({s3_url})", unsafe_allow_html=True)
205
- else:
206
- st.error(f"Le fichier {format} n'a pas pu être téléchargé sur S3.")
207
 
208
  if __name__ == "__main__":
209
  app()
 
24
  # Configuration de la page Streamlit
25
  st.set_page_config(layout="wide")
26
 
27
+ # Récupération des clés AWS à partir des secrets d'environnement
28
  aws_access_key = os.environ.get("AWS_ACCESS_KEY_ID")
29
  aws_secret_key = os.environ.get("AWS_SECRET_ACCESS_KEY")
30
 
 
32
  s3_client = boto3.client(
33
  "s3",
34
  aws_access_key_id=aws_access_key,
35
+ aws_secret_access_key=aws_secret_key,
36
  )
37
 
38
  # Fonction pour télécharger un fichier sur AWS S3
 
45
  logger.error(f"Erreur lors du téléchargement vers S3 : {str(e)}")
46
  return None
47
 
48
+ # Liste des dates disponibles (extraites pour simplifier)
49
+ AVAILABLE_DATES = [18641231, 18701231, 18801231, 18901231, 20211231]
 
 
 
 
50
 
51
  @st.cache_data
52
  def uploaded_file_to_gdf(data):
 
79
  def add_date_to_image(image, date):
80
  draw = ImageDraw.Draw(image)
81
  font = ImageFont.load_default()
82
+ text = str(date // 10000) # Extraire seulement l'année
83
+
84
+ # Ajouter un fond noir derrière le texte pour plus de lisibilité
85
+ bbox = draw.textbbox((0, 0), text, font=font)
86
+ textwidth = bbox[2] - bbox[0]
87
+ textheight = bbox[3] - bbox[1]
88
+
89
+ margin = 10
90
+ x = image.width - textwidth - margin
91
+ y = image.height - textheight - margin
92
+
93
+ draw.rectangle((x-5, y-5, x+textwidth+5, y+textheight+5), fill="black")
94
+ draw.text((x, y), text, font=font, fill="white")
95
+
96
  return image
97
 
98
  async def fetch_image(session, url, date, semaphore):
 
102
  if response.status == 200:
103
  data = await response.read()
104
  img = Image.open(BytesIO(data))
105
+
106
+ # Vérification si l'image est vide ou transparente (exemple de vérification simple)
107
+ if img.mode == 'RGBA' and all(pixel == (0, 0, 0, 0) for pixel in img.getdata()):
108
+ logger.error(f"L'image pour {date} est vide ou transparente.")
109
+ return None
110
+
111
  logger.info(f"Image pour {date} téléchargée avec succès")
112
  return add_date_to_image(img, date)
113
  else:
114
  logger.error(f"Échec de la récupération de l'image pour {date} : {response.status}")
115
  except Exception as e:
116
  logger.error(f"Erreur lors de la récupération de l'image pour {date} : {str(e)}")
117
+ return None
118
 
119
  async def download_images(bbox, width, height, available_years):
120
+ semaphore = asyncio.Semaphore(20) # Limiter à 20 requêtes simultanées
121
  async with aiohttp.ClientSession() as session:
122
  tasks = [fetch_image(session, get_wms_url(bbox, width, height, date), date, semaphore) for date in available_years]
123
  images = await asyncio.gather(*tasks)
124
+
125
  # Filtrer les images qui ne sont pas None
126
  images = [img for img in images if img is not None]
127
+
128
  logger.info(f"{len(images)} images téléchargées avec succès")
129
  return images
130
 
131
  def process_images_stream(images, format_option, speed, temp_dir):
132
  results = {}
133
+
134
  if "GIF" in format_option and images:
135
  gif_path = os.path.join(temp_dir, "timelapse.gif")
136
+ with imageio.get_writer(gif_path, mode='I', fps=speed) as writer:
137
  for img in images:
138
  writer.append_data(np.array(img))
139
  results["GIF"] = gif_path
140
+
141
  if "MP4" in format_option and images:
142
  mp4_path = os.path.join(temp_dir, "timelapse.mp4")
143
+ with imageio.get_writer(mp4_path, fps=speed) as writer:
144
  for img in images:
145
  writer.append_data(np.array(img))
146
  results["MP4"] = mp4_path
147
+
148
  if "Images individuelles (ZIP)" in format_option and images:
149
  zip_path = os.path.join(temp_dir, "images.zip")
150
  with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
151
  for i, img in enumerate(images):
152
  img_path = os.path.join(temp_dir, f"image_{i}.png")
153
  img.save(img_path)
154
+ zipf.write(img_path)
155
  os.remove(img_path)
156
  results["ZIP"] = zip_path
157
+
158
  return results
159
 
160
  def app():
161
  st.title("Générateur de Timelapse Historique Suisse")
162
+
163
  st.markdown("Une application web interactive pour créer des timelapses historiques de la Suisse en utilisant WMS-Time.")
164
+
165
  row1_col1, row1_col2 = st.columns([2, 1])
166
+
167
  with row1_col1:
168
  m = folium.Map(location=[46.8182, 8.2275], zoom_start=8)
169
+
170
  folium.TileLayer(
171
  tiles="https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.pixelkarte-farbe/default/current/3857/{z}/{x}/{y}.jpeg",
172
+ attr="© swisstopo", name="swisstopo"
 
173
  ).add_to(m)
174
+
175
  plugins.Draw(export=True).add_to(m)
176
+
177
  folium.LayerControl().add_to(m)
178
+
179
+ folium_static(m)
180
 
181
  with row1_col2:
182
  data = st.file_uploader("Téléchargez un fichier GeoJSON à utiliser comme ROI.", type=["geojson", "kml", "zip"])
183
+
184
  start_year = st.selectbox("Sélectionnez l'année de début:", [date // 10000 for date in AVAILABLE_DATES])
185
+
186
  end_year = st.selectbox("Sélectionnez l'année de fin:", [date // 10000 for date in AVAILABLE_DATES])
187
+
188
+ size_options = {"HD (720p)": (1280, 720), "Full HD (1080p)": (1920, 1080), "2K": (2560, 1440), "4K": (3840, 2160)}
189
+
 
 
 
 
190
  size_choice = st.selectbox("Choisissez la taille de l'image:", list(size_options.keys()))
191
+
192
  width, height = size_options[size_choice]
193
+
194
+ speed = st.slider("Images par seconde:", 1, 30)
195
+
196
  format_option = st.multiselect(
197
+ "Choisissez le(s) format(s) de sortie:",
198
+ ["GIF", "MP4", "Images individuelles (ZIP)"],
199
  default=["GIF"]
200
  )
201
+
202
  submitted = st.button("Générer le Timelapse")
203
 
204
+ if submitted:
205
+ if data is None:
206
+ st.warning("Veuillez télécharger un fichier GeoJSON.")
207
+
208
+ else:
209
+ gdf = uploaded_file_to_gdf(data)
210
+ bbox = tuple(gdf.total_bounds)
211
+
212
+ available_years = [date for date in AVAILABLE_DATES if start_year <= date // 10000 <= end_year]
213
+
214
+ images = asyncio.run(download_images(bbox, width, height, available_years))
215
+
216
+ if not images:
217
+ st.error("Aucune image n'a été téléchargée. Veuillez vérifier votre sélection ou réessayer.")
218
+
219
  else:
220
+ with tempfile.TemporaryDirectory() as temp_dir:
221
+ results = process_images_stream(images, format_option, speed, temp_dir)
222
+
223
+ # Téléchargement des fichiers sur S3 et génération des liens pour chaque format généré.
224
+ for format_type, path in results.items():
225
+ s3_url = upload_to_s3(path,"nom-du-bucket-s3", os.path.basename(path))
226
+ if s3_url:
227
+ st.markdown(f"[Télécharger le timelapse {format_type}]({s3_url})", unsafe_allow_html=True)
228
+ else:
229
+ st.error(f"Le fichier {format_type} n'a pas pu être téléchargé sur S3.")
 
 
 
 
 
 
 
 
230
 
231
  if __name__ == "__main__":
232
  app()