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 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 get_to_point_ol_data(xoff, yoff): global dataset_dir, dataset_ol, no_data_value dir_data_value = cu.get_raster_int_value(dataset_dir, xoff, yoff) to_point = cu.get_to_point(xoff, yoff, dir_data_value) if len(to_point) < 1: return no_data_value else: return cu.get_raster_int_value(dataset_ol, to_point[0], to_point[1])
def get_to_point_ol_data(xoff, yoff): global dir_ds, slope_ds, no_data_value dir_data_value = cu.get_raster_int_value(dir_ds, xoff, yoff) to_point = cu.get_to_point(xoff, yoff, dir_data_value) if len(to_point) < 1: return no_data_value else: return cu.get_raster_int_value(slope_ds, to_point[0], to_point[1])
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 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 clear_buffer(water_buf): global water_buffer_value, no_data_value, dataset_ol for cell in water_buf: data_value = cu.get_raster_int_value(dataset_ol, cell[0], cell[1]) if data_value == water_buffer_value: cu.set_raster_int_value(dataset_ol, cell[0], cell[1], no_data_value)
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 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 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 down_point_coord(b_point, dir_index): current_dir_path = find_data_by_point(b_point, dir_index) cu_dir_ds = gdal.Open(current_dir_path) dir_off = cu.coord_to_off(b_point, cu_dir_ds) dir_value = cu.get_raster_int_value(cu_dir_ds, dir_off[0], dir_off[1]) to_off = cu.get_to_point(dir_off[0], dir_off[1], dir_value) to_coord = cu.off_to_coord(to_off, cu_dir_ds) cu_dir_ds = None return to_coord
def dir_reclassify(old_tif_path, updated_tif_path, final_points_txt=None): update_value_2array = [1, 2, 4, 8, 16, 32, 64, 128] new_value_array = [1, 8, 7, 6, 5, 4, 3, 2] final_value = -1 old_ds = gdal.Open(old_tif_path) print("Create Classified Raster") # 创建坡面提取结果数据 no_data_value = 0 file_format = "GTiff" full_geotransform = old_ds.GetGeoTransform() driver = gdal.GetDriverByName(file_format) result_data_path = updated_tif_path copy_ds = driver.Create(result_data_path, old_ds.RasterXSize, old_ds.RasterYSize, 1, gdal.GDT_Byte, options=['COMPRESS=DEFLATE']) copy_ds.SetGeoTransform(full_geotransform) copy_ds.SetProjection(old_ds.GetProjection()) copy_ds.GetRasterBand(1).SetNoDataValue(no_data_value) txt_flag = 0 final_f = None if final_points_txt is not None: print("Record Final Points.") txt_flag = 1 if os.path.exists(final_points_txt): os.remove(final_points_txt) if txt_flag: final_f = open(final_points_txt, "a") print("Direction Raster Classify...") for j in range(copy_ds.RasterYSize): for i in range(copy_ds.RasterXSize): data_value = cu.get_raster_un_int_value(old_ds, i, j) if data_value in update_value_2array: index = update_value_2array.index(data_value) new_value = new_value_array[index] cu.set_raster_int_value(copy_ds, i, j, new_value) else: data_value = cu.get_raster_int_value(old_ds, i, j) # 如果是内流点则随意赋值流向 if data_value == final_value and txt_flag: # 拟为内流终点赋值流向 # cu.set_raster_int_value(copy_ds, i, j, 1) # 记录内流区终点到txt final_record_item = [i, j] final_record_str = ','.join(str(k) for k in final_record_item) final_f.write(final_record_str + '\n') else: cu.set_raster_int_value(copy_ds, i, j, no_data_value) old_ds = None copy_ds = None final_f = None
def outlets_index_order(boundary_array, outlet_ds): outlet_order = [] # 得到流域集合边界上出口栅格和其在多边形内边界上的追踪序号 # 初始化记录出口点及其与前者出口点在追踪给数组中相差距离的数组 record_distance = {} # 初始化记录与前者出口点在追踪给数组中相差距离 distance = 0 for index in boundary_array: distance += 1 # 获得此索引在出口点数据中的值 trace_value = cu.get_raster_int_value(outlet_ds, index[0], index[1]) # 若为出口点则记录 if trace_value > 0: key = ','.join(str(k) for k in index) record_distance[key] = distance distance = 0 # 更新第一个记录的点与前者间的距离 key_f = [key for key in record_distance.keys()][0] value_f = [value for value in record_distance.values()][0] record_distance[key_f] = value_f + distance # 根据得到的序号得到流域出口的最佳排序 # 与前者距离最大的值 max_distance_index = 0 # 与前者距离最大的出口点在出口数组中的索引 max_dis_index_mark = 0 # 得到距离数组 distance_array = [value for value in record_distance.values()] for i in range(len(distance_array)): distance = distance_array[i] if distance > max_distance_index: max_distance_index = distance max_dis_index_mark = i # 出口点集 outlet_set = [] point_off_str = [key for key in record_distance.keys()] for point_str in point_off_str: point_temp = point_str.split(',') point = [int(point_temp[0]), int(point_temp[1])] outlet_set.append(point) # 以标记的位置为起点记录出口点 for i in range(max_dis_index_mark, len(outlet_set)): outlet_order.append(outlet_set[i]) for i in range(0, max_dis_index_mark): outlet_order.append(outlet_set[i]) return outlet_order
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
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
def watershed_recode(river_record_path, watershed_tif_path, dir_tif_path, water_tif_path): # 创建数据集 watershed_ds = gdal.Open(watershed_tif_path) dir_ds = gdal.Open(dir_tif_path) # 读取河系信息到内存 print("Reading rivers info...") # 初始化河系像元索引 rivers_index = [] rivers_info = {} with open(river_record_path, 'r') as river_file: for line in river_file.readlines(): river_info_str = line.strip('\n') river_info = river_info_str.split(',') # 将river像元的x,y索引作为字典的key river_point_str = river_info[0] + ',' + river_info[1] # 将river像元的流向和汇流累积量作为字典的value river_info_detail = float(river_info[2]) rivers_info[river_point_str] = river_info_detail rivers_index.append([int(river_info[0]), int(river_info[1])]) # 创建河段集合 print("Building rivers group...") river_reaches = {} # 继续创建标识 flag = 1 # 开始创建 while flag: flag = 0 # 取汇流累积量最小的像元索引 min_acc_river = min(rivers_info, key=rivers_info.get) # 获取子流域标识值 current_cell = min_acc_river.split(',') watershed_value = cu.get_raster_int_value(watershed_ds, int(current_cell[0]), int(current_cell[1])) # 若不在子流域则继续寻找 if watershed_value < 0: del rivers_info[min_acc_river] if rivers_info: flag = 1 # 若在子流域则作为起点 else: # 初始化要遍历的河流起点数组 river_starts = [min_acc_river] # 若河流起点数组不为空则遍历河段 while len(river_starts) > 0: # 开始追踪河段 start = river_starts.pop() # 创建河段索引记录数组 river_reach = [] # 获得此像元索引 start_xy = start.split(',') # 获取此河段对应子流域Id标识 watershed_id = cu.get_raster_int_value(watershed_ds, int(start_xy[0]), int(start_xy[1])) # 初始化追踪数组 tracking = [start] # 开始追踪河段的像元 while len(tracking) > 0: # 取出像元并记录 cell_str = tracking.pop() del rivers_info[cell_str] river_reach.append(cell_str) # 获得像元xy索引 cell_xy = cell_str.split(',') n_x = cell_xy[0] n_y = cell_xy[1] # 获得流向的像元 dir = cu.get_raster_int_value(dir_ds, int(n_x), int(n_y)) to_point = cu.get_to_point(int(n_x), int(n_y), dir) to_point_str = ','.join(str(k) for k in to_point) # 若下游像元在原河流数组 if to_point_str in rivers_info.keys(): # 获取此点在子流域数据的值 watershed_value = cu.get_raster_int_value(watershed_ds, to_point[0], to_point[1]) # 若在子流域内 if watershed_value >= 0: # 若在同子流域内则记录为河段 if watershed_value == watershed_id: tracking.append(to_point_str) # 若不在同一子流域则记录为下一河段起点 else: river_starts.append(to_point_str) # 若不在子流域内则搜索下游河段的起点 else: # 初始化搜索数组 find_next_start = [to_point] # 开始搜索 while len(find_next_start) > 0: # 取出像元 river_cell = find_next_start.pop() # 在原河流数组中清除记录 river_cell_str = ','.join(str(k) for k in river_cell) del rivers_info[river_cell_str] # 获得下游像元 dir = cu.get_raster_int_value(dir_ds, river_cell[0], river_cell[1]) next_point = cu.get_to_point(dir, river_cell[0], river_cell[1]) # 若下游像元在原河流数组 next_point_str = ','.join(str(k) for k in next_point) if next_point_str in rivers_info.keys(): # 获取此点在子流域数据的值 watershed_value = cu.get_raster_int_value(watershed_ds, next_point[0], next_point[1]) # 若在子流域内 if watershed_value >= 0: # 则记录为下一河段起点 river_starts.append(next_point_str) # 若不在子流域内则继续搜索下游河段的起点 else: find_next_start.append(next_point) # 将河段存入集合 if watershed_id in river_reaches.keys(): update_array = river_reaches[watershed_id] update_array.append(river_reach) river_reaches[watershed_id] = update_array else: river_reaches[watershed_id] = [river_reach] # 若河流像元未全部遍历则继续 if len(rivers_info) > 0: flag = 1 print("Searching rivers in watersheds need recode...") # 记录当前子流域标识最大值 max_ws_id = 0 # 初始化在需要重新编码子流域中的河段集合 recode_ws_rivers = [] # 筛选出涉及处理的子流域 for watershed, watershed_rivers in river_reaches.items(): watershed_id = int(watershed) if watershed_id > max_ws_id: max_ws_id = watershed_id # 若存在多个河段则需要进行重新唯一编码 if len(watershed_rivers) > 1: # print("%s, %d" % (watershed, len(watershed_rivers))) # print(watershed_rivers) # 找出每组中除最长河段的其他河段 max_len = 0 max_river_start = '' for river in watershed_rivers: if len(river) > max_len: max_len = len(river) max_river_start = river[0] for river in watershed_rivers: if len(river) <= max_len and max_river_start not in river: recode_ws_rivers.append(river) print("Recoding watersheds by rivers...") # 在需要重新编码的子流域中的河段 watershed_count = 0 for river in recode_ws_rivers: max_ws_id += 1 watershed_count += 1 total_count = len(recode_ws_rivers) print("\r> updating watersheds.....................%d/%d" % (watershed_count, total_count), end='') river_count = 0 print('') for river_cell in river: river_count += 1 total_r_count = len(river) print("\r>> update by river cell: %d/%d" % (river_count, total_r_count), end='') cell_xy = river_cell.split(',') recode_from_river(max_ws_id, int(cell_xy[0]), int(cell_xy[1]), watershed_tif_path, dir_tif_path, water_tif_path, rivers_index) print(".") watershed_ds = None dir_ds = None
def get_slope_surface(lake_tif_path, dir_tif_path, acc_tif_path, slope_tif_path, route_tif_path, river_threshold, no_data=None): print("Extract Start") global lake_ds, dir_ds, acc_ds, slope_ds, route_ds, river_th, water_ol_bufs, no_data_value river_th = river_threshold lake_ds = gdal.Open(lake_tif_path) dir_ds = gdal.Open(dir_tif_path) acc_ds = gdal.Open(acc_tif_path) if no_data is not None: no_data_value = no_data else: no_data_value = int(lake_ds.GetRasterBand(1).GetNoDataValue()) dir_geotransform = dir_ds.GetGeoTransform() full_geotransform = dir_geotransform # 创建坡面提取结果数据 file_format = "GTiff" driver = gdal.GetDriverByName(file_format) slope_ds = driver.Create(slope_tif_path, dir_ds.RasterXSize, dir_ds.RasterYSize, 1, gdal.GDT_Int32, options=['COMPRESS=DEFLATE']) slope_ds.SetGeoTransform(full_geotransform) slope_ds.SetProjection(dir_ds.GetProjection()) slope_ds.GetRasterBand(1).SetNoDataValue(no_data_value) # 创建坡面流路结果数据 route_ds = driver.Create(route_tif_path, dir_ds.RasterXSize, dir_ds.RasterYSize, 1, gdal.GDT_Int16, options=['COMPRESS=DEFLATE']) route_ds.SetGeoTransform(full_geotransform) route_ds.SetProjection(dir_ds.GetProjection()) route_ds.GetRasterBand(1).SetNoDataValue(no_data_value) print("Get lakes' outline...") for i in range(lake_ds.RasterYSize): for j in range(lake_ds.RasterXSize): # 获取水体数据某点的值 scan_value = cu.get_raster_int_value(lake_ds, j, i) # 若是水体内的像元 if scan_value == water_value: # 计算水体数据的x,y坐标 off_point = cu.off_transform(j, i, lake_ds, slope_ds) re_xoff = off_point[0] re_yoff = off_point[1] # 若在数据集内 if cu.in_data(re_xoff, re_yoff, slope_ds.RasterXSize, slope_ds.RasterYSize): # 获取结果数据的值 re_data_value = cu.get_raster_int_value(slope_ds, re_xoff, re_yoff) # 若未记录则继续 if re_data_value != water_value: # 新建数组用于记录此水体外边界 water_ol_buf = [] # 结果数据记录水体 cu.set_raster_int_value(slope_ds, re_xoff, re_yoff, water_value) # 使用3*3区域生成水体外包围像元集 buffer_search(j, i, water_ol_buf) # 若有新的水体外边界则记录到集合 if len(water_ol_buf) > 0: # 将此水体的外边界记录到集合中 water_ol_bufs.append(water_ol_buf) print("Sort the extraction of slope surface...") # 对水体的坡面提取排序(由小到大) water_ol_bufs_ordered = [] surface_route_start = water_order(water_ol_bufs, water_ol_bufs_ordered) print("Search slope surface inflow points...") # 搜索水体外边界上坡面像元集合 # 坡面id初始化 # 上游流入点的集合 upstream_inflows = [] for water_ol_buf in water_ol_bufs_ordered: slope_surface_inflows(water_ol_buf, upstream_inflows) print("Merge lakes' slope surface...") # 合并坡面入流口相邻的坡面 s_new_id = 0 for upstream_inflow in upstream_inflows: s_new_id = surface_merge(upstream_inflow, s_new_id) print("Record slope surface route...") # 提取坡面流路 get_surface_route(surface_route_start) print("Clear marks...") # 清除边界线标记 for water_ol_buf in water_ol_bufs_ordered: clear_buffer(water_ol_buf) lake_ds = None dir_ds = None acc_ds = None slope_ds = None route_ds = None print("Extract End")
def clear_buffer(water_buf): global water_buffer_value, no_data_value, slope_ds for cell in water_buf: data_value = cu.get_raster_int_value(slope_ds, cell[0], cell[1]) if data_value == water_buffer_value: cu.set_raster_int_value(slope_ds, cell[0], cell[1], no_data_value)
def watershed_erase_area(dem_tif_path, dir_tif_path, acc_tif_path, stream_tif_path, water_s_s_tif_path, result_path): print("Erasing Mask Area from Dataset") # 获取数据集 dem_old_ds = gdal.Open(dem_tif_path) dir_old_ds = gdal.Open(dir_tif_path) acc_old_ds = gdal.Open(acc_tif_path) stream_old_ds = gdal.Open(stream_tif_path) mask_ds = gdal.Open(water_s_s_tif_path) # 获取无数据标识 dem_no_data = get_nodata_value(dem_old_ds) dir_no_data = get_nodata_value(dir_old_ds) acc_no_data = get_nodata_value(acc_old_ds) stream_no_data = get_nodata_value(stream_old_ds) mask_no_data = get_nodata_value(mask_ds) # 新数据路径 dem_new_path = result_path + "/dem_erase.tif" dir_new_path = result_path + "/dir_erase.tif" acc_new_path = result_path + "/acc_erase.tif" stream_new_path = result_path + "/stream_erase.tif" # 创建结果数据 file_format = "GTiff" driver = gdal.GetDriverByName(file_format) dem_new_ds = driver.CreateCopy(dem_new_path, dem_old_ds) dir_new_ds = driver.CreateCopy(dir_new_path, dir_old_ds) acc_new_ds = driver.CreateCopy(acc_new_path, acc_old_ds) stream_new_ds = driver.CreateCopy(stream_new_path, stream_old_ds) # 剔除掩膜区域处理 for j in range(mask_ds.RasterYSize): for i in range(mask_ds.RasterXSize): mask_data = cu.get_raster_int_value(mask_ds, i, j) if mask_data != mask_no_data: # 处理DEM result_point = cu.off_transform(i, j, mask_ds, dem_new_ds) if cu.in_data(result_point[0], result_point[1], dem_new_ds.RasterXSize, dem_new_ds.RasterYSize): cu.set_raster_float_value(dem_new_ds, result_point[0], result_point[1], dem_no_data) # 处理流向 result_point = cu.off_transform(i, j, mask_ds, dir_new_ds) if cu.in_data(result_point[0], result_point[1], dir_new_ds.RasterXSize, dir_new_ds.RasterYSize): cu.set_raster_int_value(dir_new_ds, result_point[0], result_point[1], int(dir_no_data)) # 处理汇流累积量 result_point = cu.off_transform(i, j, mask_ds, acc_new_ds) if cu.in_data(result_point[0], result_point[1], acc_new_ds.RasterXSize, acc_new_ds.RasterYSize): cu.set_raster_float_value(acc_new_ds, result_point[0], result_point[1], acc_no_data) # 处理河网 result_point = cu.off_transform(i, j, mask_ds, stream_new_ds) if cu.in_data(result_point[0], result_point[1], stream_new_ds.RasterXSize, stream_new_ds.RasterYSize): cu.set_raster_int_value(stream_new_ds, result_point[0], result_point[1], int(stream_no_data)) dem_old_ds = None dir_old_ds = None acc_old_ds = None stream_old_ds = None dem_new_ds = None dir_new_ds = None acc_new_ds = None stream_new_ds = None mask_ds = None return [dem_new_path, dir_new_path, acc_new_path, stream_new_path]