如何用Python rioxarray重投影时保留原图像尺寸并去除空像素?
解决rioxarray重投影后空像素冗余问题
问题根源
默认调用rio.reproject()时,会自动计算目标坐标系下覆盖原影像完整地理范围的最小外接矩形,原数据未覆盖的区域会被填充为空值,最终导致输出影像出现大量无效空像素、文件体积翻倍。
两种无空像素重投影方案
方案1:重投影后裁剪无效区域
先完成重投影,再移除全为空值的边缘行列,仅保留有有效数据的最小范围:
import rioxarray rast_path = "old_projection.tif" rds = rioxarray.open_rasterio(rast_path) # 执行重投影 rds_3996 = rds.rio.reproject("EPSG:3996") # 自动裁剪全空的边缘行和列 rds_3996_trimmed = rds_3996.rio.trim() # 保存结果 rds_3996_trimmed.rio.to_raster("new_projection_no_empty.tif")
rio.trim()会自动识别并移除所有像素均为空值的边缘区域,精准保留有效数据范围。
方案2:重投影时直接限定目标范围
先计算原数据在目标坐标系下的精确边界,直接定义输出影像的范围和尺寸,从根源避免空像素生成:
import rioxarray from pyproj import Transformer from affine import Affine rast_path = "old_projection.tif" rds = rioxarray.open_rasterio(rast_path) # 初始化坐标系转换器 transformer = Transformer.from_crs("EPSG:4326", "EPSG:3996", always_xy=True) # 获取原影像的地理边界 min_x, min_y, max_x, max_y = rds.rio.bounds() # 转换原影像四个角点到目标坐标系 corners = [(min_x, min_y), (max_x, min_y), (min_x, max_y), (max_x, max_y)] transformed_corners = [transformer.transform(x, y) for x, y in corners] # 计算目标坐标系下的有效边界 tgt_min_x = min([x for x, y in transformed_corners]) tgt_max_x = max([x for x, y in transformed_corners]) tgt_min_y = min([y for x, y in transformed_corners]) tgt_max_y = max([y for x, y in transformed_corners]) # 沿用原影像分辨率,或按需调整 res_x, res_y = rds.rio.resolution() # 计算输出影像的宽高 width = int((tgt_max_x - tgt_min_x) / res_x) height = int((tgt_max_y - tgt_min_y) / abs(res_y)) # 构建输出影像的仿射变换参数 tgt_transform = Affine(res_x, 0.0, tgt_min_x, 0.0, -abs(res_y), tgt_max_y) # 带参数重投影,直接生成无空像素的影像 rds_3996 = rds.rio.reproject( "EPSG:3996", transform=tgt_transform, shape=(height, width) ) rds_3996.rio.to_raster("new_projection_no_empty.tif")
此方法在重投影阶段就限定了输出范围,无需后续裁剪,效率更高。
注意事项
- 如果原影像空值标记不是默认的
NaN,需提前用rds.rio.set_nodata()指定正确空值,确保空像素识别准确。 - EPSG:3996为米制坐标系,调整分辨率时需注意单位匹配,避免出现尺度偏差。
内容的提问来源于stack exchange,提问作者Marcus K.
相关产品推荐
相关产品推荐

