python:克里金插值

python:克里金插值
最近写代码遇到了使用样本数据做克里金插值的事情。于是将Excel保存的【x坐标,y坐标,样本值】数据结合tif数据做了克里金插值,并将代码记录下来。


克里金插值结果:

python:克里金插值_第1张图片

输入数据格式:

python:克里金插值_第2张图片

import os, sys
import pandas as pd
from sklearn.gaussian_process import GaussianProcessRegressor
import numpy as np
from numpy import inf
from osgeo import gdal
from tqdm import tqdm
import pykrige.kriging_tools as kt
from pykrige.ok import OrdinaryKriging
from numpy import genfromtxt

# 读写tif的类
class GRID:
    # 读图像文件
    def read_img(self, filename):
        dataset = gdal.Open(filename)  # 打开文件
        im_width = dataset.RasterXSize  # 栅格矩阵的列数
        im_height = dataset.RasterYSize  # 栅格矩阵的行数
        im_geotrans = dataset.GetGeoTransform()  # 仿射矩阵
        im_proj = dataset.GetProjection()  # 地图投影信息
        im_data = dataset.ReadAsArray(0, 0, im_width, im_height)  # 将数据写成数组,对应栅格矩阵
        im_data = np.array(im_data)
        del dataset  # 关闭对象,文件dataset
        return im_proj, im_geotrans, im_data, im_width, im_height

    # 写文件,写成tiff
    def write_img(self, filename, im_proj, im_geotrans, im_data):
        # 判断栅格数据的数据类型
        if 'int8' in im_data.dtype.name:
            datatype = gdal.GDT_Byte
        elif 'int16' in im_data.dtype.name:
            datatype = gdal.GDT_UInt16
        else:
            datatype = gdal.GDT_Float32
        # 判读数组维数
        if len(im_data.shape) == 3:
            im_bands, im_height, im_width = im_data.shape
        else:
            im_bands, (im_height, im_width) = 1, im_data.shape
        # 创建文件
        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

#读取每个tiff图像的属性信息,和上面函数相似,懒得改了,混着用。
def Readxy(RasterFile):
    ds = gdal.Open(RasterFile,gdal.GA_ReadOnly)
    if ds is None:
        print ('Cannot open ',RasterFile)
        sys.exit(1)
    cols = ds.RasterXSize
    rows = ds.RasterYSize
    band = ds.GetRasterBand(1)
    # data = band.ReadAsArray(0,0,cols,rows)
    noDataValue = band.GetNoDataValue()
    projection=ds.GetProjection()
    geotransform = ds.GetGeoTransform()
    return rows,cols,geotransform,projection,noDataValue

# 克里金插值
def KrigingInterpolate(InputExcelPathAndName, X_coordinateField, Y_coordinateField, Sample_valueField,
                       tifDataPath, tifName, resultDataSetPath, outputKrigingTifName):
                       
    Data = pd.read_excel(InputExcelPathAndName)
    Points = Data.loc[:, [X_coordinateField, Y_coordinateField]].values
    Values = Data.loc[:, [Sample_valueField]].values
    Points1 = np.array(Points)
    Values1 = np.array(Values)
    # 数据去空值
    Points1 = np.nan_to_num(Points1)
    Points1[Points1 == inf] = np.finfo(np.float16).max
    Values1 = np.nan_to_num(Values1)
    Values1[Values1 == inf] = np.finfo(np.float16).max
    # 读取遥感影像数据
    run = GRID()
    # 这一个没有参与运算,主要为了读取它的行列数、投影信息、坐标系和noData值
    rows, cols, geotransform, projection, noDataValue = Readxy(tifDataPath + tifName)
    print(rows, cols, geotransform, projection, noDataValue)
    nXsize = cols
    nYsize = rows
    # **********************************//
    dataset = gdal.Open(tifDataPath + tifName)  # 打开tif
    adfGeoTransform = dataset.GetGeoTransform()  # 读取地理信息
    # 左上角地理坐标
    # print(adfGeoTransform[0])
    # print(adfGeoTransform[3])
    # 右下角地理坐标
    px = adfGeoTransform[0] + nXsize * adfGeoTransform[1] + nYsize * adfGeoTransform[2]
    py = adfGeoTransform[3] + nXsize * adfGeoTransform[4] + nYsize * adfGeoTransform[5]
    
    OK = OrdinaryKriging(
        Points1[:, 0],
        Points1[:, 1],
        Values1[:, 0],
        variogram_model="linear",
        verbose=False,
        enable_plotting=False,
    )
    gridx = np.arange(adfGeoTransform[0], px, adfGeoTransform[1])
    gridy = np.arange(adfGeoTransform[3], py, adfGeoTransform[5])
    print(type(gridy), gridx)
    z, ss = OK.execute("grid", gridx, gridy)
    run.write_img(resultDataSetPath + '//' + outputKrigingTifName + '.tif',
                  projection, geotransform, z)

def removeFile(removeTifFileFolder, removeTifName):
    filePathAndName = removeTifFileFolder + '//' + removeTifName
    os.remove(filePathAndName)

if __name__ == "__main__":
    # 样本点数据
	InputExcelPathAndName = "E:\\RemoteSensing\\2018Sample_ALL.xlsx"
	# 保存x坐标的表头
	X_coordinateField = 'x_coor'
	# 保存y坐标的表头
	Y_coordinateField = 'y_coor'
	# 插值点的值
	Sample_valueField = 'TN'
	# 参考tif(提供插值的栅格数和行列号)
	# 参考tif所在的文件夹
	tifDataPath = 'E:\\RemoteSensing\\DataSet\\'
	# 参考tif的名字
	tifName = 'NDVI_Resample150m.tif'
	# 克里金插值结果保存的文件夹
	resultDataSetPath = 'E:\\RemoteSensing\\resultDataSet'
	# 克里金插值结果保存的名字
	outputKrigingTifName = 'KrigingInterpolate'
	
	# ************************** 运行克里金插值函数 ************************ #
	KrigingInterpolate(InputExcelPathAndName, X_coordinateField, Y_coordinateField, Sample_valueField,
	                       tifDataPath, tifName, resultDataSetPath, outputKrigingTifName)
	                       
	# 删除不需要的tif
	removeTifFileFolder = 'E:\\RemoteSensing\\resultDataSet'
	removeTifName = 'regressionTN.tif'
	removeFile(removeTifFileFolder, removeTifName)

你可能感兴趣的:(python,ArcGIS,python,经验分享)