等高線図のポリゴンを平滑化しますか?


52

レベルのすべてのポリゴンが使用可能な等高線図を次に示します。

すべての頂点を正確な位置に保持したままポリゴンを滑らかにする方法を尋ねましょう

実際、輪郭はグリッドデータの上に作成されるため、グリッドデータを平滑化することをお勧めします。したがって、結果の輪郭はより滑らかになります。ガウスフィルターなどの平滑化機能は小さなデータパックを削除し、3番目の変数の範囲、たとえば、アプリケーションで許可されていない高さを変更するため、これは私の希望どおりに機能しないことに注意してください。

実際、私は2Dポリゴン(凸、凹、自己交差などのあらゆるタイプ)の平滑化を合理的に無痛(コードのページを忘れる)で正確に行うことができるコード(好ましくはPythonで)を探しています。

参考までに、ArcGISにはこれを完全に行う機能がありますがサードパーティの商用アプリケーションを使用することは、この質問に対する私の選択ではありません。

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


1)

Scipy.interpolate:

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

ご覧のとおり、結果のスプライン(赤)は満足のいくものではありません!

2)

ここで与えられたコードを使用した結果はここにあります。うまく機能していません!

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

3)

私にとって最善の解決策は、次の図のようなもので、1つの値のみを変更することで、正方形が徐々に平滑化されることです。あらゆる形のポリゴンを平滑化するための同様のコンセプトを期待しています。

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

スプラインがポイントを通過する条件を満たします。

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

4)

Pythonでの彼のデータに関する「whuberのアイデア」の行ごとの実装です。結果が良くないので、おそらくいくつかのバグがあります。

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

K = 2は災害なので、k> = 4の場合です。

5)

問題のある場所の1つのポイントを削除すると、結果のスプラインはwhuberと同じになりました。しかし、なぜこの方法がすべての場合に機能しないのかは疑問です。

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

6)

whuberのデータの適切なスムージングは​​、次のようにすることができます(ベクトルグラフィックソフトウェアで描画)

4):

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

7)

いくつかの象徴的な形については、Pythonバージョンのwhuberのコードの結果を参照してください。

ここに画像の説明を入力してください
なお、この方法は、ポリラインのために動作しないようだということ。コーナーポリライン(輪郭)については、緑色が必要ですが、赤色になります。等高線マップは常にポリラインであるため、これに対処する必要がありますが、閉じたポリラインは私の例のようにポリゴンとして扱うことができます。また、アップデート4で発生した問題がまだ対処されていないというわけでもありません。

8)[私の最後]

これが最終的な解決策です(完璧ではありません!):

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

星が指す領域について何かしなければならないことを忘れないでください。おそらく私のコードにバグがあるか、提案された方法はすべての状況を考慮し、望ましい出力を提供するためにさらなる開発が必要です。


「多角形」の輪郭をどのように生成していますか?DEMのエッジと交差する輪郭はそれ自体に決して閉じないので、それらは常に線ではありませんか?
ピスタチオ

GRASSのv.generalize関数を使用して、適切な結果の輪郭線の平滑化を行いましたが、非常に密な輪郭を持つマップの場合はしばらく時間がかかります。
ピスタチオ

@pistachionut等高線レベルはポリラインであると考えることができます。最初の段階で純粋なコードを探しています。利用できない場合は、Python用の軽量パッケージ。
開発者

おそらく見scipy.org/Cookbook/Interpolationあなたがスプラインにしたいように聞こえるので
PolyGeo

1
リンクの@Pablo Bezier曲線は、ポリラインに適しています。whuber'sは、ポリゴンに対してほとんどうまく機能します。したがって、彼らは一緒に質問に対処することができます。無料で知識を共有してくれてありがとう。
開発者

回答:


37

数字のシーケンスをスプラインするほとんどの方法は、ポリゴンをスプラインします。トリックは、エンドポイントでスプラインをスムーズに「閉じる」ことです。これを行うには、頂点を端の周りに「ラップ」します。次に、x座標とy座標を別々にスプラインします。

これがの実例ですRspline基本統計パッケージで利用可能なデフォルトのキュービックプロシージャを使用します。より制御するには、お好みの手順に置き換えてください。単に「制御点」として使用するのではなく、必ず数値をスプラインする(つまり、補間する)ようにしてください。

