PyOpenGL3.0について

PyOpenGLはOpenGLPythonで扱うためのライブラリです。

PyOpenGL3.0のインストール

PyOpenGL3.0の公式サイトhttp://pyopengl.sourceforge.net/documentation/installation.html
Downloads>PyOpenGLからダウンロード。PyOpenGL-3.0.1.win32.exeを起動するとすぐにインストール終了。

PyOpenGLの簡単なサンプル

黒画面に三角形を表示するだけのサンプルです。OpenGLの関数をそのまま利用することができます。
InitGLでOpenGLの初期化、DrawGLSceneで描画を行っています。

from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *

def init():                
    glClearColor(0.0, 0.0, 0.0, 0.0) 
      
def display():
    glClear(GL_COLOR_BUFFER_BIT)
    glBegin(GL_TRIANGLE_STRIP)
    glVertex2d(0.,0.)
    glVertex2d(0.7,0.7)
    glVertex2d(0.,0.7)
    glEnd()

    #double buffer
    glutSwapBuffers()

def main():
    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE)
    glutInitWindowSize(400, 300)
    glutInitWindowPosition(0, 0)

    glutCreateWindow("PyOpenGL")
    glutDisplayFunc(display)
    init()
    glutMainLoop()

main()

matplotlibで画像を表示する

matplotlibで画像を表示させるための手順について。
matplotlibはPILを利用して画像の描画を行っているため、PILの機能に準じた処理になります。PILを使って画像の値を配列形式として読み込む作業を、matplotlibを使うと簡単に行うことができます。

画像の読み込みと描画

最も単純なサンプルです。

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
img=mpimg.imread('test.png') #image to array
plt.imshow(img) #array to 2Dfigure

plt.show()

matplotlib.imageのimreadで画像を配列に変換します。配列のデータを、pyplotの図にレンダリングする関数がimshowです。

print img

例えば全ての成分が赤であるRGB画像では次のように値が格納されます。


[ [ [ 1. 0. 0.]
[ 1. 0. 0.]
[ 1. 0. 0.]

...,
[ 1. 0. 0.]
[ 1. 0. 0.]
[ 1. 0. 0.] ] ]

ヒストグラムの表示

pyplotにヒストグラムを表示する機能としてhist関数が提供されているのでこれ画像処理用のヒストグラムにしてみます。

import matplotlib.pyplot as plt
import matplotlib.image as mpimg

img=mpimg.imread('test.png')

plt.figure(1)
#red
plt.subplot(311)
r_img = img[:,:,0]
plt.hist(r_img.flatten(), 256, range=(0.0,1.0), fc='r', ec='k')
#green
plt.subplot(312)
g_img = img[:,:,1]
plt.hist(g_img.flatten(), 256, range=(0.0,1.0), fc='g', ec='k')
#blue
plt.subplot(313)
b_img = img[:,:,2]
plt.hist(b_img.flatten(), 256, range=(0.0,1.0), fc='b', ec='k')

plt.show()

引数のfcは棒グラフの棒の色、ecは棒のエッジ部分の色です。色の情報を0.から1.までの範囲で描画します。
img[:,:,0]で赤の成分を、img[:,:,1],img[:,:,2]で緑と青の成分を抽出した配列を生成します。例えば、全ての成分が赤であるRGB画像に対してimg[:,:,0]は下のような配列を生成します。


[ [ 1. 1. 1. ..., 1. 1. 1.]
[ 1. 1. 1. ..., 1. 1. 1.]
[ 1. 1. 1. ..., 1. 1. 1.]
...,
[ 1. 1. 1. ..., 1. 1. 1.]
[ 1. 1. 1. ..., 1. 1. 1.]
[ 1. 1. 1. ..., 1. 1. 1.] ]
plt.subplot(31*)で3つの図を用意して、上からR,G,Bに対応したヒストグラムを描いています。

scipyと組み合わせる

scipyを使うと画像処理テスト用のレナ画像を読み込めます。読み込んだ画像の形式は、RGBそれぞれの二次元配列のリストです。Rだけ取り出すにはimg[0]だけでよいです。ただし、値はさきほどと違って0.から255.になっているので注意。

from scipy import signal, misc
from numpy import *
img = misc.lena().astype(float32)
print img


[ [ 162. 162. 162. ..., 170. 155. 128.]
[ 162. 162. 162. ..., 170. 155. 128.]
[ 162. 162. 162. ..., 170. 155. 128.]
...,
[ 43. 43. 50. ..., 104. 100. 98.]
[ 44. 44. 55. ..., 104. 105. 108.]
[ 44. 44. 55. ..., 104. 105. 108.] ]

import matplotlib.pyplot as plt
import matplotlib.image as mpimg

