【画像描画】pythonで円・楕円を描いてみる

虹色の楕円重ね合わせ pythonで簡単プログラミング

#python #Pillow #画像 #円 #楕円 #ellipse #色 #RGB

この記事では、pythonのPILというモジュール(Pillow)で円・楕円を描く方法についてわかりやすく解説します。

本記事では、主としてWindows、および、python3を前提にしています。
スポンサーリンク

絵を描くための準備

本記事では、画像を描くための準備は、下記のプログラムで行います。

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() # 画面に表示する

<ファイル名:ellipse.py>

実行は以下のようにして行います。

python ellipse.py

結果は以下のとおり、真っ白な500✕600ドットのキャンバスが表示されます。
なお、小生のPCでは画像表示にXnViewというソフトを使っているため、プログラムで、im.show()関数を実行したときに、これが起動されました。
読者の方は、違うソフトが起動されると思います。

円を描くことに集中するため、この部分のプログラムの詳細な説明はここではしません。コメントに簡単な説明をしていますので、参照してください。
詳しい説明が必要な場合は、『【第4回】にっこちゃんを描いてやんわりと関数・モジュールを学ぶ(解説編)』の『画像を描くキャンバスの作成』以降を参照してください。

座標について

画像の表示で使う座標は、下図のように
左上が (x, y)=(0, 0) で、
左に行くにつれて x座標が増え、
下に行くにつれて y座標が増えます。
中学で学ぶ数学の座標では、y座標は下が0で、上に行くにつれて増えますが、コンピュータでは、逆になるため、注意が必要です。

円を描いてみる

Pillowで円を描くには、ellipse関数を使います。
以下の入力が必要です。
・ 円の開始位置x座標, y座標
・ 円の終了位置x座標, y座標
・ 円の中を塗りつぶす色の赤(Red)成分, 緑(Greeen)成分, 青(Blue)成分
・ 円の枠の色の赤(Red)成分, 緑(Greeen)成分, 青(Blue)成分

プログラム中に書くと、以下になります。

draw.ellipse(   (円の開始位置x座標, y座標,      円の終了位置x座標, y座標), 
             fill=(   円の中を塗りつぶす色のRed成分,    Greeen成分,     Blue成分), 
             outline=(   円の枠の色のRed成分,    Greeen成分,    Blue成分))

では、まずオーソドックスに、
500✕600ドットのキャンバスの左上に、100✕100の大きさで、黒で塗りつぶした円を描いてみます。
以下の行を付け加えます。

draw.ellipse((   0,    0,  100,  100), fill=(  0,   0,   0), outline=(  0,   0,   0))

ellipse関数の最初の入力 ( 0, 0, 100, 100) は、
円の開始位置x座標, y座標, 円の終了位置x座標, y座標
です。

2つ目の入力 fill=( 0, 0, 0), outline=( 0, 0, 0)) は、
fill=(円の中を塗りつぶす色の赤(Red成分), 緑(Greeen成分), 青(Blue成分)),
outline=(円の枠の色の赤(Red成分), 緑(Greeen成分), 青(Blue成分)))
です。
黒はRed成分, Greeen成分, Blue成分の全てが0の場合に黒となります。

付け加えた後のプログラムは以下になります。

<ファイル名:ellipse.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.ellipse((   0,    0,  100,  100), fill=(  0,   0,   0), outline=(  0,   0,   0))

im.show() # 画面に表示する

実行した結果は以下のとおりに表示されます。

円をいくつか並べてみる

円をいくつか並べてみます。
座標をずらして5つ追加して並べます。

<ファイル名:ellipse.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.ellipse((   0,    0,  100,  100), fill=(  0,   0,   0), outline=(  0,   0,   0))
draw.ellipse((   0,  100,  100,  200), fill=(  0,   0,   0), outline=(  0,   0,   0))
draw.ellipse((   0,  200,  100,  300), fill=(  0,   0,   0), outline=(  0,   0,   0))
draw.ellipse((   0,  300,  100,  400), fill=(  0,   0,   0), outline=(  0,   0,   0))
draw.ellipse((   0,  400,  100,  500), fill=(  0,   0,   0), outline=(  0,   0,   0))
draw.ellipse((   0,  500,  100,  600), fill=(  0,   0,   0), outline=(  0,   0,   0))

im.show() # 画面に表示する

プログラムの着色部分を見るとわかりますが、y座標を100ずつずらしました。
結果は以下のとおりになります。

色を変える

黒では面白くないので、色を変えてみます。
色は、赤(Red), 緑(Green), 青(Blue)の3色を指定して混ぜた色になります。
それぞれ、0 ~ 255の数値で濃さを指定します。

