【Matplotlib】画像の読み込みと保存

当サイトではアフィリエイトプログラムを利用して商品を紹介しています。

画像の作成・読み込み・保存

画像と配列

Scikit-image というパッケージには、色々な画像データが収められています。その中から chelsea (チェルシー) という可愛い「にゃんこ」の画像を読み込んでみましょう。

# PYTHON_NUMPY_IMAGE

# In[1]

import numpy as np
import matplotlib.pyplot as plt

# Scikit-imageから猫の画像データを取得
from skimage.data import chelsea

# 画像表示用のFigureとAxesを作成
fig = plt.figure()
ax = fig.add_subplot(111)

# 配列に画像データを格納
img = chelsea()

# 画像を表示
ax.imshow(img)

Scikit-image chelsea
matplotlib.axes.Axes.imshow() はデータを画像に変えて表示する関数ですが、元の画像データはどのような形式で記述されているのでしょうか?
 
print() 関数でデータの大きさと中身を表示してみます。

# In[2]

np.set_printoptions(threshold=10)

print("データの形状:\n{}".format(img.shape))
print(img)
データの形状:
(300, 451, 3)

[[[143 120 104]
  [143 120 104]
  [141 118 102]
  ...
  [ 45  27  13]
  [ 45  27  13]
  [ 45  27  13]]

 [[146 123 107]
  [145 122 106]
  [143 120 104]
  ...
  [ 46  29  13]
  [ 45  29  13]
  [ 47  30  14]]

 [[148 126 112]
  [147 125 111]
  [146 122 109]
  ...
  [ 48  28  17]
  [ 49  29  18]
  [ 50  30  19]]

 ...

 [[ 92  58  30]
  [105  71  43]
  [132  98  71]
  ...
  [172 145 138]
  [172 145 138]
  [172 145 138]]

 [[128  92  60]
  [139 103  71]
  [134  95  64]
  ...
  [166 142 132]
  [166 142 132]
  [167 143 133]]

 [[139 103  71]
  [127  88  57]
  [125  86  53]
  ...
  [161 137 127]
  [161 137 127]
  [162 138 128]]]

このように、画像データは三次元配列として格納されています。データの意味を理解するために、小さな配列を作成して「配列から画像を生成する」という逆手順を実行してみます。

# In[3]

# FigureとAxesを作成
fig = plt.figure()
ax = fig.add_subplot(111)

# 乱数シードを設定
np.random.seed(0)

# ランダム配列を生成
data_r = np.random.randint(0, 255, (3, 3))
print("data_r:\n{}".format(data_r))

# データを赤単色画像に変換
ax.imshow(data_r, "Reds")

# data_r:
# [[172  47 117]
#  [192  67 251]
#  [195 103   9]]

Python 赤単色画像
imshow() のカラーマップに “Reds” を指定して、配列を赤単色画像に変換しています。
配列の各要素はマス目 (ピクセル) ごとの濃淡を 0 ~ 255 の数値で表しています。
同じようにして、緑単色画像を作成します。

# In[4]

fig = plt.figure()
ax = fig.add_subplot(111)

np.random.seed(1)
data_g = np.random.randint(0, 255, (3, 3))
print("data_g:\n{}".format(data_g))

img = np.array(data_g)
ax.imshow(img, "Greens")

# data_g:
# [[ 37 235 140]
#  [ 72 137 203]
#  [133  79 192]]

Python 緑単色画像
最後に青単色画像です。

# In[5]

fig = plt.figure()
ax = fig.add_subplot(111)

np.random.seed(2)
data_b = np.random.randint(0, 255, (3, 3))
print("data_b:\n{}".format(data_b))

img = np.array(data_b)
ax.imshow(img, "Blues")

# data_b:
# [[168  15 237]
#  [ 72  22  43]
#  [210  75 104]]

Python 青単色画像
赤 (R)、緑 (G)、青 (B) の 3 原色の組み合わせ (RGB) によって、他の色を作り出すことができます。上で作成した 3 種類の画像データを numpy.dstack() で重ね合わせてみましょう。

# In[6]

# 3枚の画像データを重ねる
data = np.dstack((data_r, data_g, data_b))

print(data)

'''
[[[172  37 168]
  [ 47 235  15]
  [117 140 237]]

 [[192  72  72]
  [ 67 137  22]
  [251 203  43]]

 [[195 133 210]
  [103  79  75]
  [  9 192 104]]]
'''

配列の最初の要素 [172 37 168] は左上のピクセルが (赤 172, 緑 37, 青 168) の割合で混ぜ合わされた色であることを意味しています。imshow() に 3 次元配列を渡すと、自動的に色を重ね合わせた画像を表示ます。

# In[7]

fig = plt.figure()
ax = fig.add_subplot(111)

# 画像データを作成
img = np.array(data)

# 画像を表示
ax.imshow(img, vmin=0, vmax=255)

plt.savefig("color_image.png", bbox_inches="tight")

Python 色の重ね合わせ

画像を作成:Axes.imshow()

