我爱编程Geomatics(GIS,GPS,RS,Surveying)基于Android的出租车拼车系统

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

2018-06-16  本文已影响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来处理一下。明天更新。

上一篇下一篇

猜你喜欢

热点阅读