web-dev-qa-db-ja.com

閉曲線を一連の点に適合させる

ループを形成するポイントのセットptsがあり、次のようになります。

enter image description here

これは 1243002 に多少似ていますが、ポイントのペアの間にポイントを置く代わりに、ポイントを通る滑らかな曲線を当てはめたい(座標は質問の最後に与えられます)ので、 補間scipyドキュメントに似たものを試しました:

values = pts
tck = interpolate.splrep(values[:,0], values[:,1], s=1)
xnew = np.arange(2,7,0.01)
ynew = interpolate.splev(xnew, tck, der=0)

しかし、私はこのエラーを受け取ります:

ValueError:入力データのエラー

そのような適合を見つける方法はありますか?

ポイントの座標:

pts = array([[ 6.55525 ,  3.05472 ],
   [ 6.17284 ,  2.802609],
   [ 5.53946 ,  2.649209],
   [ 4.93053 ,  2.444444],
   [ 4.32544 ,  2.318749],
   [ 3.90982 ,  2.2875  ],
   [ 3.51294 ,  2.221875],
   [ 3.09107 ,  2.29375 ],
   [ 2.64013 ,  2.4375  ],
   [ 2.275444,  2.653124],
   [ 2.137945,  3.26562 ],
   [ 2.15982 ,  3.84375 ],
   [ 2.20982 ,  4.31562 ],
   [ 2.334704,  4.87873 ],
   [ 2.314264,  5.5047  ],
   [ 2.311709,  5.9135  ],
   [ 2.29638 ,  6.42961 ],
   [ 2.619374,  6.75021 ],
   [ 3.32448 ,  6.66353 ],
   [ 3.31582 ,  5.68866 ],
   [ 3.35159 ,  5.17255 ],
   [ 3.48482 ,  4.73125 ],
   [ 3.70669 ,  4.51875 ],
   [ 4.23639 ,  4.58968 ],
   [ 4.39592 ,  4.94615 ],
   [ 4.33527 ,  5.33862 ],
   [ 3.95968 ,  5.61967 ],
   [ 3.56366 ,  5.73976 ],
   [ 3.78818 ,  6.55292 ],
   [ 4.27712 ,  6.8283  ],
   [ 4.89532 ,  6.78615 ],
   [ 5.35334 ,  6.72433 ],
   [ 5.71583 ,  6.54449 ],
   [ 6.13452 ,  6.46019 ],
   [ 6.54478 ,  6.26068 ],
   [ 6.7873  ,  5.74615 ],
   [ 6.64086 ,  5.25269 ],
   [ 6.45649 ,  4.86206 ],
   [ 6.41586 ,  4.46519 ],
   [ 5.44711 ,  4.26519 ],
   [ 5.04087 ,  4.10581 ],
   [ 4.70013 ,  3.67405 ],
   [ 4.83482 ,  3.4375  ],
   [ 5.34086 ,  3.43394 ],
   [ 5.76392 ,  3.55156 ],
   [ 6.37056 ,  3.8778  ],
   [ 6.53116 ,  3.47228 ]])
30
Mahdi

実際、あなたはあなたの質問の解決策からそれほど遠くありませんでした。

パラメトリックBスプライン補間に scipy.interpolate.splprep を使用するのが最も簡単なアプローチです。 per=1パラメーターを指定すると、閉じた曲線もネイティブにサポートされます。

import numpy as np
from scipy.interpolate import splprep, splev
import matplotlib.pyplot as plt

# define pts from the question

tck, u = splprep(pts.T, u=None, s=0.0, per=1) 
u_new = np.linspace(u.min(), u.max(), 1000)
x_new, y_new = splev(u_new, tck, der=0)

plt.plot(pts[:,0], pts[:,1], 'ro')
plt.plot(x_new, y_new, 'b--')
plt.show()

enter image description here

