scikit-image

Форк
0
/
_montage.py 
158 строк · 4.7 Кб
1
import numpy as np
2

3
from .._shared import utils
4
from .. import exposure
5

6
__all__ = ['montage']
7

8

9
@utils.channel_as_last_axis(multichannel_output=False)
10
def montage(
11
    arr_in,
12
    fill='mean',
13
    rescale_intensity=False,
14
    grid_shape=None,
15
    padding_width=0,
16
    *,
17
    channel_axis=None,
18
):
19
    """Create a montage of several single- or multichannel images.
20

21
    Create a rectangular montage from an input array representing an ensemble
22
    of equally shaped single- (gray) or multichannel (color) images.
23

24
    For example, ``montage(arr_in)`` called with the following `arr_in`
25

26
    +---+---+---+
27
    | 1 | 2 | 3 |
28
    +---+---+---+
29

30
    will return
31

32
    +---+---+
33
    | 1 | 2 |
34
    +---+---+
35
    | 3 | * |
36
    +---+---+
37

38
    where the '*' patch will be determined by the `fill` parameter.
39

40
    Parameters
41
    ----------
42
    arr_in : ndarray, shape (K, M, N[, C])
43
        An array representing an ensemble of `K` images of equal shape.
44
    fill : float or array-like of floats or 'mean', optional
45
        Value to fill the padding areas and/or the extra tiles in
46
        the output array. Has to be `float` for single channel collections.
47
        For multichannel collections has to be an array-like of shape of
48
        number of channels. If `mean`, uses the mean value over all images.
49
    rescale_intensity : bool, optional
50
        Whether to rescale the intensity of each image to [0, 1].
51
    grid_shape : tuple, optional
52
        The desired grid shape for the montage `(ntiles_row, ntiles_column)`.
53
        The default aspect ratio is square.
54
    padding_width : int, optional
55
        The size of the spacing between the tiles and between the tiles and
56
        the borders. If non-zero, makes the boundaries of individual images
57
        easier to perceive.
58
    channel_axis : int or None, optional
59
        If None, the image is assumed to be a grayscale (single channel) image.
60
        Otherwise, this parameter indicates which axis of the array corresponds
61
        to channels.
62

63
    Returns
64
    -------
65
    arr_out : (K*(M+p)+p, K*(N+p)+p[, C]) ndarray
66
        Output array with input images glued together (including padding `p`).
67

68
    Examples
69
    --------
70
    >>> import numpy as np
71
    >>> from skimage.util import montage
72
    >>> arr_in = np.arange(3 * 2 * 2).reshape(3, 2, 2)
73
    >>> arr_in  # doctest: +NORMALIZE_WHITESPACE
74
    array([[[ 0,  1],
75
            [ 2,  3]],
76
           [[ 4,  5],
77
            [ 6,  7]],
78
           [[ 8,  9],
79
            [10, 11]]])
80
    >>> arr_out = montage(arr_in)
81
    >>> arr_out.shape
82
    (4, 4)
83
    >>> arr_out
84
    array([[ 0,  1,  4,  5],
85
           [ 2,  3,  6,  7],
86
           [ 8,  9,  5,  5],
87
           [10, 11,  5,  5]])
88
    >>> arr_in.mean()
89
    5.5
90
    >>> arr_out_nonsquare = montage(arr_in, grid_shape=(1, 3))
91
    >>> arr_out_nonsquare
92
    array([[ 0,  1,  4,  5,  8,  9],
93
           [ 2,  3,  6,  7, 10, 11]])
94
    >>> arr_out_nonsquare.shape
95
    (2, 6)
96
    """
97

98
    if channel_axis is not None:
99
        arr_in = np.asarray(arr_in)
100
    else:
101
        arr_in = np.asarray(arr_in)[..., np.newaxis]
102

103
    if arr_in.ndim != 4:
104
        raise ValueError(
105
            'Input array has to be 3-dimensional for grayscale '
106
            'images, or 4-dimensional with a `channel_axis` '
107
            'specified.'
108
        )
109

110
    n_images, n_rows, n_cols, n_chan = arr_in.shape
111

112
    if grid_shape:
113
        ntiles_row, ntiles_col = (int(s) for s in grid_shape)
114
    else:
115
        ntiles_row = ntiles_col = int(np.ceil(np.sqrt(n_images)))
116

117
    # Rescale intensity if necessary
118
    if rescale_intensity:
119
        for i in range(n_images):
120
            arr_in[i] = exposure.rescale_intensity(arr_in[i])
121

122
    # Calculate the fill value
123
    if fill == 'mean':
124
        fill = arr_in.mean(axis=(0, 1, 2))
125
    fill = np.atleast_1d(fill).astype(arr_in.dtype)
126

127
    # Pre-allocate an array with padding for montage
128
    n_pad = padding_width
129
    arr_out = np.empty(
130
        (
131
            (n_rows + n_pad) * ntiles_row + n_pad,
132
            (n_cols + n_pad) * ntiles_col + n_pad,
133
            n_chan,
134
        ),
135
        dtype=arr_in.dtype,
136
    )
137
    for idx_chan in range(n_chan):
138
        arr_out[..., idx_chan] = fill[idx_chan]
139

140
    slices_row = [
141
        slice(n_pad + (n_rows + n_pad) * n, n_pad + (n_rows + n_pad) * n + n_rows)
142
        for n in range(ntiles_row)
143
    ]
144
    slices_col = [
145
        slice(n_pad + (n_cols + n_pad) * n, n_pad + (n_cols + n_pad) * n + n_cols)
146
        for n in range(ntiles_col)
147
    ]
148

149
    # Copy the data to the output array
150
    for idx_image, image in enumerate(arr_in):
151
        idx_sr = idx_image // ntiles_col
152
        idx_sc = idx_image % ntiles_col
153
        arr_out[slices_row[idx_sr], slices_col[idx_sc], :] = image
154

155
    if channel_axis is not None:
156
        return arr_out
157
    else:
158
        return arr_out[..., 0]
159

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.