2017-02-04 2 views
6

Есть ли более идиоматический способ отображения сетки изображений, как в приведенном ниже примере?Идентичный способ отображения изображений в сетке с 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 

Я попытался с помощью hstack и reshape и т.д., но не мог получить правильное поведение.

Я заинтересован в использовании numpy для этого, потому что существует ограничение на количество изображений, которые вы можете построить с помощью matplotlib, на номера subplot и imshow.

Если вам нужны примеры данных для тестирования вы можете использовать веб-камеру, как так:

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

plt.imshow(gallery(np.array([img]*6))) 
+0

Какая форма 'array'? – Divakar

+0

Его 4 измерения (индекс, строки, столбцы, интенсивность). Где интенсивность = 3. –

+0

Я не могу запустить его. Не могли бы вы разместить образец/проверить его в конце? – Divakar

ответ

7
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 разделить на части первой оси на две оси, одна длиной nrows и одной длины ncols:

array.reshape(nrows, ncols, height, width, intensity) 

Это позволяет использовать swapaxes(1,2), чтобы изменить порядок осей так что форма становится (nrows, height, ncols, weight, intensity). Обратите внимание, что это место nrows рядом с height и ncols рядом с width.

С reshape does not change the raveled order данных reshape(height*nrows, width*ncols, intensity) теперь производит желаемый массив.

Это (по духу) так же, как идея, используемая в unblockshaped function.

3

Другим способом является использование view_as_blocks. Затем вы избегаете поменять оси вручную:

from skimage.util import view_as_blocks 

def refactor(im_in,ncols=3): 
    n,h,w,c = im_in.shape 
    dn = (-n)%ncols # trailing images 
    im_out = (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