[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”)
はじめまして。東北大学大学院工学研究科航空宇宙工学専攻の松山俊太郎と申します。
私が現在進めている研究にスプライン補完が必要なためぜひ当記事のコード”spline.py”および”mat.py”をお借りしたいのですが、ご許可いただけませんでしょうか。
ご返答お待ちしております。
お返事遅くなりすんません&ライセンスが明記してなくてすんません。
たしか、両者とも、記事中のリンク先ページのアルゴリズムを参考にはしていますが、コード自体は引用してなかったように思います。
ご自由にお使いください。
できましたら、引用元(URL)の明記をしていただけるとうれしいですが、義務ではありません。
バグなどが残っている可能性がありますので、その点はご注意ください。
mat.py、spline.pyは、将来的にblenderのプラグインを書きたいと思い、配布しやすいように作ったものなので、もっと枯れた、高性能のライブラリがPythonには有るかと思います。研究目的であれば、そちらをあたったほうがいいかも?
科学計算モジュールSciPy/matplotlib には、スプライン補間関数があったような気がするのですが、しばらく使ってないのでよく憶えてません(汗
研究がんばってください
ご快諾ありがとうございます。URLの件、承知しました。
spline補完した点列を渡す最低限の機能が欲しいだけなのでScyPyはちょっと大げさかなと…研究室のワークステーションに入れるのも面倒ですし(笑