TL;DR
Google Colaboratoryでなにか描画して表示するにはIPython.display.display
を使うと良い。
はじめに
Google Colaboratory上で何かイメージを描画し、それを表示するのは意外に面倒だった。その方法をいくつか紹介する。
PILによるイメージ描画
まず、何か絵を描く。個人的にはCairoに慣れているのでpycairoを使いたいが、Google Colab上ではpycairoが入らない。import cairo
すると無いと言われ、!pip install pycairo
すると失敗する。もともとCairoのライブラリが入っていないらしい。というわけでPILを使う。
from PIL import Image, ImageDraw
im = Image.new("RGB", (256,256))
draw = ImageDraw.Draw(im)
draw.ellipse((64,64,192,192),fill=(255,0,0))
これで、イメージに黒字に赤い丸が描画されたはずである。以下はセルの実行結果であるが、実行結果であるイメージは表示されない。im
に格納されただけである。
どうにかしてそれを表示しましょう、というのが本稿の目的である。
案1: matplotlib+numpyを使う
まず、イメージデータをnumpy配列に変換し、matplotlibのpyplot.imshowを使う、という方法がある。
import matplotlib.pyplot as plt
import numpy as np
plt.imshow(np.array(im))
一応表示されるのだが、不要な軸があったりする。
(2021年4月9日追記)
いま同じことをすると、軸が表示されないようですね。どこかでデフォルト設定が変わった?
案2: バッファに吐いてIPython.display.Image
で表示
一度io.BytesIO
で作ったバッファに保存し、そのバッファをIPython.display.Image
で表示する。
import io
buf = io.BytesIO()
im.save(buf,"PNG")
data = buf.getvalue()
IPython.display.Image(data)
PILのImage.saveは、ファイル名を指定する場合はタイプを自動判別してくれるが、バッファに吐く時にはタイプを明示しないといけないことに注意。実行するとこうなる。
余計な軸などが表示されず、イメージがそのまま表示されるのでいい感じである。
案3: 一度ファイルに吐いてIPython.display.Image
で表示
先の例では一度バッファに吐いて、getvalue()
で生データを取得し、それをIPython.display.Image
に食わせていた。それなら一度ファイルに吐いてしまった方が楽な気もする。
import IPython
im.save("test.png")
IPython.display.Image("test.png")
まとめ
Google Colabで「お絵かき」をするのは意外に面倒くさい。3つの方法を紹介したが、個人的にはファイルに吐いてしまって表示する方法が一番楽な気がする。というわけで、Google Colab上で「お絵かき」をするサンプルはこんな感じになる。
from PIL import Image, ImageDraw
import IPython
im = Image.new("RGB", (256,256))
draw = ImageDraw.Draw(im)
draw.ellipse((64,64,192,192),fill=(255,0,0))
im.save("test.png")
IPython.display.Image("test.png")
Google Colabにおける実行結果はこんな感じ。
importも最低限だし、これが一番楽なんじゃないかなぁ。
案4: IPython.display.display
を使う (2019年10月1日追記)
IPython.display
にはdisplay
という関数があり、それはイメージをそのまま表示できることを後で知った。
from IPython.display import display
display(im)
これが一番楽ですね。
案5: (2020年11月26日追記)
コメント欄での指摘の通り、セルでPIL.Image.Image
をそのまま評価してしまうのがもっと楽ですね。
from PIL import Image, ImageDraw
im = Image.new("RGB", (256,256))
draw = ImageDraw.Draw(im)
draw.ellipse((64,64,192,192),fill=(255,0,0))
im