You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Geotiff影像与Folium地图叠加时内部像素偏移问题求助

解决Folium叠加GeoTIFF的像素偏移问题

问题根源

你遇到的整体位置正确但内部像素偏移的问题,核心原因是GDAL读取的栅格行顺序与Leaflet(Folium基于Leaflet)的渲染顺序相反:GDAL返回的数组第一行对应影像的顶部,而Leaflet的ImageOverlay是从底部开始向上绘制,导致像素行错位,从而出现轻微偏移。

解决方案

1. 反转栅格数组行顺序

直接调整GDAL读取的数组,匹配Leaflet的渲染逻辑:
将img = ds.GetRasterBand(1).ReadAsArray()修改为:

img = np.flipud(ds.GetRasterBand(1).ReadAsArray())

2. 严谨处理坐标转换(可选但推荐)

如果你的GeoTIFF不是EPSG:4326投影,手动计算边界可能因投影不匹配产生误差,建议用GDAL的坐标转换工具获取准确的WGS84边界:

from osgeo import osr

# 获取影像原始投影
srs = osr.SpatialReference()
srs.ImportFromWkt(ds.GetProjection())
# 定义目标投影(WGS84,Folium的bounds需要此坐标)
target_srs = osr.SpatialReference()
target_srs.ImportFromEPSG(4326)
transform = osr.CoordinateTransformation(srs, target_srs)

# 计算影像四至点并转换为WGS84
ul_x, ul_y = GT[0], GT[3]
lr_x, lr_y = GT[0] + width*xRes, GT[3] + height*yRes
ul_lon, ul_lat, _ = transform.TransformPoint(ul_x, ul_y)
lr_lon, lr_lat, _ = transform.TransformPoint(lr_x, lr_y)

# 设置正确的bounds格式:[[西南纬度, 西南经度], [东北纬度, 东北经度]]
bounds = [[lr_lat, ul_lon], [ul_lat, lr_lon]]

3. 正确启用Mercator投影转换

如果影像原始投影是EPSG:4326,给ImageOverlay添加Mercator_project=True参数,确保自动转换为地图使用的EPSG:3857投影。

修改后的完整代码

#!/usr/bin/env python3
import numpy as np
from osgeo import gdal, osr
import folium
import branca.colormap as cm
from matplotlib import colors as colors

def mapvalue2color(value, cmap): 
    if (value == 0):
        return (1, 0, 0, 0)
    else:
        return colors.to_rgba(cmap(value), 0.7)   # alpha channel=0.7 tuple (r, g, b, a)

colormap = cm.LinearColormap(["red", "magenta"], vmin=6, vmax=8) 

# 初始化地图,EPSG:3857是Leaflet默认CRS,无需修改
folium_map = folium.Map(location=[46.3, 3.5], tiles='openstreetmap', zoom_start=10, max_zoom=18)

ds = gdal.Open("./data.tif")
# 反转栅格行顺序,匹配Leaflet渲染逻辑
img = np.flipud(ds.GetRasterBand(1).ReadAsArray())
GT = ds.GetGeoTransform()
xRes = GT[1]
yRes = GT[5]
width = ds.RasterXSize
height = ds.RasterYSize 

# 处理坐标转换,确保bounds使用WGS84坐标
srs = osr.SpatialReference()
srs.ImportFromWkt(ds.GetProjection())
target_srs = osr.SpatialReference()
target_srs.ImportFromEPSG(4326)
transform = osr.CoordinateTransformation(srs, target_srs)

# 计算影像四至点并转换为WGS84
ul_x, ul_y = GT[0], GT[3]
lr_x, lr_y = GT[0] + width*xRes, GT[3] + height*yRes
ul_lon, ul_lat, _ = transform.TransformPoint(ul_x, ul_y)
lr_lon, lr_lat, _ = transform.TransformPoint(lr_x, lr_y)

# 正确设置bounds:[[西南角(lat, lon)], [东北角(lat, lon)]]
bounds = [[lr_lat, ul_lon], [ul_lat, lr_lon]]

folium.raster_layers.ImageOverlay(
    image=img,
    opacity=0.5,
    bounds=bounds,
    colormap=lambda value: mapvalue2color(value, colormap),
    Mercator_project=True  # 影像为EPSG:4326时开启
).add_to(folium_map)

# 转换标记点坐标(如果原始投影非WGS84)
marker_x = GT[0] + xRes*9
marker_y = GT[3] + yRes*4
marker_lon, marker_lat, _ = transform.TransformPoint(marker_x, marker_y)
folium.Marker(
    location=[marker_lat, marker_lon],
    popup=folium.Popup(f"lat : {marker_lat:.6f}<br>lon : {marker_lon:.6f}", max_width=500),
).add_to(folium_map)

map_path = "./map.html"
folium_map.save(map_path)

说明

修改后,栅格行顺序与Leaflet渲染逻辑一致,坐标转换也更准确,能彻底解决像素偏移问题。如果你的GeoTIFF本身就是EPSG:4326投影,坐标转换部分可以简化,但保留该代码能兼容更多投影场景。

内容的提问来源于stack exchange,提问作者vincentL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 16:24:56