#
# Splining a polygon.
#
#   The rows of 'xy' give coordinates of the boundary vertices, in order.
#   'vertices' is the number of spline vertices to create.
#              (Not all are used: some are clipped from the ends.)
#   'k' is the number of points to wrap around the ends to obtain
#       a smooth periodic spline.
#
#   Returns an array of points. 
# 
spline.poly <- function(xy, vertices, k=3, ...) {
    # Assert: xy is an n by 2 matrix with n >= k.

    # Wrap k vertices around each end.
    n <- dim(xy)[1]
    if (k >= 1) {
        data <- rbind(xy[(n-k+1):n,], xy, xy[1:k, ])
    } else {
        data <- xy
    }

    # Spline the x and y coordinates.
    data.spline <- spline(1:(n+2*k), data[,1], n=vertices, ...)
    x <- data.spline$x
    x1 <- data.spline$y
    x2 <- spline(1:(n+2*k), data[,2], n=vertices, ...)$y

    # Retain only the middle part.
    cbind(x1, x2)[k < x & x <= n+k, ]
}

その使用法を説明するために、小さな(ただし複雑な)ポリゴンを作成しましょう。

#
# Example polygon, randomly generated.
#
set.seed(17)
n.vertices <- 10
theta <- (runif(n.vertices) + 1:n.vertices - 1) * 2 * pi / n.vertices
r <- rgamma(n.vertices, shape=3)
xy <- cbind(cos(theta) * r, sin(theta) * r)

上記のコードを使用してスプラインします。スプラインを滑らかにするには、頂点の数を100から増やします。滑らかさを低下させるには、頂点の数を減らします。

s <- spline.poly(xy, 100, k=3)

結果を見るために、(a)元のポリゴンを赤の破線でプロットし、最初と最後の頂点間のギャップを示します(つまり、境界ポリラインを閉じません)。(b)スプラインが灰色で表示され、もう一度ギャップが表示されます。(ギャップが非常に小さいため、その端点は青い点で強調表示されます。)

plot(s, type="l", lwd=2, col="Gray")
lines(xy, col="Red", lty=2, lwd=2)
points(xy, col="Red", pch=19)
points(s, cex=0.8)
points(s[c(1,dim(s)[1]),], col="Blue", pch=19)

スプラインポリゴン


5
素敵な答え。平滑化の結果として輪郭が交差しないことを保証する方法はありますか?
カーククイケンドール

@Kirk、それはいい質問です。この形式の平滑化による非交差を保証する方法は知りません。(実際、スムージングされたポリラインが非自己交差であることを保証する方法すら見ていません。しかし、これはほとんどの輪郭にとって大きな問題ではありません。)それを行うには、元に戻す必要があります。 DEMではなく、より良い方法を使用して、そもそも等高線を計算します。(存在しているより良い方法-彼らは長い間知られてきた- 。しかし、私の知る限りでは最も人気のあるGISesのいくつかは、それらを使用しないでください)
whuber

最初に、私はまだPythonであなたの答えを実装しようとしていますが、成功していません。次に、正方形にメソッドを適用した場合、結果はどうなりますか?あなたは私が質問で描いたものを参照するかもしれません。
開発者

1
良い解決策を与えるので、私はこれを答えとして受け入れました。それは完璧なものではありませんが、回避策がいくつかありましたが、上記の質問とコメントで述べたポイントを満たす解決策が見つかることを期待しています。また、質問に対するwhuberのコメント[QC]を検討することもできますが、そこには良いトリックがあります。最後に、素敵なScipyパッケージがインストールされていれば、Pythonへの翻訳はほとんど簡単です。また、QCでのPabloのコメントは、ポリライン、つまりベジェ曲線の可能な解決策であると考えてください。皆さん、頑張ってください。
開発者

1
あなたの答えを見て、私は数学をうまくやっていないことを後悔しています!!!
ビナヤン

2

これは古い投稿であることは知っていますが、探しているものがGoogleに表示されたので、解決策を投稿すると思いました。

私はこれを2Dカーブフィッティングの演習ではなく、3Dの演習と考えています。データを3Dと見なすことで、曲線が互いに交差しないようにし、他の輪郭からの情報を使用して現在の曲線の推定値を改善できます。

次のiPython抽出では、SciPyが提供する3次補間を使用しています。すべての輪郭の高さが等距離である限り、プロットしたz値は重要ではないことに注意してください。

In [1]: %pylab inline
        pylab.rcParams['figure.figsize'] = (10, 10)
        Populating the interactive namespace from numpy and matplotlib

