cyang-kth / fmm

Fast map matching, an open source framework in C++
https://fmm-wiki.github.io/
Apache License 2.0
875 stars 205 forks source link

FMM trajectories do not match start and end points #237

Open seffylmz opened 2 years ago

seffylmz commented 2 years ago

FMM fits quite well except for the start and end points of the trajectories. As seen on the picture, the map matched trajectory (red) starts at the nearest node instead of the starting point of the original trajectory (black). Any suggestion on that?

MM

I am using a script similar to the provided example:

from fmm import Network,NetworkGraph,FastMapMatch,FastMapMatchConfig,UBODT
from fmm import GPSConfig,ResultConfig
from fmm import UBODTGenAlgorithm

# Load network data and graph
network = Network("network-new/edges.shp", "fid", "u", "v")
print "Nodes {} edges {}".format(network.get_node_count(),network.get_edge_count())
graph = NetworkGraph(network)

#Precompute an UBODT file
ubodt_gen = UBODTGenAlgorithm(network,graph)
status = ubodt_gen.generate_ubodt("ubodt.txt", 0.003, binary=False, use_omp=True)
print status

#Load UBODT data
ubodt = UBODT.read_ubodt_csv("ubodt.txt")

#Create FMM model
model = FastMapMatch(network,graph,ubodt)

#Define FMM configuration
k = 12
radius = 200
gps_error = 100
fmm_config = FastMapMatchConfig(k,radius,gps_error)

#Match trajectories in GPS file
input_config = GPSConfig()
input_config.file = 'gps/traj_0.csv'
input_config.id = 'id'

print input_config.to_string()

result_config = ResultConfig()
result_config.file = 'gps/mr_0_n.txt'
result_config.output_config.write_opath = True
print result_config.to_string()

status = model.match_gps_file(input_config, result_config, fmm_config)
print status
cyang-kth commented 2 years ago

If your data is in unit of degrees, the current configuration is too large. Try to reduce radius and GPS error by a factor of 1e-5(1 degree=1e5 meters, 1 meter = 1e-5 degree)。

Keep all units in degrees if you do not want to project your GPS and network data into meters.

seffylmz commented 2 years ago

Thanks for the quick response. I also tried reduced parameters and various others (also for delta and vmax) but always facing the same issue.

It seems to me that the trajectory points are only located at nodes and break points of edges. Thus, points in the middle of an edge are not matched. Can it be related to the network files?

I have generated the network files by using this snippet:

def save_graph_shapefile_directional(G, filepath=None, encoding="utf-8"):
    # default filepath if none was provided
    if filepath is None:
        filepath = os.path.join(ox.settings.data_folder, "graph_shapefile")

    # if save folder does not already exist, create it (shapefiles
    # get saved as set of files)
    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")

    # convert undirected graph to gdfs and stringify non-numeric columns
    gdf_nodes, gdf_edges = ox.utils_graph.graph_to_gdfs(G)
    gdf_nodes = ox.io._stringify_nonnumeric_cols(gdf_nodes)
    gdf_edges = ox.io._stringify_nonnumeric_cols(gdf_edges)
    # We need an unique ID for each edge
    gdf_edges["fid"] = np.arange(0, gdf_edges.shape[0], dtype='int')
    # save the nodes and edges as separate ESRI shapefiles
    gdf_nodes.to_file(filepath_nodes, encoding=encoding)
    gdf_edges.to_file(filepath_edges, encoding=encoding)

print("osmnx version",ox.__version__)

# Download by a bounding box
boundary_polygon = Polygon(coordinates)
G = ox.graph_from_polygon(boundary_polygon, network_type='drive')
start_time = time.time()
save_graph_shapefile_directional(G, filepath='./network-new')
print("--- %s seconds ---" % (time.time() - start_time))
cyang-kth commented 2 years ago

You could try other search radius and gps error, also check the direction of each edge to assure the direction of edge is consistent with the GPS movement.