BikeDNA(九) 特征匹配

news2024/9/26 1:17:32

BikeDNA(九) 特征匹配

特征匹配采用参考数据并尝试识别 OSM 数据集中的相应特征。 特征匹配是比较单个特征而不是研究区域网格单元水平上的特征特征的必要前提。

方法

将两个道路数据集中的特征与其数字化特征的方式以及边缘之间潜在的一对多关系进行匹配(例如,一个数据集仅映射道路中心线,而另一个数据集映射每辆自行车的几何形状) 车道)并不是一项简单的任务。

这里使用的方法将所有网络边缘转换为统一长度的较小段,然后再寻找参考和 OSM 数据之间的潜在匹配。 匹配是根据对象之间的缓冲距离、角度和无向 Hausdorff 距离完成的,并且基于 Koukoletsos et al. (2012) and Will (2014)。

根据匹配结果,计算以下值:

  • 匹配和不匹配边缘的总数和每个网格单元的数量和长度
  • 匹配边缘的属性比较:它们对自行车基础设施受保护或不受保护的分类是否相同?

解释

直观地探索特征匹配结果非常重要,因为匹配的成功率会影响如何解释匹配数的分析。

如果两个数据集中的特征被不同地数字化 - 例如 如果一个数据集将自行车轨道数字化为大部分直线,而另一个数据集包含更多蜿蜒轨道,则匹配将失败。 如果它们彼此放置得太远,也会出现这种情况。 如果可以通过视觉确认两个数据集中确实存在相同的特征,则缺乏匹配表明两个数据集中的几何形状差异太大。 然而,如果可以确认大多数真实的相应特征已被识别,则区域中缺乏匹配表明存在错误或遗漏。

Warning

特征匹配的计算成本很高,并且需要一段时间才能计算。 对于此存储库中提供的测试数据(具有大约 800 公里的 OSM 网络),单元运行大约需要 20 分钟。

# Load libraries, settings and data

import json
import numbers
import os.path
import pickle

import contextily as cx
import folium
import geopandas as gpd
import matplotlib.colors as colors
import matplotlib.pyplot as plt
import osmnx as ox
import pandas as pd
import yaml
import numpy as np

from src import evaluation_functions as eval_func
from src import matching_functions as match_func
from src import plotting_functions as plot_func

# Read in dictionaries with settings
%run ../settings/yaml_variables.py
%run ../settings/plotting.py
%run ../settings/tiledict.py
%run ../settings/paths.py

# # Load data
%run ../settings/load_osmdata.py
%run ../settings/load_refdata.py
%run ../settings/df_styler.py

# Combine grid geodataframes
grid = osm_grid.merge(ref_grid)
assert len(grid) == len(osm_grid) == len(ref_grid)
D:\tmp_resource\BikeDNA-main\BikeDNA-main\scripts\settings\plotting.py:49: MatplotlibDeprecationWarning: The get_cmap function was deprecated in Matplotlib 3.7 and will be removed two minor releases later. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap(obj)`` instead.
  cmap = cm.get_cmap(cmap_name, n)
D:\tmp_resource\BikeDNA-main\BikeDNA-main\scripts\settings\plotting.py:46: MatplotlibDeprecationWarning: The get_cmap function was deprecated in Matplotlib 3.7 and will be removed two minor releases later. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap(obj)`` instead.
  cmap = cm.get_cmap(cmap_name)


OSM graphs loaded successfully!
OSM data loaded successfully!
Reference graphs loaded successfully!
Reference data loaded successfully!


<string>:49: MatplotlibDeprecationWarning: The get_cmap function was deprecated in Matplotlib 3.7 and will be removed two minor releases later. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap(obj)`` instead.
<string>:46: MatplotlibDeprecationWarning: The get_cmap function was deprecated in Matplotlib 3.7 and will be removed two minor releases later. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap(obj)`` instead.

1. 匹配特征

1.1 运行并绘制特征匹配

User configurations

在特征匹配中,用户必须指出:
  • 线段长度(所有要素在匹配之前分割成的线段长度,以米为单位)(segment_length)。
  • 用于查找潜在匹配项的缓冲区距离(即可以表示同一对象的两个段之间的最大距离)(buffer_dist)。
  • 可以被视为匹配的要素之间的最大豪斯多夫距离(在本文中,它指的是两个几何图形之间的最大距离。例如,长度为 25 米的线段 A 可能位于线段 10 米的缓冲距离内 B,但如果它们相互垂直,Hausdorff 距离将大于 10 米)(hausdorff_threshold)。
  • 线段之间的角度阈值,然后它们不再被视为潜在匹配(angular_threshold)。
# Define feature matching user settings

segment_length = 10  # The shorter the segments, the longer the matching process will take. For cities with a gridded street network with streets as straight lines, longer segments will usually work fine
buffer_dist = 15
hausdorff_threshold = 17
angular_threshold = 30

for s in [segment_length, buffer_dist, hausdorff_threshold, angular_threshold]:
    assert isinstance(s, int) or isinstance(s, float), print(
        "Settings must be integer or float values!"
    )
osm_seg_fp = compare_results_data_fp + f"osm_segments_{segment_length}.gpkg"
ref_seg_fp = compare_results_data_fp + f"ref_segments_{segment_length}.gpkg"

