如何解决Streamlit中下载Google Earth Engine影像的报错问题
解决GEE影像通过Streamlit下载按钮导出GeoTIFF的报错问题
问题背景
尝试从Google Earth Engine下载GeoTiff格式的火灾数据,在实现Streamlit下载按钮时触发报错:
Invalid binary data format: <class ‘ee.image.Image’>
原始代码
import datetime import ee import streamlit as st import geemap.foliumap as geemap import os import folium Map = geemap.Map(locate_control=True) col1, col2, col3, col4, col5= st.columns([1, 1, 1, 2, 2]) with col1: longitude = st.number_input("Longitude", 102, 110, 105) with col2: latitude = st.number_input("Latitude", 10, 16, 12) with col3: zoom = st.number_input("Zoom", 0, 20, 7) Map.setCenter(longitude, latitude, zoom) with col4: start = st.date_input("Start Date for Fire Forest: YYYY/MM/DD", datetime.date(2021, 1, 1)) with col5: end = st.date_input("End Date for Fire Forest: YYYY/MM/DD", datetime.date(2021, 1, 3)) start_date = start.strftime("%Y-%m-%d") end_date = end.strftime("%Y-%m-%d") countries=ee.FeatureCollection("USDOS/LSIB_SIMPLE/2017") country = countries.filter(ee.Filter.eq('country_na', 'Cambodia')); esa = ee.ImageCollection("FIRMS").select('T21').filterBounds(country).filterDate(start_date,end_date).mosaic().clip(country) esa_vis = {"min": 325,"max": 400,"palette": ['red', 'orange', 'yellow'],} Map.addLayer(country,{}, name ="Cambodia Global Boundary") Map.addLayer(esa, esa_vis, 'fire') #To test export image out_dir = os.path.join(os.path.expanduser('~'), 'Downloads') filename = os.path.join(out_dir, 'fire.tiff') # image = esa.clip(country).unmask() date=(start_date,end_date) geemap.ee_export_image(esa, filename=filename, scale=30, region=country, file_per_band=False) st.download_button('Download fire Output (.tiff)', esa, file_name = "fire.tiff", mime= "image/GeoTIFF") #Add legend labels = ['Fire Detection'] colors = ['#FF0000'] Map.add_legend( title="Legend", labels=labels, colors=colors) #Press on map and show lat and lng Map.add_child(folium.LatLngPopup()) Map.to_streamlit(height=550)
报错原因
st.download_button的data参数要求传入本地二进制数据/字节流,但代码中直接传入了GEE云端的ee.Image对象(esa),这个对象只是云端影像的引用,并非可直接下载的本地数据,因此触发格式错误。
解决方案
先将GEE影像下载到本地临时文件,再读取文件的二进制内容传给下载按钮。修改后的完整代码如下:
修改后的完整代码
import datetime import ee import streamlit as st import geemap.foliumap as geemap import os import folium # 初始化GEE授权 ee.Initialize() Map = geemap.Map(locate_control=True) col1, col2, col3, col4, col5= st.columns([1, 1, 1, 2, 2]) with col1: longitude = st.number_input("Longitude", 102, 110, 105) with col2: latitude = st.number_input("Latitude", 10, 16, 12) with col3: zoom = st.number_input("Zoom", 0, 20, 7) Map.setCenter(longitude, latitude, zoom) with col4: start = st.date_input("Start Date for Fire Forest: YYYY/MM/DD", datetime.date(2021, 1, 1)) with col5: end = st.date_input("End Date for Fire Forest: YYYY/MM/DD", datetime.date(2021, 1, 3)) start_date = start.strftime("%Y-%m-%d") end_date = end.strftime("%Y-%m-%d") countries=ee.FeatureCollection("USDOS/LSIB_SIMPLE/2017") country = countries.filter(ee.Filter.eq('country_na', 'Cambodia')); esa = ee.ImageCollection("FIRMS").select('T21').filterBounds(country).filterDate(start_date,end_date).mosaic().clip(country) esa_vis = {"min": 325,"max": 400,"palette": ['red', 'orange', 'yellow'],} Map.addLayer(country,{}, name ="Cambodia Global Boundary") Map.addLayer(esa, esa_vis, 'fire') # 将GEE影像下载到本地指定路径 out_dir = os.path.join(os.path.expanduser('~'), 'Downloads') filename = os.path.join(out_dir, 'fire.tiff') geemap.ee_export_image(esa, filename=filename, scale=30, region=country, file_per_band=False) # 读取本地文件二进制数据,传给下载按钮 if os.path.exists(filename): with open(filename, "rb") as f: tiff_data = f.read() st.download_button( label='Download fire Output (.tiff)', data=tiff_data, file_name="fire.tiff", mime="image/GeoTIFF" ) else: st.error("影像下载失败,请检查GEE授权或网络连接") # 添加图例 labels = ['Fire Detection'] colors = ['#FF0000'] Map.add_legend( title="Legend", labels=labels, colors=colors) # 点击地图显示经纬度 Map.add_child(folium.LatLngPopup()) Map.to_streamlit(height=550)
关键修改点
- 新增
ee.Initialize()确保GEE授权完成,避免下载失败 - 保留
geemap.ee_export_image完成云端影像到本地的下载 - 通过
open(filename, "rb")读取本地GeoTIFF的二进制数据 - 将二进制数据
iff_data作为st.download_button的data参数传入
大文件替代方案
如果处理超大影像,推荐直接生成GEE官方下载链接,避免本地存储压力:
# 生成GEE原生下载链接 download_url = esa.getDownloadURL({ 'scale': 30, 'region': country.geometry(), 'filePerBand': False }) # 在Streamlit中显示下载链接 st.markdown(f"[点击下载火灾数据]({download_url})", unsafe_allow_html=True)
内容的提问来源于stack exchange,提问作者Remote Sensing and Mapping
相关产品推荐
相关产品推荐

