2009-08-09 9 views
2

Python에서 Catmull-Rom 스플라인을 세 점에서 계산할 수있는 라이브러리 또는 함수가 있습니까?Python의 Catmull-Rom 스플라인

최종적으로 필요한 것은 스플라인을 따라 점의 x, y 좌표입니다 (단, 스플라인 곡선은 3 단위 길이이며, 원하는 길이만큼 스플라인을 따라 등거리가됩니다. 스플라인 길이 0, 1, 2, 3에서의 x, y 좌표)

정말 재미 있지 않습니다. 나는 혼자서 글을 쓰고 있지만 좋은 것을 발견하면 테스트 (또는 시간 절약)에 도움이 될 것입니다.

답변

6

3 점? Catmull-Rom은 4 점에 대해 정의됩니다. 예를 들어 p_1 p0 p1 p2; 입방체 곡선은 p0에서 p1로 이동하고 외부 점 p_1과 p2는 p0과 p1에서 기울기를 결정합니다. 3 점을 통과

for j in range(1, len(P)-2): # skip the ends 
    for t in range(10): # t: 0 .1 .2 .. .9 
     p = spline_4p(t/10, P[j-1], P[j], P[j+1], P[j+2]) 
     # draw p 

def spline_4p(t, p_1, p0, p1, p2): 
    """ Catmull-Rom 
     (Ps can be numpy vectors or arrays too: colors, curves ...) 
    """ 
     # wikipedia Catmull-Rom -> Cubic_Hermite_spline 
     # 0 -> p0, 1 -> p1, 1/2 -> (- p_1 + 9 p0 + 9 p1 - p2)/16 
    # assert 0 <= t <= 1 
    return (
      t*((2-t)*t - 1) * p_1 
     + (t*t*(3*t - 5) + 2) * p0 
     + t*((4 - 3*t)*t + 1) * p1 
     + (t-1)*t*t   * p2)/2 

하나 사용 구분 이차 곡선 - 는 Dodgson, Quadratic Interpolation for Image Resampling 참조 : 가 배열 P 일부 지점을 통해 곡선을 그리려면 같은 것을 할. 정말로 무엇을하고 싶습니까?

+0

끝점의 경사에 대한 두 개의 필수 끝 점 플러스 –

+0

spline_4p (t, p_1, p0, p1, p2)가 p0 .. p1이 될 때 spline_4p (t, p0, p1, p2, p3) p1과 p3가 기울기에 영향을 미침 Hth? – denis

+0

t 사이클에서 우리는 t를 float으로 캐스트해야합니다 : p = spline_4p (float (t)/10, P [j- 1], P [j], P [j + 1], P [j + 2]) – alrusdi

1

여기에 : jj_catmull이 있는데, 아마도 파이썬에있는 것 같습니다. 아마도 거기에서 필요한 것을 찾을 수있을 것입니다. .

+0

ooohhh .. 반짝! 감사합니다. 가능한 한 빨리 살펴 보겠습니다. 그것은 내가 필요로하는 것처럼 보이지만 세부 사항을 확인해야합니다. –

+0

아니, XSi 물건을 강력하게 사용합니다. : –

1

앞서 언급했듯이 catmull-rom에는 4 점이 필요하며 끝 점이 문제가됩니다. 나는 자연적인 3 차 스플라인 (알고있는 데이터 범위를 넘어서는 잠재적 인 오버 슈트가 내 애플리케이션에서 비실용적 임) 대신에 이러한 것을 적용하려고했다. @ denis의 코드와 비슷하게, 여기에 도움이 될만한 것이있다. (몇 가지를 주목하라.) 1이 코드는 무작위로 포인트를 생성하는데, 주석 처리 된 예제를 사용하여 자신의 데이터를 사용하는 방법에 대해 확신 할 수있을 것이다. 2) 도메인의 1 %의 임의의 거리를 사용하여 첫 번째/마지막 두 점 사이의 기울기를 유지하면서 확장 된 끝점을 만듭니다. 3) 나는) 비교를 위해 유니폼, 구심력과 chordial 매듭 매개 변수화를 포함

Catmull-Rom Python Code Output Example Image

# coding: utf-8 

# In[1]: 

import numpy 
import matplotlib.pyplot as plt 
get_ipython().magic(u'pylab inline') 


# In[2]: 

