def record_rivers(work_path, river_tif_path, acc_tif_path): # 创建结果数据文件夹 if not os.path.exists(work_path): os.makedirs(work_path) # 创建数据集 river_ds = gdal.Open(river_tif_path) acc_ds = gdal.Open(acc_tif_path) # 创建河流记录文件 river_record_txt = work_path + "/river_record.txt" if os.path.exists(river_record_txt): os.remove(river_record_txt) print("Recording rivers...") # 记录河流信息到文件 with open(river_record_txt, 'a') as river_f: for i in range(river_ds.RasterYSize): for j in range(river_ds.RasterXSize): # 获取river中该点的值 river_value = cu.get_raster_int_value(river_ds, j, i) # 判断是否为河流 if river_value == 1: # 需要记录的河系信息:x索引,y索引,汇流累积量 river_cell_acc = cu.get_raster_float_value(acc_ds, j, i) river_record_item = [j, i, river_cell_acc] # 记录到文件中 river_record_str = ','.join(str(k) for k in river_record_item) river_f.write(river_record_str + '\n') print("File write over.")
def record_temp_nodata(acc_paths, dir_paths): # 初始化有效nodata的坐标索引集合 temp_nodata = [] # 遍历数据块 for index in range(0, len(acc_paths)): acc_tif = acc_paths[index] dir_tif = dir_paths[index] acc_ds = gdal.Open(acc_tif) dir_ds = gdal.Open(dir_tif) acc_nodata = acc_ds.GetRasterBand(1).GetNoDataValue() # # 遍历数据块的像元 for y in range(acc_ds.RasterYSize): for x in range(acc_ds.RasterXSize): # 判断是否为nodata acc_value = cu.get_raster_float_value(acc_ds, x, y) if acc_value == acc_nodata: # 判断是否为有效nodata dir_off = cu.off_transform(x, y, acc_ds, dir_ds) dir_value = cu.get_raster_int_value( dir_ds, dir_off[0], dir_off[1]) # 若是有效nodata则记录其左上角坐标索引 if dir_value in [1, 2, 3, 4, 5, 6, 7, 8]: # 当前像元的左上角坐标 transform = acc_ds.GetGeoTransform() xy_current = [ transform[0] + x * transform[1], transform[3] + y * transform[5] ] # 记录到数组 temp_nodata.append(xy_current) acc_ds = None dir_ds = None return temp_nodata
def spill_point_dir(inner_ras_indexes, dem_ds): # 内边界的高程 inner_dem = [] for ras_index in inner_ras_indexes: dem_value = cu.get_raster_float_value(dem_ds, ras_index[0], ras_index[1]) inner_dem.append(dem_value) # 获得最低位置的索引 spill_pt_index = list(map(inner_dem.index, heapq.nsmallest(1, inner_dem)))[0] spill_pt = inner_ras_indexes[spill_pt_index] # 获得溢出方向 spill_dir = get_spill_dir(inner_ras_indexes, spill_pt_index) # 得到接收点索引 reception_pt = cu.get_to_point(spill_pt[0], spill_pt[1], spill_dir) # # 输出到tif # temp_path = r'G:\Graduation\Program\Data\41\endorheic_area0\outlet_dir.tif' # file_format = "GTiff" # driver = gdal.GetDriverByName(file_format) # temp_ds = driver.Create(temp_path, dem_ds.RasterXSize, dem_ds.RasterYSize, 1, gdal.GDT_Int16, options=['COMPRESS=DEFLATE']) # temp_ds.SetGeoTransform(dem_ds.GetGeoTransform()) # temp_ds.SetProjection(dem_ds.GetProjection()) # temp_ds.GetRasterBand(1).SetNoDataValue(-1) # cu.set_raster_int_value(temp_ds, spill_pt[0], spill_pt[1], spill_dir) # temp_ds = None return spill_pt, spill_dir, reception_pt
def get_surface_route(surface_route_start): global acc_ds, dir_ds, route_ds, slope_ds, water_value, river_th, surface_route_value # 提取各水体的坡面流路 for route_start_point in surface_route_start: # 初始化流路追踪数组 judge_route = [route_start_point] while len(judge_route) > 0: current_point = judge_route.pop() xoff = current_point[0] yoff = current_point[1] # 获取此点其汇流累积量 acc_off = cu.off_transform(xoff, yoff, slope_ds, acc_ds) acc_value = cu.get_raster_float_value(acc_ds, acc_off[0], acc_off[1]) # 获取此点在结果数据的值 ol_value = cu.get_raster_int_value(slope_ds, xoff, yoff) # 若流向的点不为水体且不为河道则继续 if ol_value != water_value and acc_value < river_th: # 记录此点为坡面流路 cu.set_raster_int_value(route_ds, xoff, yoff, surface_route_value) # 获取此点流向 dir_value = cu.get_raster_int_value(dir_ds, xoff, yoff) # 获取其流向的点 to_point = cu.get_to_point(xoff, yoff, dir_value) if len(to_point) > 0: to_p_a_off = cu.off_transform(to_point[0], to_point[1], slope_ds, acc_ds) if cu.in_data(to_p_a_off[0], to_p_a_off[1], acc_ds.RasterXSize, acc_ds.RasterYSize): # 加入判断数组 judge_route.append(to_point)
def slope_surface_inflows(water_buf, upstream_inflows): global slope_ds, acc_ds, water_buffer_value, river_th # 定义非河道出入流处的外边界点集 upstream_inflow = [] # 遍历水体的外边线更新由边界线直接流入水体的部分 for x_y_couple in water_buf: xoff = x_y_couple[0] yoff = x_y_couple[1] # 判断是否为边界上的非河道出入流处且未被标记 ol_data_value = cu.get_raster_int_value(slope_ds, xoff, yoff) acc_off = cu.off_transform(xoff, yoff, slope_ds, acc_ds) acc_data_value = cu.get_raster_float_value(acc_ds, acc_off[0], acc_off[1]) not_is_channel = ol_data_value == water_buffer_value and acc_data_value < river_th # 若为非河道出入流处 if not_is_channel: # 判断是否指向水体 to_point_data = get_to_point_ol_data(xoff, yoff) judge_to_water = to_point_data == water_value # 若流向水体 if judge_to_water: # 记录为水体外边界上的直接入流点 upstream_inflow.append(x_y_couple) # 搜索外边界上坡面间接入流点 outline_upstream_search(xoff, yoff, water_buf, upstream_inflow) upstream_inflows.append(upstream_inflow)
def add_final_to_river(dir_tif, final_points_txt, river_tif, acc_tif, river_th=None): dir_ds = gdal.Open(dir_tif, 1) rt_ds = gdal.Open(river_tif, 1) acc_ds = gdal.Open(acc_tif) # 将内流区域终点更新到河流数据 with open(final_points_txt, 'r') as final_file: for line in final_file.readlines(): final_info_str = line.strip('\n') final_info = final_info_str.split(',') # 将final像元的x,y索引 f_x_coord = float(final_info[0]) f_y_coord = float(final_info[1]) final_off = cu.coord_to_off([f_x_coord, f_y_coord], rt_ds) final_xoff = final_off[0] final_yoff = final_off[1] # 得到在河流中对应的索引 r_off = cu.off_transform(final_xoff, final_yoff, dir_ds, rt_ds) # 若在数据内 if cu.in_data(r_off[0], r_off[1], rt_ds.RasterXSize, rt_ds.RasterYSize): # 寻找内流终点周边最小汇流累积像元(最后形成虚拟河系) ne_cells = cu.get_8_dir(final_xoff, final_yoff) min_acc_point = [] min_acc = cu.get_raster_float_value(acc_ds, final_xoff, final_yoff) for point in ne_cells: acc_value = cu.get_raster_float_value( acc_ds, point[0], point[1]) if acc_value < min_acc: min_acc = acc_value min_acc_point = point # 若最小累积量像元不成为河系 if river_th is None or min_acc < river_th: # 则赋值内流终点流向该方向 dir_value = 1 if river_th is not None: dir_value = cu.dir_between_points( [final_xoff, final_yoff], min_acc_point) cu.set_raster_int_value(dir_ds, final_xoff, final_yoff, dir_value) # 记录Final point到河流 cu.set_raster_int_value(rt_ds, r_off[0], r_off[1], 1)
def water_order(old_water_bufs, new_water_bufs): global dataset_ol, dataset_acc recode_acc = [] new_water_bufs.clear() # 各水体外边界上最大汇流累积量位置的集合 surface_route_start = [] for water_buf in old_water_bufs: # 获取此水体外边界最大汇流累积量 max_acc = 0.0 # 记录最大汇流累积量位置索引 max_acc_point = water_buf[0] for point in water_buf: # 获得汇流累积量 acc_point = cu.off_transform(point[0], point[1], dataset_ol, dataset_acc) acc_value = cu.get_raster_float_value(dataset_acc, acc_point[0], acc_point[1]) # 更新最大值记录 if acc_value > max_acc: max_acc = acc_value max_acc_point = point # 插入排序 if len(recode_acc) == 0: # 若为空则为第一个 recode_acc.append(max_acc) new_water_bufs.append(water_buf) surface_route_start.append(max_acc_point) else: for index in range(len(recode_acc)): if recode_acc[index] > max_acc: # 若为中间值则插入队 recode_acc.insert(index, max_acc) new_water_bufs.insert(index, water_buf) surface_route_start.insert(index, max_acc_point) break if index == len( recode_acc) - 1 and recode_acc[index] < max_acc: # 若无更大值则追加到队尾 recode_acc.append(max_acc) new_water_bufs.append(water_buf) surface_route_start.append(max_acc_point) return surface_route_start
def spill_point_dir(inner_ras_indexes, dem_ds): global temp_ds # 内边界的高程 inner_dem = [] for ras_index in inner_ras_indexes: dem_value = cu.get_raster_float_value(dem_ds, ras_index[0], ras_index[1]) inner_dem.append(dem_value) # 获得最低位置的索引 spill_pt_index = list(map(inner_dem.index, heapq.nsmallest(1, inner_dem)))[0] spill_pt = inner_ras_indexes[spill_pt_index] # 获得溢出方向 spill_dir = get_spill_dir(inner_ras_indexes, spill_pt_index) # 得到接收点索引 reception_pt = cu.get_to_point(spill_pt[0], spill_pt[1], spill_dir) cu.set_raster_int_value(temp_ds, spill_pt[0], spill_pt[1], spill_dir) return spill_pt, spill_dir, reception_pt
def divide_outlet_to_group(outlets_order, acc_ds): acc_array = [] # 获得所有出口点的acc值 for outlet in outlets_order: acc_value = cu.get_raster_float_value(acc_ds, outlet[0], outlet[1]) acc_array.append(acc_value) # 得到最大4个acc值所对应的数组索引 max_4_acc = [] max_4_index = [] for index in range(len(acc_array)): acc_value = acc_array[index] max_4_acc.append(acc_value) max_4_index.append(index) if len(max_4_acc) > 4: array_index = list( map(max_4_acc.index, heapq.nlargest(4, max_4_acc))) n_max_4_acc = [] n_max_4_index = [] for n_index in array_index: n_max_4_acc.append(max_4_acc[n_index]) n_max_4_index.append(max_4_index[n_index]) max_4_acc = n_max_4_acc[:] max_4_index = n_max_4_index[:] # max_4_index = list(map(acc_array.index, heapq.nlargest(4, acc_array))) # 对4大acc对应索引从小到大排序 max_4_index.sort() # 根据四大流域对夹杂的中间子流域分组 odd_1 = outlets_order[0:max_4_index[0]] even_2 = [outlets_order[max_4_index[0]]] odd_3 = outlets_order[max_4_index[0] + 1:max_4_index[1]] even_4 = [outlets_order[max_4_index[1]]] odd_5 = outlets_order[max_4_index[1] + 1:max_4_index[2]] even_6 = [outlets_order[max_4_index[2]]] odd_7 = outlets_order[max_4_index[2] + 1:max_4_index[3]] even_8 = [outlets_order[max_4_index[3]]] odd_9 = outlets_order[max_4_index[3] + 1:] return [odd_1, even_2, odd_3, even_4, odd_5, even_6, odd_7, even_8, odd_9]
def able_update_acc(b_point, x_size, y_size, acc_index, dir_index): global nc # 获取acc整体数据边界 total_lt = list(acc_index.values())[0][0][:] total_rb = list(acc_index.values())[0][0][:] for value in acc_index.values(): if total_lt[0] >= value[0][0]: total_lt[0] = value[0][0] if total_lt[1] <= value[0][1]: total_lt[1] = value[0][1] if total_rb[0] <= value[1][0]: total_rb[0] = value[1][0] if total_rb[1] >= value[1][1]: total_rb[1] = value[1][1] # 初始化上游像元汇流累积量(初始化为0) up_cells_acc = 0 # 初始化标记存在上游像元(初始化为不存在) up_cell_flag = 0 # 初始化标记存在上游像元acc暂为nodata(初始化为存在nodata上游点) up_nodata_flag = 0 # 获取周边像元坐标(左上角)从邻近像元搜索 n_cells = cu.get_8_dir_coord(b_point[0], b_point[1], x_size, y_size) for n_cell in n_cells: # 得到所处数据块 acc_path = find_data_by_point(n_cell, acc_index) dir_path = find_data_by_point(n_cell, dir_index) if acc_path != "" and dir_path != "": # 判断是否为上游点 dir_ds = gdal.Open(dir_path) # 根据坐标转为索引 n_off = cu.coord_to_off(n_cell, dir_ds) # 获得此处流向值 dir_value = cu.get_raster_int_value(dir_ds, n_off[0], n_off[1]) # 获得下游像元索引 d_off = cu.get_to_point(n_off[0], n_off[1], dir_value) # 若为有下游像元 if d_off: # 获取该下游像元的坐标 d_coord = cu.off_to_coord(d_off, dir_ds) # 若该下游像元坐标与当前坐标相同则此邻近像元为上游像元 if d_coord == b_point: up_cell_flag = 1 # 获取此上游像元处的汇流累积量值 acc_ds = gdal.Open(acc_path) n_acc_off = cu.coord_to_off(n_cell, acc_ds) n_acc = cu.get_raster_float_value(acc_ds, n_acc_off[0], n_acc_off[1]) # 若此acc值为nodata则标记存在上游像元acc暂为nodata if int(n_acc) <= 0: up_nodata_flag = 1 break # 否则记录当前值到总上游累积量 else: up_cells_acc += n_acc acc_ds = None dir_ds = None # 若存在上游像元 if up_cell_flag: # 若上游像元均有有效acc值 if up_nodata_flag == 0: # 更新上游acc总值和自身累积量值到当前像元 current_acc = up_cells_acc + 1.0 return current_acc # 存在上游像元暂为nodata else: return 0 # 若不存在上游像元 else: # 若考虑边界污染 if nc: # 若在边界上 if in_edge(b_point, total_lt, total_rb): return 0 else: # 否则作为汇流起始点 return 1.0 # 若不考虑边界污染 else: return 1.0