我想要做的简短版本是以格式(h,w,num_images)拍摄一堆图像并将它们平铺在网格中以生成可以轻松绘制的单个图像,但是我我希望将它们放在网格中,即用环绕(我想在张量流中做到这一点,即图形输出准备绘制的网格图像)。
输入:
a。)列数(即单行上的最大图像数)
OR
b。)最大宽度(例如屏幕宽度)。并自动计算以上
我有笨拙的代码可以做到这一点,但它很慢,在GPU上做这件事我觉得更有意义。
我的张量流图代码是这个(t是卷积层的输出,所以最后一个轴包含图像堆栈):
act = tf.squeeze(t) # batch size is 1, so remove it
act = tf.unstack(act, num=num_filters, axis=-1) # split last axis (filters) into list of (h, w)
act = tf.stack(act) # re-stack on first axis
这给了我(num_filters,h,w),我把它写成了一个我写的更通用的numpy代码,把它放在一个网格中(我的numpy代码很长,因为它更通用,适用于可变大小的图像,所以我不在下面包括它)。
这可以直接在tensorflow中进行吗?
(注意,如果我要做tf.concat而不是tf.stack,我可以将它们并排放置,但它们没有环绕)
答案 0 :(得分:2)
已向TensorFlow添加了一个功能完全符合此要求的功能:tf.contrib.gan.eval.image_grid。它接受形状为[batch, width, height, channels]
的输入张量,图像网格的形状,每个图像的尺寸以及图像通道的数量作为参数。它效果很好,并且易于使用。
答案 1 :(得分:1)
对于具有形状[批次,宽度,高度,通道]的图像,可以使用
在tensorflow中完成def image_grid(x, size=6):
t = tf.unstack(x[:size * size], num=size*size, axis=0)
rows = [tf.concat(t[i*size:(i+1)*size], axis=0)
for i in range(size)]
image = tf.concat(rows, axis=1)
return image[None]
答案 2 :(得分:0)
我的numpy代码在不到20行中完成它并且非常快。当我平铺10000x10000x3的图像时,速度非常快。如果图像不足,它会用零填充最后几个图块。
def reshape_row(arr):
return reduce(lambda x, y: np.concatenate((x,y), axis=1), arr)
def reshape_col(arr):
return reduce(lambda x, y: np.concatenate((x,y), axis=0), arr)
def arbitrary_rows_cols(arr, num_rows, num_cols, gray=False):
num_images, height, width, depth, = arr.shape
rows = []
for i in range(num_rows):
row_image = arr[i*num_cols:i*num_cols+num_cols]
r_n, r_h, r_w, r_d = row_image.shape
if row_image.shape[0] != num_cols:
for _ in range(num_cols - row_image.shape[0]):
row_image = np.concatenate((row_image, np.expand_dims(np.zeros((height, width, depth)), axis=0)), axis=0)
row_image = reshape_row(row_image)
rows.append(row_image)
mosaic = reshape_col(rows)
return mosaic
您可以将此代码转换为TensorFlow代码,它可能会更快。看到性能比较会很有趣。
答案 3 :(得分:0)
实际上我只是通过输入行数找到了一种非常简单的方法(这不是理想的,但现在还不错)。
def make_grid(t, num_images, num_rows=2):
'''takes stack of images as (1, w, h, num_images) and tiles them into a grid'''
t = tf.squeeze(t) # remove single batch, TODO make more flexible to work with higher batch size
t = tf.unstack(t, num=num_images, axis=-1) # split last axis (num_images) into list of (h, w)
t = tf.concat(t, axis=1) # tile all images horizontally into single row
t = tf.split(t, num_rows, axis=1) # split into desired number of rows
t = tf.concat(t, axis=0) # tile rows vertically
return t
答案 4 :(得分:0)
如果您未指定所需的列数,则我有一个可增大正方形网格的函数,否则将具有n_cols的网格
def tf_batch_to_canvas(X, cols: int = None):
"""
reshape a batch of images into a grid canvas to form a single image.
Parameters
----------
X: Tensor
Batch of images to format. [N, H, W, C]-shaped
cols: int
how many columns the grid should have. If None, a square grid will be created.
Returns
-------
image_grid: Tensor
Tensor representing the image grid. [1, HH, WW, C]-shaped
Raises
------
ValueError: The input tensor must be 4 dimensional
Examples
--------
x = np.ones((9, 100, 100, 3))
x = tf.convert_to_tensor(x)
canvas = batches.tf_batch_to_canvas(x)
assert canvas.shape == (1, 300, 300, 3)
canvas = batches.tf_batch_to_canvas(x, cols=5)
assert canvas.shape == (1, 200, 500, 3)
"""
if len(X.shape.as_list()) > 4:
raise ValueError("input tensor has more than 4 dimensions.")
N, H, W, C = X.shape.as_list()
rc = math.sqrt(N)
if cols is None:
rows = cols = math.ceil(rc)
else:
cols = max(1, cols)
rows = math.ceil(N / cols)
n_gray_tiles = cols * rows - N
if n_gray_tiles > 0:
gray_tiles = tf.zeros((n_gray_tiles, H, W, C), X.dtype)
X = tf.concat([X, gray_tiles], 0)
image_shape = (H, W)
n_channels = C
return image_grid(X, (rows, cols), image_shape, n_channels)
https://github.com/theRealSuperMario/edflow/blob/tf_batches/edflow/iterators/tf_batches.py#L8-L53
基本上,您现在可以使用tf.contrib.gan.eval.image_grid
,具体取决于您的张量流版本。
https://www.tensorflow.org/api_docs/python/tf/contrib/gan/eval/image_grid