Python处理OpenStreetMap(OSM)数据

问题

做项目的时候发现osm自定义区域导出后,还是会有延伸到区域外的数据,且会影响其他软件导入osm后的锚点,如下图,黑色背景的区域全是多余的数据

推测官网导出的规则为:只要某条道路的其中一部分存在于我们选择的区域内,osm就会导出该条道路包含的全部节点。

这个问题似乎没办法避免,于是想到了用python手动处理一下osm数据,将多余节点删除。

分析

首先进行分析,我们先观察一下osm的数据格式

发现osm数据采用的也是xml格式,所以我们可以使用ElementTree API来处理

我们还能看到,其中第3行bounds正是我们所设置的导出区域范围,而其他node也有它们自己所在的经纬度信息

所以方法很简单:我们先获取到bounds的经纬信息,再用它来遍历所有node做对比,删除经纬度不在范围内的行即可。

注意在所有node列出后,还有一些way块。经过对比可发现,其中子节点nd的ref属性正对应前面node的id属性,说明从这里开始的数据是在引用前面的节点来构成道路。所以我们删了某个node后同样需要到后面把它的引用也删掉,否则后续导入就会报错!

分析完毕,下面直接上代码。

代码

#author:dizzyding
#date:2020/9/16
#verison:python3.8

import xml.etree.ElementTree as xee
 
def osmProcess():
    # 读取文件
    domTree = xee.parse("osm.osm")

    # 获得所有节点的内容
    root = domTree.getroot()

    # 获得所选区域的经纬度范围
    bound = root.findall("bounds")
    maxLat = float(bound[0].get("maxlat"))
    maxLon = float(bound[0].get("maxlon"))
    minLat = float(bound[0].get("minlat"))
    minLon = float(bound[0].get("minlon"))
    # 输出所选区域的经纬度范围
    print('Bounds:' + '\n' + 'minLat: ' + str(minLat) + '\n' + 'maxLat: ' + str(maxLat) + '\n' + 
    'minLon: ' + str(minLon) + '\n' + 'maxLon: ' + str(maxLon) + '\n' +'Nodes: ')

    # 存储不在所选区域内的node ID
    IDlist = []

    # 逐个检查node
    nodes = root.findall("node")
    for node in nodes:
        # 当前节点的经纬度和ID
        Lat = float(node.get("lat"))
        Lon = float(node.get("lon"))
        ID = node.get("id")
        #输出node信息
        print('nodeID:' + ID + ', Lat:' + str(Lat) + ', Lon:' + str(Lon) + ', Bound: ' , end='')
        # 判断
        if Lat < minLat or Lat > maxLat or Lon < minLon or Lon > maxLon:
            root.remove(node)
            IDlist.append(ID)
            #输出bound比对情况,若Lat和Lon均不符合则只输出Lat
            if Lat < minLat:
                print('Lat < min')
            elif Lat > maxLat:
                print('Lat > max')
            elif Lon < minLon:
                print('Lon < min')
            elif Lon > maxLon:
                print('Lon > max')
        else:
            print('Satisfied')

    # 删除不在所选区域内的node在后续道路的参照行
    ways = root.findall("way")
    for ID in IDlist:
        for way in ways:
            refnodes = way.findall("nd")
            for node in refnodes:
                if node.get("ref") == ID:
                    way.remove(node)

    # 输出文件
    domTree.write("out.osm",encoding="utf8")
 
if __name__=="__main__":
    osmProcess()

效果

运行完后效果是这样的,超出的节点全被干掉了

丢进Houdini里也能直接居中对齐了,不用再手动调参数

### 使用PythonOpenStreetMap获取数据 为了从OpenStreetMap (OSM) 获取地理空间数据处理这些数据,通常会采用 `osmnx` 或者 `geopandas` 库来简化操作过程。下面介绍一种利用 `osmnx` 来下载 OSM 数据的方式。 #### 安装所需库 首先安装必要的 Python 包: ```bash pip install osmnx geopandas matplotlib ``` #### 下载特定区域的数据 通过定义地理位置边界框或指定地点名称,可以从 OSM 中提取道路网络或其他基础设施信息。这里展示了一个简单的例子,它展示了如何基于位置名下载步行路径网,并绘制出来[^1]。 ```python import osmnx as ox place_name = "Piedmont, California, USA" graph = ox.graph_from_place(place_name, network_type='walk') fig, ax = ox.plot_graph(graph) ``` 这段代码将会创建一个图形对象 (`graph`) 表示所选地区的行走路线图,并将其可视化显示在一个图表里。 对于更复杂的需求,比如想要获取 POI(兴趣点)、建筑物轮廓或者其他类型的要素,则可以根据具体需求调整参数设置。例如,如果要检索某城市的全部餐馆位置,可以这样做: ```python tags = {'amenity': 'restaurant'} gdf = ox.geometries_from_place('New York City', tags=tags) print(gdf[['name', 'addr:full']]) ``` 此段脚本将返回纽约市内所有标记为餐厅的兴趣点及其地址字段的信息列表。 另外,在某些情况下可能还需要访问原始的 OSM XML 文件或是数据库中的表结构;这时就需要借助像 `osm2pgsql` 这样的工具先导入数据至 PostgreSQL/PostGIS 环境下再进一步分析[^3]。 最后值得注意的是,当涉及到大量请求时应当遵循 OSM 的使用条款以及速率限制规定,以免给服务器带来过重负担。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TakiDing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值