ただしこの色は、光を重ね合わせて混ぜる色になるため、絵の具で混ぜた色とは異なります。たとえば、絵の具の場合は、赤、緑、青を全て混ぜると黒くなりますが、パソコンのモニタやスマホの画面では、白になります。
この色の指定形式をRGB形式といい、pythonに限らず、どのような言語で使用する場合でも共通です。

では、色を0か255にして順に変えてみます。
枠の色は黒のままにします。

<ファイル名:ellipse.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.ellipse((   0,    0,  100,  100), fill=(  0,   0,   0), outline=(  0,   0,   0))
draw.ellipse((   0,  100,  100,  200), fill=(255,   0,   0), outline=(  0,   0,   0))
draw.ellipse((   0,  200,  100,  300), fill=(  0, 255,   0), outline=(  0,   0,   0))
draw.ellipse((   0,  300,  100,  400), fill=(  0,   0, 255), outline=(  0,   0,   0))
draw.ellipse((   0,  400,  100,  500), fill=(255, 255,   0), outline=(  0,   0,   0))
draw.ellipse((   0,  500,  100,  600), fill=(  0, 255, 255), outline=(  0,   0,   0))
draw.ellipse(( 100,    0,  200,  100), fill=(255, 255, 255), outline=(  0,   0,   0))

im.show() # 画面に表示する

結果は以下となります。

キャンバスにまだ余りがありますし、せっかくなので、0と255だけではなく、中間の色も表示してみます。
枠(outline)は同じ色にします。
量が多くなるので、プログラムが見にくくなりますが、受け入れてください。

<ファイル名:ellipse.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.ellipse((   0,    0,  100,  100), fill=(  0,   0,   0), outline=(  0,   0,   0))
draw.ellipse((   0,  100,  100,  200), fill=( 50,   0,   0), outline=( 50,   0,   0))
draw.ellipse((   0,  200,  100,  300), fill=(100,   0,   0), outline=(100,   0,   0))
draw.ellipse((   0,  300,  100,  400), fill=(150,   0,   0), outline=(150,   0,   0))
draw.ellipse((   0,  400,  100,  500), fill=(200,   0,   0), outline=(200,   0,   0))
draw.ellipse((   0,  500,  100,  600), fill=(250,   0,   0), outline=(250,   0,   0))

draw.ellipse(( 100,    0,  200,  100), fill=(250,   0,   0), outline=(250,   0,   0))
draw.ellipse(( 100,  100,  200,  200), fill=(250,  50,   0), outline=(250,  50,   0))
draw.ellipse(( 100,  200,  200,  300), fill=(250, 100,   0), outline=(250, 100,   0))
draw.ellipse(( 100,  300,  200,  400), fill=(250, 150,   0), outline=(250, 150,   0))
draw.ellipse(( 100,  400,  200,  500), fill=(250, 200,   0), outline=(250, 200,   0))
draw.ellipse(( 100,  500,  200,  600), fill=(250, 250,   0), outline=(250, 250,   0))

draw.ellipse(( 200,    0,  300,  100), fill=(250, 250,   0), outline=(250, 250,   0))
draw.ellipse(( 200,  100,  300,  200), fill=(200, 250,   0), outline=(200, 250,   0))
draw.ellipse(( 200,  200,  300,  300), fill=(150, 250,   0), outline=(150, 250,   0))
draw.ellipse(( 200,  300,  300,  400), fill=(100, 250,   0), outline=(100, 250,   0))
draw.ellipse(( 200,  400,  300,  500), fill=( 50, 250,   0), outline=( 50, 250,   0))
draw.ellipse(( 200,  500,  300,  600), fill=(  0, 250,   0), outline=(  0, 250,   0))

draw.ellipse(( 300,    0,  400,  100), fill=(  0, 250,   0), outline=(  0, 250,   0))
draw.ellipse(( 300,  100,  400,  200), fill=(  0, 200,  50), outline=(  0, 200,  50))
draw.ellipse(( 300,  200,  400,  300), fill=(  0, 150, 100), outline=(  0, 150, 100))
draw.ellipse(( 300,  300,  400,  400), fill=(  0, 100, 150), outline=(  0, 100, 150))
draw.ellipse(( 300,  400,  400,  500), fill=(  0,  50, 200), outline=(  0,  50, 200))
draw.ellipse(( 300,  500,  400,  600), fill=(  0,   0, 250), outline=(  0,   0, 250))

