一文教会你使用GEHistoricalImagery工具下载历史高分辨率影像:工具配置,单景与多影像批量下载
做地物解译、土地覆盖分类或地块核查时你有没有遇到过这种情况分析思路已经有了第一步却卡在“去哪找一张合适的影像”。公开影像找到了细小地物却未必看得清软件上看得清想按研究区边界保存一张带坐标的Tiff数据又不知道怎么导出。好不容易找到一张满足条件现在的影像研究还要求回看几年前要能够进行多时相对比。更让人头疼的是文件下载下来了才发现局部模糊、有空洞或者实际日期并不是自己以为的那一年。大量的科研时间花在了“找图、取图、验图”上真正的分析还没开始。如果你遇到了这个问题建议评论区分享你的困难瞬间。影像要清晰、要历史日期、要能直接进 GIS这几个条件往往得同时满足这也是我最近在处理数据时遇到的问题。于是这篇文章想解决一个具体目标给定研究区边界和目标日期怎样下载成能在 QGIS/ArcGIS 中检查的高分辨率影像并把同样的操作扩展到多个区域为了把这些重复操作省下来这次我们用到一款开源工具——GEHistoricalImagery。它由 GitHub 开发者Mbucari开源维护支持获取高清的历史谷歌影像。给定研究区边界、目标日期和影像层级它就能查询可用影像、下载瓦片并拼接成带地理参考的GeoTIFF供 QGIS、ArcGIS 等软件使用。配合 PowerShell 脚本还可以将同一套操作扩展到多个研究区。今天我们花上几分钟时间来系统学习一下。1. 准备文件和目录工具发布网址Releases · Mbucari/GEHistoricalImagery · GitHub我们需要从GitHub中获取与你的 Windows 架构匹配的发行包解压目前最新版是V0.7.1。作为普通使用者优先用发行包普通 Intel 或 AMD 处理器的 Windows 电脑按时选择 Windows x6464 位发行包不要选择 Linux、macOS 或 ARM64 版本。若不确定可在自己电脑中按照“设置 → 系统 → 系统信息 → 系统类型”步骤查。当然如果你的是苹果或者是其他的操作系统选择对应的安装包就行自己改源码才需要下载Source Code版本这里如果大家后续涉及到一些别的参数的修改可以私信小编再出一期编译源代码版本的结果想学的同学多多关注支持。首先我们先学习非源码版本的影像操作D 盘创建D:\GEHI_Tutorial。总而言之选一个空间充足的盘后文路径同步替换。初学者建议先使用英文文件夹名将下载的win-x64压缩文件包放到此处解压。2.工具试运行我们按照WindowsR输入Powershell打开终端打开指定文件夹。cd D:\GEHI_Tutorial\GEHistoricalImagery.0.7.1-win-x64查看帮助 .\GEHistoricalImagery.bat --help如果你的和我一样出现了下面的报错那么首先你需要检查gdal的依赖文件是否有问题Test-Path .\gdal\gdal_wrap.dll Test-Path .\gdal\gdal.dll结果显示为True这时你需要安装安装或修复微软官方 Visual C x64 运行库一般问题可以解决https://aka.ms/vc14/vc_redist.x64.exe安装完可能需要重启电脑此时点击重启即可。再输入上面的命令一般可以正常显示接下来我们来执行下面命令查看下载的参数 .\GEHistoricalImagery.bat download --help得到的结果如下一般得到的参数包含日期格式分辨率层级区域经纬度等等坐标体系具体代码命令涵盖的参数如下GEHistoricalImagery 0.7.1ea52e62b7eb9e608ebdbf199d20e785245a6d5c7 Copyright (C) 2026 GEHistoricalImagery -o file.ext, --outputfile.ext Required. Output raster image save location --ofFORMAT (Default: GTiff) GDAL raster file output format --coNAMEVALUE GDAL raster file creation options --scaleS (Default: 1) Geo transform scale factor --offset-xX (Default: 0) Geo transform X offset --offset-yY (Default: 0) Geo transform Y offset --scale-first (Default: false) Perform scaling before offsetting X and Y -d yyyy/MM/dd, --dateyyyy/MM/dd Required. Imagery Date(s). One or more dates, either separated by a comma (,) or supplied with multiple --date options. --date-matchMatchType (Default: Closest) Type of date match to use for tiles [Closest] Use the closest date [Exact] Require an exact date match [ClosestBefore] Use the closest date before the specified date [ClosestAfter] Use the closest date after the specified date --exact-date Require an exact date match for tiles to be downloaded (overrides --date-match) --layer-date (Wayback only) The date specifies a layer instead of an image capture date --target-srSpatialReference Warp image to Spatial Reference. Either EPSG:#### or path to projection file (file system or web) -z N, --zoomN Required. Zoom level [1-23] --region-filefile.kmz Path to a kmz or kml file containing the region geometry (polygon or polyline with at least three vertices) --regionLt0,Ln0Lt1,Ln1... A list of geographic coordinates which are the vertices of the polygonal area of interest. Vertex coordinates delimited with a . --lower-leftLAT,LONG Geographic coordinate of the lower-left (southwest) corner of the rectangular area of interest. --upper-rightLAT,LONG Geographic coordinate of the upper-right (northeast) corner of the rectangular area of interest. -p N, --parallelN (Default: ALL_CPUS) Number of concurrent downloads --providerProvider (Default: TM) Aerial imagery provider [TM] Google Earth Time Machine [Wayback] ESRI World Imagery Wayback --no-cache (Default: false) Disable local caching -q (Default: false) Quiet mode --help Display this help screen. --version Display version information.具体每个参数的解读各位读者感兴趣可以阅读作者官网给出的教程GEHistoricalImagery/docs/download.md at master · Mbucari/GEHistoricalImagery · GitHub这里我们来举个例子我们想下载lower-left 39.619819,104.856121 --upper-right 39.638393,104.824990围成的矩形框的影像数据日期是2024年6月5日设置分辨率级别20级一般1-23级是有效的23级最高我们可以使用如下的命令进行GEHistoricalImagery download --lower-left 39.619819,104.856121 --upper-right 39.638393,104.824990 --zoom 20 --date 2024/06/05 --target-sr https://epsg.io/103248.wkt --output ./Cherry Creek 1.tif执行后可能初学者会遇到这样的报错显示连接方没有反应如下一般这种时候就需要一点魔法了可以借助AI完成报错处理和配置。果到目前位置你都能够跟上我们的奏那就恭喜你所有的配置都顺利完成了。3.尝试下载重新执行 .\GEHistoricalImagery.bat download --lower-left 39.619819,-104.856121 --upper-right 39.638393,-104.824990 --zoom 20 --date 2024/06/05 --output .\Cherry Creek 1.tif特别注意经纬度先纬后经正负分清左下较小右上较大。输入前先在地图上核对位置。注意看这时你应该会看到工具已经在正常运行了我们等待数据正常下载完此时检查文件夹可以看到数据已经下载成功了。小编这里又将层级改成22级又执行了一版大家可以看 .\GEHistoricalImagery.bat download --lower-left 39.619819,-104.856121 --upper-right 39.638393,-104.824990 --zoom 22 --date 2024/06/05 --output .\Cherry Creek 1.tif我们在QGIS中打开影像大家可以看到这是下载下来的22级的影像的效果放大到植被建筑和道路基本上效果还是很清晰的不过上面的是基于经纬度得到的那么问题来了如果大家想要下载指定研究区域不规则边界的影像怎么办这个工具能帮我们实现目标吗4. 基于指定感兴趣的研究区下载影像前面我们用两个角点定义了矩形。但真实研究区往往不是方方正正的它可能是一个小流域、一块农田也可能是一片形状不规则的样地。这时就可以把研究区边界交给工具。GEHistoricalImagery 支持读取 KML/KMZ 文件不需要再手动填写每个顶点的经纬度。如果你的手里已有 SHP 边界这里小编以庐山的shp文件为例我们先把它进行数据转换。1ArcGIS工具箱直接转对于初学者而言很简单按照工具箱——转换工具——转为KML这里输入我们的图层命名为test_01虽然工具名叫“转 KML”输出文件扩展名填写.kmz便能够转成kmz文件。2利用代码直接转代码比较方便便于大家进行批量的文件转换当你的手上有很多个shp的时候代码将发挥大的作用。我们这里以单景影响为例展示如何借助代码完成kmz转换。from pathlib import Path import geopandas as gpd import simplekml # 1. 设置输入、输出路径 shp Path(rD:\GEHI_Tutorial\GEHistoricalImagery.0.7.1-win-x64\lushan\lushanGCS.shp) output shp.parent / lushan.kmz # 2. 读取边界转换为 WGS84 经纬度 gdf gpd.read_file(shp).to_crs(epsg4326) # 3. 将所有面放入同一个研究区 kml simplekml.Kml() region kml.newmultigeometry(name庐山) for geometry in gdf.geometry: polygons [geometry] if geometry.geom_type Polygon else geometry.geoms for polygon in polygons: region.newpolygon( outerboundaryislist(polygon.exterior.coords), innerboundaryis[list(ring.coords) for ring in polygon.interiors] ) # 4. 保存 KMZ kml.savekmz(str(output)) print(转换完成, output)对转换后的结果借助QGIS检查直接拖进去结果如下如果一份 SHP 属性表中有多个流域或地块或者研究区域希望指定ID每个编号生成一个 KMZ。假设属性表中有一个编号字段名字为Basin_ID可以使用下面的代码进行批量转换。from pathlib import Path import geopandas as gpd import simplekml # 1. 修改这四项 shp Path(rD:\GIS_Data\basins.shp) # 包含多个研究区的 SHP output_dir shp.parent / kmz_batch id_field Basin_ID # 属性表中的编号字段 target_ids [22, 24, 29, 44, 51, 84] # 需要导出的编号 # 2. 读取数据转换坐标 gdf gpd.read_file(shp).to_crs(epsg4326) output_dir.mkdir(parentsTrue, exist_okTrue) # 3. 按编号循环导出 for basin_id in target_ids: selected gdf[gdf[id_field] basin_id] if selected.empty: print(f跳过没有找到编号 {basin_id}) continue kml simplekml.Kml() region kml.newmultigeometry(namefbasin_{basin_id}) for geometry in selected.geometry: polygons [geometry] if geometry.geom_type Polygon else geometry.geoms for polygon in polygons: region.newpolygon( outerboundaryislist(polygon.exterior.coords), innerboundaryis[list(ring.coords) for ring in polygon.interiors] ) output output_dir / fbasin_{basin_id}.kmz kml.savekmz(str(output)) print(转换完成, output.name)其他转换方式大家可以参考如下的文章如何将ShapefileShp文件转换为KMLkml、kmz文件 - Imgiser - 博客园两种将SHP转KML文件的方法 - 知乎现在我们已经有了kmz文件接下来我们执行命令 .\GEHistoricalImagery.bat download --region-file .\test_01.kmz --zoom 20 --date 2024/06/05 --output .\lushan_target20240605_z20.tif此时便可以按照指定的研究区进行影像的查询和下载了我们同样以2024年6月5日为例。发现影像太大了 因为研究区域很大下载很慢作为演示我们下载17级的各位如果要高清的就自己更改Zoom级别就行。展示最终的下载结果其实是非常nice的边界到时候大家掩膜提取一下就行。5.批量下载影像假设我们现在有一批小流域的kmz文件D:\GEHI_Tutorial\GEHistoricalImagery.0.7.1-win-x64\river_kmz我们现在需要同时获取这些kmz的影像文件怎么办我们先来测试001-002两份文件下载能不能正常进行。在Powershell中执行下面的代码直接复制粘贴过去# 1. 下载设置 $tool D:\GEHI_Tutorial\GEHistoricalImagery.0.7.1-win-x64\GEHistoricalImagery.bat $kmzDir D:\GEHI_Tutorial\GEHistoricalImagery.0.7.1-win-x64\river_kmz $outputDir D:\GEHI_Tutorial\river_images_z21 $start 1 $end 2 $zoom 21 $targetDate 2024/06/01 # 2. 检查工具和输入目录 if (-not (Test-Path -LiteralPath $tool -PathType Leaf)) { throw Download tool not found: $tool } if (-not (Test-Path -LiteralPath $kmzDir -PathType Container)) { throw KMZ folder not found: $kmzDir } New-Item -ItemType Directory -Force -Path $outputDir | Out-Null # 每次运行使用独立的子文件夹避免覆盖已有影像 $runDir Join-Path $outputDir (Get-Date -Format yyyyMMdd_HHmmss_fff) New-Item -ItemType Directory -Path $runDir | Out-Null $results () Write-Host Output: $runDir -ForegroundColor Cyan # 3. 按编号依次下载 foreach ($number in $start..$end) { $name basin_{0:D3} -f $number $kmz Join-Path $kmzDir ($name .kmz) $tif Join-Path $runDir ($name .tif) if (-not (Test-Path -LiteralPath $kmz -PathType Leaf)) { Write-Host MISSING: $kmz -ForegroundColor Yellow $results [pscustomobject]{ Basin $name Status MissingKMZ ExitCode Output } continue } Write-Host n[$number/$end] Downloading $name -ForegroundColor Cyan $tool download --region-file $kmz --zoom $zoom --date $targetDate --output $tif $code $LASTEXITCODE $hasTif Test-Path -LiteralPath $tif -PathType Leaf if ($hasTif) { $hasTif (Get-Item -LiteralPath $tif).Length -gt 0 } if ($code -eq 0 -and $hasTif) { $status Created_NeedsGISCheck Write-Host TIFF created: $name -ForegroundColor Green } else { $status NeedsCheck Write-Host Needs checking: $name; exitCode$code -ForegroundColor Yellow } $results [pscustomobject]{ Basin $name Status $status ExitCode $code Output $tif } # 每完成一个流域就更新记录不会删除任何影像 $results | Export-Csv -LiteralPath (Join-Path $runDir results.csv) -NoTypeInformation -Encoding UTF8 } $results | Export-Csv -LiteralPath (Join-Path $runDir results.csv) -NoTypeInformation -Encoding UTF8 Write-Host nBatch finished. Output: $runDir -ForegroundColor Cyan粘贴过程中会显示是否要进行多行粘贴直接选仍然粘贴运行表现正常会显示[1/2] Downloading basin_001 Grabbing Image Tiles... ... Saving Image: Done! TIFF created: basin_001 [2/2] Downloading basin_002 ...如现在程序正在正常运行已经完成了一个影像的下载。下载完成展示一下得到的结果这是basin_001的结果。这是basin_002的结果。整体效果还是非常不错的影像也很高清符合解译的要求。既然前两个流域可以成功我们这时只需要将参数改成如下即可批量完成300多个流域的下载$start 3 $end 313即此时代码的头部改成# 1. 下载设置 $tool D:\GEHI_Tutorial\GEHistoricalImagery.0.7.1-win-x64\GEHistoricalImagery.bat $kmzDir D:\GEHI_Tutorial\GEHistoricalImagery.0.7.1-win-x64\river_kmz $outputDir D:\GEHI_Tutorial\river_images_z21 $start 1 $end 313当然有的同学可能觉得Powershell比较难用Python 可以通过Subprocess调用发布版工具依次下载多个 KMZ不需要源码也不需要编译。代码如下from pathlib import Path from datetime import datetime import subprocess import os import csv # 1. 参数设置 tool_dir Path(rD:\GEHI_Tutorial\GEHistoricalImagery.0.7.1-win-x64) kmz_dir tool_dir / river_kmz start 3 # 001、002已完成从003开始 end 313 zoom 21 target_date 2024/06/01 proxy http://127.0.0.1:7890 # 改为FlClash实际端口 # 每次运行创建独立文件夹避免覆盖已有影像 run_dir ( Path(rD:\GEHI_Tutorial\river_images_python) / datetime.now().strftime(%Y%m%d_%H%M%S_%f) ) # 2. 检查路径 exe tool_dir / gdal / GEHistoricalImagery.exe if not exe.is_file(): raise FileNotFoundError(f没有找到下载程序{exe}) if not kmz_dir.is_dir(): raise FileNotFoundError(f没有找到KMZ文件夹{kmz_dir}) run_dir.mkdir(parentsTrue) # 3. 配置运行环境 # 与发布版BAT的设置一致确保程序能找到GDAL等配套文件 env os.environ.copy() env[GDAL_DATA] str(tool_dir / gdal) env[GEOTIFF_CSV] str(tool_dir / gdal) env[PROJ_LIB] str(tool_dir / gdal) env[GEHistoricalImagery_Cache] str(tool_dir / cache) env[HTTP_PROXY] proxy env[HTTPS_PROXY] proxy env[ALL_PROXY] proxy # 4. 依次下载并记录结果 print(f影像输出目录{run_dir}, flushTrue) with (run_dir / results.csv).open( w, newline, encodingutf-8-sig ) as record: writer csv.writer(record) writer.writerow([流域, 状态, 退出码, 影像路径]) for number in range(start, end 1): name fbasin_{number:03d} kmz kmz_dir / f{name}.kmz tif run_dir / f{name}.tif if not kmz.is_file(): print(f跳过找不到 {kmz.name}, flushTrue) writer.writerow([name, 缺少KMZ, , ]) record.flush() continue print(f\n[{number}/{end}] 正在下载 {name}, flushTrue) command [ str(exe), download, --region-file, str(kmz), --zoom, str(zoom), --date, target_date, --output, str(tif), ] try: result subprocess.run( command, cwdstr(tool_dir), envenv, checkFalse, ) except OSError as error: print(f程序启动失败{error}, flushTrue) writer.writerow([name, 启动失败, , str(tif)]) record.flush() continue has_tif tif.is_file() and tif.stat().st_size 0 if result.returncode 0 and has_tif: status 已生成待GIS检查 print(f已生成{tif.name}, flushTrue) else: status 需要检查 print( f需要检查{name}退出码{result.returncode}未删除任何文件, flushTrue, ) writer.writerow([name, status, result.returncode, str(tif)]) record.flush() print(f\n批量任务结束结果保存在{run_dir}, flushTrue)上述代码需要大家配置工具的存储地址存储目录kmz的目录如果大家的文件不是像案例这样的文件组织结构建议代码部分也做统一的检查如下是程序运行过程我们同样可以检查Python下载的影像质量。另外在数据下载的过程中一般会遇到一些运行结果的提示含义如下内容实际含义应做的检查--date 2025/07/15以这一天为查找目标默认取邻近可用日期阅读瓦片替代日期日志不能仅凭文件名认定拍摄年份Substituting level 20 imagery from 2025/03/23某瓦片用了 20 级拍摄日期显示为 2025/03/23记录实际层级和日期检查局部清晰度25252 out of 25252 downloaded这一次所需的瓦片下载数达到显示的总数仍需检查 TIFF 和空间范围0 out of 5113 downloaded此次请求没有得到可用瓦片检查代理、KMZ、多日期/多层级不应只重复原命令No imagery available for tile该瓦片在此次查询未取得影像结合总下载数、日志和输出判断不等于所有年份所有层级都不存在官方文档说明默认会找邻近日期并可用低层级影像补洞官方版本关于补洞的说明是最多低两级。也就是说当指定20级时若不存在20级的影像将回退到19级19级没有将回退到18级。折腾到这里我们终于可以说我们有能力下载一张好影像了。不过请求21级不代表每个位置都有21级的原始影像指定某个日期也不代表整幅图都拍摄于那一天。下载完成后记得放进 GIS 里看一眼位置对不对、范围全不全、有没有黑块日期是否符合自己的研究需求。如果中途报错也先别急着重新安装、重新编译。看看是路径没写对、代理没连上还是 KMZ 里有多个区域等着选择。我们前面遇到的不少问题就藏在这些小地方。建议第一次上手的朋友先挑一个小研究区跑通再用两个 KMZ 测试批量最后才把整批任务交给程序。等第一张能正确定位的影像出现在 GIS 里后面的操作就顺手多了。希望这篇教程能让你少绕几圈把时间留给真正想做的分析。毕竟下载只是起点影像里藏着什么才是接下来有意思的部分。今天的学习到这里就结束了创作不易如果对你的学习有帮助记得点赞关注转发哦您的支持是我们更新最大动力参考资料https://github.com/Mbucari/GEHistoricalImageryhttps://github.com/Mbucari/GEHistoricalImagery/blob/master/docs/download.mdhttps://github.com/Mbucari/GEHistoricalImagery/blob/master/docs/availability.mdhttps://github.com/Mbucari/GEHistoricalImagery/blob/master/docs/regions.mdhttps://github.com/chen08209/FlClash在此特别鸣谢野老不至提供的灵感和素材。