scikit-imageで画像を縦・横に連結(montage)
scikit-imageのskimage.util.montage()
を使うと、同じサイズの複数の画像を縦横に連結(結合)できる。
ここでは、以下の内容について説明する。
skimage.util.montage()
の基本的な使い方- 余白部分の値(色)を指定: 引数
fill
- レイアウトを指定: 引数
grid_shape
- 枠線・境界線の幅を指定: 引数
padding_width
- カラー画像(三次元配列)を処理: 引数
multichannel
PillowやOpenCVを使った画像の連結については以下の記事を参照。サイズが異なる画像の連結についても説明している。
なお、本記事におけるscikit-imageのバージョンは0.16.2
。
skimage.util.montage()の基本的な使い方
以下の同じ形状shape
の3つの二次元配列numpy.ndarray
を例とする。カラー画像(三次元配列)を使った例は後述。
import numpy as np
import skimage.util
a = np.arange(1, 7).reshape(2, 3)
print(a)
# [[1 2 3]
# [4 5 6]]
b = a * 10
print(b)
# [[10 20 30]
# [40 50 60]]
c = a * 100
print(c)
# [[100 200 300]
# [400 500 600]]
skimage.util.montage()
の第一引数にそれらの配列を要素とするリストを指定すると、縦横に連結されたnumpy.ndarray
が返される。
m = skimage.util.montage([a, b, c])
print(m)
# [[ 1 2 3 10 20 30]
# [ 4 5 6 40 50 60]
# [100 200 300 129 129 129]
# [400 500 600 129 129 129]]
print(m.shape)
# (4, 6)
この例では、3つの配列が2 x 2のレイアウトに配置され、右下の足りない部分(余白)は全体の平均値である129
で埋められている。これらは後述の引数で変更可能。
skimage.util.montage()
内部では配列のリストがM行N列のK個の配列からなる形状(K, M, N)
のnumpy.ndarray
として処理される。
その形で引数に指定してもOK。
abc = np.array([a, b, c])
print(abc)
# [[[ 1 2 3]
# [ 4 5 6]]
#
# [[ 10 20 30]
# [ 40 50 60]]
#
# [[100 200 300]
# [400 500 600]]]
print(abc.shape)
# (3, 2, 3)
print(skimage.util.montage(abc))
# [[ 1 2 3 10 20 30]
# [ 4 5 6 40 50 60]
# [100 200 300 129 129 129]
# [400 500 600 129 129 129]]
個々の配列は同じ形状shape
でないと(K, M, N)
のnumpy.ndarray
に変換できないためエラーとなる。
d = a[:, :2]
print(d)
# [[1 2]
# [4 5]]
# skimage.util.montage([a, b, c, d])
# ValueError: could not broadcast input array from shape (2,3) into shape (2)
余白部分の値(色)を指定: 引数fill
デフォルトでは余白部分の値は全体の平均値となる。
m = skimage.util.montage([a, b, c])
print(m)
# [[ 1 2 3 10 20 30]
# [ 4 5 6 40 50 60]
# [100 200 300 129 129 129]
# [400 500 600 129 129 129]]
print(np.mean(np.array([a, b, c])))
# 129.5
引数fill
で余白を埋める値を指定できる。
print(skimage.util.montage([a, b, c], fill=0))
# [[ 1 2 3 10 20 30]
# [ 4 5 6 40 50 60]
# [100 200 300 0 0 0]
# [400 500 600 0 0 0]]
レイアウトを指定: 引数grid_shape
デフォルトでは、行数(縦の連結個数)と列数(横の連結個数)が同数のレイアウトに連結される。
引数grid_shape
にタプル(行数, 列数)
で縦横のレイアウトを指定できる。
print(skimage.util.montage([a, b, c], grid_shape=(1, 3)))
# [[ 1 2 3 10 20 30 100 200 300]
# [ 4 5 6 40 50 60 400 500 600]]
print(skimage.util.montage([a, b, c], grid_shape=(3, 1)))
# [[ 1 2 3]
# [ 4 5 6]
# [ 10 20 30]
# [ 40 50 60]
# [100 200 300]
# [400 500 600]]
元の配列より少ないとエラーとなる。
# print(skimage.util.montage([a, b, c], grid_shape=(1, 2)))
# IndexError: list index out of range
元の配列より多いと足りない部分(余白)は引数fill
の値で埋められる。上述の通り、デフォルトは平均値。
print(skimage.util.montage([a, b, c], grid_shape=(2, 3)))
# [[ 1 2 3 10 20 30 100 200 300]
# [ 4 5 6 40 50 60 400 500 600]
# [129 129 129 129 129 129 129 129 129]
# [129 129 129 129 129 129 129 129 129]]
print(skimage.util.montage([a, b, c], grid_shape=(2, 3), fill=0))
# [[ 1 2 3 10 20 30 100 200 300]
# [ 4 5 6 40 50 60 400 500 600]
# [ 0 0 0 0 0 0 0 0 0]
# [ 0 0 0 0 0 0 0 0 0]]
枠線・境界線の幅を指定: 引数padding_width
引数padding_width
を指定すると、枠線および境界線の幅を指定できる。これまでの例のようにデフォルトはpadding_width=0
なので枠線も境界線もなし。
print(skimage.util.montage([a, b, c], padding_width=1))
# [[129 129 129 129 129 129 129 129 129]
# [129 1 2 3 129 10 20 30 129]
# [129 4 5 6 129 40 50 60 129]
# [129 129 129 129 129 129 129 129 129]
# [129 100 200 300 129 129 129 129 129]
# [129 400 500 600 129 129 129 129 129]
# [129 129 129 129 129 129 129 129 129]]
枠線・境界線の値も引数fill
で指定できる。
print(skimage.util.montage([a, b, c], padding_width=1, fill=0))
# [[ 0 0 0 0 0 0 0 0 0]
# [ 0 1 2 3 0 10 20 30 0]
# [ 0 4 5 6 0 40 50 60 0]
# [ 0 0 0 0 0 0 0 0 0]
# [ 0 100 200 300 0 0 0 0 0]
# [ 0 400 500 600 0 0 0 0 0]
# [ 0 0 0 0 0 0 0 0 0]]
カラー画像(三次元配列)を処理: 引数multichannel
カラー画像は三次元配列として読み込まれる。
三次元配列をskimage.util.montage()
で処理するには、引数multichannel
をTrue
とする。
import skimage.io
import skimage.util
a = skimage.io.imread('data/src/lena.jpg')
print(a.shape)
# (225, 400, 3)
b = a // 2
c = a // 3
m = skimage.util.montage([a, b, c], multichannel=True)
print(m.shape)
# (450, 800, 3)
skimage.io.imsave('data/dst/skimage_montage_default.jpg', m)
元画像。
結果画像。
デフォルトはmultichannel=False
なので省略するとエラーになる。要注意。
# skimage.util.montage([a, b, c])
# ValueError: Input array has to be either 3- or 4-dimensional
上の結果画像から分かるように、デフォルトでは余白部分は各色(各チャンネル)の平均値の色で埋められる。
引数fill
で任意の色を指定可能。(R, G, B)
のタプルで指定する。
m_fill = skimage.util.montage([a, b, c], fill=(255, 128, 0), multichannel=True)
skimage.io.imsave('data/dst/skimage_montage_fill.jpg', m_fill)
そのほか、grid_shape
やpadding_width
の使い方は二次元配列と同じ。
m_1_3_pad = skimage.util.montage([a, b, c],
fill=(0, 0, 0),
grid_shape=(1, 3),
padding_width=10,
multichannel=True)
print(m_1_3_pad.shape)
# (245, 1240, 3)
skimage.io.imsave('data/dst/skimage_montage_1_3_pad.jpg', m_1_3_pad)