def CatmullRomSpline(P0, P1, P2, P3, a, nPoints=100): 
    """ 
    P0, P1, P2, and P3 should be (x,y) point pairs that define the Catmull-Rom spline. 
    nPoints is the number of points to include in this curve segment. 
    """ 
    # Convert the points to numpy so that we can do array multiplication 
    P0, P1, P2, P3 = map(numpy.array, [P0, P1, P2, P3]) 

    # Calculate t0 to t4 
    alpha = a 
    def tj(ti, Pi, Pj): 
    xi, yi = Pi 
    xj, yj = Pj 
    return (((xj-xi)**2 + (yj-yi)**2)**0.5)**alpha + ti 

    t0 = 0 
    t1 = tj(t0, P0, P1) 
    t2 = tj(t1, P1, P2) 
    t3 = tj(t2, P2, P3) 

    # Only calculate points between P1 and P2 
    t = numpy.linspace(t1,t2,nPoints) 

    # Reshape so that we can multiply by the points P0 to P3 
    # and get a point for each value of t. 
    t = t.reshape(len(t),1) 

    A1 = (t1-t)/(t1-t0)*P0 + (t-t0)/(t1-t0)*P1 
    A2 = (t2-t)/(t2-t1)*P1 + (t-t1)/(t2-t1)*P2 
    A3 = (t3-t)/(t3-t2)*P2 + (t-t2)/(t3-t2)*P3 

    B1 = (t2-t)/(t2-t0)*A1 + (t-t0)/(t2-t0)*A2 
    B2 = (t3-t)/(t3-t1)*A2 + (t-t1)/(t3-t1)*A3 

    C = (t2-t)/(t2-t1)*B1 + (t-t1)/(t2-t1)*B2 
    return C 

def CatmullRomChain(P,alpha): 
    """ 
    Calculate Catmull Rom for a chain of points and return the combined curve. 
    """ 
    sz = len(P) 

    # The curve C will contain an array of (x,y) points. 
    C = [] 
    for i in range(sz-3): 
    c = CatmullRomSpline(P[i], P[i+1], P[i+2], P[i+3],alpha) 
    C.extend(c) 

    return C 


# In[139]: 

# Define a set of points for curve to go through 
Points = numpy.random.rand(10,2) 
#Points=array([array([153.01,722.67]),array([152.73,699.92]),array([152.91,683.04]),array([154.6,643.45]), 
#  array([158.07,603.97])]) 
#Points = array([array([0,92.05330318]), 
#    array([2.39580622,29.76345192]), 
#    array([10.01564963,16.91470591]), 
#    array([15.26219886,71.56301997]), 
#    array([15.51234733,73.76834447]), 
#    array([24.88468545,50.89432899]), 
#    array([27.83934153,81.1341789]), 
#    array([36.80443404,56.55810783]), 
#    array([43.1404725,16.96946811]), 
#    array([45.27824599,15.75903418]), 
#    array([51.58871027,90.63583215])]) 

x1=Points[0][0] 
x2=Points[1][0] 
y1=Points[0][1] 
y2=Points[1][1] 
x3=Points[-2][0] 
x4=Points[-1][0] 
y3=Points[-2][1] 
y4=Points[-1][1] 
dom=max(Points[:,0])-min(Points[:,0]) 
rng=max(Points[:,1])-min(Points[:,1]) 
pctdom=1 
pctdom=float(pctdom)/100 
prex=x1+sign(x1-x2)*dom*pctdom 
prey=(y1-y2)/(x1-x2)*(prex-x1)+y1 
endx=x4+sign(x4-x3)*dom*pctdom 
endy=(y4-y3)/(x4-x3)*(endx-x4)+y4 
print len(Points) 
Points=list(Points) 
Points.insert(0,array([prex,prey])) 
Points.append(array([endx,endy])) 
print len(Points) 


# In[140]: 

#Define alpha 
a=0. 

# Calculate the Catmull-Rom splines through the points 
c = CatmullRomChain(Points,a) 

# Convert the Catmull-Rom curve points into x and y arrays and plot 
x,y = zip(*c) 
plt.plot(x,y,c='green',zorder=10) 

a=0.5 
c = CatmullRomChain(Points,a) 
x,y = zip(*c) 
plt.plot(x,y,c='blue') 

a=1. 
c = CatmullRomChain(Points,a) 
x,y = zip(*c) 
plt.plot(x,y,c='red') 

# Plot the control points 
px, py = zip(*Points) 
plt.plot(px,py,'o',c='black') 

plt.grid(b=True) 
plt.show() 


# In[141]: 

Points 


# In[104]: 
+0

또한 Catmull Rom은 보간법에 대해 상황이 다양하다는 점에 유의해야합니다 ... 보간법에 대한 실제 함수가 아니기 때문에 Catmull Rom은 f (x)가 아니라 f (t)를 제공합니다. 여기서 t는 두 점 사이의 거리입니다 ... x, y 거리가 아닌 직선 거리에서! 따라서 t o 간단한 보간법을 사용하면 많은 "t"를 공급 한 다음 선형 적으로 x, y 공간에서 실제 점을 얻기 위해 선형 보간을 수행하지만 올바른 catmull rom 세그먼트를 따라 삽입 할 때는 신중해야합니다. – Vlox