98 lines
4.1 KiB
Python
98 lines
4.1 KiB
Python
import rasterio
|
||
from rasterio.windows import Window
|
||
import geopandas as gpd
|
||
from shapely.geometry import box
|
||
import numpy as np
|
||
import os
|
||
|
||
# 参数设置
|
||
image_path = 'path/to/your/image.tif' # 替换为您的影像路径(20000x20000)
|
||
shapefile_path = 'path/to/your/shapefile.shp' # 替换为您的图斑Shapefile路径
|
||
output_dir = 'path/to/output/tiles' # 输出切片目录
|
||
tile_size = 1024 # 固定切片大小
|
||
max_overlap_ratio = 0.2 # 重叠小于20%
|
||
min_step = int(tile_size * (1 - max_overlap_ratio)) # 最小步长 ≈820
|
||
|
||
# 创建输出目录
|
||
os.makedirs(output_dir, exist_ok=True)
|
||
|
||
# 读取影像
|
||
with rasterio.open(image_path) as src:
|
||
image_width, image_height = src.width, src.height
|
||
assert image_width == 20000 and image_height == 20000, "影像大小不匹配"
|
||
transform = src.transform # 地理变换矩阵
|
||
|
||
# 读取图斑数据(假设CRS一致)
|
||
gdf = gpd.read_file(shapefile_path)
|
||
# 确保图斑CRS与影像一致,如果不一致需转换:gdf = gdf.to_crs(src.crs)
|
||
|
||
# 初始化切片列表,避免重叠过多
|
||
generated_windows = []
|
||
|
||
for idx, row in gdf.iterrows():
|
||
geom = row.geometry # 获取单个图斑多边形
|
||
|
||
# 计算图斑的边界框 (minx, miny, maxx, maxy) - 像素坐标
|
||
minx, miny, maxx, maxy = geom.bounds
|
||
bbox_width = maxx - minx
|
||
bbox_height = maxy - miny
|
||
|
||
# 如果图斑太大,无法放入单个1024x1024切片,需处理(这里简单跳过,您可修改)
|
||
if bbox_width > tile_size or bbox_height > tile_size:
|
||
print(f"图斑 {idx} 太大 ({bbox_width}x{bbox_height}),跳过或需多切片处理")
|
||
continue
|
||
|
||
# 计算覆盖完整图斑的最小窗口:居中扩展到1024x1024
|
||
center_x = (minx + maxx) / 2
|
||
center_y = (miny + maxy) / 2
|
||
half_tile = tile_size / 2
|
||
win_minx = max(0, center_x - half_tile)
|
||
win_miny = max(0, center_y - half_tile)
|
||
win_maxx = min(image_width, center_x + half_tile)
|
||
win_maxy = min(image_height, center_y + half_tile)
|
||
|
||
# 调整以确保正好1024x1024(如果边界不足,padding或调整)
|
||
if win_maxx - win_minx < tile_size:
|
||
win_minx = max(0, win_maxx - tile_size)
|
||
if win_maxy - win_miny < tile_size:
|
||
win_miny = max(0, win_maxy - tile_size)
|
||
|
||
proposed_window = Window(win_minx, win_miny, tile_size, tile_size)
|
||
|
||
# 检查与现有窗口的重叠,确保<20%
|
||
too_much_overlap = False
|
||
for existing_win in generated_windows:
|
||
# 计算重叠区域
|
||
overlap_x = max(0, min(win_minx + tile_size, existing_win.col_off + tile_size) - max(win_minx, existing_win.col_off))
|
||
overlap_y = max(0, min(win_miny + tile_size, existing_win.row_off + tile_size) - max(win_miny, existing_win.row_off))
|
||
overlap_area = overlap_x * overlap_y
|
||
if overlap_area > (tile_size * tile_size * max_overlap_ratio):
|
||
too_much_overlap = True
|
||
break
|
||
|
||
if too_much_overlap:
|
||
# 如果重叠太大,调整位置(这里简单跳过,您可实现更复杂的调整,如偏移步长)
|
||
print(f"图斑 {idx} 的窗口重叠过多,跳过或调整")
|
||
continue
|
||
|
||
# 添加到列表
|
||
generated_windows.append(proposed_window)
|
||
|
||
# 裁剪并保存切片
|
||
tile_data = src.read(window=proposed_window)
|
||
tile_meta = src.meta.copy()
|
||
tile_meta.update({
|
||
'width': proposed_window.width,
|
||
'height': proposed_window.height,
|
||
'transform': rasterio.windows.transform(proposed_window, src.transform)
|
||
})
|
||
output_path = os.path.join(output_dir, f'tile_{idx}.tif')
|
||
with rasterio.open(output_path, 'w', **tile_meta) as dst:
|
||
dst.write(tile_data)
|
||
|
||
print(f"生成切片 {output_path},覆盖图斑 {idx}")
|
||
|
||
print(f"总共生成 {len(generated_windows)} 个切片")
|
||
|
||
# 注意:这个代码确保每个切片包含至少一个完整图斑,但可能有图斑被多个切片覆盖(如果重叠允许)。如果需要覆盖所有图斑的最优 tiling,请提供更多细节。
|