Pythonで画像をタイル状に一覧表示する方法。 ~Matplotlibの便利な使い方~

2020年3月29日

今日は画像をタイル状に一覧表示する方法を紹介します。

フォルダー内に画像がたくさんあるとViewer(ビューワー)で見るのも面倒ですよね。

そんなとき、手っ取り早く一覧表示して全体を見たいと思ったことはありませんか。

一覧表示させることで各画像を比較し易くなり、全体を早く把握することができます。

Matplotlibを使って画像を一覧表示する

以下のソースコードを見てください。

import cv2
import glob
import numpy as np
from PIL import Image
from natsort import natsorted
from matplotlib import pyplot as plt

# タイル状に pm × pm 枚配置
pm = 2

# 所定のフォルダ内にあるjpgファイルを連続で読み込んでリスト化する
files = glob.glob("./test_photo/hana/temp" + "/*.jpg")

# 空の入れ物(リスト)を準備
d = []

# ファイル名が数字の場合、natsortedで
# 自然順(ファイル番号の小さい順)に1枚づつ読み込まれる
for i in natsorted(files):
    img = Image.open(i)
    img = np.asarray(img)
    #img = cv2.resize(img, (300, 300), cv2.INTER_LANCZOS4)
    d.append(img)

# タイル状に画像を一覧表示
fig, ax = plt.subplots(pm, pm, figsize=(10, 10))
fig.subplots_adjust(hspace=0, wspace=0)

for i in range(pm):
    for j in range(pm):
        ax[i, j].xaxis.set_major_locator(plt.NullLocator())
        ax[i, j].yaxis.set_major_locator(plt.NullLocator())
        ax[i, j].imshow(d[pm*i+j], cmap="bone")

plt.show()

ソースコードを順に説明します。

最初に必要なライブラリを import してください。

これまでの記事で何度も出てきたライブラリばかりです。

特に新しいものはありません。

最初にタイル状に一覧表示するための一辺の枚数を決めます。

今回は pm = 2 としています。この意味は、一辺2枚で合計4枚表示させるということです。

実際は何枚でも表示させることができます。

ただし、表示枚数を多くすると1枚1枚の画像が小さくなってしまい、見にくくなります。

このため pm = 2~6 が適当だと思います。

pm = 2 で計4枚表示、pm = 6 で計36枚表示です。

次に、glob.glob() で所定のフォルダ内にある jpg 画像を読み込み files に代入します。

このとき、画像の拡張子は png でも大丈夫です。

次に、d = [ ] で空のリストを用意しておきます。

続いて for 文の箇所を説明します。

まず natsorted() を使います。

ファイル名が数字の場合、数字の小さい順に読み込まれます。

つまり、ファイル名を数字にしておき、数字順で表示順をコントロールできるということです。

なお、files に入っている画像データは一枚ずつ読み込まれます。

Image.open( i )で読み込まれた画像は PIL Image データとなっています。

このため np.asarray(img) で 画像データを ndarray 型に変換しておきます。

その後、画像サイズを変更したければ cv2.resize() で画像のサイズを変更することもできます。

ちなみに、上記のソースコードでは「#」をコードの先頭につけてコメントアウト(実行しない行)としています。サイズ変更が必要な場合は、「#」を消してください。

cv2.resize() のカッコの中身を説明しておきます。

  • 第一引数:画像データ(ndarray 型のデータ)
  • 第二引数:画像サイズ(w、h)= (幅、高さ)
  • 第三引数:画像の補完手法

今回は、第三引数の補完方法として「cv2.INTER_LANCZOS4」を使っています。

画質にこだわらないなら「cv2.INTER_LINEAR」を使った方が計算負荷が小さく処理速度は速いです。

個人的には、計算負荷が多少大きくても「cv2.INTER_LANCZOS4」の方が画質が良いのでこちらをよく使います。

その後、画像データを append() で d に追加しておきます。

次に、画像をタイル状に一覧表示させるため plt.subplots() を使います。

これは、Matplotlib でオブジェクト指向インターフェースを用いて画像を表示させる方法です。

ここでは、そういうものだ、くらいに覚えておけば良いです。

カッコ内の引数の意味は以下の通りです。

(pm, pm, figsize=(10, 10)) =(行, 列, figsize=(10inch, 10inch))

