Search code examples
pythontensorflowimage-resizing

Resizing images with dynamic shape in tensorflow


I want to resize 3D images with a dynamic shape, for instance go from shape (64,64,64,1) to (128,128,128,1). The idea is to unstack the image along one axis, then use tf.image.resize_images and stack them again.

My issue is that tf.unstack can not handle variable sized inputs. If I run my code I obtain "ValueError: Cannot infer num from shape (?, ?, ?, 1)"

I have considered using tf.split instead, however it expects an integer input. Does anybody know a workaround?

Here is an example:

import tensorflow as tf
import numpy as np

def resize_by_axis(image, dim_1, dim_2, ax):

    resized_list = []

    # Unstack along axis to obtain 2D images
    unstack_img_depth_list = tf.unstack(image, axis = ax)

    # Resize 2D images
    for i in unstack_img_depth_list:
        resized_list.append(tf.image.resize_images(i, [dim_1, dim_2], method=1, align_corners=True))

    # Stack it to 3D
    stack_img = tf.stack(resized_list, axis=ax)
    return stack_img

#X = tf.placeholder(tf.float32, shape=[64,64,64,1])
X = tf.placeholder(tf.float32, shape=[None,None,None,1])

# Get new shape
shape = tf.cast(tf.shape(X), dtype=tf.float32) * tf.constant(2, dtype=tf.float32)
x_new = tf.cast(shape[0], dtype=tf.int32)
y_new = tf.cast(shape[1], dtype=tf.int32)
z_new = tf.cast(shape[2], dtype=tf.int32)

# Reshape
X_reshaped_along_xy = resize_by_axis(X, dim_1=x_new, dim_2=y_new, ax=2)
X_reshaped_along_xyz= resize_by_axis(X_reshaped_along_xy, dim_1=x_new, dim_2=z_new, ax=1)

init = tf.global_variables_initializer()

# Run
with tf.Session() as sess:
    sess.run(init)
    result = X_reshaped_along_xyz.eval(feed_dict={X : np.zeros((64,64,64,1))})
    print(result.shape)

Solution

  • tf.image.resize_images can resize multiple images at the same time, but it does not allow you to pick the batch axis. However, you can manipulate the dimensions of the tensor to put the axis that you want first, so it is used as batch dimension, and then put it back after resizing:

    import tensorflow as tf
    
    def resize_by_axis(image, dim_1, dim_2, ax):
        # Make permutation of dimensions to put ax first
        dims = tf.range(tf.rank(image))
        perm1 = tf.concat([[ax], dims[:ax], dims[ax + 1:]], axis=0)
        # Transpose to put ax dimension first
        image_tr = tf.transpose(image, perm1)
        # Resize
        resized_tr = tf.image.resize_images(image_tr, [dim_1, dim_2],
                                            method=1, align_corners=True)
        # Make permutation of dimensions to put ax in its place
        perm2 = tf.concat([dims[:ax] + 1, [0], dims[ax + 1:]], axis=0)
        # Transpose to put ax in its place
        resized = tf.transpose(resized_tr, perm2)
        return resized
    

    In your example:

    import tensorflow as tf
    import numpy as np
    
    X = tf.placeholder(tf.float32, shape=[None, None, None, 1])
    
    # Get new shape
    shape = tf.cast(tf.shape(X), dtype=tf.float32) * tf.constant(2, dtype=tf.float32)
    x_new = tf.cast(shape[0], dtype=tf.int32)
    y_new = tf.cast(shape[1], dtype=tf.int32)
    z_new = tf.cast(shape[2], dtype=tf.int32)
    
    # Reshape
    X_reshaped_along_xy = resize_by_axis(X, dim_1=x_new, dim_2=y_new, ax=2)
    X_reshaped_along_xyz = resize_by_axis(X_reshaped_along_xy, dim_1=x_new, dim_2=z_new, ax=1)
    
    init = tf.global_variables_initializer()
    
    # Run
    with tf.Session() as sess:
        sess.run(init)
        result = X_reshaped_along_xyz.eval(feed_dict={X : np.zeros((64, 64, 64, 1))})
        print(result.shape)
        # (128, 128, 128, 1)