Slide 1

Slide 1 text

0 2つの曲線を⽐較する⽅法ってあるの? 〜フレシェ距離を試してみた〜 2024-07-19 第99回NearMe技術勉強会 Kaito Asahi

Slide 2

Slide 2 text

1 こんなお悩みはありませんか?

Slide 3

Slide 3 text

2 任意の2つの曲線同士がどのくらい似ているのか 定量的に確認したいです!

Slide 4

Slide 4 text

3 任意の2つの曲線同士がどのくらい似ているのか 定量的に確認したいです! 2つの経路がどのくらい似ているのか知りたくて ...

Slide 5

Slide 5 text

4 任意の2つの曲線同士がどのくらい似ているのか 定量的に確認したいです! 2つの経路がどのくらい似ているのか知りたくて ... そんなあなたに朗報?です!!

Slide 6

Slide 6 text

5 任意の2つの曲線同士がどのくらい似ているのか 定量的に確認したいです! 2つの経路がどのくらい似ているのか知りたくて ... そんなあなたに朗報?です!! フレシェ距離が役に立つかもです ...

Slide 7

Slide 7 text

6 この2つの曲線は似ていますか...?

Slide 8

Slide 8 text

7 この2つの曲線は似ていますか...? まあ似ていない...

Slide 9

Slide 9 text

8 この2つの曲線は似ていますか...?

Slide 10

Slide 10 text

9 この2つの曲線は似ていますか...? 似ているかも!!

Slide 11

Slide 11 text

10 この2つの曲線は似ていますか...? 似ているかも!! なぜ似ていると思ったのか?

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

13 形状までを⽐較するための距離(フレシェ距離) ● フレシェ距離 ○ ある2つの線分列P, Qで作られる曲線の形状を⽐較するときに使えるもの(fは連続 で単調増加)

Slide 15

Slide 15 text

14 形状までを⽐較するための距離(フレシェ距離) ● フレシェ距離 ○ ある2つの線分列P, Qで作られる曲線の形状を⽐較するときに使えるもの(fは連続 で単調増加) 深掘りします

Slide 16

Slide 16 text

15 形状までを⽐較するための距離(フレシェ距離) ● フレシェ距離のイメージ ○ よくある例として、ペットと飼い主が散歩しているときの様⼦

Slide 17

Slide 17 text

16 形状までを⽐較するための距離(フレシェ距離) ● フレシェ距離のイメージ ○ よくある例として、ペットと飼い主が散歩しているときの様⼦ ○ 必要最低限のリードの⻑さがフレシェ距離に当たる(最も小さい最大距離) 速すぎだよ ペットに過信はできないので、リードの 長さには余裕があった方がよさそう

Slide 18

Slide 18 text

17 形状までを⽐較するための距離(フレシェ距離) ● フレシェ距離のイメージ ○ よくある例として、⽝と飼い主が散歩しているときの様⼦ ○ 必要なリードの最⼩の⻑さがフレシェ距離に当たる(最も小さい最大距離)

Slide 19

Slide 19 text

18 形状までを⽐較するための距離(フレシェ距離) ● フレシェ距離のイメージ ○ よくある例として、⽝と飼い主が散歩しているときの様⼦ ○ 必要なリードの最⼩の⻑さがフレシェ距離に当たる(最も小さい最大距離) 最大でどのくらい離れる のかを計算

Slide 20

Slide 20 text

19 形状までを⽐較するための距離(フレシェ距離) ● フレシェ距離のイメージ ○ よくある例として、⽝と飼い主が散歩しているときの様⼦ ○ 必要なリードの最⼩の⻑さがフレシェ距離に当たる(最も小さい最大距離) 最大でどのくらい離れる のかを計算 どのくらいの長さのリードが必 要かの最低限を計算

Slide 21

Slide 21 text

20 フレシェ距離の計算

Slide 22

Slide 22 text

21 フレシェ距離の計算 最大でどのくらい離れる のかを計算 どのくらいの長さのリードが必 要かの最低限を計算 ある程度近い距離の部分だけで 計算したいな ...

Slide 23

Slide 23 text

22 ● ⾃由ダイアグラム(free-space diagram) ○ 閾値 ε (正の値)を定めておき、線分間の距離が ε 以下である点対を探す フレシェ距離の計算

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

25

Slide 27

Slide 27 text

26 ● ⾃由ダイアグラム、Reachable space、Monotone curveのイメージ フレシェ距離の計算

Slide 28

Slide 28 text

27 ● ⾃由ダイアグラム、Reachable space、Monotone curveのイメージ フレシェ距離の計算 孤立 孤立

Slide 29

Slide 29 text

28 ● ⾃由ダイアグラム、Reachable space、Monotone curveのイメージ フレシェ距離の計算

Slide 30

Slide 30 text

29 ● ⾃由ダイアグラム、Reachable space、Monotone curveのイメージ フレシェ距離の計算 時を逆行せずに 最後まで進めた

Slide 31

Slide 31 text

30 ● 以下のリンク先にnotebookを⽤意しました ○ https://colab.research.google.com/drive/1LYYE605QMyOrNyT2d75CU5wsQiUBs6I Y?usp=sharing ● 内容 ○ free-spaceの作成と可視化 ○ reachable-spaceの作成と可視化 ○ monotone curveの作成と可視化 ○ フレシェ距離の計算 ● 以下の論⽂を参考に作成しました ○ https://arxiv.org/abs/1901.01504 フレシェ距離の計算をやってみよう

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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 アルゴリズムの詳細 線分間の距離が ε以下であ るものを絞り込める

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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 アルゴリズムの詳細 単調増加するパスが描けるかを判定

Slide 36

Slide 36 text

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]

Slide 37

Slide 37 text

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]

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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 参考⽂献

Slide 41

Slide 41 text

40 Thank you