TIFF 图像变化趋势分析

一、Theil-Sen Median 变化趋势分析

Theil-Sen Median 方法能反映变化趋势,公式如下:

β v = M e d i a n ( v j ‾ − v i ‾ j − i ) \beta_{v}=Median\left(\frac{\overline{v_j}-\overline{v_i}}{j-i}\right) βv=Median(j−ivj−vi)

其中 v v v 表示变化的指标, v j ‾ \overline{v_j} vj 和 v i ‾ \overline{v_i} vi 表示第 j j j 年和第 i i i 年指标 f f f 的平均值。当 β v > 0 \beta_v>0 βv>0 时,表明指标变化呈改善趋势,反之降低。

二、Mann-Kendall 检验

Mann-Kendall 方法能检验变化趋势显著性,公式如下:

S = ∑ i = 1 n − 1 ∑ j = i + 1 n f ( v ‾ j − v ‾ i ) S=\sum_{i=1}^{n-1}{\sum_{j=i+1}^{n}{f\left(\overline v_j-\overline v_i\right)}} S=i=1∑n−1j=i+1∑nf(vj−vi)
f ( v ‾ j − v ‾ i ) = { 1 , v ‾ j − v ‾ i > 0 0 , v ‾ j − v ‾ i = 0 − 1 , v ‾ j − v ‾ i < 0 f\left(\overline v_j-\overline v_i\right)=\left\{\begin{matrix} 1, & \overline v_j-\overline v_i>0 \\ 0, & \overline v_j-\overline v_i=0 \\ -1, & \overline v_j-\overline v_i<0 \end{matrix}\right. f(vj−vi)=⎩ ⎨ ⎧1,0,−1,vj−vi>0vj−vi=0vj−vi<0

方差: V ( S ) = n ( n − 1 ) ( 2 n + 5 ) 18 V(S)=\frac{n(n-1)(2n+5)}{18} V(S)=18n(n−1)(2n+5) ,统计量:

Z = { S − 1 V ( S ) , S > 0 0 , S = 0 S + 1 V ( S ) , S < 0 Z=\left\{\begin{matrix} \frac{S-1}{\sqrt{V(S)}}, & S>0 \\ 0, & S=0 \\ \frac{S+1}{\sqrt{V(S)}}, & S<0 \end{matrix}\right. Z=⎩ ⎨ ⎧V(S) S−1,0,V(S) S+1,S>0S=0S<0

其中 n n n 表示指标变化的时间长度, f f f 为符号函数,统计量 Z Z Z 的取值范围为 ( − ∞ , + ∞ ) \left(-\infty,+\infty\right) (−∞,+∞) ,表示在给定显著水平 α \alpha α 下,当 ∣ Z ∣ > μ 1 − α 2 \left|Z\right|>\mu_{1-\frac{\alpha}{2}} ∣Z∣>μ1−2α 时,趋势显著。

三、Hurst 指数分析

给定指标 v v v 的时间序列 v t , t = 1 , 2 , ⋯   , n v_t,t=1,2,\cdots,n vt,t=1,2,⋯,n ,对于任意正整数 u u u ,定义均值序列、累计差、极差和标准差如下:

v u ‾ = 1 u ∑ t = 1 u v t , u = 1 , 2 , ⋯   , n \overline{v_u}=\frac{1}{u}\sum_{t=1}^u{v_t},u=1,2,\cdots,n vu=u1t=1∑uvt,u=1,2,⋯,n
X ( t , u ) = ∑ t = 1 u v t − v u , 1 ≤ t ≤ u X(t,u)=\sum_{t=1}^u{v_t-v_u},1\le t\le u X(t,u)=t=1∑uvt−vu,1≤t≤u
R u = max ⁡ 1 ≤ t ≤ u X ( t , u ) , u = 1 , 2 , ⋯   , n R_u=\max_{1\le t\le u}X(t,u),u=1,2,\cdots,n Ru=1≤t≤umaxX(t,u),u=1,2,⋯,n
S u = 1 u ∑ t = 1 u ( v t − v u ‾ ) 2 S_u=\sqrt{\frac{1}{u}\sum_{t=1}^{u}\left(v_t-\overline{v_u}\right)^2} Su=u1t=1∑u(vt−vu)2

若存在 R S ∝ u H \frac{R}{S}\propto u^H SR∝uH ,表示该时间序列的指标存在 Hurst 现象,大小用 H H H 表示,若 H = 0.5 H=0.5 H=0.5 则该指标自相关性为 0 ,即时间序列前后变化是完全随机的;当 0.5 < H < 1 0.5<H<1 0.5<H<1 ,表示该指标自相关性大于 0 ,即时间序列前后变化一致,且越接近 1 持续性能力越强;当 0 < H < 0.5 0<H<0.5 0<H<0.5 ,表示该指标时间序列自相关性小于 0 ,越接近 0 反持续性能力越强。

四、代码

python 复制代码
import os

import numpy as np
from osgeo import gdal


def read_img(filename):
    # 打开文件
    dataset = gdal.Open(filename)

    # 获取栅格数据的元信息
    im_width = dataset.RasterXSize  # 栅格矩阵的列数
    im_height = dataset.RasterYSize  # 栅格矩阵的行数
    im_bands = dataset.RasterCount  # 波段数
    im_geotrans = dataset.GetGeoTransform()  # 仿射矩阵,左上角像素的大地坐标和像素分辨率
    im_proj = dataset.GetProjection()  # 地图投影信息,字符串表示

    # 读取栅格数据到数组
    im_data = dataset.ReadAsArray(0, 0, im_width, im_height)

    # 返回元信息、投影、仿射矩阵和数据数组
    return im_proj, im_geotrans, im_data


def write_img(filename, im_proj, im_geotrans, im_data, driverName="GTiff"):
    # 判断栅格数据的数据类型
    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(driverName)
    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])


def theil_sen_slope(data):
    n_timepoints, height, width = data.shape
    i, j = np.triu_indices(n_timepoints, k=1)  # 获取数据索引的上三角部分
    index_diff = i - j
    index_diff = index_diff[:, np.newaxis]
    # 将数据的时间轴展平,便于进行矩阵操作
    flat_data = data.reshape(n_timepoints, -1)
    # 计算斜率
    slope_values = (flat_data[j] - flat_data[i]) / index_diff
    # 根据每列计算中位数
    slopes = np.median(slope_values, axis=0)
    # 将结果重新形状成与原始数据的高度和宽度相匹配的形状
    slopes = slopes.reshape(height, width)
    return slopes


def mann_kendall_test(data):
    height, width = data.shape[1], data.shape[2]
    Z_values = np.zeros((height, width))
    for h in range(height):
        for w in range(width):
            data_values = data[:, h, w]
            n = len(data_values)
            i, j = np.triu_indices(n, k=1)  # 获取数据索引的上三角部分
            slope_values = data_values[j] - data_values[i]
            # 计算 sgn(slope_j - slope_i)
            sgn_values = np.sign(slope_values)
            # 计算 S
            S = np.sum(sgn_values)
            # 计算 var(S)
            var_S = (n * (n - 1) * (2 * n + 5)) / 18
            # 计算 Z
            if S > 0:
                Z = (S - 1) / np.sqrt(var_S)
            elif S < 0:
                Z = (S + 1) / np.sqrt(var_S)
            else:
                Z = 0
            Z_values[h, w] = Z
    return Z_values


def Hurst(data):
    from sklearn.linear_model import LinearRegression
    n_timepoints, height, width = data.shape
    cumsum_data = np.cumsum(data, axis=0)
    divisor = np.arange(1, n_timepoints + 1)[:, np.newaxis, np.newaxis]
    means = cumsum_data / divisor
    i, j = np.triu_indices(n_timepoints, k=0)
    point = list(zip(i, j))
    X_t_tau = [[] for _ in range(n_timepoints)]
    for x, y in point:
        X_t_tau[y].append(cumsum_data[x] - means[y] * (x + 1))
    R_tau = []
    for row in X_t_tau:
        tmp = np.zeros((height, width))
        row = np.array(row)
        for h in range(height):
            for w in range(width):
                tmp[h, w] = np.max(row[:, h, w]) - np.min(row[:, h, w])
        R_tau.append(tmp)
    R_tau = np.stack(R_tau)
    cumsum_data = np.cumsum((data - means)**2, axis=0)
    S_tau = (cumsum_data / divisor)**0.5
    log_tau = np.log(np.arange(1, n_timepoints + 1))
    log_R_S_ratio = np.log(R_tau / S_tau)
    model = LinearRegression()
    model.fit(log_tau.reshape(-1, 1), log_R_S_ratio.reshape(n_timepoints, -1))
    fit_result = model.coef_.reshape(height, width)
    # for h in range(height):
    #     for w in range(width):
    #         X_current_position = mean_log_R_S_ratio[:, h, w]
    #         model.fit(X_current_position, log_tau)
    #         fit_result[h, w] = model.coef_[0]
    return fit_result


def run():
    data_path = "E:/by/dataset/生态系统质量/"
    out_path = "E:/by/output/生态系统质量/"
    if not os.path.exists(out_path):
        os.makedirs(out_path)
    files = [file for file in os.listdir(data_path) if file.endswith(".tif")]
    data_list = []
    for file in files:
        proj, geotrans, band = read_img(data_path + file)
        data = np.ma.masked_where(
            np.logical_or(band == np.finfo(np.float32).min, np.isnan(band)), band
        )
        data_list.append(data)
    # 将列表转换为数组
    data = np.stack(data_list, axis=0)
    # theil_sen_slope
    # tss = theil_sen_slope(data)
    # write_img(out_path + "tss.tif", proj, geotrans, tss)
    # print('theil_sen_slope finished!')

    # mann_kendall_test
    # mk = mann_kendall_test(data)
    # write_img(out_path + "mk.tif", proj, geotrans, mk)
    # print('mann_kendall_test finished!')

    # Hurst
    hurst = Hurst(data)
    write_img(out_path + "hurst.tif", proj, geotrans, hurst)
    print('hurst finished!')


if __name__ == "__main__":
    run()
相关推荐
李小星同志4 分钟前
高级算法设计与分析 学习笔记6 B树
笔记·学习
霜晨月c16 分钟前
MFC 使用细节
笔记·学习·mfc
小江湖199429 分钟前
元数据保护者,Caesium压缩不丢重要信息
运维·学习·软件需求·改行学it
dot.Net安全矩阵1 小时前
.NET内网实战:通过命令行解密Web.config
前端·学习·安全·web安全·矩阵·.net
微刻时光1 小时前
Redis集群知识及实战
数据库·redis·笔记·学习·程序人生·缓存
潮汐退涨月冷风霜3 小时前
机器学习之非监督学习(四)K-means 聚类算法
学习·算法·机器学习
GoppViper4 小时前
golang学习笔记29——golang 中如何将 GitHub 最新提交的版本设置为 v1.0.0
笔记·git·后端·学习·golang·github·源代码管理
羊小猪~~4 小时前
深度学习基础案例5--VGG16人脸识别(体验学习的痛苦与乐趣)
人工智能·python·深度学习·学习·算法·机器学习·cnn
Charles Ray4 小时前
C++学习笔记 —— 内存分配 new
c++·笔记·学习
我要吐泡泡了哦5 小时前
GAMES104:15 游戏引擎的玩法系统基础-学习笔记
笔记·学习·游戏引擎