Upgrade to Pro — share decks privately, control downloads, hide ads and more …

2つの曲線を比較する方法ってあるの? 〜フレシェ距離を試してみた〜 with Python

2つの曲線を比較する方法ってあるの? 〜フレシェ距離を試してみた〜 with Python

More Decks by NearMeの技術発表資料です

Other Decks in Programming

Transcript

  1. 11 集合同⼠を⽐べる⽅法のうちの1つ • ハウスドルフ距離(Hausdorff distance) ◦ ある2つの集合A, B(距離空間の部分空間)の隔たり(距離のようなもの)を測る もの ◦

    最⼤でこのくらい進んだらもう⽚⽅の集合のどれかの要素には到達できるみたいな 感じ これだと... → 要素同⼠での⽐較となり、線分のような連続かつ順序があるものを考慮できない...
  2. 12 集合同⼠を⽐べる⽅法のうちの1つ • ハウスドルフ距離(Hausdorff distance) ◦ ある2つの集合A, B(距離空間の部分空間)の隔たり(距離のようなもの)を測る もの ◦

    最⼤でこのくらい進んだらもう⽚⽅の集合のどれかの要素には到達できるみたいな 感じ これだと... → 要素同⼠での⽐較となり、線分のような連続かつ順序があるものを考慮できない... そこで...
  3. 23 • ⾃由ダイアグラム(free-space diagram) ◦ 閾値 ε (正の値)を定めておき、線分間の距離が ε 以下である点対を探す

    • Reachable space ◦ free-spaceの中でもダイアグラムの(0, 0)から終端まで単調パスが到達可能な領域 ◦ 孤⽴している領域などは除外される フレシェ距離の計算
  4. 24 • ⾃由ダイアグラム(free-space diagram) ◦ 閾値 ε (正の値)を定めておき、線分間の距離が ε 以下である点対を探す

    • Reachable space ◦ free-spaceの中でもダイアグラムの(0, 0)から終端まで単調パスが到達可能な領域 ◦ 孤⽴している領域などは除外される • Monotone curve ◦ Reachable space内で単調に引くことのできるパス フレシェ距離の計算
  5. 25

  6. 30 • 以下のリンク先にnotebookを⽤意しました ◦ https://colab.research.google.com/drive/1LYYE605QMyOrNyT2d75CU5wsQiUBs6I Y?usp=sharing • 内容 ◦ free-spaceの作成と可視化

    ◦ reachable-spaceの作成と可視化 ◦ monotone curveの作成と可視化 ◦ フレシェ距離の計算 • 以下の論⽂を参考に作成しました ◦ https://arxiv.org/abs/1901.01504 フレシェ距離の計算をやってみよう
  7. 31 • free-space作成: アルゴリズムの詳細 def calculate_free_space(curve1, curve2, epsilon): m, n

    = len(curve1), len(curve2) free_space = np.zeros((m, n)) for i in range(m): for j in range(n): if i == 0 and j == 0: free_space[i, j] = euclidean_distance(curve1[i], curve2[j]) <= epsilon elif i == 0: free_space[i, j] = point_to_segment_distance(curve1[i], curve2[j-1], curve2[j]) <= epsilon elif j == 0: free_space[i, j] = point_to_segment_distance(curve2[j], curve1[i-1], curve1[i]) <= epsilon else: dist1 = point_to_segment_distance(curve1[i], curve2[j-1], curve2[j]) dist2 = point_to_segment_distance(curve2[j], curve1[i-1], curve1[i]) free_space[i, j] = min(dist1, dist2) <= epsilon return free_space
  8. 32 • free-space作成: def calculate_free_space(curve1, curve2, epsilon): m, n =

    len(curve1), len(curve2) free_space = np.zeros((m, n)) for i in range(m): for j in range(n): if i == 0 and j == 0: free_space[i, j] = euclidean_distance(curve1[i], curve2[j]) <= epsilon elif i == 0: free_space[i, j] = point_to_segment_distance(curve1[i], curve2[j-1], curve2[j]) <= epsilon elif j == 0: free_space[i, j] = point_to_segment_distance(curve2[j], curve1[i-1], curve1[i]) <= epsilon else: dist1 = point_to_segment_distance(curve1[i], curve2[j-1], curve2[j]) dist2 = point_to_segment_distance(curve2[j], curve1[i-1], curve1[i]) free_space[i, j] = min(dist1, dist2) <= epsilon return free_space アルゴリズムの詳細 線分間の距離が ε以下であ るものを絞り込める
  9. 33 • reachable-space作成: アルゴリズムの詳細 def calculate_reachable_space(free_space): m, n = free_space.shape

    reachable = np.zeros((m, n)) reachable[0, 0] = free_space[0, 0] for i in range(1, m): reachable[i, 0] = reachable[i-1, 0] and free_space[i, 0] for j in range(1, n): reachable[0, j] = reachable[0, j-1] and free_space[0, j] for i in range(1, m): for j in range(1, n): reachable[i, j] = free_space[i, j] and (reachable[i-1, j] or reachable[i, j-1] or reachable[i-1, j-1]) return reachable
  10. 34 • reachable-space作成: def calculate_reachable_space(free_space): m, n = free_space.shape reachable

    = np.zeros((m, n)) reachable[0, 0] = free_space[0, 0] for i in range(1, m): reachable[i, 0] = reachable[i-1, 0] and free_space[i, 0] for j in range(1, n): reachable[0, j] = reachable[0, j-1] and free_space[0, j] for i in range(1, m): for j in range(1, n): reachable[i, j] = free_space[i, j] and (reachable[i-1, j] or reachable[i, j-1] or reachable[i-1, j-1]) return reachable アルゴリズムの詳細 単調増加するパスが描けるかを判定
  11. 35 • monotone curve作成: (判定⾃体は定数時間) アルゴリズムの詳細 def find_monotone_path(reachable): m, n

    = reachable.shape if not reachable[-1, -1]: return None path = [(m-1, n-1)] i, j = m-1, n-1 while i > 0 or j > 0: if i > 0 and reachable[i-1, j]: i -= 1 elif j > 0 and reachable[i, j-1]: j -= 1 else: i -= 1 j -= 1 path.append((i, j)) return path[::-1]
  12. 36 • monotone curve作成: (判定⾃体は定数時間) アルゴリズムの詳細 • 探索している部分が reachableであれば、 pathを

    追加する def find_monotone_path(reachable): m, n = reachable.shape if not reachable[-1, -1]: return None path = [(m-1, n-1)] i, j = m-1, n-1 while i > 0 or j > 0: if i > 0 and reachable[i-1, j]: i -= 1 elif j > 0 and reachable[i, j-1]: j -= 1 else: i -= 1 j -= 1 path.append((i, j)) return path[::-1]
  13. 37 • フレシェ距離の計算: アルゴリズムの詳細 def calculate_frechet_distance(curve1, curve2, epsilon_min=0, epsilon_max=None, tolerance=1e-6):

    if epsilon_max is None: epsilon_max = max( max(euclidean_distance(p1, p2) for p1 in curve1 for p2 in curve2), max(point_to_segment_distance(p, curve1[i], curve1[i+1]) for i in range(len(curve1)-1) for p in curve2), max(point_to_segment_distance(p, curve2[i], curve2[i+1]) for i in range(len(curve2)-1) for p in curve1) ) final_path = None while epsilon_max - epsilon_min > tolerance: epsilon = (epsilon_min + epsilon_max) / 2 free_space = calculate_free_space(curve1, curve2, epsilon) reachable = calculate_reachable_space(free_space) path = find_monotone_path(reachable) if path is not None: epsilon_max = epsilon final_path = path else: epsilon_min = epsilon return epsilon_max, final_path
  14. 38 • フレシェ距離の計算: アルゴリズムの詳細 • pathが存在する ◦ もっと下があるはず ◦ epsilonの最大値を小さくする

    • pathが存在しない ◦ これ以下には存在しない ◦ epsilonの最大値を小さくする 二分探索でフレシェ距離を計算する def calculate_frechet_distance(curve1, curve2, epsilon_min=0, epsilon_max=None, tolerance=1e-6): if epsilon_max is None: epsilon_max = max( max(euclidean_distance(p1, p2) for p1 in curve1 for p2 in curve2), max(point_to_segment_distance(p, curve1[i], curve1[i+1]) for i in range(len(curve1)-1) for p in curve2), max(point_to_segment_distance(p, curve2[i], curve2[i+1]) for i in range(len(curve2)-1) for p in curve1) ) final_path = None while epsilon_max - epsilon_min > tolerance: epsilon = (epsilon_min + epsilon_max) / 2 free_space = calculate_free_space(curve1, curve2, epsilon) reachable = calculate_reachable_space(free_space) path = find_monotone_path(reachable) if path is not None: epsilon_max = epsilon final_path = path else: epsilon_min = epsilon return epsilon_max, final_path
  15. 39 • Fréchet距離の計算アルゴリズム ◦ https://qiita.com/takilog/items/9dba1db42fe6f75587df • Walking the Dog Fast

    in Practice: Algorithm Engineering of the Fréchet Distance ◦ https://arxiv.org/abs/1901.01504 • Computing Discrete Fréchet Distance ◦ http://www.kr.tuwien.ac.at/staff/eiter/et-archive/cdtr9464.pdf 参考⽂献