FMM 笔记:在colab上执行FMM

windows上配置FMM很麻烦,一直没整好,于是尝试了在colab上执行FMM

参考内容:jalal1/fmm_jupyter: Install Fast map matching (FMM) using Jupyter Notebook (github.com)

1 下载数据

# download file from GitHub
! wget https://raw.githubusercontent.com/jalal1/fmm_jupyter/master/data/100_trajectories.txt

'''
--2024-02-26 06:55:39--  https://raw.githubusercontent.com/jalal1/fmm_jupyter/master/data/100_trajectories.txt
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 25479 (25K) [text/plain]
Saving to: ‘100_trajectories.txt.1’

100_trajectories.tx 100%[===================>]  24.88K  --.-KB/s    in 0.002s  

2024-02-26 06:55:39 (14.5 MB/s) - ‘100_trajectories.txt.1’ saved [25479/25479]
'''
!head /content/100_trajectories.txt
'''
Participant2_2019_March2019_Shot0140.jpg:33.509364058739486 -86.78954869584962,33.50978487475548 -86.78860322799623,33.51365016246786 -86.792410503766
Participant2_2019_May2019_Shot0142.jpg:33.51094614347225 -86.78923299192616,33.509571534630986 -86.78998517826301,33.51938097370663 -86.79837386198179,33.50822037079172 -86.82131054613122,33.51100887200205 -86.82332334728943,33.51131870158742 -86.83317062553503
Participant2_2019_November2019_Shot0127.jpg:33.50679887410579 -86.80424681374738,33.51400856087657 -86.80915731051758,33.51335332100002 -86.81056606651244,33.51288259528744 -86.81025033563954
Participant2_2019_November2019_Shot0198.jpg:33.51188921624417 -86.78723301871021,33.509581833511554 -86.79156995015465,33.48366945634628 -86.78709029437786,33.4661537869968 -86.76220036737358
Participant2_2019_November2019_Shot0267.jpg:33.49995290121026 -86.79772386799166,33.50518863176492 -86.80128439451919,33.51110099859621 -86.78887415090277,33.51283854022087 -86.79006323287805
Participant2_2019_October2019_Shot0187.jpg:33.431744652524394 -86.78865692928392,33.41219602478363 -86.80614290578389,33.39369496042756 -86.78484564702798,33.44019957219545 -86.73004735468466,33.432929592595286 -86.71506989666614,33.42762893295855 -86.71850312293473
Participant2_2019_October2019_Shot0260.jpg:33.51279925614481 -86.79913689098413,33.503445430924174 -86.81408181202305,33.520344991596886 -86.82636479131318,33.51047914218212 -86.87755295215898,33.51026907691468 -86.86043852784368
Participant2_2019_October2019_Shot0332.jpg:33.51122148954738 -86.78863346669883,33.504151067453506 -86.80345417768335
Participant2_2019_September2019_Shot0144.jpg:33.51200390143716 -86.78691735071938,33.50896338168748 -86.79209170963797,33.491358620011404 -86.78773912055813,33.48207783715377 -86.81082652404592,33.481094654107274 -86.8041556616955
Participant2_2019_September2019_Shot0216.jpg:33.488167281458445 -86.80800831137027,33.4910545025647 -86.80109811986188,33.4971313972488 -86.8035525597632,33.49960965872394 -86.79837052923209
'''

1.1 预处理数据

import os
raw_trajectories = []

with open('/content/100_trajectories.txt', 'r') as f:
    for line in f:
      line_values = line.split(":")
      traj = line_values[1]
      #去掉trajectories每一行前面的.jpg部分

      raw_trajectory = []
      for x in traj.split(','):
        #每一个逗号分割的是一组经纬度

        lat, lon = x.split(" ")
        #将每一个经纬度record 分成经度 & 纬度

        raw_trajectory.append((float(lat), float(lon)))

      raw_trajectories.append(raw_trajectory)

print("Number of trajectories: ", len(raw_trajectories))
#Number of trajectories:  100

2 在colab上安装FMM

# Install all the requirements with:
! sudo apt-get install libboost-dev libboost-serialization-dev \
gdal-bin libgdal-dev make cmake libbz2-dev libexpat1-dev swig python-dev-is-python3


!git clone https://github.com/cyang-kth/fmm.git


import os
# change working directory
os.chdir("fmm")

if not os.path.exists('build'):
  os.mkdir('build')
# ! mkdir build
os.chdir("build")
# ! cd build
! cmake ..
! make -j4
! sudo make install

2.1 验证是否安装成功