#img=mpimg.imread('test.png')
from scipy import signal, misc
from numpy import *

img = misc.lena().astype(float32)

plt.figure(1)
#red
plt.subplot(311)
r_img = img[0]
plt.hist(r_img.flatten(), 256, range=(0.,255.), fc='r', ec='k')
#green
plt.subplot(312)
g_img = img[1]
plt.hist(g_img.flatten(), 256, range=(0.,255.), fc='g', ec='k')
#blue
plt.subplot(313)
b_img = img[2]
plt.hist(b_img.flatten(), 256, range=(0.,255.), fc='b', ec='k')

plt.show()

matplotlibをwxPythonで扱う

matplotlibで描いたグラフをwxPythonのパネル上に表示できると、matplotlibの機能を直接利用できるアプリケーションを作成することができます。次のコードは、3次元のグラフをパネル上にプロットさせて表示させた例です。

import matplotlib
matplotlib.interactive( True )
matplotlib.use( 'WXAgg' )

import wx
class myWxPlot(wx.Panel):
    def __init__( self, parent):
        from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
        from matplotlib.figure import Figure
        
        self.parent = parent
        wx.Panel.__init__( self, parent)

        #matplotlib figure
        self.figure = Figure( None )
        self.figure.set_facecolor( (0.7,0.7,1.) )
        self.subplot = self.figure.add_subplot( 111 )
        #canvas
        self.canvas = FigureCanvasWxAgg( self, -1, self.figure )
        self.canvas.SetBackgroundColour( wx.Color( 100,255,255 ) )

        self._SetSize()
        self.draw()

    def _SetSize( self ):
        size = tuple( self.parent.GetClientSize() )
        self.SetSize( size )
        self.canvas.SetSize( size )
        self.figure.set_size_inches( float( size[0] )/self.figure.get_dpi(),
                                     float( size[1] )/self.figure.get_dpi() )

    def draw(self):
        from mpl_toolkits.mplot3d import Axes3D
        import numpy as np
        
        x = np.arange(-3, 3, 0.25)
        y = np.arange(-3, 3, 0.25)
        X, Y = np.meshgrid(x, y)
        Z = np.sin(X)+ np.cos(Y)
        
        ax = Axes3D(self.figure)
        ax.plot_wireframe(X,Y,Z)


app = wx.App()
frame = wx.Frame( None, size=(500,500) )
panel = myWxPlot( frame )
frame.Show()
app.MainLoop()

matplotlibがwxPythonを使って描画するように設定するため、下のように 'WXAgg' を指定します。

import matplotlib
matplotlib.interactive( True )
matplotlib.use( 'WXAgg' )

myWxPlotクラスにmatplotlib.figureとsubplot,canvas(matplotlibが表示するためのwxPython用キャンバス)をメンバ変数として持たせます。
キャンバスを扱うために、初期化子内で次のモジュールをインポートします。

from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg

また、グラフを描画する図であるmatplotlib.figureを扱うのでこのモジュールも同時にインポートします。

from matplotlib.figure import Figure

2次元の図を描く場合は、figure上にsubplotを作成してそこに描画することになるので、subplotを一つメンバとして保持させておきます。
matplotlib.figureに背景色を付けるにはset_facecolorでfloatのタプルによって色を指定します。一方canvasの方はint型タプル(0〜255)で色を指定するので注意が必要です。

        #matplotlib figure
        self.figure = Figure( None )
        self.figure.set_facecolor( (0.7,0.7,1.) )
        self.subplot = self.figure.add_subplot( 111 )
        #canvas
        self.canvas = FigureCanvasWxAgg( self, -1, self.figure )
        self.canvas.SetBackgroundColour( wx.Color( 100,255,255 ) )

_SetSizeでfigureとcanvas、パネル自身のサイズを設定しており、drawメソッドで描画の処理を行っています。
2次元のグラフを描画するコードが次の例です。subplotにグラフをplotしています。

    def draw(self):
        import numpy as np

        theta = np.arange(0,200, 0.1)
        x = 2*np.cos(theta/7)
        y = 3*np.sin(theta/3)

        self.subplot.plot(x,y, '-r')

        self.subplot.set_title("Sample", fontsize = 12)
        self.subplot.set_xlabel("x")
        self.subplot.set_ylabel("y")
        self.subplot.set_xlim([-4, 4])
        self.subplot.set_ylim([-4, 4])

また下の例では、mpl_toolkits.mplot3dを利用してfigureに3次元のグラフをplotしています。

    def draw(self):
        from mpl_toolkits.mplot3d import Axes3D
        import numpy as np
        
        x = np.arange(-3, 3, 0.25)
        y = np.arange(-3, 3, 0.25)
        X, Y = np.meshgrid(x, y)
        Z = np.sin(X)+ np.cos(Y)
        
        ax = Axes3D(self.figure)
        ax.plot_wireframe(X,Y,Z)

