[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はちょっと大げさかなと…研究室のワークステーションに入れるのも面倒ですし(笑