# Verfication of installation
!fmm
'''
[info][fmm_app_config.cpp:49 ] Start reading FMM configuration from arguments
fmm argument lists:
--ubodt (required) <string>: Ubodt file name
--network (required) <string>: Network file name
--network_id (optional) <string>: Network id name (id)
--source (optional) <string>: Network source name (source)
--target (optional) <string>: Network target name (target)
--gps (required) <string>: GPS file name
--gps_id (optional) <string>: GPS id name (id)
--gps_x (optional) <string>: GPS x name (x)
--gps_y (optional) <string>: GPS y name (y)
--gps_timestamp (optional) <string>: GPS timestamp name (timestamp)
--gps_geom (optional) <string>: GPS geometry name (geom)
--gps_point (optional): if specified read input data as gps point, otherwise (default) read input data as trajectory
--output (required) <string>: Output file name
--output_fields (optional) <string>: Output fields
  opath,cpath,tpath,mgeom,pgeom,
  offset,error,spdist,tp,ep,length,duration,speed,all
-k/--candidates (optional) <int>: Number of candidates (8)
-r/--radius (optional) <double>: search radius (network data unit) (300)
-e/--error (optional) <double>: GPS error (network data unit) (50)
--reverse_tolerance (optional) <double>: proportion of reverse movement allowed on an edge
-l/--log_level (optional) <int>: log level (2)
-s/--step (optional) <int>: progress report step (100)
--use_omp: use OpenMP for multithreaded map matching
-h/--help:print help information
For xml configuration, check example folder
'''
# Change to the parent folder which contains fmm_test.py
if os.getcwd() != "/content/fmm/example/python":
  os.chdir("/content/fmm/example/python")
os.system('python fmm_test.py')
#256

3 在colab上安装其他需要的包

!pip install osmnx

! pip install folium

4 从OSM中提取需要的shp文件

osmnx笔记:从OpenStreetMap中提取点和边的shp文件(FMM文件准备内容)-CSDN博客

import osmnx as ox
import time
from shapely.geometry import Polygon
import os
import numpy as np
from fmm import Network,NetworkGraph,STMATCH,STMATCHConfig

def save_graph_shapefile_directional(G, filepath=None, encoding="utf-8"):
    if filepath is None:
        filepath = os.path.join(ox.settings.data_folder, "graph_shapefile")
    #保存shp文件的默认路径

    
    if not filepath == "" and not os.path.exists(filepath):
        os.makedirs(filepath)
    #如果文件保存路径不存在,那么创建之

    filepath_nodes = os.path.join(filepath, "nodes.shp")
    filepath_edges = os.path.join(filepath, "edges.shp")
    #点和边shp文件的保存路径

    gdf_nodes, gdf_edges = ox.utils_graph.graph_to_gdfs(G)
    #提取graph中的点和边

    gdf_nodes = ox.io._stringify_nonnumeric_cols(gdf_nodes)
    gdf_edges = ox.io._stringify_nonnumeric_cols(gdf_edges)
    # 将点和边的geoDataFrame中非数值的部分转化成字符串

    
    gdf_edges["fid"] = np.arange(0, gdf_edges.shape[0], dtype='int')
    #每一条边一个id
    
    gdf_nodes.to_file(filepath_nodes, encoding=encoding)
    gdf_edges.to_file(filepath_edges, encoding=encoding)
    #保存边和点的shp文件
bounds = (-86.9671,-86.5901,33.3472,33.6598)

x1,x2,y1,y2 = bounds
boundary_polygon = Polygon([(x1,y1),(x2,y1),(x2,y2),(x1,y2)])
G = ox.graph_from_polygon(boundary_polygon, network_type='drive')
#用ox.graph_from_bbox也可以

save_graph_shapefile_directional(G, filepath='./network-new')
!mv '/content/network-new' '/content/fmm/example/python/network-new'

5 进行地图匹配(st-matching)

论文笔记:Map-Matching for low-sampling-rate GPS trajectories(ST-matching)-CSDN博客

