def outline_upstream_search(xoff, yoff, water_buf, upstream_inflow): global dir_ds, slope_ds, water_value # 创建搜索数组 search_inflows = [[xoff, yoff]] # 开始搜索 while len(search_inflows) > 0: # 取出初始像元 cell_off = search_inflows.pop() xoff = cell_off[0] yoff = cell_off[1] # 搜索周边像元 ol_dir_array = cu.get_8_dir(xoff, yoff) for ol_n_cell in ol_dir_array: n_xoff = ol_n_cell[0] n_yoff = ol_n_cell[1] # 判断像元是否在数据集内且是否为有效流向 judge_in_data = cu.in_data(n_xoff, n_yoff, dir_ds.RasterXSize, dir_ds.RasterYSize) if judge_in_data: # 判断是否在水体内 ol_data = cu.get_raster_int_value(slope_ds, n_xoff, n_yoff) # 若不在水体则继续 if ol_data != water_value: dir_data_value = cu.get_raster_int_value(dir_ds, n_xoff, n_yoff) to_point = cu.get_to_point(n_xoff, n_yoff, dir_data_value) if len(to_point) != 0: # 若为上游点 if to_point[0] == xoff and to_point[1] == yoff: # 判断是否在外边界上,若是则记录 if ol_n_cell in water_buf: # 则记录为外边界上的上游坡面入流点 upstream_inflow.append([n_xoff, n_yoff]) # 继续遍历相邻像元 search_inflows.append(ol_n_cell)
def get_new_slope_surface(xoff, yoff, upstream_inflow, inflow_points): global acc_ds, river_th, slope_ds # 初始化搜索数组 search_array = [[xoff, yoff]] # 若继续搜索 while len(search_array) > 0: cell_xy = search_array.pop() neighbor_points = cu.get_8_dir(cell_xy[0], cell_xy[1]) # 遍历周边点 for point in neighbor_points: judge_in_data = cu.in_data(point[0], point[1], slope_ds.RasterXSize, slope_ds.RasterYSize) if judge_in_data: # 若该点为水体入流点且未记录合并 if point in upstream_inflow and point not in inflow_points: # 判断两点间是否穿插河道 # 两点若不存在中间点 if point[0] == cell_xy[0] or point[1] == cell_xy[1]: no_river = 1 else: # 判断中间点是否为河道 bd1_point = cu.off_transform(cell_xy[0], point[1], slope_ds, acc_ds) bd2_point = cu.off_transform(point[0], cell_xy[1], slope_ds, acc_ds) between_data_value1 = cu.get_raster_int_value(acc_ds, bd1_point[0], bd1_point[1]) between_data_value2 = cu.get_raster_int_value(acc_ds, bd2_point[0], bd2_point[1]) no_river = between_data_value1 < river_th and between_data_value2 < river_th # 若未穿插河道 if no_river: # 记录到当前坡面入流点集 inflow_points.append(point) # 以此点继续遍历 search_array.append(point) return inflow_points
def outlet_basins(outlet, result_ds, s_id, dir_ds): # 创建追踪数组 trace_array = [outlet] # 若需要继续追踪 while len(trace_array) > 0: # 取出当前像元 cur_cell = trace_array.pop() cur_x = cur_cell[0] cur_y = cur_cell[1] # 对当前像元赋值 cu.set_raster_int_value(result_ds, cur_x, cur_y, s_id) # 获取周边像元索引 n_8_cells = cu.get_8_dir(cur_x, cur_y) # 遍历8个像元 for n_cell in n_8_cells: n_x = n_cell[0] n_y = n_cell[1] # 若在数据范围内 if cu.in_data(n_x, n_y, dir_ds.RasterXSize, dir_ds.RasterYSize): # 获得当前点流向值 dir_value = cu.get_raster_int_value(dir_ds, n_x, n_y) # 获得下游点索引 to_point = cu.get_to_point_128(n_x, n_y, dir_value) # 若为当前点的上游点 if to_point == cur_cell: # 将此像元加入到流域追踪数组 trace_array.append(n_cell)
def surface_merge(upstream_inflow, new_slope_surface_id): global slope_ds, dir_ds, water_buffer_value, water_value # 定义合并后的坡面分组 slope_surface_unit = [] # 遍历上游流入点对坡面与水体相交处的入流口分组 for upstream_point in upstream_inflow: # 判断坡面入流点已参与合并 not_in_unit = 1 for index in range(0, len(slope_surface_unit), 1): if upstream_point in slope_surface_unit[index]: not_in_unit = 0 break # 若坡面入流点未参与合并 if not_in_unit: # 创建新坡面集合并添加新坡面的首个水体入流点 slope_surface = [upstream_point] # 获取新坡面集合的入流点集 slope_surface = get_new_slope_surface(upstream_point[0], upstream_point[1], upstream_inflow, slope_surface) # 将新坡面放入合并后的坡面集合中 slope_surface_unit.append(slope_surface) # 获取合并后新坡面的id new_slope_surface_id += 1 # 以各合并坡面的入口点集开始合并坡面 for index in range(0, len(slope_surface_unit), 1): # print(slope_surface_unit[index]) # 获取合并后新坡面与水体的交界点 s_s_inflows = slope_surface_unit[index] for inflow_point in s_s_inflows: # 初始化需要更新的像元集 to_update_points = [inflow_point] # 循环直到待更新数组为空 while len(to_update_points) > 0: # 取出第一个点 to_update_point = to_update_points.pop() # 更新此点id cu.set_raster_int_value(slope_ds, to_update_point[0], to_update_point[1], new_slope_surface_id) # 获取此点周边需要更新的像元集 # 获取邻近像元 neighbor_points = cu.get_8_dir(to_update_point[0], to_update_point[1]) # 判断各像元是否需要更新 for point in neighbor_points: point_x = point[0] point_y = point[1] judge_in_data = cu.in_data(point_x, point_y, slope_ds.RasterXSize, slope_ds.RasterYSize) if judge_in_data: # 若不为水体则继续 ol_data = cu.get_raster_int_value(slope_ds, point_x, point_y) if ol_data != water_value: # 若是当前点的上游点 dir_point = cu.off_transform(point_x, point_y, slope_ds, dir_ds) dir_value = cu.get_raster_int_value(dir_ds, dir_point[0], dir_point[1]) to_point = cu.get_to_point(point_x, point_y, dir_value) if to_point == to_update_point: # 加入待更新数组 to_update_points.append(point) return new_slope_surface_id
def judge_from_water(xoff, yoff): global dir_ds, slope_ds, water_value neighbor_points = cu.get_8_dir(xoff, yoff) for point in neighbor_points: dir_value = cu.get_raster_int_value(dir_ds, point[0], point[1]) to_point = cu.get_to_point(point[0], point[1], dir_value) ol_value = cu.get_raster_int_value(slope_ds, point[0], point[1]) if ol_value == water_value and to_point[0] == xoff and to_point[1] == yoff: return 1 return 0
def buffer_search(o_res_xoff, o_res_yoff, water_ol_buf): global lake_ds, slope_ds, river_th, water_channel # 存储需要遍历的水体像元 water_points = [[o_res_xoff, o_res_yoff]] # 循环方式遍历水体像元 while len(water_points) > 0: current_point = water_points.pop() res_dir_array = cu.get_8_dir(current_point[0], current_point[1]) for index in range(0, 8, 1): # 水体数据中的索引 res_xoff = res_dir_array[index][0] res_yoff = res_dir_array[index][1] # 结果数据的该点索引 ol_point_off = cu.off_transform(res_xoff, res_yoff, lake_ds, slope_ds) re_xoff = ol_point_off[0] re_yoff = ol_point_off[1] # 若在数据内 if cu.in_data(re_xoff, re_yoff, slope_ds.RasterXSize, slope_ds.RasterYSize): # 判断是否记录在外边界数组 in_ol_array = ol_point_off in water_ol_buf # 判断是否在水体数据范围内 in_water_data = cu.in_data(res_xoff, res_yoff, lake_ds.RasterXSize, lake_ds.RasterYSize) # 若在水体数据中进一步判断是否为水体内像元 if in_water_data: data_value = cu.get_raster_int_value( lake_ds, res_xoff, res_yoff) not_in_water = data_value != water_value else: not_in_water = True # 若不是水体像元且未记录则记录,即记录新边界点 if not in_ol_array and not_in_water: # 添加缓冲区数组记录 water_ol_buf.append([re_xoff, re_yoff]) # 标记为水体外边界 cu.set_raster_int_value(slope_ds, re_xoff, re_yoff, water_buffer_value) # 判断是否在结果数据中记录水体 ol_data_value = cu.get_raster_int_value( slope_ds, re_xoff, re_yoff) recode_water = ol_data_value == water_value # 若是水体且未记录,则继续搜索 if not recode_water and not not_in_water: cu.set_raster_int_value(slope_ds, re_xoff, re_yoff, water_value) water_points.append([res_xoff, res_yoff])
def get_data_boundary_cells(data_tif, boundary_tif): data_ds = gdal.Open(data_tif) # 创建边界点数据 print("Create Boundary file...") file_format = "GTiff" driver = gdal.GetDriverByName(file_format) full_geotransform = data_ds.GetGeoTransform() b_ds = driver.Create(boundary_tif, data_ds.RasterXSize, data_ds.RasterYSize, 1, gdal.GDT_Byte, options=['COMPRESS=DEFLATE']) b_ds.SetGeoTransform(full_geotransform) b_ds.SetProjection(data_ds.GetProjection()) b_ds.GetRasterBand(1).SetNoDataValue(0) # 遍历基础数据记录边界点 print("Get Boundary Cells...") # nodata值 no_data = int(data_ds.GetRasterBand(1).GetNoDataValue()) for i in range(data_ds.RasterYSize): # 前个像元点 f_point_value = None for j in range(data_ds.RasterXSize): # 若为首尾行 if i == 0 or i == data_ds.RasterYSize - 1: c_point_value = cu.get_raster_int_value(data_ds, j, i) # 若为数据点则记录 if c_point_value != no_data: cu.set_raster_int_value(b_ds, j, i, 1) else: # 若为第一个点或为行最后一个点 if j == 0 or j == data_ds.RasterXSize - 1: c_point = [j, i] f_point_value = cu.get_raster_int_value(data_ds, c_point[0], c_point[1]) # 若为数据点则记录 if f_point_value != no_data: cu.set_raster_int_value(b_ds, c_point[0], c_point[1], 1) # 若不为第一个点 else: c_point = [j, i] # 获取当前点的值 c_point_value = cu.get_raster_int_value(data_ds, c_point[0], c_point[1]) # 若当前点为数据点 if c_point_value != no_data: # 获取周边邻接像元 n_points = cu.get_8_dir(c_point[0], c_point[1]) # 若周边存在无数据像元则记录 for n_point in n_points: n_point_value = cu.get_raster_int_value(data_ds, n_point[0], n_point[1]) if n_point_value == no_data: cu.set_raster_int_value(b_ds, c_point[0], c_point[1], 1) break
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 get_no_inflow_cells(dir_tif, no_inflow_tif): dir_ds = gdal.Open(dir_tif) # 创建无流入点数据 print("Create No inflow file...") file_format = "GTiff" driver = gdal.GetDriverByName(file_format) full_geotransform = dir_ds.GetGeoTransform() ni_ds = driver.Create(no_inflow_tif, dir_ds.RasterXSize, dir_ds.RasterYSize, 1, gdal.GDT_Int32, options=['COMPRESS=DEFLATE']) ni_ds.SetGeoTransform(full_geotransform) ni_ds.SetProjection(dir_ds.GetProjection()) ni_ds.GetRasterBand(1).SetNoDataValue(0) # 遍历基础数据记录无流入点 print("Get No Inflow Data...") for i in range(dir_ds.RasterYSize): for j in range(dir_ds.RasterXSize): c_point = [j, i] # 邻近像元索引 n_points = cu.get_8_dir(c_point[0], c_point[1]) # 初始化流入标记 inflow_flag = 0 for n_point in n_points: # 判断是否在数据内 in_data = cu.in_data(n_point[0], n_point[1], dir_ds.RasterXSize, dir_ds.RasterYSize) if in_data: # 判断是否流向原像元点 n_dir = cu.get_raster_int_value(dir_ds, n_point[0], n_point[1]) to_point = cu.get_to_point(n_point[0], n_point[1], n_dir) if to_point == c_point: inflow_flag = 1 break # 若无流入则记录 if not inflow_flag: cu.set_raster_int_value(ni_ds, c_point[0], c_point[1], 1)
def recode_from_river(watershed_id, river_x, river_y, watershed_tif_path, dir_tif_path, water_tif_path, rivers_index): global water_value # 创建数据集 watershed_ds = gdal.OpenEx(watershed_tif_path, 1) dir_ds = gdal.Open(dir_tif_path) water_ds = gdal.Open(water_tif_path) # 初始化需要赋值的像元集合 update_cells = [[river_x, river_y]] # 更新区域内像元值 # print(">>> update cell:", end='') while len(update_cells) > 0: # 取出要更新的像元索引 update_cell = update_cells.pop() # print(update_cell, end='') # 更新像元值 cu.set_raster_int_value(watershed_ds, update_cell[0], update_cell[1], watershed_id) # print('update: ', update_cell, '->', watershed_id) # 得到邻近像元集合 neighbor_cells = cu.get_8_dir(update_cell[0], update_cell[1]) # 搜索上游像元 for neighbor_cell in neighbor_cells: n_x = neighbor_cell[0] n_y = neighbor_cell[1] # 判断邻近点是否在数据内 if cu.in_data(n_x, n_y, watershed_ds.RasterXSize, watershed_ds.RasterYSize): # 若不为河段并不为湖泊/水库(即若为子流域) water_off = cu.off_transform(n_x, n_y, watershed_ds, water_ds) in_water = cu.is_water_cell(water_ds, water_off[0], water_off[1], water_value) if neighbor_cell not in rivers_index and not in_water: dir_value = cu.get_raster_int_value(dir_ds, n_x, n_y) to_point = cu.get_to_point(n_x, n_y, dir_value) # 若为上游点 if to_point == update_cell: # 加入更新数组 update_cells.append(neighbor_cell) watershed_ds = None dir_ds = None
def get_trace_points(dir_tif, flag_tif, trace_tif, seaside_txt=None, final_txt=None): coastline_value = 0 final_value = -1 dir_ds = gdal.Open(dir_tif) f_ds = gdal.Open(flag_tif) # 创建trace start数据 print("Create Trace file...") file_format = "GTiff" driver = gdal.GetDriverByName(file_format) full_geotransform = dir_ds.GetGeoTransform() trace_ds = driver.Create(trace_tif, dir_ds.RasterXSize, dir_ds.RasterYSize, 1, gdal.GDT_Byte, options=['COMPRESS=DEFLATE']) trace_ds.SetGeoTransform(full_geotransform) trace_ds.SetProjection(dir_ds.GetProjection()) trace_ds.GetRasterBand(1).SetNoDataValue(0) # 创建记录文件 seaside_flag = 0 seaside_f = None if seaside_txt is not None: print("Record Final Points.") seaside_flag = 1 if os.path.exists(seaside_txt): os.remove(seaside_txt) if seaside_flag: seaside_f = open(seaside_txt, "a") final_flag = 0 final_f = None if final_txt is not None: print("Record Final Points.") final_flag = 1 if os.path.exists(final_txt): os.remove(final_txt) if final_flag: final_f = open(final_txt, "a") # 遍历基础数据记录seaside print("Get Trace Data...") for i in range(f_ds.RasterYSize): for j in range(f_ds.RasterXSize): # 获取流向的值 flag_value = cu.get_raster_int_value(f_ds, j, i) # 如果是coastline if flag_value == coastline_value: # 获取周边像元索引 neibor_cells = cu.get_8_dir(j, i) # 遍历 for n_cell in neibor_cells: # 判断是否在数据内 in_data = cu.in_data(n_cell[0], n_cell[1], dir_ds.RasterXSize, dir_ds.RasterYSize) # 若在数据内 if in_data: # 获取流向值 dir_value = cu.get_raster_int_value(dir_ds, n_cell[0], n_cell[1]) # 获取流向的像元索引 n_to_point = cu.get_to_point(n_cell[0], n_cell[1], dir_value) # 若为当前上游像元 if n_to_point == [j, i]: # 记录为seaside cu.set_raster_int_value(trace_ds, n_cell[0], n_cell[1], 1) # 记录到文件 if seaside_flag: # 获得栅格像元左上角坐标 seaside_record_item = cu.off_to_coord([j, i], f_ds) seaside_record_str = ','.join(str(k) for k in seaside_record_item) seaside_f.write(seaside_record_str + '\n') # 如果是final point elif flag_value == final_value: # 记录为final points cu.set_raster_int_value(trace_ds, j, i, 1) # 记录到文件 if final_flag: final_record_item = cu.off_to_coord([j, i], f_ds) final_record_str = ','.join(str(k) for k in final_record_item) final_f.write(final_record_str + '\n') dir_ds = None f_ds = None trace_ds = None seaside_f = None final_f = None