可変個数の引数について

pythonでは、*argsという書式を使うと関数へ可変個数の引数を渡すことができます。

def function(arg1, arg2, *args):
    print "arg1:", arg1
    print "arg2:", arg2
    for arg in args:
        print "arg:", arg

function(0, 1, 2 , "aaa", "bbb")


arg1: 0
arg2: 1
arg: 2
arg: aaa
arg: bbb

キーワード引数

関数にキーワード = 値という書式の引数を渡すことも可能です。

def eat(price, food='potato', mode='quickly'):
    print "price:",price,"yen"
    print "food:",food
    print "mode:",mode
    

eat(10000, food='tofu', mode='deliciously')


price: 10000 yen
food: tofu
mode: deliciously

可変個のキーワード引数を関数に渡すには、**keyworgsという書式を利用します。

def function(arg1, **keywords):
    print "arg1:", arg1
    for key in keywords:
        print "keywords:",  key, keywords[key]

function(arg1=1, arg2="aaa", arg3=9)


arg1: 1
keywords: arg2 aaa
keywords: arg3 9

matplotlibで3Dグラフを描画する

準備

データ処理用にnumpy、プロット用にpyplot、3次元なのでmpl_toolkits.mplot3dをインポートします。

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

描画するデータの作成

3次元で描画するにはメッシュ(2次元の網目)を作成するために2次元の配列を用意する必要があります。
まずarangeメソッドでx,yそれぞれを1次元領域で分割します。

x = np.arange(-3, 3, 0.25)
y = np.arange(-3, 3, 0.25)

2次元メッシュを作成するにはmeshgridメソッドを利用します。この関数の戻り値はX,Yに対応する行列で、Xは行にxの配列を、Yは列にyの配列を入れたものになっています。

X, Y = np.meshgrid(x, y)
print "x=" , x
print "X=" , X
print "y=" , y
print "Y=" , Y


x= [-3. -2. -1. 0. 1. 2.]
X= [ [-3. -2. -1. 0. 1. 2.]
[-3. -2. -1. 0. 1. 2.]
[-3. -2. -1. 0. 1. 2.]
[-3. -2. -1. 0. 1. 2.]
[-3. -2. -1. 0. 1. 2.] ]
y= [-1. 0. 1. 2. 3.]
Y= [ [-1. -1. -1. -1. -1. -1.]
[ 0. 0. 0. 0. 0. 0.]
[ 1. 1. 1. 1. 1. 1.]
[ 2. 2. 2. 2. 2. 2.]
[ 3. 3. 3. 3. 3. 3.] ]

このXYを直接利用してzを計算します。計算結果も2次元配列になります。

x = np.arange(-3, 3, 0.25)
y = np.arange(-3, 3, 0.25)
X, Y = np.meshgrid(x, y)
Z = np.sin(X)+ np.cos(Y)


Z= [[ 0.3991823 -0.36899512 -0.30116868 0.54030231 1.38177329 1.44959973]
[ 0.85887999 0.09070257 0.15852902 1. 1.84147098 1.90929743]
[ 0.3991823 -0.36899512 -0.30116868 0.54030231 1.38177329 1.44959973]
[-0.55726684 -1.32544426 -1.25761782 -0.41614684 0.42532415 0.49315059]
[-1.1311125 -1.89928992 -1.83146348 -0.9899925 -0.14852151 -0.08069507]]

グラフの作成

figureメソッドでまず2次元の図を生成します。そのあとAxes3D関数で3次元版に変換します。
あとは、予め計算させておいた3次元の点列X,Y,Zをplotなどの3次元プロット関数に渡せばOKです。

fig = plt.figure()
ax = Axes3D(fig)
ax.plot_wireframe(X,Y,Z)

ここまでの処理をまとめると下のようになります。

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

x = np.arange(-3, 3, 0.25)
y = np.arange(-3, 3, 0.25)
X, Y = np.meshgrid(x, y)
Z = np.sin(X)+ np.cos(Y)

fig = plt.figure()
ax = Axes3D(fig)
ax.plot_wireframe(X,Y,Z) #<---ここでplot

plt.show()


plot_wireframe以外にもいくつか関数が用意されていて様々な図を描くことができます。

ワイヤーフレーム

ax.plot_wireframe(X,Y,Z)

サーフェス

ax.plot_surface(X, Y, Z, rstride=1, cstride=1)

3次元プロット

plot3Dは単に与えられた1次元配列を3次元プロットする関数です。X,Y,Zは2次元配列なので、numpy.ravel関数で2次元配列を1次元配列に変換してから引数として渡します。図を描くと全て直線でつながっていることが分かります。

