You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何跨时间识别道路几何?——基于OSMNX 0.12匹配阿姆斯特丹不同日期的特定道路路段

匹配不同日期OSM路网中的对应路段:可行方案

当然可以实现!你遇到的节点ID变化问题在OSM历史数据中很常见——路段可能因为编辑(比如节点微调、路段拆分/合并)导致节点或路段ID变更,但空间位置基本不变。下面给你两种实用的解决思路,结合你的代码来落地:

方法1:基于空间特征匹配(最简单直接)

既然两个路段在空间上是同一段路,我们可以通过计算空间重叠度或邻近性来匹配。用GeoPandas的空间分析功能就能快速实现:

步骤:

  1. 提取你关注的1月1日目标路段,统一使用阿姆斯特丹本地投影坐标系(EPSG:28992),避免地理坐标系的距离误差
  2. 计算3月1日路网中每个路段与目标路段的重叠比例,取比例最高的即为对应路段

修改你的代码,加入匹配逻辑:

import osmnx
import datetime
import geopandas as gpd

bbox = (52.36477309990933, 4.897592764542301, 52.369790450504155, 4.912605158495796)
custom_filter = '["area"!~"yes"]'\
'["highway"!~"cycleway|footway|path|pedestrian|steps|track|corridor|proposed|construction|bridleway|abandoned|platform|raceway"]'\
'["motor_vehicle"!~"no"]'\
'["motorcar"!~"no"]'\
'["access"!~"private"]'\
'["service"!~"private|emergency_access"]'
dates_to_query = ["20200101", "20200301"]
road_networks = []
modified_road_segments = []
node_of_interest = 25596477

# 加载两个日期的路网并转换坐标系
for date_to_query in dates_to_query:
    date_to_query = datetime.datetime.strptime(date_to_query, "%Y%m%d").isoformat()
    custom_settings = f"""[out:json][timeout:180][date:"{date_to_query}"]"""
    graph = osmnx.graph_from_bbox(north=bbox[2], south=bbox[0], west=bbox[1], east=bbox[3], custom_settings=custom_settings, custom_filter=custom_filter)
    nodes, road_network_gdf = osmnx.graph_to_gdfs(graph.to_undirected())
    road_network_gdf = road_network_gdf.to_crs(epsg=28992)
    road_networks.append(road_network_gdf)
    modified_road_segments.append(road_network_gdf[ road_network_gdf['u'] == node_of_interest ] )

# 提取1月的目标路段
jan_target = modified_road_segments[0].iloc[0]

# 定义函数计算路段重叠比例
def calculate_overlap(row):
    intersection = jan_target.geometry.intersection(row.geometry)
    if intersection.length == 0:
        return 0
    # 取重叠长度与较短路段长度的比例,更准确反映匹配度
    return intersection.length / min(jan_target.geometry.length, row.geometry.length)

# 计算3月路网中所有路段的重叠比例
march_gdf = road_networks[1]
march_gdf['overlap_ratio'] = march_gdf.apply(calculate_overlap, axis=1)

# 获取匹配的路段(重叠比例最高的)
matching_segment = march_gdf[march_gdf['overlap_ratio'] == march_gdf['overlap_ratio'].max()]
print("匹配到的3月1日路段信息:")
print(matching_segment[['u', 'v', 'osmid', 'geometry']])

这个方法的优势是不需要依赖OSM的历史API,适合批量处理多个路段的匹配。

方法2:基于OSM元素历史追踪(精确溯源)

如果需要精确追踪OSM元素的演变(比如知道路段是否被拆分、合并或修改),可以直接调用OSM的API查询元素的历史版本:

步骤:

  1. 从1月的路段中获取其OSM Way ID(即osmid列的值)
  2. 调用OSM历史API查询该Way的所有版本,找到2020年3月1日对应的版本,或查看是否有替代的Way

示例代码:

import requests
import xml.etree.ElementTree as ET

# 获取1月目标路段的OSM Way ID
jan_way_id = modified_road_segments[0]['osmid'].iloc[0]

# 调用OSM历史API
history_url = f"https://api.openstreetmap.org/api/0.6/way/{jan_way_id}/history"
response = requests.get(history_url)
root = ET.fromstring(response.content)

# 遍历所有版本,找到2020-03-01之前的最新版本
target_date = datetime.datetime(2020, 3, 1)
latest_version = None
for way in root.findall('way'):
    version_date = datetime.datetime.strptime(way.attrib['timestamp'], "%Y-%m-%dT%H:%M:%SZ")
    if version_date <= target_date:
        latest_version = way
        break

if latest_version:
    print(f"目标Way在2020-03-01的版本ID: {latest_version.attrib['version']}")
    # 查看该版本的节点组成
    nodes = [nd.attrib['ref'] for nd in latest_version.findall('nd')]
    print(f"该版本的节点列表: {nodes}")
else:
    print("该Way在2020-03-01已被删除,可能被新的Way替代")

如果原Way被删除,你可以通过查询该区域的历史变更,找到空间位置高度重合的替代Way。

为什么会出现节点ID变化?

OSM的节点和Way ID并非永久不变:

  • 节点可能因为位置微调被删除后重建,导致ID变更
  • 路段(Way)可能被拆分、合并,或编辑时替换了部分节点,导致u/v的节点ID变化
  • 部分编辑操作会直接创建新的Way替代旧的,旧Way被标记为删除

内容的提问来源于stack exchange,提问作者Diana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 04:57:39