#python #Pillow #画像 #多角形 #line #色 #RGB
この記事では、pythonのPILというモジュール(Pillow)で多角形(五角形)を描く方法について、わかりやすく解説します。
絵を描くための準備
本記事では、画像を描くための準備は、下記のプログラムで行います。
<ファイル名:pentagon.py>
from PIL import Image, ImageDraw # PILからImage, ImageDrawクラスを取り出す
im = Image.new('RGB', ( 500, 600), (255, 255, 255)) # 500 ✕ 600ドットで白(=(255,255,255)の
# キャンバスを準備する
draw = ImageDraw.Draw(im) # 絵を描き込むバケツ(ImageDraw.Drwオブジェクト)を準備する
im.show() # 画面に表示する
実行は以下のようにして行います。
python pentagon.py
結果は以下のとおり、真っ白な500✕600ドットのキャンバスが表示されます。
なお、小生のPCでは画像表示にXnViewというソフトを使っているため、プログラムで、im.show()関数を実行したときに、これが起動されました。
読者の方は、違うソフトが起動されると思います。
円を描くことに集中するため、この部分のプログラムの詳細な説明はここではしません。コメントに簡単な説明をしていますので、参照してください。
詳しい説明が必要な場合は、『【第4回】にっこちゃんを描いてやんわりと関数・モジュールを学ぶ(解説編)』の『画像を描くキャンバスの作成』以降を参照してください。
座標について
画像の表示で使う座標は、下図のように
左上が (x, y)=(0, 0) で、
左に行くにつれて x座標が増え、
下に行くにつれて y座標が増えます。
中学で学ぶ数学の座標では、y座標は下が0で、上に行くにつれて増えますが、コンピュータでは、逆になるため、注意が必要です。
五角形を描いてみる
Pillowで多角形を描くには、直線をつなげて描きます。
そのためline関数を使います。
以下の入力が必要です。
・ 直線の開始位置x座標, y座標 ✕ 多角形の辺の数
・ 直線の終了位置x座標, y座標 ✕ 多角形の辺の数
・ 直線の色の赤(Red)成分, 緑(Green)成分, 青(Blue)成分
・ 直線の幅
・ 直線の連結部分の形状
プログラム中に書くと、以下になります。
draw.line( ( (直線の開始位置x座標, y座標), (直線の終了位置x座標, y座標)
(直線の開始位置x座標, y座標), (直線の終了位置x座標, y座標)
: (多角形の辺の数だけ繰り返し)
(直線の開始位置x座標, y座標), (直線の終了位置x座標, y座標) ),
fill=( 直線の色のRed成分, Green成分, Blue成分),
width=直線の幅,
joint=直線の連結部分の形状 )
実は直線の座標の指定方法にはいくつかの書式がありますが、この記事では現時点で最も問題のない(Pillowのバグを発生させない)書式で記載しています。
本記事では、多角形の中でも五角形を描画します。
では、まず五角形の1辺を描画します。
キャンバスの左上(250, 30)から、(468, 209)に黒い線を描いてみます。
以下の行を付け加えます。
draw.line((( 250, 30),( 468, 209)), fill=( 0, 0, 0))
line関数の最初の入力 (( 0, 0), ( 500, 500)) は、
直線の開始位置x座標, y座標, 直線の終了位置x座標, y座標
です。
括弧 ”(“, “)” が外側に余分についていますが、これについては後述します。
2つ目の入力 fill=( 0, 0, 0) は、
fill=(直線の色の赤(Red成分), 緑(Green成分), 青(Blue成分)),
です。
Red成分, Green成分, Blue成分の全てが0の場合に黒となります。
付け加えた後のプログラムは以下になります。
<ファイル名:pentagon.py>
from PIL import Image, ImageDraw # PILからImage, ImageDrawクラスを取り出す
im = Image.new('RGB', ( 500, 600), (255, 255, 255)) # 500 ✕ 600ドットで白(=(255,255,255)の
# キャンバスを準備する
draw = ImageDraw.Draw(im) # 絵を描き込むバケツ(ImageDraw.Drwオブジェクト)を準備する
draw.line((( 250, 30),( 468, 209)), fill=( 0, 0, 0))
im.show() # 画面に表示する
実行した結果は以下のとおりに表示されます。
では、残りの直線も描いてみます。
多角形は、1つのline関数に、x,y座標を下記のように複数つなげて書くことで、描画することができます。
なお、五角形の頂点の座標は、数学の計算が必要となり難しいので、ここでは割愛します。
<ファイル名:pentagon.py>
from PIL import Image, ImageDraw # PILからImage, ImageDrawクラスを取り出す
im = Image.new('RGB', ( 500, 600), (255, 255, 255)) # 500 ✕ 600ドットで白(=(255,255,255)の
# キャンバスを準備する
draw = ImageDraw.Draw(im) # 絵を描き込むバケツ(ImageDraw.Drwオブジェクト)を準備する
draw.line((( 250, 30),( 468, 209),( 385, 466),( 115, 466),( 32, 209),( 250, 30),( 468, 209)), fill=( 0, 0, 0))
im.show() # 画面に表示する
実行すると以下となります。
さて、ここで、直線の幅を操作してみます。
line関数の入力に、widthを追加します。
“width=50″で、直線の幅を50ドットにします。
<ファイル名:pentagon.py>
from PIL import Image, ImageDraw # PILからImage, ImageDrawクラスを取り出す
im = Image.new('RGB', ( 500, 600), (255, 255, 255)) # 500 ✕ 600ドットで白(=(255,255,255)の
# キャンバスを準備する
draw = ImageDraw.Draw(im) # 絵を描き込むバケツ(ImageDraw.Drwオブジェクト)を準備する
draw.line((( 250, 30),( 468, 209),( 385, 466),( 115, 466),( 32, 209),( 250, 30),( 468, 209)), fill=( 0, 0, 0), width=50)
im.show() # 画面に表示する
実行すると以下になりました。
予想に反して、線のつなぎ目が離れてしまっています。
線のつなぎ目を綺麗に連結させます。
line関数の入力に、”joint=’curve'”を追加します。
‘curve’なので、丸みのある連結を行います。
<ファイル名:pentagon.py>
from PIL import Image, ImageDraw # PILからImage, ImageDrawクラスを取り出す
im = Image.new('RGB', ( 500, 600), (255, 255, 255)) # 500 ✕ 600ドットで白(=(255,255,255)の
# キャンバスを準備する
draw = ImageDraw.Draw(im) # 絵を描き込むバケツ(ImageDraw.Drwオブジェクト)を準備する
draw.line((( 250, 30),( 468, 209),( 385, 466),( 115, 466),( 32, 209),( 250, 30),( 468, 209)), fill=( 0, 0, 0), width=50, joint='curve')
im.show() # 画面に表示する
実行すると以下になります。
グラデーションで塗りつぶしてしまう
ここまで来ると、色が黒のままでは地味ですので、この際、中をグラデーションで塗りつぶしてみます。
しかし、そのためには、五角形をいくつも中に描いていくことになります。
ですので、書くのを避けていた計算式をプログラムしてしまいます。
<ファイル名:pentagon.py>
from PIL import Image, ImageDraw # PILからImage, ImageDrawクラスを取り出す
import math as m # 三角関数含む数学計算モジュール
im = Image.new('RGB', ( 500, 600), (255, 255, 255)) # 500 ✕ 600ドットで白(=(255,255,255)の
# キャンバスを準備する
draw = ImageDraw.Draw(im) # 絵を描き込むバケツ(ImageDraw.Drwオブジェクト)を準備する
xoffset = 250 # 五角形中心のx座標
yoffset = 30 # 五角形の天井のy座標
delta = 10 # 五角形のサイズの増減ドット数
red = 200 # 赤要素
green = 50 # 緑要素
blue = 0 # 青要素
# spoke_len ... 五角形のスポーク(中心から頂点までの長さ)
for spoke_len in range(230, 0, -delta) : # 230から0まで-deltaでspoke_lenを減らす
cos18 = int(spoke_len * m.cos(18/180 * m.pi)) # スポークをcos 18°傾けたx座標成分
sin18 = int(spoke_len * m.sin(18/180 * m.pi)) # スポークをsin 18°傾けたy座標成分
cos54 = int(spoke_len * m.cos(54/180 * m.pi)) # スポークをcos 54°傾けたx座標成分
sin54 = int(spoke_len * m.sin(54/180 * m.pi)) # スポークをsin 54°傾けたy座標成分
# 五角形の各頂点の座標
x1 = xoffset
y1 = yoffset
x2 = xoffset + cos18
y2 = spoke_len - sin18 + yoffset
x3 = xoffset + cos54
y3 = spoke_len + sin54 + yoffset
x4 = xoffset - cos54
y4 = spoke_len + sin54 + yoffset
x5 = xoffset - cos18
y5 = spoke_len - sin18 + yoffset
draw.line(((x1, y1),(x2, y2),(x3, y3),(x4, y4),(x5, y5),(x1, y1),(x2, y2)),
fill=(red, green, blue), width=50, joint='curve')
# 黄色に変化させる
red = red + 10
green = green + 10
# スポークが短くなる分、五角形の天井を下へ移動する
yoffset = yoffset + delta
im.show() # 画面に表示する
上記のプログラムはおおよそ、以下の処理を行っています。
詳細についてはプログラム中のコメントを参照してください。
1.for文で五角形のスポーク(中心から頂点までの長さ)をだんだん小さくしていく
2.五角形の中心を一定にしたまま、頂点の座標を三角関数(cos,sin)を使って計算する
3.五角形を描画する
4.色値を変化させる
5.スポークが短くなる分、五角形の天井を下へ移動させる
実行結果は以下になります。
最後に
いかがでしたでしょうか?
五角形などの多角形は直線を描画するline関数で描画することができます。
また、今回は、line関数に以下のオプションが指定できることが分かりました。
- 直線の幅
- 直線の連結部分の形状
また、
- for文
- range関数
- 三角関数(cos,sin)を使った計算
など、プログラミングならではの特別な処理についても解説しました。
ということで、また別の描画方法を解説しますので、ご期待ください!
この記事へのお問い合わせや、無料のサポート、一歩踏み込んだ有料サポートが必要な場合は、ホームページからメールで受け付けています。お気軽にご連絡ください。
コメント