当前位置: 首页 > news >正文

基于python的栅格数据标准差椭圆

基于python的栅格数据标准差椭圆

方法介绍

标准差椭圆空间统计方法(standard deviational elipse,SDE)能够精确地揭示地理要素空间分布整体特征。该方法基于研究对象的空间区位和空间结构,从全局性空间的角度定量解释地理要素空间分布的中心性、展布性、方向性、空间形态等特征,揭示地理要素的空间分布及时空演化过程。其计算过程如下:

  1. 计算平均/加权平均中心
    • 对于点集 (xi,yi)(x_i, y_i)(xi,yi) 和对应权重 wiw_iwi,加权平均中心计算为:xˉ=∑i=1nwixi∑i=1nwiyˉ=∑i=1nwiyi∑i=1nwi\begin{align}\bar{x} = \frac{\sum_{i=1}^n w_i x_i}{\sum_{i=1}^n w_i}\\\bar{y} = \frac{\sum_{i=1}^n w_i y_i}{\sum_{i=1}^n w_i}\end{align}xˉ=i=1nwii=1nwixiyˉ=i=1nwii=1nwiyi
  2. **计算加权协方差矩阵:Σ=[Cov(X,X)Cov(X,Y)Cov(Y,X)Cov(Y,Y)]Cov(X,Y)=∑i=1nwi⋅(xi−xˉ)⋅(yi−yˉ)\begin{align} \Sigma &= \begin{bmatrix} Cov(X,X) & Cov(X,Y) \\Cov(Y,X) & Cov(Y,Y)\end{bmatrix}\\Cov(X,Y) &= \sum_{i=1}^n w_i \cdot (x_i - \bar{x}) \cdot (y_i - \bar{y})\end{align}ΣCov(X,Y)=[Cov(X,X)Cov(Y,X)Cov(X,Y)Cov(Y,Y)]=i=1nwi(xixˉ)(yiyˉ)
  3. 特征值和特征向量:
    • 求解特征方程:∣Σ−λI∣=0|\Sigma - \lambda I| = 0∣ΣλI=0
      得到特征值 λ1,λ2\lambda_1, \lambda_2λ1,λ2 和对应的特征向量 v1⃗,v2⃗\vec{v_1}, \vec{v_2}v1,v2
  4. 椭圆参数计算:
    • 长短半轴:α=λ1χ2,p2β=λ2χ2,p2\begin{align}\alpha = \sqrt{\lambda_1 \chi^2_{2,p}}\\ \beta = \sqrt{\lambda_2 \chi^2_{2,p}}\end{align}α=λ1χ2,p2β=λ2χ2,p2 其中 χ2,p2\chi^2_{2,p}χ2,p2 是自由度为 2,置信水平为 p 的卡方分布临界值(两倍标准差即为 0.63)
    • 旋转角度:θ=arctan⁡(v12v11)\theta = \arctan(\frac{v_{12}}{v_{11}})θ=arctan(v11v12) 其中 v11,v12v_{11}, v_{12}v11,v12 是第一特征向量的分量
  5. 计算椭圆参数方程:x(t)=xˉ+αcos⁡(t)cos⁡(θ)−βsin⁡(t)sin⁡(θ)y(t)=yˉ+αcos⁡(t)sin⁡(θ)+βsin⁡(t)cos⁡(θ)\begin{align}x(t) &= \bar{x} + \alpha \cos(t)\cos(\theta) - \beta \sin(t)\sin(\theta)\\y(t) &= \bar{y} + \alpha \cos(t)\sin(\theta) + \beta \sin(t)\cos(\theta) \\ \end{align}x(t)y(t)=xˉ+αcos(t)cos(θ)βsin(t)sin(θ)=yˉ+αcos(t)sin(θ)+βsin(t)cos(θ) 其中 t∈[0,2π]t \in[0,2\pi]t[0,2π]

这些公式主要由以下函数来计算:

  • np.average() 计算加权平均
  • np.cov() 计算加权协方差矩阵
  • np.linalg.eig() 计算特征值和特征向量
  • chi2.ppf() 计算卡方分布临界值

代码展示

  • 首先需要读取栅格数据为数组形式进行计算,这里使用 rasterio 库:
def raster_to_points(raster_path):# 读取栅格数据with rasterio.open(raster_path) as src:# 读取栅格数据的第一波段band1 = src.read(1)nodata = src.nodata# 获取栅格数据的行列号rows, cols = np.where(band1 != nodata)# 将行列号转换为地理坐标x_coords, y_coords = src.xy(rows, cols)# 将坐标组合成点数据points = np.column_stack((x_coords, y_coords))# 假设权重为栅格值weights = band1[rows, cols]return points, weights, src.crs
  • 然后计算椭圆的参数,这里使用 numpy 和 scipy.stats 库:
def calculate_ellipse(data, weight, confidence_level):# 计算均值mean = np.average(data, axis=0, weights=weight)# 计算加权协方差矩阵cov_matrix = np.cov(data, rowvar=False, aweights=weight)# 协方差矩阵的特征值和特征向量eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)# 计算椭圆长短半轴chi2_val = chi2.ppf(confidence_level, df=2)alpha = np.sqrt(eigenvalues[0] * chi2_val)beta = np.sqrt(eigenvalues[1] * chi2_val)# 计算椭圆角度angle = np.degrees(np.arctan2(*eigenvectors[:, 0][::-1]))# 绘制椭圆ellipse = Ellipse(xy=mean, width=alpha * 2, height=beta * 2, angle=angle, fc='None', lw=2)ellipse_info = {'mean': mean,'alpha': alpha,'beta': beta,'angle': angle}return ellipse, ellipse_info
  • 最后生成椭圆方程,并用 geopandas 库给椭圆添加地理信息,保存为矢量文件:
def create_ellipse_polygon(mean, alpha, beta, angle, num_points=100):# 生成椭圆上的点theta = np.linspace(0, 2 * np.pi, num_points)# 椭圆参数方程x = mean[0] + alpha * np.cos(theta) * np.cos(np.radians(angle)) - beta * np.sin(theta) * np.sin(np.radians(angle))y = mean[1] + alpha * np.cos(theta) * np.sin(np.radians(angle)) + beta * np.sin(theta) * np.cos(np.radians(angle))# 创建多边形return Polygon(zip(x, y))
def process_raster(raster_path, output_shp_path):...gdf = gpd.GeoDataFrame({'confidence': ['63%'],  # 置信度'center_x': [mean[0]],  # 中心点 X 坐标'center_y': [mean[1]],  # 中心点 Y 坐标'major_axis': [alpha],  # 长半轴'minor_axis': [beta],   # 短半轴'angle': [angle],       # 旋转角度'geometry': [ellipse_polygon]}, crs=crs)gdf.to_file(output_shp_path, driver='ESRI Shapefile')...

完整代码

import numpy as np
from matplotlib.patches import Ellipse
from scipy.stats import chi2
import rasterio
import geopandas as gpd
from shapely.geometry import Polygon
import os
def calculate_ellipse(data, weight, confidence_level):# 计算均值mean = np.average(data, axis=0, weights=weight)# 计算加权协方差矩阵cov_matrix = np.cov(data, rowvar=False, aweights=weight)# 协方差矩阵的特征值和特征向量eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)# 计算椭圆长短半轴chi2_val = chi2.ppf(confidence_level, df=2)alpha = np.sqrt(eigenvalues[0] * chi2_val)beta = np.sqrt(eigenvalues[1] * chi2_val)# 计算椭圆角度angle = np.degrees(np.arctan2(*eigenvectors[:, 0][::-1]))# 绘制椭圆ellipse = Ellipse(xy=mean, width=alpha * 2, height=beta * 2, angle=angle, fc='None', lw=2)ellipse_info = {'mean': mean,'alpha': alpha,'beta': beta,'angle': angle}return ellipse, ellipse_info
def raster_to_points(raster_path):# 读取栅格数据with rasterio.open(raster_path) as src:# 读取栅格数据的第一波段band1 = src.read(1)nodata = src.nodata# 获取栅格数据的行列号rows, cols = np.where(band1 != nodata)# 将行列号转换为地理坐标x_coords, y_coords = src.xy(rows, cols)# 将坐标组合成点数据points = np.column_stack((x_coords, y_coords))# 假设权重为栅格值weights = band1[rows, cols]return points, weights, src.crs
def create_ellipse_polygon(mean, alpha, beta, angle, num_points=100):# 生成椭圆上的点theta = np.linspace(0, 2 * np.pi, num_points)# 椭圆参数方程x = mean[0] + alpha * np.cos(theta) * np.cos(np.radians(angle)) - beta * np.sin(theta) * np.sin(np.radians(angle))y = mean[1] + alpha * np.cos(theta) * np.sin(np.radians(angle)) + beta * np.sin(theta) * np.cos(np.radians(angle))# 创建多边形return Polygon(zip(x, y))
def process_raster(raster_path, output_shp_path):# 创建输出目录(如果不存在)os.makedirs(os.path.dirname(output_shp_path), exist_ok=True)# 处理栅格数据points, weights, crs = raster_to_points(raster_path)weights = (weights - np.min(weights))# 计算椭圆_, ellipse_info = calculate_ellipse(points, weights, 0.63)mean = ellipse_info['mean']alpha = ellipse_info['alpha']beta = ellipse_info['beta']angle = ellipse_info['angle']# 保存为shpellipse_polygon = create_ellipse_polygon(mean, alpha, beta, angle, num_points=100)gdf = gpd.GeoDataFrame({'confidence': ['63%'],  # 置信度'center_x': [mean[0]],  # 中心点 X 坐标'center_y': [mean[1]],  # 中心点 Y 坐标'major_axis': [alpha],  # 长半轴'minor_axis': [beta],   # 短半轴'angle': [angle],       # 旋转角度'geometry': [ellipse_polygon]}, crs=crs)gdf.to_file(output_shp_path, driver='ESRI Shapefile')
if __name__ == '__main__':# 输入输出路径raster_path = 'input.tif'  # 输入栅格文件路径output_shp_path = 'output.shp'  # 输出shapefile路径# 处理数据process_raster(raster_path, output_shp_path)

结论

以大同市 2019 年的夜间灯光指数为例,程序运行结果与 Arcgis 地理处理中的标准差椭圆基本一致:(由于计算的浮点数问题存在较小偏差)
|550
参考资料:
方向分布(标准差椭圆)算法
标准差椭圆算法实现

http://www.dtcms.com/a/278121.html

相关文章:

  • Can201-Introduction to Networking:Transport Layer 传输层
  • 跨领域科学探索智能体设计与实现
  • 模块化编程为何使用函数指针分析(一)(深入分析指针的实际应用)
  • 【uniapp】元胞自动机GameOfLife生命游戏项目开发流程详解
  • Java SE--图书管理系统模拟实现
  • 模型占用显存大小评估
  • 【AI大模型】ComfyUI:Stable Diffusion可视化工作流
  • java基础编程(入门)
  • C++多线程知识点梳理
  • 深入理解 Java Map 与 Set
  • 每天学一个八股(二)——详解HashMap
  • 封装---优化try..catch错误处理方式
  • 【echarts踩坑记录】为什么第二个Y轴最大值不整洁
  • Acrobat 表单中的下拉菜单(附示例下载)
  • 使用docker的常用命令
  • RS4585自动收发电路原理图讲解
  • 从 Manifest V2 升级到 Manifest V3 的注意事项
  • Extended Nested Arrays for Consecutive Virtual Aperture Enhancement
  • 财务管理体系——解读大型企业集团财务管理体系解决方案【附全文阅读】
  • Python异步编程
  • 57.第二阶段x64游戏实战-实时监控抓取lua内容
  • 利用低汇率国家苹果订阅,120 元开通 ChatGPT Plus
  • 14.使用GoogleNet/Inception网络进行Fashion-Mnist分类
  • docker基础部署
  • ID生成策略
  • 在新版本的微信开发者工具中使用npm包
  • 用信号量实现进程互斥,进程同步,进程前驱关系(操作系统os)
  • DOS下EXE文件的分析 <1>
  • MacBook Air通过VMware Fusion Pro安装Win11
  • 从代码学习深度强化学习 - DDPG PyTorch版