File size: 7,727 Bytes
badcf3c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
import os
import numpy as np
from scipy import ndimage
# import pandas as pd
from osgeo import gdal, ogr, osr
# 1. 定义输入输出路径
dem_path = 'E:/bang/KUNKUN/data/water_depth/Dem_True/Dem11.tif'
area_dir = 'E:/bang/KUNKUN/data/water_depth/Area'
output_dir = 'E:/bang/KUNKUN/data/water_depth/Results/'
# 2. 读取DEM数据
dem_ds = gdal.Open(dem_path)
# # 查看形状
# print(dem_ds.RasterXSize, dem_ds.RasterYSize)
dem_array = dem_ds.GetRasterBand(1).ReadAsArray()
# 3. 初始化结果存储
results = []
# 4. 遍历所有面积文件
for filename in os.listdir(area_dir):
if filename.startswith('S1B_') and filename.endswith('.tif'):
# # 自定义裁剪范围(UTM坐标)
# min_x = 500000 # 最小东坐标
# max_x = 550000 # 最大东坐标
# min_y = 3100000 # 最小北坐标
# max_y = 3150000 # 最大北坐标
# # 裁剪DEM
# dem_transform = dem_ds.GetGeoTransform()
# # 计算DEM裁剪范围
# dem_min_x = int((min_x - dem_transform[0]) / dem_transform[1])
# dem_max_x = int((max_x - dem_transform[0]) / dem_transform[1])
# dem_min_y = int((max_y - dem_transform[3]) / dem_transform[5])
# dem_max_y = int((min_y - dem_transform[3]) / dem_transform[5])
# # 执行DEM裁剪
# cropped_dem = dem_array[dem_min_y:dem_max_y, dem_min_x:dem_max_x]
# # 裁剪面积数据
# area_ds = gdal.Open(os.path.join(area_dir, filename))
# area_transform = area_ds.GetGeoTransform()
# area_array = area_ds.GetRasterBand(1).ReadAsArray()
# # 计算面积数据裁剪范围
# area_min_x = int((min_x - area_transform[0]) / area_transform[1])
# area_max_x = int((max_x - area_transform[0]) / area_transform[1])
# area_min_y = int((max_y - area_transform[3]) / area_transform[5])
# area_max_y = int((min_y - area_transform[3]) / area_transform[5])
# # 执行面积数据裁剪
# cropped_area = area_array[area_min_y:area_max_y, area_min_x:area_max_x]
# 解析日期
parts = filename.split('_')
year = parts[1]
month = parts[2]
day = parts[3].split('.')[0]
date = f"{year}-{month}-{day}"
print(f"日期:{date}")
# 5. 处理当前日期的面积文件
area_ds = gdal.Open(os.path.join(area_dir, filename))
area_array = area_ds.GetRasterBand(1).ReadAsArray()
# 6. 水体连通性分析
labeled_array, num_features = ndimage.label(area_array)
print(f"湖泊数量:{num_features}")
# 去除小面积子湖
min_area_pixels = int(1000 * 1000 / 88.36) # 1000平方公里转换为像素数
removed_count = 0
for i in range(1, num_features + 1):
size = np.sum(labeled_array == i)
if size < min_area_pixels:
labeled_array[labeled_array == i] = 0
removed_count += 1
# print(f"去除小面积湖泊:{i}")
# 计算剩余湖泊数量
remaining_labels = np.unique(labeled_array)
remaining_count = len(remaining_labels) - 1 # 减去背景值0
print(f"去除小湖数量:{removed_count}")
print(f"剩余湖泊数量:{remaining_count}")
# 8. 重新编号
unique_labels = np.unique(labeled_array)
unique_labels = unique_labels[unique_labels != 0] # 排除背景值0
relabeled_array = np.zeros_like(labeled_array)
new_label = 1
for old_label in unique_labels:
size = np.sum(labeled_array == old_label)
if size >= min_area_pixels: # 再次检查湖泊面积
relabeled_array[labeled_array == old_label] = new_label
new_label += 1
print(f"重新编号:{np.unique(relabeled_array[relabeled_array != 0])}") # 只显示非零值
# 计算边缘高程的中位数
for label in range(1, new_label): # 使用重新编号后的标签
mask = relabeled_array == label
if np.sum(mask) == 0: # 如果没有像素点,跳过
continue
# 提取边界点
structure = ndimage.generate_binary_structure(2, 2) # 8连通
eroded_mask = ndimage.binary_erosion(mask, structure=structure)
boundary_mask = mask & ~eroded_mask # 边界掩码
# 提取边界点的高程值
y_indices, x_indices = np.where(boundary_mask)
if len(y_indices) == 0 or len(x_indices) == 0: # 如果没有边界点,跳过
continue
# 将边界点坐标转换为地理坐标
transform = area_ds.GetGeoTransform()
x_coords = transform[0] + x_indices * transform[1]
y_coords = transform[3] + y_indices * transform[5]
# 将地理坐标转换为DEM的像素坐标
dem_transform = dem_ds.GetGeoTransform()
dem_xs = ((x_coords - dem_transform[0]) / dem_transform[1]).astype(int)
dem_ys = ((y_coords - dem_transform[3]) / dem_transform[5]).astype(int)
# 提取边界点的高程值
boundary_depths = []
for dem_x, dem_y in zip(dem_xs, dem_ys):
if 0 <= dem_x < dem_array.shape[1] and 0 <= dem_y < dem_array.shape[0]:
boundary_depths.append(dem_array[dem_y, dem_x])
# 计算边界高程的中位数
if len(boundary_depths) > 0:
median_boundary_depth = np.nanmedian(boundary_depths)
else:
median_boundary_depth = np.nan
# 存储结果
results.append({
'date': date,
'lake_id': label,
'longitude': np.nanmean(x_coords), # 湖泊边界中心经度
'latitude': np.nanmean(y_coords), # 湖泊边界中心纬度
'depth': median_boundary_depth # 边界高程的中位数
})
print(f"结果:{results}")
# 创建新的数组,初始化为nodata值
nodata_value = -9999 # 设置nodata值
output_array = np.full_like(relabeled_array, nodata_value, dtype=np.float32)
# 将符合标准的湖泊赋值为中位数高程
for result in results:
label = result['lake_id']
median_depth = result['depth']
mask = relabeled_array == label
output_array[mask] = median_depth
# 设置GDAL配置选项,强制使用EPSG官方参数
gdal.SetConfigOption('GTIFF_SRS_SOURCE', 'EPSG')
# 写入新的TIFF文件
driver = gdal.GetDriverByName('GTiff')
output_path = os.path.join(output_dir, f'{date}_processed_B.tif')
# 创建输出文件
output_ds = driver.Create(output_path, relabeled_array.shape[1], relabeled_array.shape[0], 1, gdal.GDT_Float32)
# 设置地理变换和投影
output_ds.SetGeoTransform(area_ds.GetGeoTransform())
output_ds.SetProjection(area_ds.GetProjection())
# 写入数据
output_band = output_ds.GetRasterBand(1)
output_band.WriteArray(output_array)
# 设置nodata值
output_band.SetNoDataValue(nodata_value)
# 刷新缓存
output_ds.FlushCache()
# 关闭文件
output_ds = None
print(f"结果已写入:{output_path}")
|