利用Arcpy筛选孤立图斑并批量更改其属性

生态系统分类在自动化分类过程中“针叶”和“阔叶”可能会出现错分的情况,Arcgis自带的栅格计算器和按属性选择具有简单易操作等特点,但是对于广域面积范围,多条件,批量筛选和更改等操作显得力不从心。利用Arcgis自带的python库(Arcpy)能够实现批量筛选和更改。

本文以某地区森林生态系统分类为案例,借助于Arcgis Pro3.0.2提供的Python3.9对分类中出现的孤立图斑进行修改。


一、数据源

本文使用的数据源包含2020年自动化分类后的图斑和2000年自动化分类的图斑(分辨率:90m)。


二、数据预处理

1. 配准

以2020年分类后的图斑为基准,将2000年分类后的影像配准到2020影像空间。

2. 做差

对2000年影像和2020年影像进行做差处理,得到差值后的影像。

3. 重分类

对做差后的影像进行重分类,分为变化影像和未变化影像。

4. 栅格转矢量

分别对差值后的影像进行栅格转矢量操作,用以数据处理。


三、数据处理

1. 整体思路

① 设置面积阈值,筛选出带有“针叶”和“阔叶”的孤立图斑。

② 计算孤立图斑周围一定范围内面积最大并带有“针叶”或者“阔叶”的图斑并筛选出来。

③ 将筛选出来面积最大图斑的分类属性赋值给孤立图斑,即达到了更改孤立图斑分类属性的效果。

整体的流程图如下:

2. isolated_change算法实现

import arcpy

# 设置环境参数
arcpy.env.workspace = "./workspace"
arcpy.env.overwriteOutput = True

# 加载Shapefile文件
input_shp_changed = "./result/changed_result.shp"
input_shp_unchanged = "./result/unchanged_result.shp"

# 创建一个文本文件用于输出过程变量
file = "./isolated_maxarea.txt"

# 获取changed图斑的特定字段
# 若获取所有字段,用["*"]
# "AREA < 10000"为SQL语句,筛选出面积小于10000的图斑
features_changed = arcpy.da.UpdateCursor(input_shp_changed, ["OID@", "SHAPE@", "CLASS", "AREA"], "AREA < 10000")

# 遍历每个图斑
with open(file, 'w', encoding = "utf-8") as f:
    for feature_changed in features_changed:
        oid_changed = feature_changed[0]
        shape_changed = feature_changed[1]
        classify_changed = feature_changed[2]
        
        # 筛选出字段里带有“阔叶”或者“针叶”的图斑
        if "阔叶" in classify_changed or "针叶" in classify_changed:

            # 要用到的arcpy.SelectLayerByLocation_management接口需要输入图层文件,将要查询的文件转换成图层
            arcpy.MakeFeatureLayer_management(input_shp_unchanged, "unchanged_lyr")
            
            # 设置查找的距离为500米
            adjacent_features = arcpy.SelectLayerByLocation_management("unchanged_lyr", "WITHIN_A_DISTANCE", shape_changed, "500 Meters")

            # 找出500米范围内面积最大的图斑
            # 一般这里使用max_area = 0, max_feature = None来初始化变量,但可能会出现"Int, None Type"不可迭代的情况,所以这里使用孤立图斑本身来初始化
            max_area = feature_changed[3]
            max_feature = feature_changed[0]
            max_classify = feature_changed[2]
            adjacent_features_cursor = arcpy.da.SearchCursor(adjacent_features, ["OID@", "AREA", "CLASS"])
            for adjacent_feature in adjacent_features_cursor:
                adjacent_oid = adjacent_feature[0]
                adjacent_area = adjacent_feature[1]
                adjacent_classify = adjacent_feature[2]
                if adjacent_area > max_area:
                    max_area = adjacent_area
                    max_feature = adjacent_oid
                    max_classify = adjacent_classify
            
            # 利用强制换行导出孤立图斑及其对应面积最大的图斑,用以检验代码运行的结果
            f.write(f"{oid_changed, classify_changed, max_feature, max_classify, max_area}\n")

            # 对孤立图斑进行更改,注意这里的缩进要在上面的if "阔叶" ~~~之后,这样才会对带有“阔叶”和“针叶”的图斑进行更改
            if "阔叶" in max_classify or "针叶" in max_classify:
                feature_changed[2] = max_classify
                features_changed.updateRow(feature_changed)

四、代码运行结果

共找到70073个孤立图斑及其对应的面积最大的图斑:

 打开更改前和更改后的矢量文件,结果如下:

与生成的txt文件对应,更改成功!


五、代码优化

此代码总共检索50多万个图斑,最终对7万多个图斑进行更改,总共耗时3个多小时,笔者对该代码进行更改,但使用了更多的循环和嵌套,运行速度远不如之前的代码,有感兴趣的可以对其进行优化(将找出临近图斑的最大面积封装成一个函数也是个不错的想法),附上代码如下:

import arcpy

arcpy.env.workspace = "./workspace"
arcpy.env.overwriteOutput = True

input_shp_changed = "./result/changed_result.shp"
input_shp_unchanged = "./result/unchanged_result.shp"

file = "./temp.txt"

with open(file, "w", encoding="utf-8") as f:

    with arcpy.da.SearchCursor(input_shp_changed, ["OID@", "SHAPE@", "CLASS", "AREA"], "AREA < 10000") as changed_cursor:
        for changed_row in changed_cursor:
            if "阔叶" in changed_row[2] or "针叶" in changed_row[2]:
                arcpy.MakeFeatureLayer_management(input_shp_unchanged, "unchanged_lyr")
                adjacent_features = arcpy.SelectLayerByLocation_management("unchanged_lyr", "WITHIN_A_DISTANCE", changed_row[1], "500 Meters")
                max_area = changed_row[3]
                max_feature = changed_row[0]
                max_classify = changed_row[2]
                adjacent_features_cursor = arcpy.da.SearchCursor(adjacent_features, ["OID@", "CLASS", "AREA"])
                for adjacent_feature in adjacent_features_cursor:
                    adjacent_oid = adjacent_feature[0]
                    adjacent_area = adjacent_feature[2]
                    adjacent_classify = adjacent_feature[1]
                    if adjacent_feature[2] > max_area:
                        max_area = adjacent_feature[2]
                        max_feature = adjacent_feature[0]
                        max_classify = adjacent_feature[1]
                f.write(f"{changed_row[0], changed_row[2], adjacent_feature[0], adjacent_feature[1], adjacent_feature[2]}\n")

                if "阔叶" in max_classify or "针叶" in max_classify:
                    feature_changed[2] = max_classify
                    features_changed.updateRow(feature_changed)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值