if os.path.exists(osm_seg_fp) and os.path.exists(ref_seg_fp):

    osm_segments = gpd.read_file(osm_seg_fp)
    ref_segments = gpd.read_file(ref_seg_fp)

    print("Segments have already been created! Continuing with existing segment data.")
    print("\n")

else:
    print("Creating edge segments for OSM and reference data...")

    osm_segments = match_func.create_segment_gdf(
    osm_edges_simplified, segment_length=segment_length
    )
    osm_segments.rename(columns={"osmid": "org_osmid"}, inplace=True)
    osm_segments["osmid"] = osm_segments[
        "edge_id"
    ]  # Because matching function assumes an id column names osmid as unique id for edges

    osm_segments.set_crs(study_crs, inplace=True)
    osm_segments.dropna(subset=["geometry"], inplace=True)

    ref_segments = match_func.create_segment_gdf(
        ref_edges_simplified, segment_length=segment_length
    )
    ref_segments.set_crs(study_crs, inplace=True)
    ref_segments.rename(columns={"seg_id": "seg_id_ref"}, inplace=True)
    ref_segments.dropna(subset=["geometry"], inplace=True)

    print("Segments created successfully!")
    print("\n")

    osm_segments.to_file(osm_seg_fp)
    ref_segments.to_file(ref_seg_fp)

    print("Segments saved!")
Creating edge segments for OSM and reference data...


d:\work\miniconda3\envs\bikeDNA\Lib\site-packages\geopandas\geoseries.py:645: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  result = super().apply(func, convert_dtype=convert_dtype, args=args, **kwargs)
d:\work\miniconda3\envs\bikeDNA\Lib\site-packages\geopandas\geoseries.py:645: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  result = super().apply(func, convert_dtype=convert_dtype, args=args, **kwargs)
d:\work\miniconda3\envs\bikeDNA\Lib\site-packages\geopandas\geoseries.py:645: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  result = super().apply(func, convert_dtype=convert_dtype, args=args, **kwargs)
d:\work\miniconda3\envs\bikeDNA\Lib\site-packages\geopandas\geoseries.py:645: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  result = super().apply(func, convert_dtype=convert_dtype, args=args, **kwargs)


Segments created successfully!


Segments saved!
matches_fp = f"../../results/compare/{study_area}/data/segment_matches_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}.pickle"

if os.path.exists(matches_fp):
    with open(matches_fp, "rb") as fp:
        segment_matches = pickle.load(fp)
    print(
        f"Segment matching has already been performed. Loading existing segment matches, matched with a buffer distance of {buffer_dist} meters, a Hausdorff distance of {hausdorff_threshold} meters, and a max angle of {angular_threshold} degrees."
    )
    print("\n")

else:
    print(
        f"Starting matching process using a buffer distance of {buffer_dist} meters, a Hausdorff distance of {hausdorff_threshold} meters, and a max angle of {angular_threshold} degrees."
    )
    print("\n")

    buffer_matches = match_func.overlay_buffer(
        reference_data=ref_segments,
        osm_data=osm_segments,
        ref_id_col="seg_id_ref",
        osm_id_col="seg_id",
        dist=buffer_dist,
    )

    print("Buffer matches found! Continuing with final matching process...")
    print("\n")
    segment_matches = match_func.find_matches_from_buffer(
        buffer_matches=buffer_matches,
        osm_edges=osm_segments,
        reference_data=ref_segments,
        angular_threshold=angular_threshold,
        hausdorff_threshold=hausdorff_threshold,
    )

    print("Feature matching completed!")

    with open(matches_fp, "wb") as f:
        pickle.dump(segment_matches, f)
Starting matching process using a buffer distance of 15 meters, a Hausdorff distance of 17 meters, and a max angle of 30 degrees.


Buffer matches found! Continuing with final matching process...


60946 reference segments were matched to OSM edges
2749 reference segments were not matched
Feature matching completed!
osm_matched_segments = osm_segments.loc[osm_segments.seg_id.isin(segment_matches.matches_id)]
osm_unmatched_segments = osm_segments.loc[~osm_segments.seg_id.isin(segment_matches.matches_id)]
# Interactive plot of segment matches

osm_edges_simplified_folium = plot_func.make_edgefeaturegroup(
    gdf=osm_edges_simplified,
    mycolor=pdict["osm_seg"],
    myweight=pdict["osm_weight"],
    nametag="OSM: all edges",
    show_edges=True,
    myalpha=pdict["osm_alpha"],
)

ref_edges_simplified_folium = plot_func.make_edgefeaturegroup(
    gdf=ref_edges_simplified,
    mycolor=pdict["ref_seg"],
    myweight=pdict["ref_weight"],
    nametag=f"{reference_name}: all edges",
    show_edges=True,
    myalpha=pdict["ref_alpha"],
)

segment_matches_folium = plot_func.make_edgefeaturegroup(
    gdf=segment_matches,
    mycolor=pdict["mat_seg"],
    myweight=pdict["mat_weight"],
    nametag=f"OSM and {reference_name}: matched segments",
    show_edges=True,
    myalpha=pdict["mat_alpha"],
)