基本的に、このアプローチは@Joe Kingtonの回答にあるアプローチとそれほど変わらない。ただし、デフォルトでは、単にインデックスではなく、ポイント間の距離に基づいてiベクトルに相当するものが選択されるため、もう少し堅牢になります( splprep documentationuパラメーターの場合)。

28
rth

問題は、xとyを直接操作しようとしているためです。呼び出す補間関数は、x値がソートされた順序であり、各x値が一意のy値を持つことを前提としています。

代わりに、パラメーター化された座標系(頂点のインデックスなど)を作成し、それを使用してxとyを別々に補間する必要があります。

まず、次のことを考慮してください。

_import numpy as np
from scipy.interpolate import interp1d # Different interface to the same function
import matplotlib.pyplot as plt

#pts = np.array([...]) # Your points

x, y = pts.T
i = np.arange(len(pts))

# 5x the original number of points
interp_i = np.linspace(0, i.max(), 5 * i.max())

xi = interp1d(i, x, kind='cubic')(interp_i)
yi = interp1d(i, y, kind='cubic')(interp_i)

fig, ax = plt.subplots()
ax.plot(xi, yi)
ax.plot(x, y, 'ko')
plt.show()
_

enter image description here

ポリゴンを閉じませんでした。必要に応じて、配列の最後に最初のポイントを追加できます(例:pts = np.vstack([pts, pts[0]])

これを行うと、ポリゴンが閉じる部分に不連続性があることに気付くでしょう。

enter image description here

これは、パラメーター化がポルギオンの終了を考慮していないためです。簡単な修正方法は、配列に「反射」点を埋め込むことです。

_import numpy as np
from scipy.interpolate import interp1d 
import matplotlib.pyplot as plt

#pts = np.array([...]) # Your points

pad = 3
pts = np.pad(pts, [(pad,pad), (0,0)], mode='wrap')
x, y = pts.T
i = np.arange(0, len(pts))

interp_i = np.linspace(pad, i.max() - pad + 1, 5 * (i.size - 2*pad))

xi = interp1d(i, x, kind='cubic')(interp_i)
yi = interp1d(i, y, kind='cubic')(interp_i)

fig, ax = plt.subplots()
ax.plot(xi, yi)
ax.plot(x, y, 'ko')
plt.show()
_

enter image description here

または、PEAKやコーナーカットアルゴリズムなどの特殊な曲線平滑化アルゴリズムを使用できます。

22
Joe Kington

ROOT Framework とパイロートインターフェースを使用して、次の画像を生成することができました Drawing Using pyroot

次のコードで(データをdata.csvというCSVに変換したので、ROOTに読み込むのが簡単になり、列タイトルがxp、ypになりました)

from ROOT import TTree, TGraph, TCanvas, TH2F

c1 = TCanvas( 'c1', 'Drawing Example', 200, 10, 700, 500 )
t=TTree('TP','Data Points')
t.ReadFile('./data.csv')
t.SetMarkerStyle(8)
t.Draw("yp:xp","","ACP")
c1.Print('pydraw.png')
10
Matt

N点を通る滑らかな閉じた曲線にフィットするために、次の制約のある線分を使用できます。

  • 各線分は、その2つの端点に触れる必要があります(線分ごとに2つの条件)
  • 各ポイントについて、左右の線分は同じ導関数を持つ必要があります(ポイントごとに2つの条件==線分ごとに2つの条件)

線分ごとに合計4つの条件に対して十分な自由度を持たせるには、各線分の方程式をy = ax ^ 3 + bx ^ 2 + cx + dにする必要があります。 (したがって、導関数はy '= 3ax ^ 2 + 2bx + cです)

提案された条件を設定すると、N * 4未知数(a1..aN、b1..bN、c1..cN、d1..dN)のN * 4線形方程式が得られ、マトリックス反転(numpy)で解くことができます。

点が同じ垂直線上にある場合、微分は「無限」になるため、特別な(ただし単純な)処理が必要です。

6