之前基于SNAP处理了Sentinel-1数据,发现地理校正之后,影像外围存在大量的nodata(用gdal读取之后变为0值),使得文件大小大了一倍。不知道是我选择的投影有问题还是哪些设置出现了问题,一直没有解决,因此又基于gdal对处理好的影像进行了裁剪,把白边去掉。
总体思路就是计算好裁剪的地理坐标后,用gdal.Translate裁剪,注意这里不生成矩阵而是直接输出tif
# -*- coding: utf-8 -*-
"""
Created on Sun Jul 2 15:22:10 2023
@author: Asus
"""
import numpy as np
from osgeo import gdal
import os
from skimage import measure
import pandas as pd
def read_tif(filename):
dataset = gdal.Open(filename) # 打开文件
print(dataset.GetRasterBand(1).GetNoDataValue())
im_width = dataset.RasterXSize # 栅格矩阵的列数
im_height = dataset.RasterYSize # 栅格矩阵的行数
im_geotrans = dataset.GetGeoTransform() # 仿射矩阵
im_proj = dataset.GetProjection() # 地图投影信息
# band = dataset.GetBand(0) #就要第一个波段
# band = dataset.GetRasterBand(1)
# ndv = 100
# band.SetNoDataValue(ndv)
# im_data= band.ReadAsArray(0, 0, im_width, im_height) # 将数据写成数组,对应栅格矩阵
im_data = dataset.ReadAsArray(0, 0, im_width, im_height) # 将数据写成数组,对应栅格矩阵
# print(im_data.shape)
# im_data=im_data[0,:,:] #只选第一个波段
del dataset
return im_proj, im_geotrans, im_data,im_width,im_height
def write_img(filename, im_proj, im_geotrans, im_data, im_height,im_width,im_bands):
# gdal数据类型包括
# gdal.GDT_Byte,
# gdal .GDT_UInt16, gdal.GDT_Int16, gdal.GDT_UInt32, gdal.GDT_Int32,
# gdal.GDT_Float32, gdal.GDT_Float64
# 判断栅格数据的数据类型
if 'int8' in im_data.dtype.name:
datatype = gdal.GDT_Byte
elif 'int16' in im_data.dtype.name:
datatype = gdal.GDT_Int16
else:
datatype = gdal.GDT_Float32
# 判读数组维数
# 创建文件
# im_bands = 1 ######################### 这里要改 保存的文件是几个波段
im_height = im_height
im_width = im_width
driver = gdal.GetDriverByName("GTiff") # 数据类型必须有,因为要计算需要多大内存空间
dataset = driver.Create(filename, im_width, im_height, im_bands, datatype)
dataset.SetGeoTransform(im_geotrans) # 写入仿射变换参数
dataset.SetProjection(im_proj) # 写入投影
if im_bands == 1:
dataset.GetRasterBand(1).WriteArray(im_data) # 写入数组数据
else:
for i in range(im_bands):
dataset.GetRasterBand(i + 1).WriteArray(im_data[i])
del dataset
def get_clip_extent(geoinfo,shp_x,shp_y):
ul_x = geoinfo[0]
ul_y = geoinfo[3]
x_res = geoinfo[1]
y_res = geoinfo[5]
geo_x_pos = int((shp_x - ul_x)/x_res)
geo_y_pos = int((ul_y - shp_y)/abs(y_res))
return (geo_x_pos,geo_y_pos)
hhpath=r'E:\Sentinel\process\temp\S1A__EW___A_20160117T154042_HH_sigma0-elp_db.tif'
anglepath=r'E:\Sentinel\process\temp\S1A__EW___A_20160117T154042_localIncidenceAngle.tif'
temppath=r'E:\Sentinel\process\temp\temp.tif'
outpath=r'E:\Sentinel\process\temp\S1A_EW_GRDM_1SDH_20160117T154042.tif'
im_proj, im_geotrans, im_data,im_width,im_height = read_tif(anglepath)
im_proj, im_geotrans, hh,im_width,im_height = read_tif(hhpath)
ulx, xres, xskew, uly, yskew, yres=im_geotrans
xres=round(xres)
yres=round(yres)
# define the corner co-ords
ulx = ulx
uly = uly
lrx = ulx + ( im_width * xres)
lry = uly + ( im_height * yres)
#没有上面这两行,如果读取出xres=-39.99999就会报错
# Make two arrays with the co-ords for each pixel
# XP = np.arange(ulx, lrx, xres, dtype=np.float64)
# YP = np.arange(uly, lry, yres, dtype=np.float64)
XP=np.linspace(ulx, lrx,im_width, dtype=np.float64)
YP=np.linspace(uly, lry,im_height, dtype=np.float64)
##改成上面这两行,因为发现等差数列有时候计算出来的数组大小与原数组影像不符合
# Make an array the same shape as data populated with the X dimensions
print('Building X dimensions...')
Xarr = np.zeros_like(im_data)
Xarr[...] = XP
# Make an array the same shape as data populated with the Y dimensions
print('Building Y dimensions...')
Yarr = np.zeros_like(im_data)
Yarr = Yarr.transpose()
Yarr[...] = YP
Yarr = Yarr.transpose()
# Mask out the X and Y co-ords arrays based on presence of valid data
#为0的就是nodata
print('Subsetting data...')
SubXarr = Xarr[im_data!=0]
SubYarr = Yarr[im_data!=0]
SubData = im_data[im_data!=0]
#Get the bounding co-ords based on presence of valid data
# note yres is -ve
print('Finding corner coords...')
Xmin = np.amin(SubXarr)
Xmax = np.amax(SubXarr) + abs(xres)
Ymin = np.amin(SubYarr) - abs(yres)
Ymax = np.amax(SubYarr)
print(Xmin, Ymin)
print(Xmax, Ymax)
window = (Xmin,Ymax,Xmax,Ymin)
# clip = srcArray[:,3496:7260,240:6936]
# 为图片创建一个新的geomatrix对象以便附加地理参照数据,
geoTrans = list(im_geotrans)
geoTrans[0] = Xmin
geoTrans[3] = Ymax
# write_img(r'Z:\download\process\2016\1\test.tif', im_proj, im_geotrans, SubData, im_height,im_width,1)
# ds=gdal.Translate(r'Z:\download\process\2016\1\test.tif',path, projWin = window)
ds=gdal.Translate(outpath,temppath, projWin = window)
后来我又发现一个基于rasterio的版本,可以直接计算出需要裁剪的行列,然后进行裁剪,代码如下
# -*- coding: utf-8 -*-
"""
Created on Fri Jul 14 15:06:22 2023
@author: Asus
"""
# -*- coding: utf-8 -*-
"""
Created on Sun Jul 2 15:22:10 2023
@author: Asus
"""
import numpy as np
from osgeo import gdal
import os
from skimage import measure
import pandas as pd
import rasterio
from rasterio.windows import Window
def read_tif(filename):
dataset = gdal.Open(filename) # 打开文件
print(dataset.GetRasterBand(1).GetNoDataValue())
im_width = dataset.RasterXSize # 栅格矩阵的列数
im_height = dataset.RasterYSize # 栅格矩阵的行数
im_geotrans = dataset.GetGeoTransform() # 仿射矩阵
im_proj = dataset.GetProjection() # 地图投影信息
# band = dataset.GetBand(0) #就要第一个波段
# band = dataset.GetRasterBand(1)
# ndv = 100
# band.SetNoDataValue(ndv)
# im_data= band.ReadAsArray(0, 0, im_width, im_height) # 将数据写成数组,对应栅格矩阵
im_data = dataset.ReadAsArray(0, 0, im_width, im_height) # 将数据写成数组,对应栅格矩阵
# print(im_data.shape)
# im_data=im_data[0,:,:] #只选第一个波段
del dataset
return im_proj, im_geotrans, im_data,im_width,im_height
def write_img(filename, im_proj, im_geotrans, im_data, im_height,im_width,im_bands):
# gdal数据类型包括
# gdal.GDT_Byte,
# gdal .GDT_UInt16, gdal.GDT_Int16, gdal.GDT_UInt32, gdal.GDT_Int32,
# gdal.GDT_Float32, gdal.GDT_Float64
# 判断栅格数据的数据类型
if 'int8' in im_data.dtype.name:
datatype = gdal.GDT_Byte
elif 'int16' in im_data.dtype.name:
datatype = gdal.GDT_Int16
else:
datatype = gdal.GDT_Float32
# 判读数组维数
# 创建文件
# im_bands = 1 ######################### 这里要改 保存的文件是几个波段
im_height = im_height
im_width = im_width
driver = gdal.GetDriverByName("GTiff") # 数据类型必须有,因为要计算需要多大内存空间
dataset = driver.Create(filename, im_width, im_height, im_bands, datatype)
dataset.SetGeoTransform(im_geotrans) # 写入仿射变换参数
dataset.SetProjection(im_proj) # 写入投影
if im_bands == 1:
dataset.GetRasterBand(1).WriteArray(im_data) # 写入数组数据
else:
for i in range(im_bands):
dataset.GetRasterBand(i + 1).WriteArray(im_data[i])
del dataset
hhpath=r'E:\Sentinel\process\temp\S1A__EW___D_20160129T092020_HH_sigma0-elp_db.tif'
anglepath=r'E:\Sentinel\process\temp\S1A__EW___D_20160129T092020_incidenceAngleFromEllipsoid.tif'
temppath=r'E:\Sentinel\process\temp\temp.tif'
outpath=r'E:\Sentinel\process\temp\S1A_EW_GRDM_1SDH_20160129T092020.tif'
im_proj, im_geotrans, im_data,im_width,im_height = read_tif(anglepath)
im_proj, im_geotrans, hh,im_width,im_height = read_tif(hhpath)
# ulx, xres, xskew, uly, yskew, yres=im_geotrans
# xres=round(xres)
# yres=round(yres)
# # define the corner co-ords
# ulx = ulx
# uly = uly
# lrx = ulx + ( im_width * xres)
# lry = uly + ( im_height * yres)
# Make two arrays with the co-ords for each pixel
# XP = np.arange(ulx, lrx, xres, dtype=np.float64)
# YP = np.arange(uly, lry, yres, dtype=np.float64)
XP=np.arange(0,im_width,1)
YP=np.arange(0,im_height,1)
# XP=np.linspace(ulx, lrx,im_width, dtype=np.float64)
# YP=np.linspace(uly, lry,im_height, dtype=np.float64)
# Make an array the same shape as data populated with the X dimensions
print('Building X dimensions...')
Xarr = np.zeros_like(im_data)
Xarr[...] = XP
# Make an array the same shape as data populated with the Y dimensions
print('Building Y dimensions...')
Yarr = np.zeros_like(im_data)
Yarr = Yarr.transpose()
Yarr[...] = YP
Yarr = Yarr.transpose()
# Mask out the X and Y co-ords arrays based on presence of valid data
print('Subsetting data...')
SubXarr = Xarr[im_data!=0]
SubYarr = Yarr[im_data!=0]
SubData = im_data[im_data!=0]
#Get the bounding co-ords based on presence of valid data
# note yres is -ve
print('Finding corner coords...')
Xmin = np.amin(SubXarr)
Xmax = np.amax(SubXarr)
Ymin = np.amin(SubYarr)
Ymax = np.amax(SubYarr)
print(Xmin, Ymin)
print(Xmax, Ymax)
window = (Xmin,Ymax,Xmax,Ymin)
with rasterio.open(temppath) as src:
window = Window(Xmin,Ymin,Xmax,Ymax)
kwargs = src.meta.copy()
kwargs.update({
'height': window.height,
'width': window.width,
'transform': rasterio.windows.transform(window, src.transform)})
with rasterio.open(outpath, 'w', **kwargs) as dst:
dst.write(src.read(window=window))