次に、fig.subplots_adjust(hspace=0, wspace=0) の意味は以下の通りです。

fig.subplots_adjust() は画像と画像の間隔を調整するメソッドです。

hspace は h方向つまり縦方向のスペースを調整します。

wspace はw方向つまり横方向のスペースを調整します。

今はどちらもゼロにしているので、くっつけて表示させるようにしています。

その後は、2重の for 文で画像の数だけループさせて画面に表示させます。

ax[i, j].xaxis.set_major_locator(plt.NullLocator()) の意味は以下の通りです。

まず、ax[ i, j ]は画像を表示させる場所を示しています。もし、i = 0 で j = 0 のときは [0, 0] の場所ということで、左上の場所に表示しなさいという命令になります。

次に xaxis はx軸のことです。

set_major_locator は、目盛りをセットしますという意味です。

カッコの中の plt.NullLocator() は、目盛りを非表示にするという意味です。

同様にy軸についても目盛りを非表示にします。

最後に、imshow() で画像を所定の位置に表示させます。

一番最後の plt.show() を書かないとパソコンの画面に一覧画像が表示されないので注意してください。

実行結果

4枚の画像がタイル状に一覧表示されました。

応用編

先ほどのソースコードをちょっと改良してみます。

まず画像の左上に番地(例:(0, 0))を表示させてみます。

また、一覧表示させた画像を所定のフォルダに保存できるようにします。

以下のソースコードをみてください。

import cv2
import glob
import numpy as np
from PIL import Image
from natsort import natsorted
from matplotlib import pyplot as plt

# タイル状に pm × pm 枚配置
pm = 2

# 所定のフォルダ内にあるjpgファイルを連続で読み込んでリスト化する
files = glob.glob("./test_photo/hana/temp" + "/*.jpg")

# 空の入れ物(リスト)を準備
d = []

# ファイル名が数字の場合、natsortedで
# 自然順(ファイル番号の小さい順)に1枚づつ読み込まれる
for i in natsorted(files):
    img = Image.open(i)
    img = np.asarray(img)
    #img = cv2.resize(img, (300, 300), cv2.INTER_LANCZOS4)
    d.append(img)

# タイル状に画像を一覧表示させる
fig, ax = plt.subplots(pm, pm, figsize=(10, 10))
fig.subplots_adjust(hspace=0, wspace=0)

for i in range(pm):
    for j in range(pm):
        ax[i, j].xaxis.set_major_locator(plt.NullLocator())
        ax[i, j].yaxis.set_major_locator(plt.NullLocator())
        ax[i, j].text(30, 60, str((i,j)), fontsize=18) # 追加した行
        ax[i, j].imshow(d[pm*i+j], cmap="bone")

plt.savefig('./test_photo/hana/temp/bara/result.png')  # 追加した行

plt.show()

2行追加しました。

最初の行は、画像の番地を表示させるものです。

一番左上が(0, 0)です。そこから左に向かって(0, 1)、(0, 2)・・・と進みます。

その後、下の行に行って左から(1, 0)、(1, 1)・・・と進みます。

カッコの中の意味は、x方向に30、y方向に60 の箇所に文字として( i, j )をフォントサイズ18で表示しなさいということです。

2番目の行は、一覧表示した画像を保存するためのコードです。

plt.savefig() で指定したフォルダに画像が保存されます。png でも jpg でも保存できます。

実行結果(応用編)

画像の左上に番地( i , j )が表示されています。

この順番で画像が表示されるということです。

さらに色んな画像が一覧表示できます。

一例を以下に示します。

これは4×4=16枚の画像を一覧表示させたものです。

前回記事で画像をクラスタリングしてカッコいい画像を作成する方法を紹介しました。

クラスタ数をいくつにすると最もカッコいい画像が作成できるか比較したいときなど便利です。

例えば、画像の左上の番地文字をファイル名や数字にしておけば、一覧表示させたときに欲しい画像がすぐに見つけられます。

アイディア次第で色々使えると思います。

まとめ

  • Matplotlib を使えばタイル状に画像を一覧表示させることができる。
  • 画像には番地やその他の好きな文字を書き込むこともできる。
  • 画像は何枚でも一覧表示させることができる。

参考書にした書籍