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}")