Pythonでスプライン曲線

[pukiwiki]
Python (PIL)でスプライン曲線、のつづき。

実行サンプル。
http://boxheadroom.com/wp/wp-content/uploads/2009/06/curve.png

紫のカクカクした線をスプライン補間すると、水色の線のようになめらかに。ついでに、太い線も描けるように。

[/pukiwiki]


[pukiwiki]
遅いですけど。
—-
必要なモジュール
-[[PIL:http://www.pythonware.com/products/pil/]]
-[[mat.py:http://boxheadroom.com/2009/06/11/py_mat]]
*参考ページ
-[[ ゲームつくろー! < DirectX技術編 < スプライン曲線上をおおよそ等速で移動する(丸み不均一スプライン):http://marupeke296.com/DXG_No34_UnuniformSprine.html]] 今回作成したモジュールは、等速になってませんけれども。 *使い方 -spline 関数(ジェネレータ) x0,y0,x1,y1,x2,y2 ~~~ という線分データを渡すと、スプライン補間してなめらかな座標データを返してくれます。 -クラス DrawCurve ImageDrawクラスを継承しています 上記 splineジェネレータを利用して、 PILにて曲線を描きます --メソッド curve おおまかな線分データを渡すと、曲線を描く キーワード引数widthで、曲線の太さを変更 *spline.py ファイル名 spline.pyとして保存してください [/pukiwiki]

# -*- coding: cp932 -*-
“””
spline.py
“””
import Image
import ImageDraw

pure=False
try :
    if pure:
        raise
    from numpy import array,dot
    pure=False
except:
    from mat import Mat,dot
    array=Mat
    pure=True


H= [  2,-2,1,1,
    -3,3,-2,-1,
    0,0,1,0,
    1,0,0,0
            ]
H=array(H)
H=H.reshape(4,4)

def spline( plist,step=4,smooth=0.5 ):
    global G,P,tlist,pl,a,H,i,plist_,l
    
    loop= plist[:2]==plist[-2:]
    
    plist=array(plist)
    l=len(plist)
    plist=plist.reshape(l//2,2)
    points,dm=plist.shape
    plist_=plist
    pl=plist
    p0 =plist[0]
    
    fstep=float(step+1)
    tlist=[]
    for tt in xrange(step+2):
        
        t=tt/fstep
        a=array([t**3.,t**2.,t,1.])
        a=a.reshape(1,4)
        tlist.append(dot(a,H))    
    tstart=0    
    for i in xrange(points-1) :
        if i==0 :
            if loop:
                
                v1=(plist[1]-plist[-2])*smooth
            else :
                v=(plist[1]-plist[0])
                v1=v*smooth
                                
        else :
            v1=(plist[i+1]-plist[i-1])*smooth
        if i==points-2 :
            if loop:
                
                v2=(plist[1]-plist[-2])*smooth                
            else :
                v2=(plist[-1]-plist[-2])*smooth
            
        else  :
            v2=(plist[i+2]-plist[i])*smooth
        p1=list(plist[i])
        p2=list(plist[i+1])
        v1=list(v1)
        v2=list(v2)
        for t in tlist[tstart:]:            
            G=array( p1+p2+v1+v2)
            G=G.reshape(4,2)
            P=dot(t,G)
            #print t.shape,G.shape,P.shape
            #print t,G,P
            if pure :
                yield [x for x in P]
            else :
                yield [list(x) for x in P][0]

        tstart=1
import math
class DrawCurve(ImageDraw.ImageDraw):
    def curve(self,plist,fill=None,width=0,step=4,smooth=0.5):
        ” plist=[x0,y0,x1,y1,x2,y2,,,,]”
        x0,y0=plist[0:2]
        r=width
        if width :
            self.ellipse( [x0-r,y0-r,x0+r,y0+r],fill=fill)
        for x,y in spline(plist,step=step,smooth=smooth):
            dx=float(x-x0)
            dy=float(y-y0)
            l=math.sqrt(dx**2+dy**2)

            if not width :
                self.line([x0,y0,x,y],fill=fill,width=0)
            elif not l:
                continue                
            else:
                tx=width*dx/l
                ty=width*dy/l
                dx=ty  # x*cos+y*sin
                dy=-tx
                self.polygon([x0-dx,y0-dy,x0+dx,y0+dy,
                              x+dx,y+dy,x-dx,y-dy],fill=fill)
                self.ellipse( [x-r,y-r,x+r,y+r],fill=fill)

            x0,y0=x,y
        
if __name__==”__main__”:
    import math
    import colorsys

    import Image,ImageDraw
    _W,_H=500,500
    im=Image.new(“RGB”,(_W,_H))
    draw=DrawCurve(im)
    draw.rectangle((0,0,_W,_H),fill=(255,255,255))
    plist=[]
    r=200.
    ox,oy=_W//2,_H//2

    #x0,y0=plist.extend([ox+r*math.sin(0),oy+r*math.cos(0)])
    for i in xrange(32):
        deg=2*math.pi*i/32.
        plist.extend([ox+r*math.sin(4*deg),oy+r*math.cos(3*deg)])
        
    plist.extend([plist[0],plist[1]])
    #draw.line(plist,fill=(0,0,0))
    x0,y0=plist[0:2]
    if False:
        for i in xrange(16):
            
            c=colorsys.hsv_to_rgb(i%4/5.,1.0,255)
            #col=”#%02x%02x%02x”%c
            
            draw.curve( plist,fill=c,step=4,smooth=i/16.)
    c=colorsys.hsv_to_rgb(0.5,1.0,255)
    draw.curve( plist,fill=c,width=3,step=4,smooth=0.5)
    c=colorsys.hsv_to_rgb(0.8,1.0,255)
    draw.curve( plist,fill=c,width=.5,step=4,smooth=0)
    
    #root.update()
    im.save(“test.png”)


Pythonでスプライン曲線」への3件のフィードバック

  1. はじめまして。東北大学大学院工学研究科航空宇宙工学専攻の松山俊太郎と申します。

    私が現在進めている研究にスプライン補完が必要なためぜひ当記事のコード”spline.py”および”mat.py”をお借りしたいのですが、ご許可いただけませんでしょうか。

    ご返答お待ちしております。

  2. お返事遅くなりすんません&ライセンスが明記してなくてすんません。

    たしか、両者とも、記事中のリンク先ページのアルゴリズムを参考にはしていますが、コード自体は引用してなかったように思います。
    ご自由にお使いください。

    できましたら、引用元(URL)の明記をしていただけるとうれしいですが、義務ではありません。
    バグなどが残っている可能性がありますので、その点はご注意ください。

    mat.py、spline.pyは、将来的にblenderのプラグインを書きたいと思い、配布しやすいように作ったものなので、もっと枯れた、高性能のライブラリがPythonには有るかと思います。研究目的であれば、そちらをあたったほうがいいかも?

    科学計算モジュールSciPy/matplotlib には、スプライン補間関数があったような気がするのですが、しばらく使ってないのでよく憶えてません(汗

    研究がんばってください

  3. ご快諾ありがとうございます。URLの件、承知しました。

    spline補完した点列を渡す最低限の機能が欲しいだけなのでScyPyはちょっと大げさかなと…研究室のワークステーションに入れるのも面倒ですし(笑

コメントを残す

メールアドレスが公開されることはありません。