note.nkmk.me

Create a montage of images with Python, scikit-image (skimage.util.montage)

Posted: 2021-09-08 / Tags: Python, scikit-image, Image Processing

Using scikit-image's skimage.util.montage(), you can create a montage by concatenating multiple images of the same size horizontally and vertically.

This article describes the following contents.

  • Basic usage of skimage.util.montage()
  • Specify the value (color) of the padding / extra areas: fill
  • Specify the layout: grid_shape
  • Specify the width of the borders: padding_width
  • Apply to color images (3D array): multichannel

For more information on concatenation of images using Pillow and OpenCV, see the following article. These articles also explain the case of different image sizes.

Note that the version of scikit-image in this article is 0.16.2.

Sponsored Link

Basic usage of skimage.util.montage()

The following three two-dimensional arrays (numpy.ndarray) of the same shape are used as examples. Examples using color images (3D arrays) are described later.

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]]

By passing a list of these arrays to the first argument of skimage.util.montage(), a vertically and horizontally concatenated array is returned.

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)

In this example, the three arrays are arranged in 2 x 2 layout, with the extra area (lower right) filled with 129, the average value of the all arrays. The layout and the values to fill in the extra area can be set with the parameters described below.

In skimage.util.montage(), the list of arrays is processed as a numpy.ndarray of shape (K, M, N) consisting of K arrays with M rows and N columns. You can specify it in that form.

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]]

If each array does not have the same shape, it cannot be converted to numpy.ndarray of (K, M, N) and an error occurs.

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)

Specify the value (color) of the padding / extra areas: fill

By default, the extra area is filled with the average value of the all arrays.

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

You can specify a value to fill with 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]]

Specify the layout: grid_shape

By default, it concatenates into a square layout with the same number of rows and columns.

You can specify a layout with grid_shape as a tuple (number of rows, number of columns).

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]]

If the number of rows * columns is less than the number of arrays, an error occurs.

# print(skimage.util.montage([a, b, c], grid_shape=(1, 2)))
# IndexError: list index out of range

If the number of rows * columns is more than the number of arrays, the extra area is filled with the value of fill. As mentioned above, by default, it is filled with the average value of all the arrays.

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]]
Sponsored Link

Specify the width of the borders: padding_width

You can specify the width of the borders by specifying padding_width. The default value is padding_width=0, so there is no border.

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]]

The border is also filled with the value of 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]]

Apply to color images (3D array): multichannel

Color images are treated as three-dimensional arrays.

To handle three-dimensional arrays with skimage.util.montage(), set multichannel to 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)

Original image:

lena

Result:

skimage.util.montage() default

Note that the default value is multichannel=False, so omitting it will result in an error.

# skimage.util.montage([a, b, c])
# ValueError: Input array has to be either 3- or 4-dimensional

As you can see from the result image above, by default the extra area (lower right) is filled with the average color.

You can specify any color in fill with a tuple of (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)

skimage.util.montage() fill

The usage of grid_shape and padding_width is the same as for two-dimensional arrays.

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)

skimage.util.montage() grid_shape, padding_width

Sponsored Link
Share

Related Categories

Related Articles