In [2]: import scipy.interpolate as si

        xs = np.array([0.0, 0.0, 4.5, 4.5,
                       0.3, 1.5, 2.3, 3.8, 3.7, 2.3,
                       1.5, 2.2, 2.8, 2.2,
                       2.1, 2.2, 2.3])
        ys = np.array([0.0, 3.0, 3.0, 0.0,
                       1.1, 2.3, 2.5, 2.3, 1.1, 0.5,
                       1.1, 2.1, 1.1, 0.8,
                       1.1, 1.3, 1.1])
        zs = np.array([0,   0,   0,   0,
                       1,   1,   1,   1,   1,   1,
                       2,   2,   2,   2,
                       3,   3,   3])
        pts = np.array([xs, ys]).transpose()

        # set up a grid for us to resample onto
        nx, ny = (100, 100)
        xrange = np.linspace(np.min(xs[zs!=0])-0.1, np.max(xs[zs!=0])+0.1, nx)
        yrange = np.linspace(np.min(ys[zs!=0])-0.1, np.max(ys[zs!=0])+0.1, ny)
        xv, yv = np.meshgrid(xrange, yrange)
        ptv = np.array([xv, yv]).transpose()

        # interpolate over the grid
        out = si.griddata(pts, zs, ptv, method='cubic').transpose()

        def close(vals):
            return np.concatenate((vals, [vals[0]]))

        # plot the results
        levels = [1, 2, 3]
        plt.plot(close(xs[zs==1]), close(ys[zs==1]))
        plt.plot(close(xs[zs==2]), close(ys[zs==2]))
        plt.plot(close(xs[zs==3]), close(ys[zs==3]))
        plt.contour(xrange, yrange, out, levels)
        plt.show()

3次補間結果

ここでの結果は最高に見えませんが、コントロールポイントが非常に少ないため、完全に有効です。広い青色の輪郭に合わせて、緑色の適合線がどのように引き出されるかに注意してください。


フィットした滑らかな曲線は、元のポリゴン/ポリラインに可能な限り近いままにしてください。
開発者

1

探しているパッケージをほぼ正確に書きました...しかし、それはPerlで、10年以上前のGD :: Polylineです。2D 3次ベジエ曲線を使用し、任意のPolygonまたは「Polyline」を「スムーズ」にします(現在は一般に「LineString」と呼ばれているものの名​​前です)。

アルゴリズムは2つのステップでした。ポリゴン内のポイントを指定して、各ポイント間に2つのベジェ制御ポイントを追加します。次に、単純なアルゴリズムを呼び出して、スプラインの区分的近似を作成します。

2番目の部分は簡単です。最初の部分はちょっとした芸術でした。ここに洞察がありました:「制御セグメント」を頂点N:と考えてくださいvN。制御セグメントは、3つの同一直線上のポイント[cNa, vN, cNb]でした。中心点は頂点でした。このコントロールセグメントの勾配は、頂点N-1から頂点N + 1までの勾配に等しくなりました。このセグメントの左部分の長さは頂点N-1から頂点Nまでの長さの1/3で、このセグメントの右部分の長さは頂点Nから頂点N + 1までの長さの1/3でした。

元の曲線が4つの頂点であった場合、 [v1, v2, v3, v4]各頂点は次の形式の制御セグメントを取得します[c2a, v2, c2b]。このような文字列これらを一緒に:[v1, c1b, c2a, v2, c2b, c3a, v3, c3b, c4a, v4]四個のベジェポイントなどの時に、彼らに4をムンク:[v1, c1b, c2a, v2]、その後[v2, c2b, c3a, v3]、というように。[c2a, v2, c2b]同一直線上にあったため、結果の曲線は各頂点で滑らかになります。

したがって、これは曲線の「タイトネス」をパラメータ化するという要件も満たします。「タイトな」カーブには1/3より小さい値を使用し、「ルーパー」フィットには大きい値を使用します。どちらの場合でも、結果の曲線は常に元の指定された点を通過します。

これにより、元のポリゴンを「囲む」滑らかな曲線が作成されました。また、滑らかな曲線を「書き込む」方法もありましたが、CPANコードには表示されません。

とにかく、現時点ではPythonで利用できるバージョンはありませんし、数字もありません。しかし...私がこれをPythonに移植する場合、ここに投稿することを確認します。


Perlコードを評価できません。可能であれば、それがどのように機能していたかを示すグラフィックを追加してください。
開発者
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.