ノート/ノート

訪問者数 1963      最終更新 2016-09-08 (木) 16:42:48

python・matplotlibで扱う画像 --- 2016/08/15

test-image-PIL-output-from-PyPlot

Pythonでのイメージの扱い、PIL(Python Image Library)とnumpy/matplotlib環境との関係

matplotlibで扱っているイメージを画像出力したかった

In [2]:
"""
Simple demo of the imshow function.
"""
import matplotlib.pyplot as plt
import matplotlib.cbook as cbook

image_file = cbook.get_sample_data('ada.png')
image = plt.imread(image_file)
plt.imshow(image)
plt.savefig('myada.png')
plt.show()

問題: matplotlibの標準的な画像出力であるshowは、グラフが目的らしく、軸があったり、たとえ軸を無しにしてもキャンバスと画像の間に枠(空白)が挿入されている。画像本体のみを出力したいが、そのやり方がよくわからない。

試した方法:

# plt.subplots_adjust(left=0.0, right=1.0,bottom=0.0, top=1.0 hspace=0.0, wspace=0.0)
# plt.axis('off')  # clear x- and y-axes
In [4]:
"""
Simple demo of the imshow function.
"""
import matplotlib.pyplot as plt
import matplotlib.cbook as cbook

image_file = cbook.get_sample_data('ada.png')
image = plt.imread(image_file)
###
plt.subplots_adjust(left=0.0, right=1.0, bottom=0.0, top=1.0, hspace=0.0, wspace=0.0)
plt.axis('off')  # clear x- and y-axes
###
plt.imshow(image)
plt.savefig('myada.png')
plt.show()

では、matplotlibで扱っているイメージを、pythonの画像ライブラリPILで出力するとどうなるか?

まず、PILについて。 現在はPILは開発が止まっているようで、そのブランチのpillowというパッケージが開発を続けているらしい。 pip install pillow

PILの使い方の例

In [ ]:
"""
Simple demo of the PIL image.show function.
"""
from PIL import Image

pilImg = Image.open("IMG_0107_320.png")
pilImg.show()   # ImageMagickを使ってXwindow上に表示してくる
pilImg.save('mytest.png')

matplotlibで扱うイメージとPILのイメージデータの間は、一般的には直接変換するサービスがある

たとえば PILで画素を操作、保存するとき では img = Image.open("tmp.png")

# Imageからnumpy.arrayへの変換
a = np.array(img)
# numpy.arrayからImageへの変換
img2 = Image.fromarray(a)
# intに変換するときは (8ビットに変換)
img2 = Image.fromarray(np.uint8(a))

というわけで、fromarrayを使えばいい、ということなのだが、この向き(PILでファイルを読んだものをnumpyのarrayに変換した後、それをもう一度PILに戻す)はうまくゆくが、matplotlibでファイルを読んだものをfromarrayでPILのデータに変換するとエラーが起こる。

いろいろなページに、np.uint8()によって符号無し8ビット整数にせよとあるが、これだけではうまくなかった。

In [5]:
"""
Simple demo of the PIL image.show function.
"""
import matplotlib.pyplot as plt
import matplotlib.cbook as cbook
from PIL import Image

image_file = cbook.get_sample_data('ada.png')
image = plt.imread(image_file)

pilImg = Image.fromarray(image)    # またはImage.fromarray(np.uint8(image))

pilImg.show()   # ImageMagickを使ってXwindow上に表示してくる
pilImg.save('myface.png')
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
/home/yamanouc/.pyenv/versions/3.5.1/envs/testchainer/lib/python3.5/site-packages/PIL/Image.py in fromarray(obj, mode)
   2166             typekey = (1, 1) + shape[2:], arr['typestr']
-> 2167             mode, rawmode = _fromarray_typemap[typekey]
   2168         except KeyError:

KeyError: ((1, 1, 4), '<f4')

During handling of the above exception, another exception occurred:

TypeError                                 Traceback (most recent call last)
<ipython-input-5-89f2ba221348> in <module>()
      9 image = plt.imread(image_file)
     10 
---> 11 pilImg = Image.fromarray(image)
     12 
     13 pilImg.show()   # ImageMagickを使ってXwindow上に表示してくる

/home/yamanouc/.pyenv/versions/3.5.1/envs/testchainer/lib/python3.5/site-packages/PIL/Image.py in fromarray(obj, mode)
   2168         except KeyError:
   2169             # print typekey
-> 2170             raise TypeError("Cannot handle this data type")
   2171     else:
   2172         rawmode = mode

TypeError: Cannot handle this data type

実行すると、fromarrayの呼び出しのところで TypeError: Cannot handle this data type となる。

結局もう1段キャストが必要だった

fromarrayに食わせる前に、一回 asarray を食わせる必要があったらしい。 pilImg = Image.fromarray(np.uint8(np.asarray(image))) とすることによって、タイプエラーは出なくなった。

In [7]:
"""
Simple demo of the PIL image.show function.
"""
import matplotlib.pyplot as plt
import matplotlib.cbook as cbook
import numpy as np
from PIL import Image

image_file = cbook.get_sample_data('ada.png')
image = plt.imread(image_file)

pilImg = Image.fromarray(np.uint8(np.asarray(image)))   # << ここを変更

pilImg.show()   # ImageMagickを使ってXwindow上に表示してくる
pilImg.save('myface.png')

ところが、生成された絵は真っ黒だった

内容をよく見ると、plt.imreadで読み込んだ値は浮動小数で0から1の間であり、PILでの出力側は整数で0から255でなければならない。

plt.imreadで読み込んだ値をそのまま整数に変換しても、全部0になるので、真っ黒になるのは当然である。

そこで、この例では255倍して、値を合わせることにする。一般性を考えて、読み込んだ値の最大値を求めて、それが256になるようにすると良いかも知れない。 image = plt.imread("IMG_0107_320.png") arrayimage = np.asarray(image) scale = 256.0 / np.max(arrayimage) pilImg = Image.fromarray(np.uint8(arrayimage*scale))

最終的には、

In [10]:
"""
Simple demo of the pyplot + PIL.
"""
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image

image = plt.imread("IMG_0107_320.png")
arrayimage = np.asarray(image)
scale = 255.0 / np.max(arrayimage)

pilImg = Image.fromarray(np.uint8(arrayimage*scale))
pilImg.show()   # This displays the image on XWindow using ImageMagick
pilImg.save('output.png')
In [ ]:
 

IMG_0107_320.pngの画像(入力)
IMG_0107_320.png

output.pngの画像(出力)
output.png


おまけ

ipynbファイルをWebとしてアップして、ビューワ Jupyter Notebook Viewer で見ることができる。(nbviewerでスライド表示もできるようになった!【Jupyter】 - Qiita、 Jupyter (iPython) Notebookを使ってプレゼンテーション資料を作る方法


添付ファイル: fileoutput.png 147件 [詳細] fileIMG_0107_320.png 160件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2016-09-08 (木) 16:42:48 (440d)