m = plot_func.make_foliumplot(
    feature_groups=[
        osm_edges_simplified_folium,
        ref_edges_simplified_folium,
        segment_matches_folium,
    ],
    layers_dict=folium_layers,
    center_gdf=osm_nodes_simplified,
    center_crs=osm_nodes_simplified.crs,
)

bounds = plot_func.compute_folium_bounds(osm_nodes_simplified)
m.fit_bounds(bounds)

m.save(
    compare_results_inter_maps_fp
    + f"segment_matches_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare.html"
)

display(m)

在这里插入图片描述

print("Interactive map saved at " + compare_results_inter_maps_fp.lstrip("../")
    + f"segment_matches_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare.html")
Interactive map saved at results/COMPARE/cph_geodk/maps_interactive/segment_matches_15_17_30_compare.html
# Plot matched and unmatched features

set_renderer(renderer_map)

# OSM
fig, ax = plt.subplots(1, 1, figsize=pdict["fsmap"])

osm_matched_segments.plot(
    ax=ax, color=pdict["match"], label="matched"
)

osm_unmatched_segments.plot(
    ax=ax, color=pdict["nomatch"], label="unmatched"
)

cx.add_basemap(ax=ax, crs=study_crs, source=cx_tile_2)
ax.set_title(area_name + ": OSM matched & unmatched features")
ax.set_axis_off()
ax.legend()

plot_func.save_fig(fig, compare_results_static_maps_fp + f"matched_OSM_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare")

# REF
ref_matched_segments = segment_matches
ref_unmatched_segments = ref_segments.loc[~ref_segments.seg_id_ref.isin(segment_matches.seg_id_ref)]

fig, ax = plt.subplots(1, 1, figsize=pdict["fsmap"])

ref_matched_segments.plot(
    ax=ax, color=pdict["match"], label="matched"
)

ref_unmatched_segments.plot(
    ax=ax, color=pdict["nomatch"], label="unmatched"
)

cx.add_basemap(ax=ax, crs=study_crs, source=cx_tile_2)
ax.set_title(area_name + f": {reference_name} matched & unmatched features")
ax.set_axis_off()
ax.legend();

plot_func.save_fig(fig, compare_results_static_maps_fp + f"matched_reference_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare")

在这里插入图片描述

在这里插入图片描述

1.2 特征匹配总结

count_matched_osm = len(
    osm_matched_segments
)
count_matched_ref = len(
    ref_matched_segments
)

perc = np.round(100*count_matched_osm/len(osm_segments), 2)
print(
    f"Edge count: {count_matched_osm} of {len(osm_segments)} OSM segments ({perc}%) were matched with a reference segment."
)

perc = np.round(100*count_matched_ref/len(ref_segments), 2)
print(
    f"Edge count: {count_matched_ref} out of {len(ref_segments)} {reference_name} segments ({perc}%) were matched with an OSM segment."
)

length_matched_osm = osm_matched_segments.geometry.length.sum()

length_unmatched_osm = osm_unmatched_segments.geometry.length.sum()

length_matched_ref = ref_matched_segments.geometry.length.sum()

length_unmatched_ref = ref_unmatched_segments.geometry.length.sum()

perc = np.round(100*length_matched_osm/osm_segments.geometry.length.sum() , 2)
print(
    f"Length: {length_matched_osm/1000:.2f} km out of {osm_segments.geometry.length.sum()/1000:.2f} km of OSM segment ({perc}%) were matched with a reference segment."
)

perc = np.round(100*length_matched_ref/ref_segments.geometry.length.sum() , 2)
print(
    f"Length: {length_matched_ref/1000:.2f} km out of {ref_segments.geometry.length.sum()/1000:.2f} km of {reference_name} segments ({perc}%) were matched with an OSM segment."
)

results_feature_matching = {
    "osm_matched_count": count_matched_osm,
    "osm_matched_count_pct": count_matched_osm / len(osm_segments) * 100,
    "ref_matched_count": count_matched_ref,
    "ref_matched_count_pct": count_matched_ref / len(ref_segments) * 100,
    "osm_matched_length": length_matched_osm,
    "osm_matched_length_pct": length_matched_osm
    / osm_segments.geometry.length.sum()
    * 100,
    "ref_matched_length": length_matched_ref,
    "ref_matched_length_pct": length_matched_ref
    / ref_segments.geometry.length.sum()
    * 100,
}
Edge count: 41967 of 82759 OSM segments (50.71%) were matched with a reference segment.
Edge count: 60946 out of 63695 GeoDanmark segments (95.68%) were matched with an OSM segment.
Length: 416.38 km out of 816.70 km of OSM segment (50.98%) were matched with a reference segment.
Length: 599.93 km out of 626.48 km of GeoDanmark segments (95.76%) were matched with an OSM segment.
# Plot matching summary

set_renderer(renderer_plot)

# Edges
fig, ax = plt.subplots(1, 1, figsize=pdict["fsbar_small"], sharex=True, sharey=False)
bars = ("OSM", "Reference")
x_pos = [0.5, 1.5]

ax.bar(
    x_pos[0],
    [len(osm_segments)],
    width=pdict["bar_single"],
    color=pdict["nomatch"],
    label="unmatched",
)
ax.bar(
    x_pos[0],
    [count_matched_osm],
    width=pdict["bar_single"],
    color=pdict["match"],
    label="matched",
)

