def test_path_outlier2(): path = [(0.8, 0.7), (0.9, 0.7), (1.1, 1.0), (1.2, 1.5), (1.2, 1.6), (1.1, 2.0), (1.1, 2.3), (1.3, 2.9), (1.2, 3.1), (1.5, 3.2), (1.8, 3.5), (2.0, 3.7), (2.1, 3.3), (2.4, 3.2), (2.6, 3.1), (2.9, 3.1), (3.0, 3.2), (3.1, 3.8), (3.0, 4.0), (3.1, 4.3), (3.1, 4.6), (3.0, 4.9)] path.insert(13, (2.3, -3.0)) mapdb = InMemMap("map", graph={ "A": ((1, 1), ["B", "C", "X"]), "B": ((1, 3), ["A", "C", "D", "K"]), "C": ((2, 2), ["A", "B", "D", "E", "X", "Y"]), "D": ((2, 4), ["B", "C", "F", "E", "K", "L"]), "E": ((3, 3), ["C", "D", "F", "Y"]), "F": ((3, 5), ["D", "E", "L"]), "X": ((2, 0), ["A", "C", "Y"]), "Y": ((3, 1), ["X", "C", "E"]), "K": ((1, 5), ["B", "D", "L"]), "L": ((2, 6), ["K", "D", "F"]) }, use_latlon=False) matcher = DistanceMatcher(mapdb, max_dist=None, min_prob_norm=0.1, max_dist_init=1, obs_noise=0.25, obs_noise_ne=1, non_emitting_states=True) _, last_idx = matcher.match(path, unique=True) if directory: # matcher.print_lattice_stats() # matcher.print_lattice() from leuvenmapmatching import visualization as mmviz # with (directory / 'lattice.gv').open('w') as ofile: # matcher.lattice_dot(file=ofile) mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True, filename=str(directory / "test_path_outlier2.png")) assert last_idx == 12
def test_path_outlier_dist(): path = [(0.8, 0.7), (0.9, 0.7), (1.1, 1.0), (1.2, 1.5), (1.2, 1.6), (1.1, 2.0), (1.1, 2.3), (1.3, 2.9), (1.2, 3.1), (1.5, 3.2), (1.8, 3.5), (2.0, 3.7), (2.1, 3.3), (2.4, 3.2), (2.6, 3.1), (2.9, 3.1), (3.0, 3.2), (3.1, 3.8), (3.0, 4.0), (3.1, 4.3), (3.1, 4.6), (3.0, 4.9)] path_sol = ['A', 'B', 'D', 'C', 'E', 'F'] path.insert(13, (2.3, 1.8)) mapdb = InMemMap("map", graph={ "A": ((1, 1), ["B", "C", "X"]), "B": ((1, 3), ["A", "C", "D", "K"]), "C": ((2, 2), ["A", "B", "D", "E", "X", "Y"]), "D": ((2, 4), ["B", "C", "F", "E", "K", "L"]), "E": ((3, 3), ["C", "D", "F", "Y"]), "F": ((3, 5), ["D", "E", "L"]), "X": ((2, 0), ["A", "C", "Y"]), "Y": ((3, 1), ["X", "C", "E"]), "K": ((1, 5), ["B", "D", "L"]), "L": ((2, 6), ["K", "D", "F"]) }, use_latlon=False) matcher = DistanceMatcher(mapdb, max_dist=None, min_prob_norm=0.0001, max_dist_init=1, obs_noise=0.5, obs_noise_ne=10, non_emitting_states=True) matcher.match(path) path_pred = matcher.path_pred_onlynodes if directory: from leuvenmapmatching import visualization as mmviz mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True, show_graph=True, filename=str(directory / "test_path_outlier_dist.png")) # TODO: Smoothing the observation distances could eliminate the outlier assert path_pred == path_sol, "Nodes not equal:\n{}\n{}".format(path_pred, path_sol)
def test_path3_dist(): path = [(3.0, 3.2), (3.1, 3.8), (3.0, 4.0), (3.1, 4.3), (3.1, 4.6), (3.0, 4.9)] path_sol = ['E', 'F'] mapdb = InMemMap("map", graph={ "E": ((3, 3), ["F"]), "F": ((3, 5), ["E"]), }, use_latlon=False) matcher = DistanceMatcher(mapdb, max_dist=None, min_prob_norm=0.0001, max_dist_init=1, obs_noise=0.25, obs_noise_ne=10, non_emitting_states=True) matcher.match(path, unique=True) path_pred = matcher.path_pred_onlynodes if directory: from leuvenmapmatching import visualization as mmviz mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True, filename=str(directory / "test_path3_dist.png")) print("Path through lattice:\n" + "\n".join(m.label for m in matcher.lattice_best)) assert path_pred == path_sol, "Nodes not equal:\n{}\n{}".format( path_pred, path_sol)
def test_route_slice1(): if directory: import matplotlib.pyplot as plt # load path, map and route from database nodes, map_con, route = load_data() # zoom_path = True # get a slice of route route_slice = route[2657:2662] # init matcher object matcher = DistanceMatcher(map_con, min_prob_norm=0.001, max_dist=200, dist_noise=6, dist_noise_ne=12, obs_noise=30, obs_noise_ne=150, non_emitting_states=True) # matching matcher.match(route_slice) path_pred = matcher.path_pred_onlynodes path_sol = [ 172815, 172816, 172817, 172818, 172819, 172820, 172821, 172822, 172823, 172824, 172825, 172826, 172827, 172828, 172829, 172830, 884148100261, 172835, 172836, 172837, 884148100254, 172806, 884148100255, 172807 ] # Can change when building db assert len(path_pred) == len(path_sol)
def test_path1_full(): prepare_files() track = gpx_to_path(track_fn) track = [loc[:2] for loc in track] track_int = interpolate_path(track, 5) map_con = create_map_from_xml(osm_fn, include_footways=True, include_parking=True) matcher = DistanceMatcher(map_con, max_dist=50, obs_noise=50, min_prob_norm=0.1) states, last_idx = matcher.match(track_int) if directory: # matcher.print_lattice_stats() mm_viz.plot_map(map_con, matcher=matcher, use_osm=True, zoom_path=True, show_graph=True, filename=str(directory / "test_path_latlon_path1.png")) assert len(states) == len(track_int), f"Path ({len(track_int)}) not fully matched by best path ({len(states)}), " + \ f"last index = {last_idx}"
def test_path1_dist(): path = [(0.8, 0.7), (0.9, 0.7), (1.1, 1.0), (1.2, 1.5), (1.2, 1.6), (1.1, 2.0), (1.1, 2.3), (1.3, 2.9), (1.2, 3.1), (1.5, 3.2), (1.8, 3.5), (2.0, 3.7), (2.1, 3.3), (2.4, 3.2), (2.6, 3.1), (2.9, 3.1), (3.0, 3.2), (3.1, 3.8), (3.0, 4.0), (3.1, 4.3), (3.1, 4.6), (3.0, 4.9)] # path_sol = ['A', ('A', 'B'), 'B', ('B', 'D'), 'D', ('D', 'E'), 'E', ('E', 'F')] path_sol_nodes = ['A', 'B', 'D', 'E', 'F'] mapdb = InMemMap("map", graph={ "A": ((1, 1), ["B", "C"]), "B": ((1, 3), ["A", "C", "D"]), "C": ((2, 2), ["A", "B", "D", "E"]), "D": ((2, 4), ["B", "C", "D", "E"]), "E": ((3, 3), ["C", "D", "F"]), "F": ((3, 5), ["D", "E"]) }, use_latlon=False) matcher = DistanceMatcher(mapdb, max_dist=None, min_prob_norm=None, obs_noise=0.5, non_emitting_states=False) matcher.match(path) if directory: from leuvenmapmatching import visualization as mmviz mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True, filename=str(directory / "test_path1_dist.png")) nodes_pred = matcher.path_pred_onlynodes assert nodes_pred == path_sol_nodes, f"Nodes not equal:\n{nodes_pred}\n{path_sol_nodes}"
def test_path1_dist(): mapdb, path1, path2, path_sol = setup_map() matcher = DistanceMatcher(mapdb, max_dist_init=1, min_prob_norm=0.5, obs_noise=0.5, non_emitting_states=True, only_edges=True) matcher.match(path1, unique=True) path_pred = matcher.path_pred_onlynodes if directory: from leuvenmapmatching import visualization as mmviz matcher.print_lattice_stats() matcher.print_lattice() print("LATTICE BEST") for m in matcher.lattice_best: print(m) with (directory / 'lattice_path1.gv').open('w') as ofile: matcher.lattice_dot(file=ofile) mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True, show_graph=True, filename=str(directory / "test_nonemitting_test_path1_dist.png")) assert path_pred == path_sol, f"Nodes not equal:\n{path_pred}\n{path_sol}"
def test_bug2(): this_path = Path(os.path.realpath(__file__)).parent / "rsrc" / "bug2" edges_fn = this_path / "edgesrl.csv" nodes_fn = this_path / "nodesrl.csv" path_fn = this_path / "path.csv" logger.debug(f"Reading map ...") mmap = SqliteMap("road_network", use_latlon=True, dir=this_path) path = [] with path_fn.open("r") as path_f: reader = csv.reader(path_f, delimiter=',') for row in reader: lat, lon = [float(coord) for coord in row] path.append((lat, lon)) node_cnt = 0 with nodes_fn.open("r") as nodes_f: reader = csv.reader(nodes_f, delimiter=',') for row in reader: nid, lonlat, _ = row nid = int(nid) lon, lat = [float(coord) for coord in lonlat[1:-1].split(",")] mmap.add_node(nid, (lat, lon), ignore_doubles=True, no_index=True, no_commit=True) node_cnt += 1 edge_cnt = 0 with edges_fn.open("r") as edges_f: reader = csv.reader(edges_f, delimiter=',') for row in reader: _eid, nid1, nid2, pid = [int(val) for val in row] mmap.add_edge(nid1, nid2, edge_type=0, path=pid, no_index=True, no_commit=True) edge_cnt += 1 logger.debug(f"... done: {node_cnt} nodes and {edge_cnt} edges") logger.debug("Indexing ...") mmap.reindex_nodes() mmap.reindex_edges() logger.debug("... done") matcher = DistanceMatcher(mmap, min_prob_norm=0.001, max_dist=200, obs_noise=4.07, non_emitting_states=True) # path = path[:2] nodes, idx = matcher.match(path, unique=True) path_pred = matcher.path_pred if directory: import matplotlib.pyplot as plt matcher.print_lattice_stats() logger.debug("Plotting post map ...") fig = plt.figure(figsize=(100, 100)) ax = fig.get_axes() mm_viz.plot_map(mmap, matcher=matcher, use_osm=True, ax=ax, show_lattice=False, show_labels=True, show_graph=False, zoom_path=True, show_matching=True) plt.savefig(str(directory / "test_bug1.png")) plt.close(fig) logger.debug("... done")
def map_matching_osm(): track = gpx_to_path("mytrack.gpx") matcher = DistanceMatcher( map_con, max_dist=100, max_dist_init=25, # meter min_prob_norm=0.001, non_emitting_length_factor=0.75, obs_noise=50, obs_noise_ne=75, # meter dist_noise=50, # meter non_emitting_states=True) states, lastidx = matcher.match(track) return
def dis_matcher(map_con, track): matcher = DistanceMatcher(map_con, max_dist=200, min_prob_norm=0.0001, non_emitting_length_factor=0.5, obs_noise=10, obs_noise_ne=10, dist_noise=100, max_lattice_width=5, avoid_goingback=True, non_emitting_states=True) states, last_idx = matcher.match(track) nodes = matcher.path_pred_onlynodes return matcher, nodes
def test_path2_proj(): prepare_files() map_con_latlon = create_map_from_xml(osm2_fn) map_con = map_con_latlon.to_xy() track = [map_con.latlon2yx(p[0], p[1]) for p in gpx_to_path(track2_fn)] matcher = DistanceMatcher(map_con, max_dist=300, max_dist_init=25, min_prob_norm=0.0001, non_emitting_length_factor=0.95, obs_noise=50, obs_noise_ne=50, dist_noise=50, max_lattice_width=5, non_emitting_states=True) states, last_idx = matcher.match(track, unique=False) nodes = matcher.path_pred_onlynodes if directory: matcher.print_lattice_stats() mm_viz.plot_map(map_con, matcher=matcher, path=track, use_osm=False, show_graph=True, show_matching=True, show_labels=5, filename=str(directory / "test_path_latlon_path2_proj.png")) nodes_sol = [ 2634474831, 1096512242, 3051083902, 1096512239, 1096512241, 1096512240, 1096508366, 1096508372, 16483861, 1096508360, 159656075, 1096508382, 16483862, 3051083898, 16526535, 3060597381, 3060515059, 16526534, 16526532, 1274158119, 16526540, 3060597377, 16526541, 16424220, 1233373340, 613125597, 1076057753 ] nodes_sol2 = [ 1096512242, 3051083902, 1096512239, 1096512241, 1096512240, 159654664, 1096508373, 1096508381, 16483859, 1096508369, 159654663, 1096508363, 16483862, 3051083898, 16526535, 3060597381, 3060515059, 16526534, 16526532, 611867918, 3060725817, 16483866, 3060725817, 611867918, 16526532, 1274158119, 16526540, 3060597377, 16526541, 16424220, 1233373340, 613125597, 1076057753 ] assert (nodes == nodes_sol) or (nodes == nodes_sol2), f"Nodes do not match: {nodes}"
def test_path3_dist(): path = [(0, 1), (0.65, 7.5), (1.9, 10.1)] path_sol = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'] mapdb = InMemMap("map", graph={ "A": ((0.00, 1), ["B"]), "B": ((0.00, 3), ["A", "C"]), "C": ((0.70, 3), ["B", "D"]), "D": ((1.00, 5), ["C", "E"]), "E": ((1.00, 6), ["D", "F"]), "F": ((0.70, 7), ["E", "G"]), "G": ((0.00, 8), ["F", "H"]), "H": ((0.0, 10), ["G", "I"]), "I": ((2.0, 10), ["H"]) }, use_latlon=False) matcher = DistanceMatcher(mapdb, max_dist_init=0.2, obs_noise=0.5, obs_noise_ne=2, dist_noise=0.5, non_emitting_states=True) states, lastidx = matcher.match(path) path_pred = matcher.path_pred_onlynodes if directory: from leuvenmapmatching import visualization as mmviz mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True, linewidth=2, filename=str(directory / "test_path_3_dist.png")) assert path_pred == path_sol, f"Nodes not equal:\n{path_pred}\n{path_sol}" for obs_idx, m in enumerate( matcher.lattice_best): # type: Tuple[int, DistanceMatching] state = m.shortkey # tuple indicating edge ne_str = "e" if m.is_emitting() else "ne" # state is emitting or not p1_str = "{:>5.2f}-{:<5.2f}".format( *m.edge_m.pi) # best matching location on graph p2_str = "{:>5.2f}-{:<5.2f}".format( *m.edge_o.pi) # best matching location on track print(f"{obs_idx:<2} | {state} | {ne_str:<2} | {p1_str} | {p2_str}")
def test_path2(): prepare_files() map_con = create_map(osm2_fn) track = [(p[0], p[1]) for p in gpx_to_path(track2_fn)] matcher = DistanceMatcher(map_con, max_dist=300, max_dist_init=25, min_prob_norm=0.0001, non_emitting_length_factor=0.75, obs_noise=50, obs_noise_ne=75, dist_noise=30, max_lattice_width=5, non_emitting_states=True) states, last_idx = matcher.match(track, unique=False) nodes = matcher.path_pred_onlynodes if directory: mm_viz.plot_map(map_con, matcher=matcher, nodes=nodes, path=track, z=17, use_osm=True, show_graph=True, show_matching=True, filename=str(directory / "test_path_latlon_path2.png")) nodes_sol = [2634474831, 1096512242, 3051083902, 1096512239, 1096512241, 1096512240, 1096508366, 1096508372, 16483861, 3051083900, 16483864, 16483865, 3060515058, 16526534, 16526532, 1274158119, 16526540, 3060597377, 16526541, 16424220, 1233373340, 613125597, 1076057753] assert nodes == nodes_sol, f"Nodes do not match: {nodes}"
def map_matching(map_con, df, s=0, n=3): trj_ids = df.trj_id.unique() for i in range(s, n): df_path = df[df['trj_id'] == trj_ids[i]] df_trj = df_path[['rawlat', 'rawlng']] track = [] max_dist = 2 for j in range(len(df_trj)): track.append((df_trj.iloc[j, 0], df_trj.iloc[j, 1])) while True: try: matcher = DistanceMatcher( map_con, max_dist=max_dist, max_dist_init=1000000, # meter min_prob_norm=0.001, non_emitting_length_factor=0.75, obs_noise=50, obs_noise_ne=75, # meter dist_noise=50, # meter non_emitting_states=True) states, lastidx = matcher.match(track) nodes = matcher.path_pred_onlynodes a = states[-1] break except: max_dist += max_dist * 0.5 print(max_dist) # print('current trajectory ID: {}'.format(trj_ids[i])) with open("file.txt", "a+") as output: for j in range(len(nodes)): trj_data = [ trj_ids[i], map_con.graph[nodes[j]][0][0], map_con.graph[nodes[j]][0][1] ] output.write('{}\n'.format(str(trj_data))) print(i)
def example2(): path = [(1, 0), (7.5, 0.65), (10.1, 1.9)] mapdb = InMemMap("mymap", graph={ "A": ((1, 0.00), ["B"]), "B": ((3, 0.00), ["A", "C"]), "C": ((4, 0.70), ["B", "D"]), "D": ((5, 1.00), ["C", "E"]), "E": ((6, 1.00), ["D", "F"]), "F": ((7, 0.70), ["E", "G"]), "G": ((8, 0.00), ["F", "H"]), "H": ((10, 0.0), ["G", "I"]), "I": ((10, 2.0), ["H"]) }, use_latlon=False) matcher = DistanceMatcher(mapdb, max_dist_init=0.2, obs_noise=1, obs_noise_ne=10, non_emitting_states=True, only_edges=True) states, _ = matcher.match(path) nodes = matcher.path_pred_onlynodes print("States\n------") print(states) print("Nodes\n------") print(nodes) print("") matcher.print_lattice_stats() mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True, filename="output.png")
def test_path1(): prepare_files() track = gpx_to_path(track_fn) track = [loc[:2] for loc in track] track = track[:5] track_int = interpolate_path(track, 5) map_con = create_map(osm_fn) matcher = DistanceMatcher(map_con, max_dist=50, obs_noise=50, min_prob_norm=0.1) states, last_idx = matcher.match(track_int) if directory: # matcher.print_lattice_stats() mm_viz.plot_map(map_con, matcher=matcher, use_osm=True, zoom_path=True, show_graph=True, filename=str(directory / "test_path_latlon_path1.png")) assert len(states) == len(track_int), f"Path ({len(track_int)}) not fully matched by best path ({len(states)}), " + \ f"last index = {last_idx}" states_sol = [(2963305939, 249348325), (2963305939, 249348325), (2963305939, 249348325), (2963305939, 249348325), (2963305939, 249348325), (2963305939, 249348325), (249348325, 1545679243), (249348325, 1545679243), (1545679243, 3663115134), (1545679243, 3663115134), (1545679243, 3663115134), (3663115134, 1545679251), (1545679251, 20910628), (1545679251, 20910628), (1545679251, 20910628), (1545679251, 20910628), (20910628, 3663115130)] assert states == states_sol, f"Got states: {states}"
def test_path4_dist_inc(): map_con = InMemMap("mymap", graph={ "A": ((1, 1), ["B", "C", "X"]), "B": ((1, 3), ["A", "C", "D", "K"]), "C": ((2, 2), ["A", "B", "D", "E", "X", "Y"]), "D": ((2, 4), ["B", "C", "D", "E", "K", "L"]), "E": ((3, 3), ["C", "D", "F", "Y"]), "F": ((3, 5), ["D", "E", "L"]), "X": ((2, 0), ["A", "C", "Y"]), "Y": ((3, 1), ["X", "C", "E"]), "K": ((1, 5), ["B", "D", "L"]), "L": ((2, 6), ["K", "D", "F"]) }, use_latlon=False) path = [(0.8, 0.7), (0.9, 0.7), (1.1, 1.0), (1.2, 1.5), (1.2, 1.6), (1.1, 2.0), (1.1, 2.3), (1.3, 2.9), (1.2, 3.1), (1.5, 3.2), (1.8, 3.5), (2.0, 3.7), (2.3, 3.5), (2.4, 3.2), (2.6, 3.1), (2.9, 3.1), (3.0, 3.2), (3.1, 3.8), (3.0, 4.0), (3.1, 4.3), (3.1, 4.6), (3.0, 4.9)] matcher = DistanceMatcher(map_con, max_dist=2, obs_noise=1, min_prob_norm=0.5) matcher.match(path[:5]) if directory: from leuvenmapmatching import visualization as mmviz mmviz.plot_map(map_con, matcher=matcher, show_labels=True, show_matching=True, show_graph=True, filename=str(directory / "test_path4_dist_inc_1.png")) matcher.match(path, expand=True) nodes = matcher.path_pred_onlynodes if directory: from leuvenmapmatching import visualization as mmviz mmviz.plot_map(map_con, matcher=matcher, show_labels=True, show_matching=True, show_graph=True, filename=str(directory / "test_path4_dist_inc_2.png")) nodes_sol = ['X', 'A', 'B', 'D', 'E', 'F'] assert nodes == nodes_sol, "Nodes not equal:\n{}\n{}".format( nodes, nodes_sol)
def test_bug1(): map_con = SqliteMap("map", use_latlon=True) map_con.add_nodes([(1, (47.590439915657, -122.238368690014)), (2, (47.5910192728043, -122.239519357681)), (3, (47.5913706421852, -122.240168452263))]) map_con.add_edges([(1, 2), (2, 3)]) path = [ # (47.59043333, -122.2384167), (47.59058333, -122.2387), (47.59071667, -122.2389833), (47.59086667, -122.2392667), (47.59101667, -122.23955), (47.59115, -122.2398333) ] path_sol = [(1, 2), (2, 3)] matcher = DistanceMatcher(map_con, min_prob_norm=0.001, max_dist=200, obs_noise=4.07, non_emitting_states=True) matcher.match(path, unique=True) path_pred = matcher.path_pred if directory: import matplotlib.pyplot as plt matcher.print_lattice_stats() logger.debug("Plotting post map ...") fig = plt.figure(figsize=(100, 100)) ax = fig.get_axes() mm_viz.plot_map(map_con, matcher=matcher, use_osm=True, ax=ax, show_lattice=False, show_labels=True, show_graph=True, zoom_path=True, show_matching=True) plt.savefig(str(directory / "test_newson_bug1.png")) plt.close(fig) logger.debug("... done") assert path_pred == path_sol, f"Edges not equal:\n{path_pred}\n{path_sol}"
def test_bug2(): this_path = Path(os.path.realpath(__file__)).parent / "rsrc" / "bug2" edges_fn = this_path / "edgesrl.csv" nodes_fn = this_path / "nodesrl.csv" path_fn = this_path / "path.csv" zip_fn = this_path / "leuvenmapmatching_testdata.zip" if not (edges_fn.exists() and nodes_fn.exists() and path_fn.exists()): import requests url = 'https://people.cs.kuleuven.be/wannes.meert/leuvenmapmatching/leuvenmapmatching_testdata.zip' logger.debug("Download testfiles from kuleuven.be") r = requests.get(url, stream=True) with zip_fn.open('wb') as ofile: for chunk in r.iter_content(chunk_size=1024): if chunk: ofile.write(chunk) import zipfile logger.debug("Unzipping leuvenmapmatching_testdata.zip") with zipfile.ZipFile(str(zip_fn), "r") as zip_ref: zip_ref.extractall(str(zip_fn.parent)) logger.debug(f"Reading map ...") mmap = SqliteMap("road_network", use_latlon=True, dir=this_path) path = [] with path_fn.open("r") as path_f: reader = csv.reader(path_f, delimiter=',') for row in reader: lat, lon = [float(coord) for coord in row] path.append((lat, lon)) node_cnt = 0 with nodes_fn.open("r") as nodes_f: reader = csv.reader(nodes_f, delimiter=',') for row in reader: nid, lonlat, _ = row nid = int(nid) lon, lat = [float(coord) for coord in lonlat[1:-1].split(",")] mmap.add_node(nid, (lat, lon), ignore_doubles=True, no_index=True, no_commit=True) node_cnt += 1 edge_cnt = 0 with edges_fn.open("r") as edges_f: reader = csv.reader(edges_f, delimiter=',') for row in reader: _eid, nid1, nid2, pid = [int(val) for val in row] mmap.add_edge(nid1, nid2, edge_type=0, path=pid, no_index=True, no_commit=True) edge_cnt += 1 logger.debug(f"... done: {node_cnt} nodes and {edge_cnt} edges") logger.debug("Indexing ...") mmap.reindex_nodes() mmap.reindex_edges() logger.debug("... done") matcher = DistanceMatcher(mmap, min_prob_norm=0.001, max_dist=200, obs_noise=4.07, non_emitting_states=True) # path = path[:2] nodes, idx = matcher.match(path, unique=True) path_pred = matcher.path_pred if directory: import matplotlib.pyplot as plt matcher.print_lattice_stats() logger.debug("Plotting post map ...") fig = plt.figure(figsize=(100, 100)) ax = fig.get_axes() mm_viz.plot_map(mmap, matcher=matcher, use_osm=True, ax=ax, show_lattice=False, show_labels=True, show_graph=False, zoom_path=True, show_matching=True) plt.savefig(str(directory / "test_bug1.png")) plt.close(fig) logger.debug("... done")
def test_route(): if directory: import matplotlib.pyplot as plt else: plt = None paths, map_con, route = load_data() route = [(lat, lon) for lat, lon in route] zoom_path = True # zoom_path = slice(2645, 2665) slice_route = None # slice_route = slice(650, 750) # slice_route = slice(2657, 2662) # First location where some observations are missing # slice_route = slice(2770, 2800) # Observations are missing # slice_route = slice(2910, 2950) # Interesting point # slice_route = slice(2910, 2929) # Interesting point # slice_route = slice(6825, 6833) # Outlier observation slice_route = slice(6300, ) # if directory is not None: # logger.debug("Plotting pre map ...") # mm_viz.plot_map(map_con_latlon, path=route_latlon, use_osm=True, # show_lattice=False, show_labels=False, show_graph=False, zoom_path=zoom_path, # filename=str(directory / "test_newson_route.png")) # logger.debug("... done") matcher = DistanceMatcher(map_con, min_prob_norm=0.0001, max_dist=200, dist_noise=15, dist_noise_ne=30, obs_noise=30, obs_noise_ne=150, non_emitting_states=True) if slice_route is None: pkl_fn = this_path / "nodes_pred.pkl" if pkl_fn.exists(): with pkl_fn.open("rb") as pkl_file: logger.debug(f"Reading predicted nodes from pkl file") route_nodes = pickle.load(pkl_file) else: matcher.match(route) route_nodes = matcher.path_pred_onlynodes with pkl_fn.open("wb") as pkl_file: pickle.dump(route_nodes, pkl_file) from leuvenmapmatching.util.evaluation import route_mismatch_factor print(route_nodes[:10]) # route_edges = map_con.nodes_to_paths(route_nodes) # print(route_edges[:10]) grnd_paths, _ = zip(*paths) print(grnd_paths[:10]) route_paths = map_con.nodes_to_paths(route_nodes) print(route_paths[:10]) logger.debug(f"Compute route mismatch factor") factor, cnt_matches, cnt_mismatches, total_length, mismatches, _, _ = \ route_mismatch_factor(map_con, route_paths, grnd_paths,window=None, keep_mismatches=True) logger.debug( f"factor = {factor}, " f"cnt_matches = {cnt_matches}/{cnt_mismatches} of {len(grnd_paths)}/{len(route_paths)}, " f"total_length = {total_length}\n" f"mismatches = " + " | ".join(str(v) for v in mismatches)) else: _, last_idx = matcher.match(route[slice_route]) logger.debug(f"Last index = {last_idx}") # matcher.match(route[2657:2662]) # First location where some observations are missing # matcher.match(route[2770:2800]) # Observations are missing # matcher.match(route[2910:2950]) # Interesting point # matcher.match(route[2910:2929]) # Interesting point # matcher.match(route[6000:]) path_pred = matcher.path_pred_onlynodes if directory: matcher.print_lattice_stats() logger.debug("Plotting post map ...") fig = plt.figure(figsize=(200, 200)) ax = fig.get_axes() mm_viz.plot_map(map_con, matcher=matcher, use_osm=True, ax=ax, show_lattice=False, show_labels=True, zoom_path=zoom_path, show_matching=True, show_graph=False) plt.savefig(str(directory / "test_newson_route_matched.png")) plt.close(fig) logger.debug("... done") logger.debug("Best path:") for m in matcher.lattice_best: logger.debug(m) print(path_pred)
def test_path3(): prepare_files() track = [(50.87881, 4.698930000000001), (50.87899, 4.69836), (50.87905000000001, 4.698110000000001), (50.879000000000005, 4.69793), (50.87903000000001, 4.69766), (50.87906, 4.697500000000001), (50.87908, 4.6973), (50.879110000000004, 4.69665), (50.87854, 4.696420000000001), (50.878440000000005, 4.696330000000001), (50.878370000000004, 4.696140000000001), (50.8783, 4.69578), (50.87832, 4.69543), (50.87767, 4.695530000000001), (50.87763, 4.695080000000001), (50.87758, 4.6948300000000005), (50.877480000000006, 4.69395), (50.877500000000005, 4.693700000000001), (50.877520000000004, 4.69343), (50.877610000000004, 4.692670000000001), (50.87776, 4.6917800000000005), (50.87783, 4.69141), (50.87744000000001, 4.6908900000000004), (50.87736, 4.690790000000001), (50.877300000000005, 4.69078), (50.876650000000005, 4.6907000000000005), (50.87597, 4.69066), (50.875820000000004, 4.69068), (50.87561, 4.6907700000000006), (50.874430000000004, 4.69136), (50.874210000000005, 4.691490000000001), (50.87413, 4.69151), (50.87406000000001, 4.69151), (50.87397000000001, 4.69148), (50.87346, 4.6913800000000005), (50.87279, 4.691260000000001), (50.872490000000006, 4.69115), (50.87259, 4.6908900000000004), (50.87225, 4.690650000000001), (50.872080000000004, 4.6904900000000005), (50.871550000000006, 4.69125), (50.87097000000001, 4.69216), (50.87033, 4.69324), (50.87017, 4.6935400000000005), (50.87012000000001, 4.69373), (50.86997, 4.69406), (50.86981, 4.694520000000001), (50.86943, 4.69585), (50.868970000000004, 4.697500000000001), (50.868770000000005, 4.698130000000001), (50.86863, 4.6985), (50.86844000000001, 4.69899), (50.868140000000004, 4.69977), (50.86802, 4.70023), (50.867920000000005, 4.70078), (50.86787, 4.701180000000001), (50.86784, 4.70195), (50.86786000000001, 4.702310000000001), (50.86791, 4.702870000000001), (50.86836, 4.7052700000000005), (50.86863, 4.7064900000000005), (50.86880000000001, 4.707210000000001), (50.869220000000006, 4.708410000000001), (50.869400000000006, 4.70891), (50.86959, 4.709350000000001), (50.86995, 4.71004), (50.87006, 4.71021), (50.870900000000006, 4.7112300000000005), (50.872260000000004, 4.712890000000001), (50.87308, 4.71389), (50.873430000000006, 4.714300000000001), (50.873560000000005, 4.71441), (50.873740000000005, 4.714530000000001), (50.874280000000006, 4.714740000000001), (50.876250000000006, 4.71544), (50.876490000000004, 4.7155700000000005), (50.876900000000006, 4.7158500000000005), (50.87709, 4.71598), (50.877190000000006, 4.716010000000001), (50.87751, 4.7160400000000005), (50.87782000000001, 4.7160400000000005), (50.87832, 4.71591), (50.87894000000001, 4.71567), (50.87975, 4.71536), (50.88004, 4.71525), (50.8804, 4.715070000000001), (50.88163, 4.71452), (50.881750000000004, 4.71447), (50.8819, 4.714390000000001), (50.882200000000005, 4.71415), (50.882470000000005, 4.7138800000000005), (50.883480000000006, 4.7127300000000005), (50.88552000000001, 4.710470000000001), (50.88624, 4.70966), (50.88635000000001, 4.7096100000000005), (50.886520000000004, 4.709580000000001), (50.88664000000001, 4.7095400000000005), (50.886750000000006, 4.709280000000001), (50.88684000000001, 4.70906), (50.886970000000005, 4.70898), (50.88705, 4.70887), (50.88714, 4.70868), (50.88743, 4.7079), (50.887840000000004, 4.7069), (50.88776000000001, 4.70687), (50.88765, 4.706790000000001), (50.887100000000004, 4.70627), (50.88702000000001, 4.70619), (50.886950000000006, 4.706040000000001), (50.886950000000006, 4.7058800000000005), (50.886970000000005, 4.705620000000001), (50.88711000000001, 4.70417), (50.88720000000001, 4.70324), (50.88723, 4.7027600000000005), (50.88709000000001, 4.70253), (50.886480000000006, 4.70148), (50.88636, 4.70131), (50.886050000000004, 4.70101), (50.88593, 4.70092), (50.885810000000006, 4.700880000000001), (50.88539, 4.7008600000000005), (50.88497, 4.70082), (50.88436, 4.70089), (50.88398, 4.70094), (50.883250000000004, 4.7010700000000005), (50.88271, 4.701160000000001), (50.88136, 4.70159), (50.881130000000006, 4.701790000000001), (50.880930000000006, 4.7020100000000005), (50.88078, 4.70223), (50.88046000000001, 4.70146), (50.88015000000001, 4.70101), (50.880030000000005, 4.700880000000001), (50.87997000000001, 4.70078), (50.879900000000006, 4.70061), (50.87984, 4.70052), (50.879960000000004, 4.70026)] track = track[:30] map_con = create_map_from_xml(osm3_fn) matcher = DistanceMatcher(map_con, max_dist_init=30, max_dist=50, min_prob_norm=0.1, obs_noise=10, obs_noise_ne=20, dist_noise=10, non_emitting_states=True) states, last_idx = matcher.match(track) if directory: # matcher.print_lattice_stats() mm_viz.plot_map(map_con, matcher=matcher, use_osm=True, zoom_path=True, show_graph=False, show_matching=True, filename=str(directory / "test_path_latlon_path3.png")) nodes = matcher.path_pred_onlynodes nodes_sol = [ 3906576303, 1150903750, 4506996820, 4506996819, 4506996798, 3906576457, 130147477, 3906576346, 231974072, 231974123, 1180606706, 19792164, 19792172, 1180606683, 1180606709, 5236409057, 19792169, 5236409056, 180241961, 180241975, 4506996259, 19792156, 5236409048, 180241625, 180241638, 231953030, 241928030, 241928031, 83796665, 231953028, 1125556965, 1380538625, 1824115892, 4909655515, 16571387, 16737662, 16571388, 179425214, 3705540990, 4567021046 ] assert nodes == nodes_sol, f"Nodes do not match: {nodes}"
def test_bug2(): from leuvenmapmatching.util.openstreetmap import locations_to_map map_con = SqliteMap("map", use_latlon=True, dir=directory) path = [(50.87205, 4.66089), (50.874550000000006, 4.672980000000001), (50.87538000000001, 4.67698), (50.875800000000005, 4.6787600000000005), (50.876520000000006, 4.6818), (50.87688000000001, 4.683280000000001), (50.87814, 4.68733), (50.87832, 4.68778), (50.87879, 4.68851), (50.87903000000001, 4.68895), (50.879560000000005, 4.689170000000001), (50.87946, 4.6900900000000005), (50.879290000000005, 4.6909600000000005), (50.87906, 4.6921800000000005), (50.87935, 4.6924), (50.879720000000006, 4.69275), (50.88002, 4.6930700000000005), (50.880430000000004, 4.693440000000001), (50.880660000000006, 4.69357), (50.880660000000006, 4.6936100000000005), (50.88058, 4.694640000000001), (50.88055000000001, 4.69491), (50.88036, 4.696160000000001), (50.88009, 4.697550000000001), (50.87986, 4.6982800000000005), (50.879720000000006, 4.698790000000001), (50.87948, 4.699730000000001), (50.87914000000001, 4.6996400000000005), (50.87894000000001, 4.6995000000000005), (50.878800000000005, 4.699350000000001), (50.8785, 4.6991000000000005), (50.87841, 4.6990300000000005)] locations_to_map(path, map_con, filename=directory / "osm.xml") path_sol = [(5777282112, 2633552218), (2633552218, 5777282111), (5777282111, 5777282110), (5777282110, 1642021707), (1642021707, 71361087), (71361087, 71364203), (71364203, 1151697757), (1151697757, 1647339017), (1647339017, 1647339030), (1647339030, 2058510349), (2058510349, 2633552212), (2633552212, 1380538577), (1380538577, 1439572271), (1439572271, 836434313), (836434313, 2633771041), (2633771041, 5042874484), (5042874484, 5042874485), (5042874485, 2518922583), (2518922583, 2659762546), (2659762546, 5777282063), (5777282063, 2633771037), (2633771037, 2633771035), (2633771035, 2633771033), (2633771033, 1151668705), (1151668705, 2633771094), (2633771094, 1151668722), (1151668722, 1151668724), (1151668724, 5543948222), (5543948222, 2058481517), (2058481517, 16933576), (16933576, 5543948221), (5543948221, 2518923620), (2518923620, 5543948020), (5543948020, 5543948019), (5543948019, 18635886), (18635886, 18635887), (18635887, 1036909153), (1036909153, 2658942230), (2658942230, 1001099975), (1001099975, 16933574), (16933574, 1125604152), (1125604152, 5543948238), (5543948238, 1125604150), (1125604150, 1125604148), (1125604148, 2634195334), (2634195334, 2087854243), (2087854243, 5543948237), (5543948237, 160226603), (160226603, 180130266), (180130266, 5543948227), (5543948227, 5543948226), (5543948226, 1195681902), (1195681902, 101135392), (101135392, 2606704673), (2606704673, 18635977), (18635977, 1026111708), (1026111708, 1026111631), (1026111631, 16571375), (16571375, 2000680621), (2000680621, 999580042), (999580042, 16571370), (16571370, 2000680620), (2000680620, 5078692402), (5078692402, 5543948008), (5543948008, 16571371), (16571371, 999579936), (999579936, 2639836143), (2639836143, 5543948014), (5543948014, 5222992316), (5222992316, 30251323), (30251323, 159701080), (159701080, 3173217124), (3173217124, 1165209673), (1165209673, 1380538689), (1380538689, 2878334668), (2878334668, 2871137399), (2871137399, 2876902981), (2876902981, 2873624508), (2873624508, 2873624509), (2873624509, 2899666507), (2899666507, 2899666518), (2899666518, 2899666513), (2899666513, 2903073945), (2903073945, 2903073951), (2903073951, 1380538681), (1380538681, 2914810627), (2914810627, 2914810618), (2914810618, 2914810607), (2914810607, 2914810604), (2914810604, 2914810483), (2914810483, 2914810462), (2914810462, 2914810464), (2914810464, 1312433523), (1312433523, 20918594), (20918594, 2634267817), (2634267817, 2967425445), (2967425445, 3201523879), (3201523879, 157217466), (157217466, 2963305939), (2963305939, 3201523877), (3201523877, 3889275909), (3889275909, 3889275897), (3889275897, 157255077), (157255077, 30251882), (30251882, 157245624), (157245624, 1150903673), (1150903673, 4504936404)] matcher = DistanceMatcher(map_con, min_prob_norm=0.001, max_dist=200, obs_noise=4.07, non_emitting_states=True) nodes, idx = matcher.match(path, unique=True) path_pred = matcher.path_pred if directory: import matplotlib.pyplot as plt matcher.print_lattice_stats() logger.debug("Plotting post map ...") fig = plt.figure(figsize=(100, 100)) ax = fig.get_axes() mm_viz.plot_map(map_con, matcher=matcher, use_osm=True, ax=ax, show_lattice=False, show_labels=True, show_graph=False, zoom_path=True, show_matching=True) plt.savefig(str(directory / "test_newson_bug1.png")) plt.close(fig) logger.debug("... done") assert path_pred == path_sol, f"Edges not equal:\n{path_pred}\n{path_sol}"
from leuvenmapmatching.matcher.distance import DistanceMatcher from leuvenmapmatching.map.inmem import InMemMap from leuvenmapmatching import visualization as mmviz path = [(1, 0), (7.5, 0.65), (10.1, 1.9)] mapdb = InMemMap("mymap", graph={ "A": ((1, 0.00), ["B"]), "B": ((3, 0.00), ["A", "C"]), "C": ((4, 0.70), ["B", "D"]), "D": ((5, 1.00), ["C", "E"]), "E": ((6, 1.00), ["D", "F"]), "F": ((7, 0.70), ["E", "G"]), "G": ((8, 0.00), ["F", "H"]), "H": ((10, 0.0), ["G", "I"]), "I": ((10, 2.0), ["H"]) }, use_latlon=False) matcher = DistanceMatcher(mapdb, max_dist_init=0.2, obs_noise=1, obs_noise_ne=10, non_emitting_states=True, only_edges=True) states, _ = matcher.match(path) nodes = matcher.path_pred_onlynodes print("States\n------") print(states) print("Nodes\n------") print(nodes) print("") matcher.print_lattice_stats() mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True filename="output.png")
def match(track, graph, streetmap, matcher_alg='DistanceMatcher', max_dist=200, max_dist_init=100, min_prob_norm=0.001, non_emitting_length_factor=0.75, obs_noise=50, obs_noise_ne=75, dist_noise=50, non_emitting_edgeid=False): ''' This function match the floating car track. Parameters: ___________ track: np.array of tuples (x,y) Array of the floating car track coordinates. graph: OSMNX road network Osmnx road network of the area of study streetmap: InMem map LeuvenMapMatching InMem map of the graph mather_alg: string Name of the matcher algorithm of choice max_dist: int maximum distance from the track max_dist_init: int initial maximum distance min_prob_norm: float Minmum normalized probability non_emitting_length_factor: float The factor no emmiting state that it takes obs_noise: int Standard Deviation of noise obs_noise_ne: int Standard Deviation of noise in non emitting state dist_noise: int distance of the noise non_emitting_edgeid: boolean If allow on-emitting states Returns: __________ edge_id: np.array of tuples An array consisting tuples, (start node id, end node id) last_idx: int Last index of the point mapped track_corr: np.array array of map matched coordinates route: np.array array of computed route of the map matched track ''' # get leuvenmapmatching InMem mam from the road network #streetmap = get_InMemMap(graph) # select the matcher of choise if (matcher_alg == 'DistanceMatcher'): matcher = DistanceMatcher( streetmap, max_dist=max_dist, max_dist_init=max_dist_init, min_prob_norm=min_prob_norm, non_emitting_length_factor=non_emitting_length_factor, obs_noise=obs_noise, obs_noise_ne=obs_noise_ne, dist_noise=dist_noise, non_emitting_edgeid=non_emitting_edgeid) elif (matcher_alg == 'NewsonKrummMatcher'): matcher = NewsonKrummMatcher( streetmap, max_dist=max_dist, max_dist_init=max_dist_init, min_prob_norm=min_prob_norm, non_emitting_length_factor=non_emitting_length_factor, obs_noise=obs_noise, obs_noise_ne=obs_noise_ne, dist_noise=dist_noise, non_emitting_edgeid=non_emitting_edgeid) elif (matcher_alg == 'SimpleMatcher'): matcher = SimpleMatcher( streetmap, max_dist=max_dist, max_dist_init=max_dist_init, min_prob_norm=min_prob_norm, non_emitting_length_factor=non_emitting_length_factor, obs_noise=obs_noise, obs_noise_ne=obs_noise_ne, dist_noise=dist_noise, non_emitting_edgeid=non_emitting_edgeid) else: print('No matcher selected') return # Perform the mapmatching edge_ids, last_idx = matcher.match(track) # Reference ellipsoid for distance geod = Geod(ellps='WGS84') proj_dist = np.zeros(len(track)) # edgeid refers to edges id (node1_id, node2_id) where the GPS point is projected lat_corr, lon_corr = [], [] lat_nodes = matcher.lattice_best for idx, m in enumerate(lat_nodes): if (idx == len(track)): break lat, lon = m.edge_m.pi[:2] lat_corr.append(lat) lon_corr.append(lon) # print(idx) _, _, distance = geod.inv(track[idx][1], track[idx][0], lon, lat) proj_dist[idx] += distance # construct array of cordinates track_corr = np.column_stack((lat_corr, lon_corr)) # get the route from the projected cordinates route = compute_route(streetmap, track_corr, edge_ids) # returns return edge_ids, last_idx, track_corr, route
def map_track_to_roads(cls, track_positions, map_matching_graph, stepsize=5, obs_noise=5, obs_noise_ne=5, max_dist_init=1000, max_dist=5, min_prob_norm=0.5, non_emitting_states=False, non_emitting_length_factor=0.75, max_lattice_width=10, dist_noise=5, dist_noise_ne=5, restrained_ne=True, avoid_goingback=True): """Map a series of track_positions to a road network using a map_matching_graph :param track_positions: a numpy array of [x, y, timestamp] where x and y are assumed to be in meters :param map_matching_graph: The map matching graph for a road network :return: An array of road edges and corresponding timestamps. When a road mapping cannot be made for a given track position, a 'None' is inserted """ track_arc_lengths_m = np.hstack([ 0, np.cumsum( np.sqrt(np.sum(np.diff(track_positions[:, :2], axis=0)**2, 1))) ]) total_track_length_m = track_arc_lengths_m[-1] if total_track_length_m == 0.0: print(f"Total track length must be > 0.0, skipping!") return [], [] elif total_track_length_m > 100000: print(f"Total track length is abnormally large " f"({total_track_length_m} meters), skipping!") return [], [] # We need to remove positions with duplicate x, y to be able # to interpolate (always keeping the latter of the two; we # never throw away the last point) ind = np.hstack([np.diff(track_arc_lengths_m), 1]) != 0 interp_f = interp1d(track_arc_lengths_m[ind], track_positions[ind], axis=0) steps = np.linspace(0, total_track_length_m, int(np.ceil(total_track_length_m / stepsize)) + 1) interp_positions = interp_f(steps) node_path = [] k = 0 matcher = DistanceMatcher( map_matching_graph, obs_noise=obs_noise, obs_noise_ne=obs_noise_ne, max_dist_init=max_dist_init, max_dist=max_dist, min_prob_norm=min_prob_norm, non_emitting_states=non_emitting_states, non_emitting_length_factor=non_emitting_length_factor, max_lattice_width=max_lattice_width, dist_noise=dist_noise, dist_noise_ne=dist_noise_ne, restrained_ne=restrained_ne, avoid_goingback=avoid_goingback) while k < len(interp_positions): node_pathi, ind = matcher.match(interp_positions[k:, :2]) if len(node_pathi) == 0: node_path.append(None) k += 1 else: node_path.extend(node_pathi) k += ind + 1 return node_path, interp_positions[:, 2]
for nid, row in edges_proj[['u', 'v']].iterrows(): map_con.add_edge(row['u'], row['v']) map_con.purge() # from leuvenmapmatching.util.gpx import gpx_to_path # #track = gpx_to_path("mytrack.gpx") # matcher = DistanceMatcher(map_con, # max_dist=0.8, # max_dist_init=25, # meter # min_prob_norm=0.01, # #non_emitting_length_factor=0.75, # obs_noise=0.5, obs_noise_ne=0.7, # meter # dist_noise=5, # meter # non_emitting_states=True) matcher = DistanceMatcher(map_con, min_prob_norm=0.05) # states, lastidx = matcher.match(list(path)) states, _ = matcher.match(path) nodes = matcher.path_pred_onlynodes print("States\n------") print(states) print("Nodes\n------") print(nodes) print("") matcher.print_lattice_stats()