news 2026/6/11 14:09:53

Sentinel-2数据转TIFF后,如何用Python快速进行地块统计分析?(附完整代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Sentinel-2数据转TIFF后,如何用Python快速进行地块统计分析?(附完整代码)

Sentinel-2数据地块统计分析的Python实战指南

当遥感数据从原始格式转换为GeoTIFF后,真正的价值挖掘才刚刚开始。本文将带您探索如何利用Python生态中的强大工具,对Sentinel-2影像进行高效的地块级统计分析,为农业监测、环境评估等应用提供量化依据。

1. 环境准备与数据检查

在开始分析前,我们需要确保工作环境配置正确。推荐使用conda创建一个独立环境:

conda create -n sentinel_analysis python=3.9 conda activate sentinel_analysis pip install geopandas rasterio rasterstats matplotlib

数据质量检查是分析前的重要步骤。使用rasterio快速检查TIFF文件:

import rasterio with rasterio.open('sentinel2_image.tif') as src: print(f"波段数: {src.count}") print(f"影像尺寸: {src.width}x{src.height}") print(f"空间分辨率: {src.res}") print(f"坐标参考系统(CRS): {src.crs}")

注意:确保矢量文件与影像使用相同的CRS,否则需要进行坐标转换

2. 地块统计核心方法

rasterstats库提供了强大的区域统计功能。我们通过以下步骤实现高效分析:

  1. 基础统计计算- 获取每个地块的基本统计量
  2. 多波段处理- 同时处理多个光谱波段
  3. 结果整合- 将统计结果与原始矢量数据关联
from rasterstats import zonal_stats import geopandas as gpd def calculate_zonal_stats(image_path, shapefile_path, stats=['mean', 'std', 'min', 'max']): # 读取矢量数据 gdf = gpd.read_file(shapefile_path) # 执行区域统计 stats_results = zonal_stats( vectors=gdf.geometry, raster=image_path, stats=stats, all_touched=True, nodata=0 ) # 将结果添加到GeoDataFrame for stat in stats: gdf[stat] = [result.get(stat) for result in stats_results] return gdf

参数说明

参数说明推荐值
all_touched是否处理所有接触到的像素True(农业应用推荐)
nodata忽略的像素值0或根据实际情况设置
stats计算的统计量['mean', 'std', 'min', 'max', 'median']

3. 多波段分析与植被指数计算

Sentinel-2的多光谱特性允许我们计算各种植被指数。以下是NDVI的计算与统计示例:

import numpy as np def calculate_ndvi_stats(red_band_path, nir_band_path, shapefile_path): # 读取红波段和近红外波段 with rasterio.open(red_band_path) as red_src: red = red_src.read(1) profile = red_src.profile with rasterio.open(nir_band_path) as nir_src: nir = nir_src.read(1) # 计算NDVI ndvi = (nir - red) / (nir + red + 1e-10) # 避免除以零 # 保存临时NDVI文件 ndvi_path = 'temp_ndvi.tif' with rasterio.open(ndvi_path, 'w', **profile) as dst: dst.write(ndvi, 1) # 计算NDVI统计 return calculate_zonal_stats(ndvi_path, shapefile_path)

常见植被指数公式

  • NDVI= (NIR - Red) / (NIR + Red)
  • NDWI= (Green - NIR) / (Green + NIR)
  • EVI= 2.5 * (NIR - Red) / (NIR + 6Red - 7.5Blue + 1)

4. 结果可视化与输出

统计分析结果的直观展示对于理解数据至关重要。以下是几种可视化方法:

1. 统计结果表格输出

import pandas as pd def save_stats_to_excel(gdf, output_path): # 转换为DataFrame并保存 df = pd.DataFrame(gdf.drop(columns='geometry')) df.to_excel(output_path, index=False)

2. 空间分布可视化

import matplotlib.pyplot as plt def plot_spatial_distribution(gdf, stat_column, title): fig, ax = plt.subplots(1, 1, figsize=(10, 8)) gdf.plot(column=stat_column, ax=ax, legend=True, legend_kwds={'label': stat_column, 'orientation': 'horizontal'}) plt.title(title) plt.tight_layout() plt.show()

3. 时间序列分析(多期影像)

def plot_time_series(stats_list, field_id, band='B8'): plt.figure(figsize=(12, 6)) dates = [s['date'] for s in stats_list] values = [s[field_id][band]['mean'] for s in stats_list] plt.plot(dates, values, 'o-') plt.xlabel('Date') plt.ylabel(f'{band} Mean Reflectance') plt.title(f'Time Series for Field {field_id}') plt.grid(True) plt.show()

5. 性能优化技巧

处理大面积影像时,性能可能成为瓶颈。以下是几种优化策略:

1. 分块处理

# 使用rasterio的窗口读取 with rasterio.open('large_image.tif') as src: window = Window(col_off=0, row_off=0, width=1000, height=1000) chunk = src.read(window=window)

2. 使用Dask进行并行计算

import dask.array as da import dask.distributed client = dask.distributed.Client() # 启动本地集群 # 创建dask数组 with rasterio.open('large_image.tif') as src: data = da.from_array(src.read(), chunks=(1, 1024, 1024))

3. 内存映射文件

# 使用rasterio的内存映射功能 with rasterio.open('large_image.tif') as src: data = src.read(masked=True, out_dtype=np.float32)

6. 完整工作流示例

以下是一个端到端的分析流程,从数据准备到结果可视化:

# 完整工作流示例 def full_analysis_workflow(): # 1. 准备数据 image_path = 'S2A_MSIL2A_20230501T100031_N0509_R122_T32TQR_20230501T134716.tif' shapefile_path = 'agricultural_fields.shp' # 2. 基础统计 stats_gdf = calculate_zonal_stats(image_path, shapefile_path) # 3. 植被指数计算 red_band = 'S2_Red.tif' nir_band = 'S2_NIR.tif' ndvi_gdf = calculate_ndvi_stats(red_band, nir_band, shapefile_path) # 4. 结果合并 final_gdf = stats_gdf.merge(ndvi_gdf[['id', 'mean']], on='id', suffixes=('', '_ndvi')) # 5. 可视化 plot_spatial_distribution(final_gdf, 'mean_ndvi', 'NDVI Distribution Across Fields') # 6. 输出 final_gdf.to_file('analysis_results.gpkg', driver='GPKG') save_stats_to_excel(final_gdf, 'field_stats.xlsx')

7. 常见问题解决方案

问题1:内存不足

解决方案

  • 使用分块处理
  • 降低数据精度(如float32→float16)
  • 增加交换空间

问题2:统计结果异常

检查步骤

  1. 确认CRS匹配
  2. 检查NoData值设置
  3. 验证影像和矢量的空间范围重叠

问题3:处理速度慢

优化方法

  • 使用更简单的几何图形
  • 降低矢量复杂度(简化多边形)
  • 预处理影像(裁剪到感兴趣区域)
# 几何简化示例 gdf['geometry'] = gdf['geometry'].simplify(tolerance=10)

8. 进阶应用方向

作物分类模型

from sklearn.ensemble import RandomForestClassifier def train_crop_classifier(features, labels): model = RandomForestClassifier(n_estimators=100) model.fit(features, labels) return model # 特征矩阵构建 features = gdf[['B4_mean', 'B8_mean', 'NDVI_mean']].values labels = gdf['crop_type'].values # 模型训练 classifier = train_crop_classifier(features, labels)

变化检测分析

def detect_changes(before_stats, after_stats, threshold=0.2): changes = {} for field_id in before_stats: delta_ndvi = after_stats[field_id]['NDVI'] - before_stats[field_id]['NDVI'] if abs(delta_ndvi) > threshold: changes[field_id] = delta_ndvi return changes

产量预测模型

import xgboost as xgb def train_yield_model(features, yields): dtrain = xgb.DMatrix(features, label=yields) params = { 'objective': 'reg:squarederror', 'max_depth': 5, 'eta': 0.1 } model = xgb.train(params, dtrain, num_boost_round=100) return model
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/11 14:06:06

Hackintool:现代化系统诊断与硬件管理工具的技术深度解析

Hackintool:现代化系统诊断与硬件管理工具的技术深度解析 【免费下载链接】Hackintool The Swiss army knife of vanilla Hackintoshing 项目地址: https://gitcode.com/gh_mirrors/ha/Hackintool 在现代计算环境中,系统诊断和硬件管理已成为开发…

作者头像 李华