前不久遇到一个需求,即对遥感影像进行批量裁剪。其实这个需求在arcgis中等一些gis软件中就可以实现,但是吧,他需要手动点比较麻烦,而且中间还生成一些我并不需要的其他文件(.tfw等等)。基于此,我就想这个能不能自己用python写一个程序实现批量裁剪,且不生成其他文件。说干就干,详见下文.
其实我主要基于gdal以及numpy和os实现的。gdal是一个开源的图像处理库,主要用于读取、写入和处理地理空间数据。numpy是一个用于科学计算的Python库,可以用来进行数据处理、数值计算、线性代数、随机数生成等操作。os库就不详细介绍了,标准库。
from osgeo import gdal, gdalconst
import numpy as np
import os
代码如下:这里介绍一下几个参数:
input_tiff:需要裁剪的tif路径
output_folder:裁剪的小图需要保存的文件夹路径
tile_size_x:裁剪小图的宽
tile_size_y:裁剪小图的长
name:裁剪小图的名称
def crop_images_tiff(input_tiff, output_folder, tile_size_x, tile_size_y, name):
# 打开输入的TIFF文件
input_ds = gdal.Open(input_tiff, gdalconst.GA_ReadOnly)
# 获取输入TIFF的基本信息
width = input_ds.RasterXSize
height = input_ds.RasterYSize
projection = input_ds.GetProjection()
# 计算水平和垂直方向上分别有多少个tile
if width % tile_size_x == 0:
num_tiles_x = width // tile_size_x
else:
num_tiles_x = width // tile_size_x + 1
if height % tile_size_y == 0:
num_tiles_y = height // tile_size_y
else:
num_tiles_y = height // tile_size_y + 1
# 创建输出文件夹
if not os.path.exists(output_folder):
os.makedirs(output_folder)
for i in range(num_tiles_x):
for j in range(num_tiles_y):
# 计算当前tile的偏移
offset_x = i * tile_size_x
offset_y = j * tile_size_y
if offset_x + tile_size_x >= width:
tile_size_x_ = width - offset_x
else:
tile_size_x_ = tile_size_x
if offset_y + tile_size_y >= height:
tile_size_y_ = height - offset_y
else:
tile_size_y_ = tile_size_y
# 读取tile数据
tile_data = input_ds.ReadAsArray(offset_x, offset_y, tile_size_x_, tile_size_y_)
# 将小于0的值变为0
tile_data[tile_data <= 0] = 0
# 使用nan_to_num函数将NaN值替换为0
tile_data = np.nan_to_num(tile_data, nan=0.0)
tile_data = tile_data[:3, :, :]
print(tile_data.shape)
# 创建输出文件
output_tiff = os.path.join(output_folder, name+f'_{i}_{j}.TIF')
output_ds = gdal.GetDriverByName('GTiff').Create(output_tiff, tile_size_x_, tile_size_y_, 3, gdalconst.GDT_Byte)
# 设置投影坐标信息
output_ds.SetProjection(projection)
# 计算新的地理坐标信息
geo_transform = list(input_ds.GetGeoTransform())
geo_transform[0] = geo_transform[0] + offset_x * geo_transform[1]
geo_transform[3] = geo_transform[3] + offset_y * geo_transform[5]
output_ds.SetGeoTransform(tuple(geo_transform))
# 将tile数据写入输出文件
for band in range(3):
output_ds.GetRasterBand(band+1).WriteArray(tile_data[band, :, :])
# 关闭输出文件
output_ds = None
# 关闭输入文件
input_ds = None
if __name__ == "__main__":
# image.tif路径
input_folder1 = r'images.tif'
# 输出images文件夹路径(保存裁剪后的图像)
output_folder1 = r'images'
dir1 = os.path.exists(output_folder1)
if dir1 != True:
os.makedirs(output_folder1)
print('正在裁剪image...')
crop_images_tiff(input_folder1, output_folder1, 512, 512, 'image')
通过gdal以及numpy实现了图像批量裁剪功能。有需要的可以参考用一下。