ax.bar(
    x_pos[1],
    [len(ref_segments)],
    width=pdict["bar_single"],
    color=pdict["nomatch"],
)
ax.bar(x_pos[1], [count_matched_ref], width=pdict["bar_single"], color=pdict["match"])

ax.set_title("Matched vs. unmatched number of segments")
ax.set_xticks(x_pos, bars)
ax.set_ylabel("Number of segments")
ax.legend()

plot_func.save_fig(fig, compare_results_plots_fp + f"matched_unmatched_edges_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare")

# Kilometers
fig, ax = plt.subplots(1, 1, figsize=pdict["fsbar_small"], sharex=True, sharey=False)
bars = ("OSM", "Reference")
x_pos = [0.5, 1.5]

ax.bar(
    x_pos[0],
    [osm_segments.geometry.length.sum() / 1000],
    width=pdict["bar_single"],
    color=pdict["nomatch"],
    label="unmatched",
)
ax.bar(
    x_pos[0],
    [length_matched_osm / 1000],
    width=pdict["bar_single"],
    color=pdict["match"],
    label="matched",
)

ax.bar(
    x_pos[1],
    [ref_segments.geometry.length.sum() / 1000],
    width=pdict["bar_single"],
    color=pdict["nomatch"],
)
ax.bar(
    x_pos[1],
    [length_matched_ref / 1000],
    width=pdict["bar_single"],
    color=pdict["match"],
)

ax.set_title("Matched vs. unmatched kilometers")
ax.set_xticks(x_pos, bars)
ax.set_ylabel("Kilometers")

ax.legend();

plot_func.save_fig(fig, compare_results_plots_fp + f"matched_unmatched_km_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare")

在这里插入图片描述

在这里插入图片描述

2.分析特征匹配结果

2.1 按基础设施类型匹配的功能

compare_protection = ref_matched_segments[
    ["protected", "geometry", "matches_id", "seg_id_ref"]
].merge(
    osm_matched_segments[["seg_id", "protected"]],
    left_on="matches_id",
    right_on="seg_id",
    how="inner",
    suffixes=("_ref", "_osm"),
)

assert len(compare_protection) == len(ref_matched_segments)

results_feature_matching["protection_level_identical"] = len(
    compare_protection.loc[
        compare_protection.protected_ref == compare_protection.protected_osm
    ]
)

results_feature_matching["protection_level_differs"] = len(
    compare_protection.loc[
        compare_protection.protected_ref != compare_protection.protected_osm
    ]
)
# Plot infrastructure type of matched features

set_renderer(renderer_map)
fig, ax = plt.subplots(1, 1, figsize=pdict["fsmap"])

compare_protection.loc[
    compare_protection.protected_ref == compare_protection.protected_osm
].plot(ax=ax, color=pdict["match"], linewidth=2, label="Same protection level")

compare_protection.loc[
    compare_protection.protected_ref != compare_protection.protected_osm
].plot(ax=ax, color=pdict["nomatch"], linewidth=2, label="Different protection levels")

cx.add_basemap(ax=ax, crs=study_crs, source=cx_tile_2)
ax.set_title("Infrastructure type of matched features")
ax.legend()

ax.set_axis_off()

plot_func.save_fig(
    fig,
    compare_results_static_maps_fp
    + f"matched_infra_type_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare",
)

在这里插入图片描述

2.2 特征匹配成功

在下图中,总结了每个数据集中匹配和不匹配片段的计数、百分比和长度。

Warning

网格单元中的一个数据集中的匹配片段的数量不一定反映另一数据集中的匹配片段的数量,因为片段可以与另一单元中的对应片段匹配。 此外,局部计数是指与网格单元相交的线段。 例如,穿过 2 个单元格的片段将被视为在 2 个不同单元格中匹配。 这不会改变匹配/不匹配片段的相对分布,但它确实需要上面匹配/不匹配片段的总体摘要使用与下面的图不同的片段总数。

# Index ref and osm segments by grid

grid = grid[['grid_id','geometry']]
osm_segments_joined = gpd.overlay(osm_segments[['geometry','seg_id','edge_id']], grid, how="intersection")

ref_segments_joined = gpd.overlay(ref_segments[['geometry','seg_id_ref','edge_id']], grid, how="intersection")

osm_segments_joined['geom_length'] = osm_segments_joined.geometry.length
ref_segments_joined['geom_length'] = ref_segments_joined.geometry.length

# Count features in each grid cell
data = [
    osm_segments_joined,
    ref_segments_joined
]
labels = ["osm_segments", "ref_segments"]

for data, label in zip(data, labels):

    df = eval_func.count_features_in_grid(data, label)

    grid = eval_func.merge_results(grid, df, "left")
    
    df = eval_func.length_features_in_grid(data, label)

    grid = eval_func.merge_results(grid, df, "left")


grid['osm_seg_dens'] = grid.length_osm_segments / (grid.area / 1000000)
grid['ref_seg_dens'] = grid.length_ref_segments / (grid.area / 1000000)
# Get matched, joined segments
osm_matched_joined = osm_segments_joined.loc[
    osm_segments_joined.seg_id.isin(osm_matched_segments.seg_id)
]

ref_matched_joined = ref_segments_joined.loc[
    ref_segments_joined.seg_id_ref.isin(ref_matched_segments.seg_id_ref)
]

