ポリラインの変曲点を見つけるアルゴリズム


22

私は変曲点、つまり線の曲線が開始および終了する点を見つけようとしています。画像を見ると、緑の線は道路または小川であり、黒の点は曲線の開始点と終了点です。 ここに画像の説明を入力してください

これらのポイントの生成を自動化するための高レベルのステップは何ですか?ArcGISデスクトップを使用しており、ArcObjectsを使用すると非常に便利です。


ソースデータはラインセグメントで構成されるポリラインであり、曲線で近似したいのですか、それともすでにアークセグメントがありますか?
U2ros

現在、線分で構成されています。
Devdatta Tengshe

1
この問題のイラストは見え飛躍で公開1のようにesri.com/news/arcuser/0110/turning.html
whuber

@whuber:非常に鋭い観察。それがまさに、イメージの作成に使用したデータソースでした。
Devdatta Tengshe

回答:


15

曲線が線分で構成されている場合、それらの線分のすべての内部点は変曲点になりますが、これは興味深いことではありません。代わりに、曲線はそれらのセグメントの頂点によって近似されていると考える必要があります。これらのセグメントを通して区分的に2回微分可能な曲線をスプライン化することにより、曲率を計算できます。厳密に言えば、変曲点は曲率がゼロの場所です。

この例では、曲率がほぼゼロである長いストレッチがあります。これは、示された点が低曲率領域のそのようなストレッチの端部に近似する必要があることを示唆しています。

したがって、効果的なアルゴリズムは、頂点をスプラインし、中間点の密なセットに沿って曲率を計算し、ほぼゼロの曲率の範囲を識別し(「近い」という意味の合理的な推定値を使用)、それらの範囲の端点をマークします。

Rこれらのアイデアを説明するための作業コードを次に示します。一連の座標として表される線ストリングから始めましょう。

xy <- matrix(c(5,20, 3,18, 2,19, 1.5,16, 5.5,9, 4.5,8, 3.5,12, 2.5,11, 3.5,3, 
               2,3, 2,6, 0,6, 2.5,-4, 4,-5, 6.5,-2, 7.5,-2.5, 7.7,-3.5, 6.5,-8), ncol=2, byrow=TRUE)

曲線のパラメータ化を実現するためにx座標y座標を別々スプラインします。(パラメーターはと呼ばれtimeます。)

n <- dim(xy)[1]
fx <- splinefun(1:n, xy[,1], method="natural")
fy <- splinefun(1:n, xy[,2], method="natural")

プロットと計算のためにスプラインを内挿します。

time <- seq(1,n,length.out=511)
uv <- sapply(time, function(t) c(fx(t), fy(t)))

パラメータ化された曲線の曲率を計算する関数が必要です。スプラインの1次および2次導関数を推定する必要があります。多くのスプライン(3次スプラインなど)では、これは簡単な代数計算です。 R最初の3つの導関数を自動的に提供します。(他の環境では、導関数を数値的に計算したい場合があります。)

curvature <- function(t, fx, fy) {
  # t is an argument to spline functions fx and fy.
  xp <- fx(t,1); yp <- fy(t,1)            # First derivatives
  xpp <- fx(t,2); ypp <- fy(t,2)          # Second derivatives
  v <- sqrt(xp^2 + yp^2)                  # Speed
  (xp*ypp - yp*xpp) / v^3                 # (Signed) curvature
  # (Left turns have positive curvature; right turns, negative.)
}

kappa <- abs(curvature(time, fx, fy))     # Absolute curvature of the data

曲線の広がりに関して、曲率ゼロのしきい値推定することを提案します。これは少なくとも良い出発点です。曲線の曲がり具合に応じて調整する必要があります(つまり、曲線が長くなると増加します)。これは、後で曲率に従ってプロットを色付けするために使用されます。

curvature.zero <- 2*pi / max(range(xy[,1]), range(xy[,2])) # A small threshold
i.col <- 1 + floor(127 * curvature.zero/(curvature.zero + kappa)) 
palette(terrain.colors(max(i.col)))                        # Colors

頂点がスプラインされ、曲率が計算されたので、変曲点を見つけるためだけに残ります。それらを表示するには、頂点をプロットし、スプラインをプロットし、その上の変曲点をマークします。