ax.plot3D(np.ravel(X),np.ravel(Y),np.ravel(Z))

等高線

contourf3Dは同じ高さを同じ色で塗りつぶす関数です。

ax.contour3D(X,Y,Z)
ax.contourf3D(X,Y,Z)


散布図

直線ではなくて点を3次元上にプロットするメソッドです。こちらも一旦1次元配列に変換してから引数に渡します。

ax.scatter3D(np.ravel(X),np.ravel(Y),np.ravel(Z))

matplotlibを使う

matplotlibはpythonでグラフを描くためのライブラリです。numpyなどと組み合わせると簡易matlabのような環境を整えることができます。

インストール

公式サイト→http://matplotlib.sourceforge.net/index.html
matplotlib 0.99.1 is available for downloadのところからダウンロードできます。Windows用の簡易インストーラmatplotlib-0.99.1.win32-py2.6.exeをダウンロードします。インストールはこれで簡単にできます。

グラフを描く

plotコマンドでプロットする点のxy座標を定めます。下の例では、x=0,1,2,y=2,3,4のグラフを、x軸0-5,y軸0-8の範囲で描画します。grid()メソッドでグリッドを表示することができます。

import matplotlib.pyplot as plt
plt.plot([0,1,2][2,3,4])
plt.axis([0,5,0,8])
plt.grid()
plt.title('sample')
plt.xlabel('x')
plt.ylabel('y')
plt.show()

Arrayによる入力

numpyをインポートし、arrayを生成してプロットすることもできます。

from matplotlib.pyplot import*
from numpy import *
x = arange(0., 7., 0.1) #form 0.0 to 7.0, interval = 0.1
plot(x,cos(x))
show()

プロットのデザイン

点の形を指定するには、'--','^','s'などを引数に指定します。

import matplotlib.pyplot as plt
import numpy
t = numpy.arange(0., 5., 1.)
plt.plot(t, t/3,        #line
         t, t/2,'--'    #dotted line
         ,t, t*1, '^'   #triangle
         ,t, t*1.5, 'v' #triangle
         , t, t*2, '<'  #triangle
         , t, t*2.5, '>'#triangle        
         ,t, t*3, 's'   #square
         , t, t*3.5, 'd'#square(dice)
         , t, t*4, 'p'  #pentagon
         , t, t*5, 'h'  #hexagon
         , t, t*6, 'o'  #circle
         , t, t*7, '+'  #cross
         , t, t*8, '*'  #star
         , t, t*9, 'x'  #cross
         , t, t*10, '.' #big dot
         , t, t*11, ',' #small dot
         )
plt.show()

色を設定するには、'r','g','b'などの接頭辞を付けます。

import matplotlib.pyplot as plt
import numpy
t = numpy.arange(0., 5., 1.)
plt.plot(t, t*2, 'r--'    #red line
         ,t, t*3,'g--'    #green
         ,t, t*4, 'b--'   #blue
         ,t, t*5, 'y--'   #yellow
         ,t, t*6, 'c--'   #cyan       
         ,t, t*7, 'm--'   #magenta
         ,t, t*8, 'w--'   #white
         ,t, t*9, 'k--'   #black
         )
plt.show()

線のカスタマイズ

plotメソッドの引数に直接指定すると下のようになります。

plt.plot(t, t*2,color = '#cccfff', linewidth=3)

plotが返すlineインスタンスのsetupメソッドにより指定する方法もあります。

import matplotlib.pyplot as plt
import numpy
t = numpy.arange(0., 5., 1.)
plt.grid()
#lines = plt.plot(t, t*2,color = '#cccfff', linewidth=3)
plt.setp(lines, color='#cccfff', linewidth=2.0)
plt.setp(lines, 'color', 'r', 'linewidth', 3.0)
plt.show()

複数のグラフを表示する

別のウインドウで複数のグラフを表示するには、figure(番号)と記述します。同じfigure内で複数のグラフを描きたい場合は、subplotメソッドを使います。描画領域の行数,描画領域の列数,グラフ番号を3ケタの数にして引数にします。例えば2*2の領域のうち3つ目の領域に描くなら、plt.subplot(223)で現在のグラフの位置を指定してplotを呼び出すとよいです。

import numpy as np
import matplotlib.pyplot as plt
x1 = np.arange(0.0, 2*np.pi, 0.1)
x2 = np.arange(0.0, 2*np.pi, 0.1)

plt.figure(1)
plt.subplot(221)
plt.plot(x1, np.sin(x1), 'r--', x2, np.sin(x2), 'k')
plt.subplot(224)
plt.plot(x2, np.sin(2*np.pi*x2), 'r--')

plt.figure(2)
plt.plot(x1, np.cos(x1), 'r--')

plt.show()