去除地理(遥感)图像的白边(无效值)

之前基于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))

你可能感兴趣的:(python,data,process,python,gdal,遥感)