web-dev-qa-db-ja.com

numpyでグリッドに画像を表示するより慣用的な方法

以下の例のように画像のグリッドを表示するより慣用的な方法はありますか?

import numpy as np

def gallery(array, ncols=3):
    nrows = np.math.ceil(len(array)/float(ncols))
    cell_w = array.shape[2]
    cell_h = array.shape[1]
    channels = array.shape[3]
    result = np.zeros((cell_h*nrows, cell_w*ncols, channels), dtype=array.dtype)
    for i in range(0, nrows):
        for j in range(0, ncols):
            result[i*cell_h:(i+1)*cell_h, j*cell_w:(j+1)*cell_w, :] = array[i*ncols+j]
    return result

hstackreshapeなどを使用してみましたが、適切な動作が得られませんでした。

subplotimshowへのmatplotlib呼び出しでプロットできる画像の数には制限があるため、numpyを使用してこれを行うことに興味があります。

テストするサンプルデータが必要な場合は、次のようにWebカメラを使用できます。

import cv2
import matplotlib.pyplot as plt
_, img = cv2.VideoCapture(0).read()

plt.imshow(gallery(np.array([img]*6)))
12
Frank Wilson
_import numpy as np
import matplotlib.pyplot as plt

def gallery(array, ncols=3):
    nindex, height, width, intensity = array.shape
    nrows = nindex//ncols
    assert nindex == nrows*ncols
    # want result.shape = (height*nrows, width*ncols, intensity)
    result = (array.reshape(nrows, ncols, height, width, intensity)
              .swapaxes(1,2)
              .reshape(height*nrows, width*ncols, intensity))
    return result

def make_array():
    from PIL import Image
    return np.array([np.asarray(Image.open('face.png').convert('RGB'))]*12)

array = make_array()
result = gallery(array)
plt.imshow(result)
plt.show()
_

収量 enter image description here


形状_(nrows*ncols, height, weight, intensity)_の配列があります。形状_(height*nrows, width*ncols, intensity)_の配列が必要です。

したがって、ここでのアイデアは、最初にreshapeを使用して、最初の軸を2つの軸に分割することです。1つは長さnrowsで、もう1つは長さncolsです。

_array.reshape(nrows, ncols, height, width, intensity)
_

これにより、swapaxes(1,2)を使用して軸が再配列され、形状が_(nrows, height, ncols, weight, intensity)_になります。これにより、nrowsheightの横に、ncolswidthの横に配置されます。

reshapeはデータの乱れた順序 を変更しないため、reshape(height*nrows, width*ncols, intensity)は目的の配列を生成します。

これは(精神的に) unblockshaped function で使用されているアイデアと同じです。

14
unutbu

別の方法は view_as_blocks を使用することです。次に、手で軸を交換することを避けます:

from skimage.util import view_as_blocks
import numpy as np

def refactor(im_in,ncols=3):
    n,h,w,c = im_in.shape
    dn = (-n)%ncols # trailing images
    im_out = (np.empty((n+dn)*h*w*c,im_in.dtype)
           .reshape(-1,w*ncols,c))
    view=view_as_blocks(im_out,(h,w,c))
    for k,im in enumerate( list(im_in) + dn*[0] ):
        view[k//ncols,k%ncols,0] = im 
    return im_out
4
B. M.

この回答は@unutbuに基づいていますが、これはHWC順序付けテンソルを扱います。さらに、指定された行/列に均等に因数分解されないチャネルの黒いタイルが表示されます。

def tile(arr, nrows, ncols):
    """
    Args:
        arr: HWC format array
        nrows: number of tiled rows
        ncols: number of tiled columns
    """
    h, w, c = arr.shape
    out_height = nrows * h
    out_width = ncols * w
    chw = np.moveaxis(arr, (0, 1, 2), (1, 2, 0))

    if c < nrows * ncols:
        chw = chw.reshape(-1).copy()
        chw.resize(nrows * ncols * h * w)

    return (chw
        .reshape(nrows, ncols, h, w)
        .swapaxes(1, 2)
        .reshape(out_height, out_width))

以下は、逆方向に対応するdetiling関数です。

def detile(arr, nrows, ncols, c, h, w):
    """
    Args:
        arr: tiled array
        nrows: number of tiled rows
        ncols: number of tiled columns
        c: channels (number of tiles to keep)
        h: height of tile
        w: width of tile
    """
    chw = (arr
        .reshape(nrows, h, ncols, w)
        .swapaxes(1, 2)
        .reshape(-1)[:c*h*w]
        .reshape(c, h, w))

    return np.moveaxis(chw, (0, 1, 2), (2, 0, 1)).reshape(h, w, c)
0
Mateen Ulhaq