# Count matched features in each grid cell
data = [osm_matched_joined, ref_matched_joined]
labels = ["osm_matched", "ref_matched"]

for data, label in zip(data, labels):

    df = eval_func.count_features_in_grid(data, label)

    grid = eval_func.merge_results(grid, df, "left")

    df = eval_func.length_of_features_in_grid(data, label)

    grid = eval_func.merge_results(grid, df, "left")


# Compute pct matched
grid["pct_matched_osm"] = (
    grid["count_osm_matched"] / grid["count_osm_segments"] * 100
)
grid["pct_matched_ref"] = (
    grid["count_ref_matched"] / grid["count_ref_segments"] * 100
)

# Compute local min, max, mean of matched
results_feature_matching["osm_pct_matched_local_min"] = grid.pct_matched_osm.min()
results_feature_matching["osm_pct_matched_local_max"] = grid.pct_matched_osm.max()
results_feature_matching["osm_pct_matched_local_mean"] = grid.pct_matched_osm.mean()
results_feature_matching["ref_pct_matched_local_min"] = grid.pct_matched_ref.min()
results_feature_matching["ref_pct_matched_local_max"] = grid.pct_matched_ref.max()
results_feature_matching["ref_pct_matched_local_mean"] = grid.pct_matched_ref.mean()

# Compute unmatched
grid.loc[
    (grid.count_osm_segments.notnull()) & (grid.count_osm_matched.isnull()),
    ["count_osm_matched"],
] = 0
grid.loc[
    (grid.count_ref_segments.notnull()) & (grid.count_ref_matched.isnull()),
    ["count_ref_matched"],
] = 0
grid.loc[
    (grid.count_osm_segments.notnull()) & (grid.pct_matched_osm.isnull()),
    ["pct_matched_osm"],
] = 0
grid.loc[
    (grid.count_ref_segments.notnull()) & (grid.pct_matched_ref.isnull()),
    ["pct_matched_ref"],
] = 0

grid.loc[
    (grid.count_osm_segments.notnull()) & (grid.length_osm_matched.isnull()),
    ["length_osm_matched"],
] = 0
grid.loc[
    (grid.count_ref_segments.notnull()) & (grid.length_ref_matched.isnull()),
    ["length_ref_matched"],
] = 0

grid["count_osm_unmatched"] = grid.count_osm_segments - grid.count_osm_matched
grid["count_ref_unmatched"] = grid.count_ref_segments - grid.count_ref_matched

grid["length_osm_unmatched"] = grid.length_osm_segments - grid.length_osm_matched
grid["length_ref_unmatched"] = grid.length_ref_segments - grid.length_ref_matched

# Compute pct unmatched
grid["pct_unmatched_osm"] = (
    grid["count_osm_unmatched"] / grid["count_osm_segments"] * 100
)
grid["pct_unmatched_ref"] = (
    grid["count_ref_unmatched"] / grid["count_ref_segments"] * 100
)

grid.loc[grid.pct_matched_osm == 100, "pct_unmatched_osm"] = 0
grid.loc[grid.pct_matched_ref == 100, "pct_unmatched_ref"] = 0
# Plot of matched features

set_renderer(renderer_map)

# Plot count of matched features
plot_cols = ["count_osm_matched", "count_ref_matched"]
plot_titles = [
    area_name + ": OSM features matched to reference data",
    area_name + f": {reference_name} features matched to OSM data",
]
filepaths = [
    compare_results_static_maps_fp
    + f"count_osm_matched_grid_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare",
    compare_results_static_maps_fp
    + f"count_osm_matched_grid_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare",
]
cmaps = [pdict["pos"]] * len(plot_cols)
no_data_cols = ["count_osm_segments", "count_ref_segments"]

norm_count_min = [0]*len(plot_cols)
norm_count_max = [grid[["count_osm_matched", "count_ref_matched"]].max().max()]*len(plot_cols)

plot_func.plot_grid_results(
    grid=grid,
    plot_cols=plot_cols,
    plot_titles=plot_titles,
    filepaths=filepaths,
    cmaps=cmaps,
    alpha=pdict["alpha_grid"],
    cx_tile=cx_tile_2,
    no_data_cols=no_data_cols,
    use_norm=True,
    norm_min=norm_count_min,
    norm_max=norm_count_max,
)

# Plot pct of count of matched features
norm_pct_min = [0]*len(plot_cols)
norm_pct_max = [100]*len(plot_cols)

plot_cols = ["pct_matched_osm", "pct_matched_ref"]
plot_titles = [
    area_name + f": percent of OSM features matched to reference data2",
    area_name + f": percent of {reference_name} features matched to OSM data2",
]
filepaths = [
    compare_results_static_maps_fp
    + f"pct_osm_matched_grid_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare",
    compare_results_static_maps_fp
    + f"pct_ref_matched_grid_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare",
]

cmaps = [pdict["seq"]] * len(plot_cols)

plot_func.plot_grid_results(
    grid=grid,
    plot_cols=plot_cols,
    plot_titles=plot_titles,
    filepaths=filepaths,
    cmaps=cmaps,
    alpha=pdict["alpha_grid"],
    cx_tile=cx_tile_2,
    no_data_cols=no_data_cols,
    use_norm=True,
    norm_min=norm_pct_min,
    norm_max=norm_pct_max,
)

