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_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
示例#3
0
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 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 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 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])
示例#7
0
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)
示例#8
0
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
示例#9
0
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_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")
示例#11
0
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]