matplotlib.axes.Axes.imshow() の詳細を解説します。この関数を使って、NumPy の配列の各要素をピクセルとする画像を作ることができます。imshow() の最も簡単な使い方は、配列とカラーマップ (cmap) を指定する方法です。この場合、渡した配列によってカラーマップは自動的に正規化されます。

# PYTHON_MATPLOTLIB_IMSHOW

# In[1]

import numpy as np
import matplotlib.pyplot as plt

# FigureとAxesを作成
fig = plt.figure()
ax = fig.add_subplot(111)

# NumPyの配列で色を指定
img = np.array([[0, 1, 2],
                [3, 4, 5],
                [6, 7, 8]])

# 配列の各要素をピクセルとする画像を表示
ax.imshow(img, "Reds")

imshow 画像作成
カラーマップを自分で正規化したい場合は、vmin と vmax を指定します。

# In[2]

fig = plt.figure()
ax = fig.add_subplot(111)

# NumPyの配列で色を指定
img = np.array([[10, 20, 30],
                [40, 50, 60],
                [70, 80, 90]])

# 配列の各要素をピクセルとする画像を表示
ax.imshow(img, "Reds", vmin=0, vmax=255)

imshow 画像作成02

画像を読み込む:plt.imread()

plt.imread() を使うと、外部の画像ファイルを読み込んで配列に格納することができます。たとえば、カレントディレクトリに BlogCat.jpg というファイルがある場合、次のコードで画像を表示させることができます。

# PYTHON_MATPLOTLIB_IMREAD

# In[1]

# FigureとAxesを作成
fig = plt.figure()
ax = fig.add_subplot(111)

# 画像を読み込んで配列に格納
img = plt.imread("BlogCat.jpg")

# 画像を表示
ax.imshow(img)

BlogCatのプロフィール写真

画像を保存:Figure.savefig(), plt.savefig()

Figure オブジェクトの savefig()Matplotlib で作成した図をファイルに出力できます。第 1 引数には保存先のファイル名を指定します。ファイル名には .png, .jpeg, .svg などの拡張子を添えて保存形式を決めます。パスを指定しなければ、ファイルはカレントディレクトリに保存されます。
他にも dpi(解像度)や facecolor(塗り潰しの色)、edgecolor(枠線の色) などを指定することができます。tight_layout に True を渡すと余白を最小限にして出力します。

# PYTHON_MATPLOTLIB_SAVEFIG

# In[1]

import numpy as np
import matplotlib.pyplot as plt

# Figureを設定してAxesを追加
fig = plt.figure(figsize=(6, 6))
ax = fig.add_subplot(111)

# Axes(サブプロット)のタイトルを設定
ax.set_title("Cubic Function", size=16)

# x軸の範囲を設定
ax.set_xlim(-2, 10)
ax.set_ylim(-100, 75)

# xのデータを作成
x = np.arange(-2, 10, 0.1)

# yのデータを作成
f = x**3 - 9*x**2 + 4*x + 1

# 軸ラベルの設定
ax.set_xlabel("x", size=14)
ax.set_ylabel("y", size=14)

# 目盛線(グリッド)の表示
ax.grid()

# データをプロット
ax.plot(x, f, color="darkblue")

# 保存先のファイル名(PNG形式)
fname = "cubic.png"

# ファイルを保存
fig.savefig(fname, dpi=64,
            facecolor="lightgray", tight_layout=True)

Python savefig()による画像ファイルの出力と保存
ファイルに出力されるグラフは次のようになります。
 
Python savefig()による画像ファイルの出力と保存②
ほとんどの場合、Figure.savefig() の代わりに plt.savefig() を使っても同じように画像を保存できます。ただし、複数の Figure オブジェクトを生成している場合には、plt.savefig() は最新の (つまり最後に生成された) Figure オブジェクトを保存します。また、MATLAB スタイルで記述している場合には、Figure オブジェクトを収める変数が明示されていないので、plt.savefig() で保存してください。

コメント

  1. HNaito より:

    下記は誤植と思われますので、ご確認ください。
    「画像を作成 : Axes.imshow( )」の説明文で、自分で規格したい場合 → 自分で正規化したい場合

  2. HNaito より:

    NumPyの「配列の連結・分割」の記事に numpy.dstack( ) や numpy.dsplit( ) の解説を追加していただき、本文の「numpy.dstack( )」にそのリンクを張っていただくとありがたいです。

    • あとりえこばと より:

      承知しました。(^^)
      さっそく記事の執筆にとりかかります。

      • HNaito より:

        たった今見て、NumPyの「配列の連結・分割」の記事が更新されているのを確認いたしました。
        さっそくのご対応ありがとうございました。これからも勉強させていただきます。

  3. HNaito より:

    PYTHON_NUMPY_IMAGE In[2] プログラムの実行結果が、三次元配列の途中の [ 47 30 14]]で終わっていますが、省略記号をうまく使って最後の [162 138 128 ]]] まで書いたほうが誤解がないと思いました。

    • あとりえこばと より:

      確かにそうですね。In[2] に
      np.set_printoptions(threshold=10)
      を追加しておきました。