4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PostGIS の ST_HausdorffDistance とは何か?

Last updated at Posted at 2023-12-20

この記事は FOSS4G Advent Calendar 2023 21日目の記事でございます。

はじめに

大学時代に、PostGIS の ST_HausdorffDistance を少し触っていたので、復習がてらどういった関数なのかまとめたいと思います。

2つのジオメトリ間の距離を表現するものとして様々な計算手法があります。ハウスドルフ距離もその1つで、ユークリッド幾何学に代表される2点間の距離ではなく、2つの部分集合に対する距離を示します。私も数学はあまり深く学んでいないため、ざっくり「2つの集合に対する距離」という認識でいます。

さて、PostgreSQLの空間情報の拡張機能であるPostGISにおいても、2つのジオメトリに対してハウスドルフ距離を計測する関数が備わっています。それが ST_HausdorffDistance です。

ハウスドルフ距離

ハウスドルフ距離は Wikipedia を見ると少し難しそうな数式が書いてありますが、原理はそこまで難しくありません。

文章で簡潔に説明すると、ジオメトリA(線形)とジオメトリB(線形)があったとして「ジオメトリAを構成する各点からジオメトリBへの最短距離を算出したうちの最大距離」が、ハウスドルフ距離です。

図で表現してみます。例えば、以下の画像のように、複数の点で構成されている2つの線分があったとします。

hausdorff_blank.png

まず、各点から線分に対する最短距離を算出します。以下の画像では、線分Bの各点から、線分Aに対する最小距離を算出します(青い線)、その中で一番最大の距離がハウスドルフ距離となります(赤い線)。

hausdorff.drawio (3).png

ST_Distance は何を返す?

ST_Distance は、線形同士であっても最短距離をそのまま返します。実際に、以下の画像の線分データに対して ST_Distance を実行してみます。

hausdorff_blank.png

SELECT 
    ST_Distance(geomA, geomB)
FROM ( 
    SELECT 
        'LINESTRING(0 0, 1 1, 2 0, 3 1, 4 0)'::geometry AS geomA,
        'LINESTRING(0 4, 1 3, 2 5, 3 3, 4 4)'::geometry AS geomB
) as t;

これを実行すると、結果は2と返ってきます。

 st_distance 
-------------
           2

なぜこの値が返ってくるのかというと、線分Aの (1,1) と、線分Bの (1,3) が最短距離となり、その距離が2であるからです。

ST_HausdorffDistance

続いて、PostGISで ST_HausdorffDistance を使ってみます。先程と同じく、以下の画像の線分データに対して ST_HausdorffDistance を実行してみます。

hausdorff_blank.png

SELECT 
    ST_HausdorffDistance(geomA, geomB)
FROM ( 
    SELECT 
        'LINESTRING(0 0, 1 1, 2 0, 3 1, 4 0)'::geometry AS geomA,
        'LINESTRING(0 4, 1 3, 2 5, 3 3, 4 4)'::geometry AS geomB
) as t;

これを実行すると、結果は 4.123105625617661 と返ってきます。

 st_hausdorffdistance 
----------------------
    4.123105625617661

なぜこの値が返ってくるのかというと、先程の原理の説明のように線分Aの (2,5) と、線分Bの (3,1) の距離がハウスドルフ距離となり、その距離が 4.123105625617661 であるからです。

各点の最短距離を出してみる

実際にハウスドルフ距離の原理に従っているかどうか調べるため、線分Bの各点から線分Aに対する最短距離を PostGIS で算出してみます。

以下は、線分Bの各点から線分Aに対する最短距離を算出するSQL文です。地道に各点からの最短距離を ST_Distance を使って算出します。

SELECT 
    ST_Distance(geomA, pointA),
    ST_Distance(geomA, pointB),
    ST_Distance(geomA, pointC),
    ST_Distance(geomA, pointD),
    ST_Distance(geomA, pointE)
FROM ( 
    SELECT 
        'LINESTRING(0 0, 1 1, 2 0, 3 1, 4 0)'::geometry AS geomA,
        'POINT(0 4)'::geometry AS pointA,
        'POINT(1 3)'::geometry AS pointB,
        'POINT(2 5)'::geometry AS pointC,
        'POINT(3 3)'::geometry AS pointD,
        'POINT(4 4)'::geometry AS pointE
) as t;

上記のSQL文をPostgreSQLのデータベースに打つと、結果は以下のようになります。

    st_distance     | st_distance |    st_distance    | st_distance |    st_distance     
--------------------+-------------+-------------------+-------------+--------------------
 3.1622776601683795 |           2 | 4.123105625617661 |           2 | 3.1622776601683795

実際にハウスドルフ距離として算出されている値は、それぞれの最短距離の最大値であることが、上記の結果からわかります。

ST_Distance と ST_HausdorffDistance の比較

以下の画像で、各関数の距離の算出方法を見てみます。 ST_Distance は赤色の線の距離を算出しています。2つの線分に対する最短距離です。 ST_HausdorffDistance は緑色の線の距離を算出しています。

hausdorff.drawio.png

補足事項

PostGIS の公式ドキュメントの ST_HausdorffDistance の説明 には、以下のNoteが貼られています。

このアルゴリズムは標準的なハウスドルフ距離と等価ではありません。しかし、使用可能な場面の大部分で正しくなる近似計算がなされています。重要なものに、それぞれが概ね平行で概ね等しい長さのラインストリングがあります。これはラインのマッチングに使える基準です。

上記の詳しい検証まではできていない&言葉の意味を完全に理解はできていません。文面をそのまま読むと、PostGISでは標準とは少し違うアルゴリズムでハウスドルフ距離の算出をしているようですが、値が正確になるような近似計算が施されているとのことです。

また、似たようなジオメトリ間の距離算出の関数として ST_FrechetDistane (フレシェ距離) があります。これは線の位置と点の並び順を考慮して距離を算出します。

参考文献

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?