[pukiwiki]
Pythonの画像ライブラリ[[PIL>ググる:Python PIL]]をつかってて困るのが、太い線を描けないことと、スプライン曲線の描画関数が無いこと。
Pythonで拡張できるCGソフト(BlenderやInkscapeなど)を使うって方法もありますけれども、今回は自前でチャレンジしてみることに。
数回に分けて必要なプログラムをメモしますー
まずは行列演算
[/pukiwiki]
[pukiwiki]
以前、Python Recipeで見たような記憶があるのですが、よくわからなかったので自前で。
普段は[[NumPy>ググる:NumPy Python]]を使ってるのですが、配布のときに「NumPy必須」ってのも困ることもあるかも、ということで、スプライン補間の計算に必要な行列の積(ドット?内積?)だけ実装することに。今回は計算量もたかが知れてますし。
◎ m x n の、2次元行列式の積のみ。
3次元以上の配列には対応してません。
printデバッグがいっぱい入っててかっこ悪いです。すんません
テストとして、ランダムな行列を作成、NumPyでの計算結果と等しいかチェックしています。
[/pukiwiki]
*mat.py
ファイル名 mat.pyとして保存してください
""" mat.py"""
def flatten(m):
f=[]
for x in m:
f.extend(x)
return f
class Mat(object):
debug=False
def __init__(self,lst=None,shape=None):
debug=self.debug
if lst and shape :
if debug :print "*1"
r,c=shape
if len(lst)!= r*c: raise "shape not match"
self.lst=lst[:]
self.shape=shape[:]
elif not lst and shape :
if debug :print "*2"
r,c=shape
self.lst=range(r*c)
if debug :print "%s (%s,%s)"%(self.lst,r,c)
self.shape=shape[:]
elif lst and not shape :
if debug :print "*3"
self.shape=(len(lst),1)
self.lst=lst[:]
else :
if debug :print "*4"
self.lst=[]
self.shape=[0,0]
self.rows,self.cols=self.shape
def __eq__(self,b):
try :
return self.shape==b.shape and self.lst==b.lst
except :
return False
def reshape( self,*shape):
#print "@reshape"
if not shape : raise "reshape error"
c=self.copy()
rows,cols=self.shape
l=rows*cols
if l!=len(self.lst) : raise "shape not match"
c.shape=shape[:]
return c
def append(self,x):
if not len(x) != self.cols :
raise "cols not match"
self.lst.append(x)
self.rows+=1
self.shape=(self.rows,self.cols)
def copy(self):
return Mat(self.lst[:],self.shape[:])
def __iter__(self):
return iter(self.lst)
def __getitem__(self,idx):
if type(idx)==int :
#print "*"
r=idx
return Mat([self.lst[r*self.cols+c] for c in xrange(self.cols)])
else :
r,c=idx
return self.lst[r*self.cols+c]
def _calc(self,b,fnc):
a=self
t=type(b)
if t==int or t==float :
c=Mat(shape=self.shape)
for i in xrange(a.rows):
for j in xrange(a.cols):
c[i,j]=fnc(a[i,j],b)
return c
elif not isinstance(b,Mat):
raise "add : type missmatch"
if a.shape!=b.shape :
raise "add : shape not match"
c=Mat(shape=a.shape)
for i in xrange(a.rows):
for j in xrange(a.cols):
c[i,j]=fnc(a[i,j],b[i,j])
return c
def __add__(self,b):
return self._calc(b,lambda x,y : x+y)
def __sub__(self,b):
return self._calc(b,lambda x,y : x-y)
def __mul__(self,b):
return self._calc(b,lambda x,y : x*y)
def __div__(self,b):
return self._calc(b,lambda x,y : x/y)
def dot(self,b):
return dot(self,b)
def __setitem__(self,idx,val):
r,c=idx
self.lst[r*self.cols+c]=val
def __repr__(self):
return repr(self.lst)
def __len__(self):
return len(self.lst)
def _set_shape(self,sh):
self.rows,self.cols=sh
def _get_shape(self):
return self.rows,self.cols
Mat.shape=property(Mat._get_shape,Mat._set_shape)
debug=False
def dot(a,b):
rows_b,cols_b=b.shape
rows_a,cols_a=a.shape
if cols_a!=rows_b : raise "shape not match"
cols_c=cols_b
rows_c=rows_a
c=Mat(shape=(rows_c,cols_c))
for i in xrange(cols_b):
for j in xrange(rows_a):
v=0
for u in xrange(cols_a):
v_=a[j,u]*b[u,i]
s=""
s+= "a%s%s (%s)"%(j,u,a[j,u])
s+= "* b %s%s (%s)"%(u,i,b[u,i])
s+= "=(%s)"%(v_)
if debug:
print s,
v+=v_
c[j,i]=v
if debug:
print "= %s "%v
if debug: print
if debug: print c
return c
import random
from random import randint
def rndmat(shape=(0,0)):
r,c=shape
if not r : r=randint(1,3)
if not c : c=randint(1,3)
m=Mat(shape=(r,c))
#print m,r,c
for j in xrange(r) :
for i in xrange(c):
m[j,i]=float(randint(1,10))
return m
array=Mat
if __name__=="__main__":
import numpy as np
Mat.debug=False
m=rndmat()
print m,m.shape
n=rndmat( ( m.shape[1],0) )
print n,n.shape
mn=dot(m,n)
print "dot",mn,mn.shape
a=np.array(m.lst).reshape(m.shape)
b=np.array(n.lst).reshape(n.shape)
print "a=",a
print "b=",b
ab=np.dot(a,b)
print "dot(a,b)=",ab
rows,cols=ab.shape
#ab=list(ab.reshape(rows*cols))
assert list(ab.reshape(rows*cols))==list(mn)
if m.shape==n.shape :
ab=a+b;rows,cols=ab.shape
assert list((ab).reshape(rows*cols))==list(m+n)
ab=a-b;rows,cols=ab.shape
assert list((ab).reshape(rows*cols))==list(m-n)
ab=a*b; rows,cols=ab.shape
assert list((ab).reshape(rows*cols))==list(m*n)
ab=a/b; rows,cols=ab.shape
assert list((ab).reshape(rows*cols))==list(m*n)
x=random.randint(0,100)
c=a+x
rows,cols=c.shape
assert list(c.reshape(rows*cols))==list(m+x)
c=a-x
rows,cols=c.shape
assert list(c.reshape(rows*cols))==list(m-x)
c=a*x
rows,cols=c.shape
assert list(c.reshape(rows*cols))==list(m*x)
c=a/x
rows,cols=c.shape
assert list(c.reshape(rows*cols))==list(m/x)
aa=array(shape=(4,3))
assert aa.shape==(4,3) and aa.rows==4 and aa.cols==3
aa2=aa.reshape(3,4)
assert aa2.shape==(3,4) and aa2.rows==3 and aa2.cols==4
print "OK"