# Plot length of matched features
norm_length_min = [0]*len(plot_cols)
norm_length_max = [grid[["length_osm_matched", "length_ref_matched"]].max().max()]*len(plot_cols)

plot_cols = ["length_osm_matched", "length_ref_matched"]
plot_titles = [
    area_name + f": length of OSM features matched to reference data (m)",
    area_name + f": length of {reference_name} features matched to OSM data (m)",
]
filepaths = [
    compare_results_static_maps_fp
    + f"length_osm_matched_grid_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare",
    compare_results_static_maps_fp
    + f"length_ref_matched_grid_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare",
]

cmaps = [pdict["pos"]] * len(plot_cols)

plot_func.plot_grid_results(
    grid=grid,
    plot_cols= plot_cols,
    plot_titles=plot_titles,
    filepaths=filepaths,
    cmaps=cmaps,
    alpha=pdict["alpha_grid"],
    cx_tile=cx_tile_2,
    no_data_cols=no_data_cols,
    use_norm=True,
    norm_min=norm_length_min,
    norm_max=norm_length_max,
)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

# Plot of unmatched features

set_renderer(renderer_map)

cmaps = [pdict["neg"]] * len(plot_cols)
no_data_cols = ["count_osm_segments", "count_ref_segments"]

# Plot count of matched features
plot_cols = ["count_osm_unmatched", "count_ref_unmatched"]
plot_titles = [
    area_name + f": OSM segments not matched to reference data",
    area_name + f": {reference_name} segments not matched to OSM data",
]
filepaths = [
    compare_results_static_maps_fp
    + f"count_osm_unmatched_grid_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare",
    compare_results_static_maps_fp
    + f"count_osm_unmatched_grid_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare",
]

norm_count_min = [0]*len(plot_cols)
norm_count_max = [grid[["count_osm_unmatched", "count_ref_unmatched"]].max().max()]*len(plot_cols)


plot_func.plot_grid_results(
    grid=grid,
    plot_cols=plot_cols,
    plot_titles=plot_titles,
    filepaths=filepaths,
    cmaps=cmaps,
    alpha=pdict["alpha_grid"],
    cx_tile=cx_tile_2,
    no_data_cols=no_data_cols,
    use_norm=True,
    norm_min=norm_count_min,
    norm_max=norm_count_max,
)

# Plot pct of count of matched segments
plot_cols = ["pct_unmatched_osm", "pct_unmatched_ref"]
plot_titles = [
    area_name + ": percent of OSM segments not matched to reference data",
    area_name + f": percent of {reference_name} segments not matched to OSM data",
]
filepaths = [
    compare_results_static_maps_fp
    + f"pct_osm_unmatched_grid_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare",
    compare_results_static_maps_fp
    + f"pct_ref_unmatched_grid_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare",
]

norm_pct_min = [0]*len(plot_cols)
norm_pct_max = [100]*len(plot_cols)

plot_func.plot_grid_results(
    grid=grid,
    plot_cols=plot_cols,
    plot_titles=plot_titles,
    filepaths=filepaths,
    cmaps=cmaps,
    alpha=pdict["alpha_grid"],
    cx_tile=cx_tile_2,
    no_data_cols=no_data_cols,
    use_norm=True,
    norm_min=norm_pct_min,
    norm_max=norm_pct_max,
)

# Plot length of matched segments
plot_cols = ["length_osm_unmatched", "length_ref_unmatched"]
plot_titles = [
    area_name + ": length of OSM segments not matched to reference data",
    area_name + f": length of {reference_name} segments not matched to OSM data",
]
filepaths = [
    compare_results_static_maps_fp
    + f"length_osm_unmatched_grid_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare",
    compare_results_static_maps_fp
    + f"length_ref_unmatched_grid_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}_compare",
]

norm_length_min = [0]*len(plot_cols)
norm_length_max = [grid[["length_osm_unmatched", "length_ref_unmatched"]].max().max()]*len(plot_cols)

plot_func.plot_grid_results(
    grid=grid,
    plot_cols=plot_cols,
    plot_titles=plot_titles,
    filepaths=filepaths,
    cmaps=cmaps,
    alpha=pdict["alpha_grid"],
    cx_tile=cx_tile_2,
    no_data_cols=no_data_cols,
    use_norm=True,
    norm_min=norm_length_min,
    norm_max=norm_length_max,
)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3. 概括

osm_keys = [x for x in results_feature_matching.keys() if "osm" in x]
ref_keys = [x for x in results_feature_matching.keys() if "ref" in x]

osm_values = [results_feature_matching[x] for x in osm_keys]
osm_df = pd.DataFrame(osm_values, index=osm_keys)

osm_df.rename({0: "OSM"}, axis=1, inplace=True)

# Convert to km
osm_df.loc["osm_matched_length"] = osm_df.loc["osm_matched_length"] / 1000

rename_metrics = {
    "osm_matched_count": "Count of matched segments",
    "osm_matched_count_pct": "Percent matched segments",
    "osm_matched_length": "Length of matched segments (km)",
    "osm_matched_length_pct": "Percent of matched network length",
    "osm_pct_matched_local_min": "Local min of % matched segments",
    "osm_pct_matched_local_max": "Local max of % matched segments",
    "osm_pct_matched_local_mean": "Local average of % matched segments",
}

