『Python数値計算ノート』ではアフィリエイトプログラムを利用して商品を紹介しています。

【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)
      を追加しておきました。