使用GDAL库按1000x1000米格网分幅处理卫图

使用GDAL库按1000x1000米格网分幅处理卫图
ytkz概述
最近一位小伙伴私信我,说他在处理卫星影像时遇到一个需求:需要将大范围的栅格影像按固定网格(比如 1000x1000 米)分割成小块瓦片,确保接边无缝,还要保存为 PNG 格式方便查看。他希望有一个简单易用的工具,最好不用装一堆环境。于是,我写了一个 Python 脚本 split_raster_into_tiles.py,用 GDAL 实现了这个功能,并用 Pyinstaller 打包成了一个独立的 .exe 文件。这篇文章就来介绍一下这个工具的用法,希望能帮到有类似需求的朋友!
需求背景
小伙伴的需求很明确:
输入:一张大范围的卫星影像(比如 TIFF 格式)。
处理:按 1000x1000 米网格分割,边缘无缝对接。
输出:生成多个小瓦片,保存为 PNG 格式(方便查看),同时保留地理信息。
额外要求:最好是个独立程序,不用折腾 。
基于这个需求,我开发了 split_raster_into_tiles.py,并用 Pyinstaller 打包成了 split_raster_into_tiles.exe。下面就来详细介绍怎么用它。
功能简介
split_raster_into_tiles.exe 是一个命令行工具,主要功能包括:
读取栅格影像(如 TIFF)。
按指定范围(默认 1000 米)分割成小瓦片。
这里要说明一下,1000米是针对的是投影坐标系的影像,单位是米。如果你的影像是地理坐标系,这个参数的单位是度数。
确保瓦片之间无缝衔接,保留地理参考信息。
输出 PNG 格式图像(用于可视化)和 TIFF 格式文件(带地理信息)。
这个工具特别适合遥感影像预处理、地图瓦片生成等场景,尤其是对非技术用户来说,免去了配置环境的麻烦。
前置条件
操作系统:Windows(其他系统需重新打包)。
输入文件:支持 GDAL 可读取的栅格格式(推荐 TIFF)。
磁盘空间:确保输出目录有足够空间存放瓦片。
打包后无需安装 Python、GDAL 或其他依赖,所有库都已集成到 .exe 中。
准备工作
把 split_raster_into_tiles.exe 放到一个工作目录,比如 C:\GIS_Tools。
准备好输入影像,比如 input.tif。
创建一个输出目录,比如 C:\output,用来保存生成的瓦片。运行程序
打开命令提示符(Windows 下按 Win + R,输入 cmd,回车)。
切换到工具所在目录:
cd C:\GIS_Tools运行程序:
split_raster_into_tiles.exe3. 输入参数
程序启动后会依次提示你输入:
输入影像路径:键入影像文件的完整路径,比如 C:\data\input.tif。
输入保存路径:键入输出目录,比如 C:\output。
分幅范围:输入分割网格的大小(单位:米),比如 1000。
输入完后按回车,程序就会开始处理。输出结果
处理完成后,输出目录中会生成一堆文件:
tile_x_y.tif:带地理信息的 TIFF 瓦片。
tile_x_y.png:对应的 PNG 图像。 控制台会显示完成信息,例如:
注意事项
路径问题:路径要写全,避免中文路径(可能会出编码问题)。
影像格式:输入文件要是 GDAL 支持的格式,TIFF 最稳。
分幅范围:默认 1000 米,可以改,比如 500 米,但太小可能会生成很多瓦片。
内存和空间:大影像处理时,确保电脑内存够用,磁盘空间充足。
错误排查:如果提示“无法打开输入影像”,检查文件路径或文件是否损坏。
总结
从一个小伙伴的需求出发,我开发并打包了 split_raster_into_tiles.exe,希望它能帮到更多处理栅格影像的朋友。工具虽小,但解决了实际问题:无缝分割、PNG 输出、免环境配置。如果你也有类似需求,不妨试试这个 .exe,或者直接告诉我你的想法,我再帮你调整代码。
技术是为需求服务的,有问题欢迎随时交流!
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2025/3/5 10:59
# @File : split_raster_into_tiles.py
'''
使用GDAL库按1000x1000米格网分幅处理卫图的Python函数代码,确保影像接边无缝并保存为PNG格式
'''
import os
import numpy as np
from osgeo import gdal
from PIL import Image, ImageDraw
def split_raster_into_tiles(input_raster_path, output_dir):
# 打开原始影像
ds = gdal.Open(input_raster_path)
if ds is None:
raise ValueError("无法打开输入影像")
# 获取影像基本信息
geotransform = ds.GetGeoTransform()
proj = ds.GetProjection()
x_size = ds.RasterXSize
y_size = ds.RasterYSize
num_bands = ds.RasterCount
px_width = abs(geotransform[1]) # 像素宽度(米)
px_height = abs(geotransform[5]) # 像素高度(米)
# 计算每个分幅的像素尺寸
tile_pixel_width = int(round(1000 / px_width))
tile_pixel_height = int(round(1000 / px_height))
# 计算分幅数量
num_x_tiles = int(np.ceil(x_size / tile_pixel_width))
num_y_tiles = int(np.ceil(y_size / tile_pixel_height))
# 创建输出目录
os.makedirs(output_dir, exist_ok=True)
# 遍历所有分幅
for x in range(num_x_tiles):
for y in range(num_y_tiles):
# 计算当前分幅的像素范围
x_offset = x * tile_pixel_width
y_offset = y * tile_pixel_height
# 计算实际读取尺寸
read_x = min(tile_pixel_width, x_size - x_offset)
read_y = min(tile_pixel_height, y_size - y_offset)
# 初始化数据数组
tile_data = np.zeros((tile_pixel_height, tile_pixel_width, num_bands), dtype=np.uint8)
# 读取每个波段数据
for b in range(num_bands):
band = ds.GetRasterBand(b + 1)
data = band.ReadAsArray(x_offset, y_offset, read_x, read_y)
# 处理边缘分幅
if data is None:
continue
# 填充数据到分幅数组
if data.ndim == 2:
tile_data[:read_y, :read_x, b] = data
else:
tile_data[:read_y, :read_x, b] = data[..., 0]
# 计算当前分幅的地理坐标
ulx = geotransform[0] + x_offset * geotransform[1]
uly = geotransform[3] + y_offset * geotransform[5]
# 创建输出文件
output_path = os.path.join(output_dir, f'tile_{x}_{y}.tif')
driver = gdal.GetDriverByName('GTiff')
target_ds = driver.Create(output_path,
tile_pixel_width,
tile_pixel_height,
num_bands,
gdal.GDT_Byte)
# 设置地理参考
new_geotransform = (
ulx, # 左上角x坐标
geotransform[1], # 像素宽度
geotransform[2], # 旋转参数
uly, # 左上角y坐标
geotransform[4], # 旋转参数
geotransform[5] # 像素高度
)
target_ds.SetGeoTransform(new_geotransform)
target_ds.SetProjection(proj)
# 写入数据
for b in range(num_bands):
target_ds.GetRasterBand(b + 1).WriteArray(tile_data[..., b])
image = Image.fromarray(tile_data, mode="RGB")
target_path = os.path.join(output_dir, f'tile_{x}_{y}.png')
image.save(target_path, 'PNG') # 保存
target_ds.FlushCache()
target_ds = None
ds = None
print(f"分幅完成,共生成 {num_x_tiles}x{num_y_tiles}={num_x_tiles * num_y_tiles} 个分幅")
if __name__ == '__main__':
file = r'F:\out1_qgis.tif'
output_dir = r'F:\output'
split_raster_into_tiles(file, output_dir)
获取工具
公众号回复分幅使用方法
结果对比
输入影像如下:
输出结果如下: