Rasterio裁剪后栅格较掩膜栅格各维度大1像素问题咨询
问题
我拥有两个尺寸不同的栅格,需将较大栅格裁剪至与较小栅格的x/y维度(而非仅经纬度范围)完全匹配。现有代码接近实现需求,但裁剪后的栅格各维度仍比掩膜栅格大1像素(754x879 vs 753x878)。为何两者维度不一致?
另外发现两个输入栅格的transform略有差异,是否因此导致栅格范围一致但维度不同?
附代码:
import rasterio import geopandas as gpd from shapely.geometry import box from rasterio.mask import raster_geometry_mask import json masking_raster = rasterio.open(path/to/file) raster_to_mask = rasterio.open(path/to/file) bbox = box(*masking_raster.bounds) geo = gpd.GeoDataFrame({'geometry': bbox}, index=[0], crs=val_file.crs) bbox_json = json.loads(gdf.to_json())['features'][0]['geometry'] masked_array, out_transform, window = raster_geometry_mask(val_file, shapes=[bbox_json], crop=True, all_touched=False) print("masking raster shape: ", masking_raster.shape) # masking raster shape: (753, 878) print("resulting masked array shape: ", masked_array.shape) # resulting masked array shape: (754, 879)
分析与解决
核心原因
- Transform差异导致像素错位:两个栅格的transform参数不一致,意味着像素网格的原点或分辨率存在细微偏差。用掩膜栅格的边界框裁剪时,目标栅格的像素无法与掩膜栅格完全对齐,裁剪范围会额外包含边界处的一行/列像素,最终维度多1。
all_touched=False的判定逻辑:该参数仅保留完全落在边界内的像素,但由于transform偏差,边界附近的目标栅格像素可能处于“部分包含”的临界状态,反而被纳入结果,导致维度增加。
精准匹配维度的解决方案
直接利用掩膜栅格的行列范围进行窗口裁剪,跳过边界框计算,确保维度完全一致:
import rasterio masking_raster = rasterio.open("path/to/masking_raster.tif") raster_to_mask = rasterio.open("path/to/raster_to_mask.tif") # 基于掩膜栅格的宽高创建精确窗口 target_window = rasterio.windows.Window.from_slices( (0, masking_raster.height), (0, masking_raster.width) ) # 读取目标栅格的对应窗口区域,同时获取匹配的transform cropped_data = raster_to_mask.read(window=target_window) output_transform = rasterio.windows.transform(target_window, raster_to_mask.transform) # 验证维度 print("masking raster shape: ", masking_raster.shape) print("cropped array shape: ", cropped_data.shape[1:]) # 忽略波段维度,只看行列
跨CRS场景的处理
如果两个栅格的坐标系(CRS)不同,需要先将目标栅格重投影到掩膜栅格的CRS和transform参数,再裁剪:
from rasterio.warp import calculate_default_transform, reproject, Resampling masking_raster = rasterio.open("path/to/masking_raster.tif") raster_to_mask = rasterio.open("path/to/raster_to_mask.tif") # 强制对齐到掩膜栅格的尺寸、transform和CRS dst_crs = masking_raster.crs dst_transform = masking_raster.transform dst_width, dst_height = masking_raster.width, masking_raster.height # 重投影并保存 with rasterio.open( "aligned_raster.tif", "w", driver="GTiff", height=dst_height, width=dst_width, count=raster_to_mask.count, dtype=raster_to_mask.dtypes[0], crs=dst_crs, transform=dst_transform, ) as dst_dataset: for band_idx in range(1, raster_to_mask.count + 1): reproject( source=rasterio.band(raster_to_mask, band_idx), destination=rasterio.band(dst_dataset, band_idx), src_transform=raster_to_mask.transform, src_crs=raster_to_mask.crs, dst_transform=dst_transform, dst_crs=dst_crs, resampling=Resampling.nearest, # 根据需求选择重采样方式 )
内容的提问来源于stack exchange,提问作者Darren C.
相关产品推荐
相关产品推荐