draw.ellipse(( 400,    0,  500,  100), fill=(  0,   0, 250), outline=(  0,   0, 250))
draw.ellipse(( 400,  100,  500,  200), fill=( 50,   0, 250), outline=( 50,   0, 250))
draw.ellipse(( 400,  200,  500,  300), fill=(100,   0, 250), outline=(100,   0, 250))
draw.ellipse(( 400,  300,  500,  400), fill=(150,   0, 250), outline=(150,   0, 250))
draw.ellipse(( 400,  400,  500,  500), fill=(200,   0, 250), outline=(200,   0, 250))
draw.ellipse(( 400,  500,  500,  600), fill=(250,   0, 250), outline=(250,   0, 250))

im.show() # 画面に表示する

実行結果です。
虹色である赤橙黄緑青藍紫せきとうおうりょくせいらんしのグラデーションになりました。

楕円を描く

ellipse関数は ellipse=楕円 であることから、実は楕円を描く関数です。
円は楕円の1つであるため、ellipse関数でどちらも描画ができます。
最後に、楕円を描いてみます。
楕円は、x, y座標のどちらかを大きくまたは小さくすることで描画できます。

<ファイル名:ellipse_rainbow.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.ellipse((   0,    0,  500,  500), fill=(  0,   0,   0), outline=(  0,   0,   0))
draw.ellipse((  10,    0,  490,  500), fill=( 50,   0,   0), outline=( 50,   0,   0))
draw.ellipse((  20,    0,  480,  500), fill=(100,   0,   0), outline=(100,   0,   0))
draw.ellipse((  30,    0,  470,  500), fill=(150,   0,   0), outline=(150,   0,   0))
draw.ellipse((  40,    0,  460,  500), fill=(200,   0,   0), outline=(200,   0,   0))
draw.ellipse((  50,    0,  450,  500), fill=(250,   0,   0), outline=(250,   0,   0))

draw.ellipse((  60,    0,  440,  500), fill=(250,  50,   0), outline=(250,  50,   0))
draw.ellipse((  70,    0,  430,  500), fill=(250, 100,   0), outline=(250, 100,   0))
draw.ellipse((  80,    0,  420,  500), fill=(250, 150,   0), outline=(250, 150,   0))
draw.ellipse((  90,    0,  410,  500), fill=(250, 200,   0), outline=(250, 200,   0))
draw.ellipse(( 100,    0,  400,  500), fill=(250, 250,   0), outline=(250, 250,   0))

draw.ellipse(( 110,    0,  390,  500), fill=(200, 250,   0), outline=(200, 250,   0))
draw.ellipse(( 120,    0,  380,  500), fill=(150, 250,   0), outline=(150, 250,   0))
draw.ellipse(( 130,    0,  370,  500), fill=(100, 250,   0), outline=(100, 250,   0))
draw.ellipse(( 140,    0,  360,  500), fill=( 50, 250,   0), outline=( 50, 250,   0))
draw.ellipse(( 150,    0,  350,  500), fill=(  0, 250,   0), outline=(  0, 250,   0))

draw.ellipse(( 160,    0,  340,  500), fill=(  0, 200,  50), outline=(  0, 200,  50))
draw.ellipse(( 170,    0,  330,  500), fill=(  0, 150, 100), outline=(  0, 150, 100))
draw.ellipse(( 180,    0,  320,  500), fill=(  0, 100, 150), outline=(  0, 100, 150))
draw.ellipse(( 190,    0,  310,  500), fill=(  0,  50, 200), outline=(  0,  50, 200))
draw.ellipse(( 200,    1,  300,  500), fill=(  0,   0, 250), outline=(  0,   0, 250))

draw.ellipse(( 210,    0,  290,  500), fill=( 50,   0, 250), outline=( 50,   0, 250))
draw.ellipse(( 220,    0,  280,  500), fill=(100,   0, 250), outline=(100,   0, 250))
draw.ellipse(( 230,    0,  270,  500), fill=(150,   0, 250), outline=(150,   0, 250))
draw.ellipse(( 240,    0,  260,  500), fill=(200,   0, 250), outline=(200,   0, 250))
draw.ellipse(( 250,    0,  250,  500), fill=(250,   0, 250), outline=(250,   0, 250))

im.show() # 画面に表示する

このプログラムでは、楕円をいくつも重ねていって、虹色グラデーションの楕円を描きます。
ellipse関数の y座標は、0と500に固定していて、x座標を左右の端から10ドットずつ縮めていって順番に楕円を重ねています。

最後に

いかがでしたでしょうか?
円、楕円を描くだけでも、以下を知る必要がありました。

  • 座標の指定方法
  • 色の指定方法
  • 追加の指定方法(枠の色)

これらの要素は、円、楕円以外の描画をおこなうときにも基本的に同じです。
ということで、また別の描画方法を解説しますので、ご期待ください!

この記事へのお問い合わせや、一歩踏み込んだサポートが必要な場合は、
ホームページからメールで受け付けています。お気軽にご連絡ください。

0

コメント

タイトルとURLをコピーしました