plot(xy, asp=1, xlab="x",ylab="y", type="n")
tmp <- sapply(2:length(kappa), function(i) lines(rbind(uv[,i-1],uv[,i]), lwd=2, col=i.col[i]))
points(t(sapply(time[diff(kappa < curvature.zero/2) != 0], 
       function(t) c(fx(t), fy(t)))), pch=19, col="Black")
points(xy)

プロット

開いた点は元の頂点でxyあり、黒い点はこのアルゴリズムで自動的に識別される変曲点です。曲線の端点で曲率を確実に計算することはできないため、これらのポイントは特別にマークされていません。


たぶん私が使った用語は間違っていたのでしょう。あなたが仮定したものは、まさに私が望んだものです。あなたの答えは有望に見えます、そして私は私のシェープファイルを処理するためにRと協力しなければなりません。
Devdatta Tengshe

3

高密度化ツールを使用できます。この場合、角度で高密度化することを選択し、次に、直線で受け入れられる最大角度を選択します。次に、結果ラインにツールを[頂点でラインを分割]に適用します。最後に、shape_lengthが最小道路長より短い線を削除します。

ここに画像の説明を入力してください

この図には、3つのステップがあります。

1-角度を使用して線を高密度化します。パラメーターとして10度を使用し、スプリットラインを使用しました。図では、曲線は初期段階にあります。

arcpy.Densify_edit("line" , "ANGLE" , "","",10)
arcpy.SplitLine_management("line" , "line_split")

2- shape_lengthが冗長でないセグメントを選択します。表にあるように、これらの冗長な長さは選択していません。次に、それらを選択して新しいフィーチャクラスにします。

arcpy.Select_analysis("line_split" , "line_split_selected")

3-折れ曲がり点である線の端にある頂点を抽出しました。

arcpy.FeatureVerticesToPoints_management("line_split_selected" , "line_split_pnt" , "DANGLE")

私はあなたの他の答えに関して同じコメントと質問を持っています:それは素晴らしいアイデアですが、同時にそれが望ましい結果を生み出すか、しきい値角度をどのように選ぶべきかは明確ではありません。読者がこの提案が実際に行うことを評価できるように、出力の図を提供していただけますか?ソリューションの一部としてESRIソフトウェアを推奨する場合、作業例の提供は特に重要です。なぜなら、それらのアルゴリズムは通常文書化されておらず、彼らが何をしているかを正確に知ることができないからです。
whuber

それが実用的なソリューションであることを非常に確かにするために、私はそれをテストする必要がありますが、テストすることはできません、私はデータを失っていますさらにテストされます。
-geogeek

答えではなくアイデアに名前を付けることができます
-geogeek

1
では、コメントに移動してほしいですか?ところで、データをテストしたい場合、質問の図に近いので、最初に回答に投稿した座標を使用できます。しかし、便利な地理データを使用しないのはなぜですか?
whuber

2
はい、本当にこのソリューションは直線だけを抽出するのに優れています。
geogeek

1

元のラインからの最大オフセットをパラメーターとして持つGeneralizeツールを使用して、ケースに合ったオフセットを選択できます。

ここに画像の説明を入力してください

元の行に「line_cur」、一般化した行に「line_gen」という名前を付けると、「line_gen」で「line_cur」をクリップできます。結果は、「line_cur」の直線セグメントになります。次に、最小道路長よりも長いShape_lengthを選択するSQLクエリを使用して、非常に短いセグメントを削除することにより、いくつかの非常に短いセグメントをクリーンアップできます。


これはいいアイデアです。ただし、実際にどの程度機能するかは明確ではありません。見つかった変曲点を示す例を示していただけますか?
whuber

写真を含むように編集しました。この写真は、このツールが直線セグメントにくっつく線を作成する方法を説明しているので、古い直線にクリップを作成して、古い直線セグメントだけを抽出する必要があります
geogeek

不明な点はありますか?
-geogeek

図には変曲点はありません。彼らはどこにいるのでしょうか?そして、一般化の許容範囲をどのように選択すべきですか?
whuber

テストを実行するにはデータが必要ですが、実験によって許容範囲を選択する必要があると思います
-geogeek
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.