2009-08-09 3 views
2

Есть ли библиотека или функция в python для вычисления сплайна Catmull-Rom из трех точек?сплайны Catmull-Rom в python

В конце концов мне нужны координаты x, y точек вдоль сплайна при условии, что они всегда равноудалены от заданного количества t вдоль сплайна (скажем, сплайновая кривая имеет длину 3 единицы, и я хочу, чтобы x, y координаты по длине сплайна 0, 1, 2 и 3)

Ничего особенного. Я пишу это сам, но если вы найдете что-то хорошее, было бы здорово для тестирования (или сэкономить время)

ответ

6

3 очка? Catmull-Rom определяется для 4 точек, например p_1 p0 p1 p2; кубическая кривая идет от p0 до p1, а внешние точки p_1 и p2 определяют наклоны при p0 и p1. Чтобы нарисовать кривую через несколько точек в массиве P, сделать что-то вроде этого:

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 

Один может использование кусочно квадратичные кривые через 3 балла - см Dodgson, Quadratic Interpolation for Image Resampling. Что вы действительно хотите сделать?

+0

3 реальных точки плюс две обязательные конечные точки для наклона в конце –

+0

spline_4p (t, p_1, p0, p1, p2) идет p0 .. p1, затем spline_4p (t, p0, p1, p2, p3) p1 .. p2, с p_1 и 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, который, кажется, находится на Python, возможно, вы можете найти то, что вам нужно там ,

+0

Оооо .. блестящий! спасибо, я посмотрю на него как можно скорее. Кажется, он делает то, что мне нужно, но мне нужно проверить детали. –

+0

Нет, он сильно использует материал XSi. :( –

1

Как уже упоминалось ранее, вам нужно 4 очка для камуфляжа, а конечные точки - проблема. Я рассматривал их применение вместо естественных кубических сплайнов (что потенциальное превышение за пределами известного диапазона данных нецелесообразно в моем приложении). Как и код @ 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 является ситуативным для интерполяции ... поскольку он не является фактической функцией в том смысле, в котором вы могли бы надеяться на интерполяцию: она не даст вам f (x), а скорее f (t) где t - расстояние между двумя вашими точками ... на линейном расстоянии, а не на расстоянии x, y! Поэтому t o получить простую интерполяцию, которую вам нужно было бы подавать на многие «т», а затем, возможно, линейно интерполировать их, чтобы получить свою фактическую точку в пространстве x, y, но вы должны быть осторожны, вы интерполируете по правильному сегменту рока. – Vlox

Смежные вопросы