美文网首页我爱编程Geomatics(GIS,GPS,RS,Surveying)基于Android的出租车拼车系统
利用Python从OSM中进行道路点的提取并导出json文件(附

利用Python从OSM中进行道路点的提取并导出json文件(附

作者: 此生望尽天涯路 | 来源:发表于2018-06-16 22:28 被阅读23次

    osm是一个开源地图,数据元素有node、ways、relations。nodes是组成道路网数据的基本元素,它可以组成其它地图结构,如ways道路或者区域;ways是node序列化的数据,ways可以是道路或者是区域,这里我们要用到的node是路的node,所以下面我要做的是如何从osm 的xml格式中提取道路的node。


    图1 点、路、区域

    osm的xml格式数据如下:

    图2 osm的xml格式数据
    从上面图中,我们可以看到,这条way是highway,是公路。
    对osm数据的处理,就是将所有是道路的点给收集起来. 这里我刚刚想起, 能不能先判断是道路,然后再把点添加呢?注意在ways中点是id表示的,所以如果要添加点, 那只能是先把所有的点先存起来形成一个字典.再通过key = id,得到value = {经度、纬度}。这是一种思路,另一种思路是, 先得到所有的点先都添加进来,(注意有些点不是道路上的点),然后把不是道路的点进行剔除。按理来说,这两种方法都是行得通的。所以今天我会依照这两种思路对osm路网数据进行处理。注意这里osm地图是xml格式的,所以需要对其进行Dom/SAX格式解析。需要用到xml.dom.minidom. / xml.parser.expat库。有关对xml格式的处理可以参考前面的博客:python解析xml

    下面是第二种思路,先将所有的点(node)全部添加进来,然后根据不是路的信息将node进行剔除。

    import json
    import xml.dom.minidom
    
    dom = xml.dom.minidom.parse('map_big.osm')
    root = dom.documentElement
    nodelist = root.getElementsByTagName('node')
    waylist = root.getElementsByTagName('way')
    
    node_dic = {}
    
    #统计记录所有node
    for node in nodelist:
        node_id = node.getAttribute('id')
        node_lat = float(node.getAttribute('lat'))
        node_lon = float(node.getAttribute('lon'))
        node_dic[node_id] = (node_lat, node_lon)
    
    print (len(node_dic))
    
    #排除非路node
    for way in waylist:
        taglist = way.getElementsByTagName('tag')
        road_flag = False
        for tag in taglist:
            if tag.getAttribute('k') == 'highway':
                road_flag = True
        if not road_flag:
            ndlist = way.getElementsByTagName('nd')
            for nd in ndlist:
                nd_id = nd.getAttribute('ref')
                if nd_id in node_dic:
                    node_dic.pop(nd_id)
    
    #print len(node_dic)
    
    
    with open('pure_map_big.json', 'w') as fout:
        json.dump(node_dic, fout)
    

    dom对xml的处理,是将文档内容全部加载到内存中,解析形成一棵树,通过对树的操作来对xml数据操作,我们可以调用dom的函数查询或者修改文档内容。它的优点也是它的缺点,正因为所有内容在内存中,所以对于一些大块头的文件,电脑就会吃完内存,然后崩了。


    注:这里的所有元素都可以是多个的。可以通过getElementsByTagName就可以得到。
    至于是不是道路(highway),可以通过tag==highway来判断,然后把不是道路的点并且存在node_list中的点进行剔除。如此操作完成后,剩下的node就是路上的点了。这个工作为以后地图匹配奠定基础。后期会实现由轨迹点映射到路段上,不过我现在更加明晰,路段是由多个这样node组成。

    得到的道路节点数:134447
    第一种思路,只将路上的点添加进来。

    import json
    import xml.dom.minidom
    
    dom = xml.dom.minidom.parse('map_big.osm')
    root = dom.documentElement
    nodelist = root.getElementsByTagName('node')
    waylist = root.getElementsByTagName('way')
    
    node_dic = {}
    
    #统计记录所有node
    for node in nodelist:
        node_id = node.getAttribute('id')
        node_lat = float(node.getAttribute('lat'))
        node_lon = float(node.getAttribute('lon'))
        node_dic[node_id] = (node_lat, node_lon)
    
    node_dic2={}
    #得到路node
    for way in waylist:
        taglist = way.getElementsByTagName('tag')
        road_flag = False
        for tag in taglist:
            if tag.getAttribute('k') == 'highway':
                road_flag = True
                break
        if  road_flag:
            ndlist = way.getElementsByTagName('nd')
            for nd in ndlist:
                nd_id = nd.getAttribute('ref')
                node_lat = node_dic[nd_id][0]
                node_lon = node_dic[nd_id][1]
                node_dic2[nd_id] = (node_lat, node_lon)
    
    print (len(node_dic2))
    
    with open('pure_map_big2.json', 'w') as fout:
        json.dump(node_dic2, fout)
    

    相关资料:
    Python3 字典 in 操作符


    Python3 字典 pop() 方法
    Python3 字典 pop() 方法
    (唉,Python有的地方都忘了,码一下,别又忘了。。)

    上面这两思路的时间复杂度都是相同的。结果不一样。当然,我不是一个个看的,只是大致看了json文件的大小,两个文件不一样,试想一下,哪个大哪个小?要回答这个问题,先看下面这张图。



    node分为三份,左边代表地点等其它点,既不是属于way中的道路点,也不属于way中的非路点。刚开始我以为node就分为两部分,要么是路上的点,要么是非路上的点。所以我以为得到路点和从node中剔除非路点是一样的。实则不然,我应该是漏了一些点,就像左边的点。这里是我想到的。


    上面是dom来解析xml,如果电脑内存吃紧,估计程序跑起来够呛。(我的内存狂升2G),SAX来处理一下。明天更新。

    相关文章

      网友评论

        本文标题:利用Python从OSM中进行道路点的提取并导出json文件(附

        本文链接:https://www.haomeiwen.com/subject/dyobeftx.html