osm_df.rename(rename_metrics, inplace=True)

ref_keys = [x for x in results_feature_matching.keys() if "ref" in x]

ref_values = [results_feature_matching[x] for x in ref_keys]
ref_df = pd.DataFrame(ref_values, index=ref_keys)

# Convert to km
ref_df.loc["ref_matched_length"] = ref_df.loc["ref_matched_length"] / 1000

ref_df.rename({0: reference_name}, axis=1, inplace=True)

rename_metrics = {
    "ref_matched_count": "Count of matched segments",
    "ref_matched_count_pct": "Percent matched segments",
    "ref_matched_length": "Length of matched segments (km)",
    "ref_matched_length_pct": "Percent of matched network length",
    "ref_pct_matched_local_min": "Local min of % matched segments",
    "ref_pct_matched_local_max": "Local max of % matched segments",
    "ref_pct_matched_local_mean": "Local average of % matched segments",
}

ref_df.rename(rename_metrics, inplace=True)
combined_results = pd.concat([osm_df, ref_df], axis=1)

combined_results.style.pipe(format_matched_style)
D:\tmp_resource\BikeDNA-main\BikeDNA-main\scripts\settings\df_styler.py:133: FutureWarning: Styler.applymap_index has been deprecated. Use Styler.map_index instead.
  styler.applymap_index(
Feature Matching Results
 OSMGeoDanmark
Count of matched segments41,96760,946
Percent matched segments51%96%
Length of matched segments (km)416600
Percent of matched network length51%96%
Local min of % matched segments1%2%
Local max of % matched segments100%100%
Local average of % matched segments73%96%
# Export to CSV

combined_results.to_csv(
    compare_results_data_fp + "feature_matching_summary_stats.csv", index=True
)

4. 保存结果

with open(
    f"../../results/compare/{study_area}/data/feature_matches__{buffer_dist}_{hausdorff_threshold}_{angular_threshold}.json",
    "w",
) as outfile:
    json.dump(results_feature_matching, outfile)

with open(
    f"../../results/compare/{study_area}/data/grid_results_feature_matching_{buffer_dist}_{hausdorff_threshold}_{angular_threshold}.pickle",
    "wb",
) as f:
    pickle.dump(grid, f)

from time import strftime
print("Time of analysis: " + strftime("%a, %d %b %Y %H:%M:%S"))
Time of analysis: Mon, 18 Dec 2023 20:41:52

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1380057.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

what is BERT?

BERT Introduction Paper 参考博客 9781838821593_ColorImages.pdf (packt-cdn.com) Bidirectional Encoder Representation from Transformer 来自Transformer的双向编码器表征 基于上下文&#xff08;context-based&#xff09;的嵌入模型。 那么基于上下文&#xff08;…

imgaug库指南(19):从入门到精通的【图像增强】之旅

引言 在深度学习和计算机视觉的世界里&#xff0c;数据是模型训练的基石&#xff0c;其质量与数量直接影响着模型的性能。然而&#xff0c;获取大量高质量的标注数据往往需要耗费大量的时间和资源。正因如此&#xff0c;数据增强技术应运而生&#xff0c;成为了解决这一问题的…

“所有伙食开销统计:轻松查看,智能管理你的餐饮支出“

你是否经常为伙食开销感到困扰&#xff0c;不知道如何有效控制和管理&#xff1f;现在&#xff0c;有了我们的伙食开销统计工具&#xff0c;这些问题将得到轻松解决&#xff01; 首先第一步&#xff0c;我们要进入晨曦记账本并在上方功能栏里选择“查看方式”。并在弹出来的列表…

数据结构第十三弹---链式二叉树基本操作(上)

链式二叉树 1、结构定义2、手动创建二叉树3、前序遍历4、中序遍历5、后序遍历6、层序遍历7、计算结点个数8、计算叶子结点个数9、计算第K层结点个数10、计算树的最大深度总结 1、结构定义 实现一个数据结构少不了数据的定义&#xff0c;所以第一步需要定义二叉树的机构。 typ…

API Monitor简易使用教程 监控Windows dll调用 监控Windows API调用 查看函数名,参数类型,参数,返回值

先看效果&#xff0c;可以显示所有dll及windows api的指定函数调用&#xff0c;以及传递的参数查看与修改。 官网下载 也有教程 我验证使用方法 1、API Filter窗口&#xff1a;选定要监听的dll函数或windows API&#xff0c;可以打断点 选中并右键勾上Breakpoint 选 Before C…

MFC为资源对话框添加消息处理函数和初始化控件

现在我VC6新建了一个对话框工程&#xff1b;又在资源添加了一个新的对话框&#xff0c;并为新的对话框添加了名为CTestDlg的类&#xff1b; 在主对话框的cpp文件包含#include "TestDlg.h"&#xff1b; 在主对话框的cpp文件的OnInitDialog()成员函数中&#xff0c;添…

web学习笔记(十五)

目录 1.Date对象 1.1日期对象的概念 1.2Date()方法的使用 1.3Date()常用方法汇总 1.4例题&#xff1a;用函数编写一个倒计时 2.函数 2.1函数的概念 2.2函数的使用 2.3函数的参数 2.4函数的声明 2.5函数的返回值 2.6异步函数 3特殊函数类型 3.1匿名函数 3.2箭头函数…

挖种子小游戏

欢迎来到程序小院 挖种子 玩法&#xff1a;看到种子点击鼠标左键进行挖种子&#xff0c;30秒内看你能够挖多少颗种子&#xff0c;快去挖种子吧^^。开始游戏https://www.ormcc.com/play/gameStart/251 html <canvas id"canvas" width"640" height"…

BSC/平衡记分卡

一、Balanced Score Card BSC即平衡计分卡&#xff08;Balanced Score Card&#xff09;&#xff0c;是常见的绩效考核方式之一&#xff0c;是从财务、客户、内部运营、学习与成长四个角度&#xff0c;将组织的战略落实为可操作的衡量指标和目标值的一种新型绩效管理体系。 是…

关于lombok插件的使用

在 idea 中有个非常好用的插件 lombok&#xff0c;可以用来在实体类中自动生成 get 、set以及构造方法&#xff0c;下面我们来学习如何使用它&#xff1a; 首先打开settings&#xff0c;按照以下方法&#xff1a; 到 marketplace 中搜索 lombok&#xff0c;我这里已经安装好了…

STM32——OLED实验

1.OLED简介 OLED&#xff0c;即有机发光二极管 OLED引脚说明 引脚说明&#xff1a; 1、CS&#xff1a;OLED片选信号&#xff08;低电平有效&#xff09; 2、WR&#xff1a;向OLED写入数据 3、RD&#xff1a;向OLED读取数据 4、D[7:0]&#xff1a;8位双向数据线&#xff0c;有…

本地静态资源打包出来,本地配置ng访问服务器(uniapp打包成h5后,使用打包资源连接测试环境测试)

1.下载ng https://nginx.org/en/download.html 2.解压下载的压缩包 3.打包h5静态资源 4.将打包出来的资源放入ng -》html文件夹下面 5.进入ng-》conf-》nginx.conf 进行转发配置 6.启动ng服务&#xff0c;点击nginx.exe 7.浏览器直接访问http://localhost:8081/#/&#x…

element-ui el-table表格勾选框条件禁用,及全勾选按钮禁用, 记录

项目场景&#xff1a; 表格的部分内容是可以被勾选的&#xff0c;部分内容是不可以被勾选的 使用的是 “element-plus”: “^2.2.22”, 以上应该都是兼容的 问题描述 要求el-table表格中&#xff0c;部分内容不可以被勾选&#xff0c;全选框在没有可选内容时&#xff0c;是禁…

日志审计系统Agent项目创建——获取Linux的ip并将得到的日志插入数据库中(Linux版本)

上一篇文章可以直接展示系统在运行过程中的日志&#xff0c;读取日志文件https://blog.csdn.net/wjl990316fddwjl/article/details/135553685 如何将得到的日志插入数据表中&#xff0c;进行更可观的展示&#xff1f; 1、创建表格并执行&#xff0c;可以看到数据库已经创建好…

基于ssm的校园预点餐系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于ssm的校园预点餐系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring Sp…

前端规范扩展

前端编程规范是基于原有vue2基础上那套《编码风格及标准》上&#xff0c;应用于vue3、typescript、vite2基础上延伸出来的扩展补充&#xff0c;持续完善 一、编码规范 ESLint 代码检测工具 Pretter 代码格式化工具配合双校验代码 Git 规范 - 编码工具 vscode 同步参考文档中…

用通俗易懂的方式讲解:如何用大语言模型构建一个知识问答系统

传统搜索系统基于关键字匹配&#xff0c;在面向&#xff1a;游戏攻略、技术图谱、知识库等业务场景时&#xff0c;缺少对用户问题理解和答案二次处理能力。 本文探索使用大语言模型&#xff08;Large Language Model, LLM&#xff09;&#xff0c;通过其对自然语言理解和生成的…

APP自动化测试(超详细)

在实习过程中&#xff0c;我接触到了一些SDL安全提测的工作。原来我是学web端渗透比较多的&#xff0c;移动端这块基本没怎么试过手&#xff0c;结果刚开始一直踩坑&#xff0c;连抓包都抓不到(&#xff34;▽&#xff34;)。 下面记录下我遇到的部分问题和解决方法&#xff0…

有没有可以拖拉拽生成一个低代码平台?

据我所知&#xff0c;低代码平台都能拖拉拽生成。作为一组数字技术工具平台&#xff0c;它能基于图形化拖拽、参数化配置等更为高效的方式&#xff0c;实现快速构建、数据编排、连接生态、中台服务等。通过少量代码或不用代码实现数字化转型中的场景应用创新。 到底啥是低代码&…

【深度学习目标检测】十六、基于深度学习的麦穗头系统-含GUI和源码(python,yolov8)

全球麦穗检测是植物表型分析领域的一个挑战&#xff0c;主要目标是检测图像中的小麦麦穗。这种检测在农业领域具有重要意义&#xff0c;可以帮助农民评估作物的健康状况和成熟度。然而&#xff0c;由于小麦麦穗在视觉上具有挑战性&#xff0c;准确检测它们是一项艰巨的任务。 全…