def match(path,points):
  network = Network(path,"fid","u","v")
  #边的shp文件,后面的三个参数分别是边的id index, source index, target index
  graph = NetworkGraph(network)
  
  print (graph.get_num_vertices())
  #图有多少个点
  #后续输出的结果是:32303

  model = STMATCH(network,graph)
  #创建一个st-matching算法模型对象,使用前面创建的network和graph作为参数
  
  wkt  = str(points)
  #将points参数转换为字符串格式,这里points是以WKT(Well-Known Text)格式表示的点集合
  

  '''
  通过STMATCHConfig为st-matching算法配置对象
  '''
  config = STMATCHConfig()
  config.k = 4
  #k——candidate的数量
  config.gps_error = 0.5
  #gps误差
  config.radius = 0.4
  #搜索半径
  config.vmax = 30
  #最大速度为30,这个参数用于限制匹配算法中考虑的最大速度
  config.factor =1.5
  #st-matching的因子为1.5


  result = model.match_wkt(wkt,config)
  #调用STMATCH模型的match_wkt方法,传入WKT格式的点集合和配置对象,进行地图匹配
  

  print (type(result))
  print ("Opath ",list(result.opath))
  print ("Cpath ",list(result.cpath))
  print ("WKT ",result.mgeom.export_wkt())
  '''
  打印:
  匹配结果对象的类型——<class 'fmm.PyMatchResult'>
  原始路径(opath)——Opath  [70255, 48283, 56497]
  修正路径(cpath)——Cpath  [70255, 48282, 48283, 48621, 48285, 48281, 42749, 40410, 31151, 56497]
  匹配结果的WKT格式几何(mgeom)——WKT  LINESTRING(-86.789547 33.50936,-86.789539 33.509363,-86.789062 33.509602,-86.788979 33.509635,-86.788736 33.509737,-86.788613 33.509786,-86.788736 33.509737,-86.788979 33.509635,-86.789062 33.509602,-86.789539 33.509363,-86.789591 33.509442,-86.789787 33.509709,-86.789832 33.50977,-86.789942 33.509946,-86.790265 33.510457,-86.790654 33.511026,-86.79103 33.511605,-86.791425 33.512179,-86.791805 33.512752,-86.792107 33.513209,-86.792414 33.513648)

  '''


  return result.mgeom.export_wkt()
  #返回匹配结果的WKT格式几何,这是一个字符串表示的几何形状
def match_trajs(network_path, traj):
  """
  match [traj] on [network_path]. [traj] should be [(lon1, lat1), (lon2, lat2), ...]
  Output: matched traj as "LINESTRING(-86.797211 33.499194, -86.7973..."
  """
  from shapely.geometry import LineString
  

  traj_ = LineString(traj)
  #创建一个 LineString 对象 traj_,将输入的轨迹点 traj 转换成LineString
  
  return match(network_path, traj_)
  '''
  调用之前定义的 match 函数,将路网数据的路径 network_path 和转换后的轨迹几何对象 traj_ 作为参数传入。
  这个函数的目的是执行地图匹配过程,并返回匹配后的轨迹(作为WKT格式的 LINESTRING)
  '''
import csv
from shapely.geometry import Point
from collections import defaultdict

edges_path = '/content/fmm/example/python/network-new/edges.shp'

matched_trajectories = []

# !! FMM the first x values !! 
x = 10
#进行多少条轨迹的快速地图匹配

for traj in raw_trajectories[:x]:
  #遍历原始轨迹列表 raw_trajectories 的前 x条轨迹
  
  # swap (lat, lon) --> (lon, lat) as FMM requires lon before lat
  traj_m = [(sub[1], sub[0]) for sub in traj]

  fmm_traj = match_trajs('/content/fmm/example/python/network-new/edges.shp', traj_m)
  #使用 match_trajs 函数将转换后的轨迹与路网进行匹配。match_trajs 函数需要路网数据文件的路径和轨迹点列表作为参数。
  print('fmm_traj',fmm_traj)
  #fmm_traj LINESTRING(-86.789547 33.50936,-86.789539 33.509363,-86.789062 33.509602,-86.788979 33.509635,-86.788736 33.509737,-86.788613 33.509786,-86.788736 33.509737,-86.788979 33.509635,-86.789062 33.509602,-86.789539 33.509363,-86.789591 33.509442,-86.789787 33.509709,-86.789832 33.50977,-86.789942 33.509946,-86.790265 33.510457,-86.790654 33.511026,-86.79103 33.511605,-86.791425 33.512179,-86.791805 33.512752,-86.792107 33.513209,-86.792414 33.513648)

  # remove LINESTRING and extra parentheses
  fmm_traj = fmm_traj.split("LINESTRING(")[1]
  fmm_traj = fmm_traj.split(")")[0]

  traj_list = []
  #初始化一个空列表 traj_list,用于存储处理后的轨迹点
  for lon_lat in fmm_traj.split(','):
    lon__lat = lon_lat.split(" ")
    # print(lon__lat)
    if len(lon__lat) == 2:
      traj_list.append((float(lon__lat[1]), float(lon__lat[0])))
    else:
      print("!! lon and lat should be 2 !!", lon__lat)
  matched_trajectories.append(traj_list)
  #将处理后的轨迹 traj_list 添加到 matched_trajectories 列表中

6 可视化匹配结果

6.1 单条结果

import random
import folium

map = folium.Map(zoom_start=13, height=700, location=[33.5186, -86.8104])

# choose random trajectory to plot
x = random.randrange(len(matched_trajectories))
#随机选择一个id

# original trajectory
folium.PolyLine(raw_trajectories[x], color='red', radiuses=2, connect=True).add_to(map)
# matched trajectory
folium.PolyLine(matched_trajectories[x], color='green', radiuses=2, connect=True).add_to(map)

map

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

UQI-LIUWJ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值