Repository: scikit-image/scikit-image

Issue:
Allow output_shape to be any iterable in resize and resize_local_mean
/skimage/transform/_warps.py", line 63, in _preprocess_resize_output_shape
    output_shape = output_shape + (image.shape[-1], )
TypeError: can only concatenate list (not "tuple") to list



Discussion:
Hello @jinfagang, and thank you for your interest in `skimage`. As the error message you kindly copy/pasted stipulates, `output_shape` must be tuple for `resize` or `resize_local_mean` to work properly.
This condition can in fact be relaxed... I modified the title of your this issue accordingly. Thank you for the report.

Resolving patch:
diff --git a/skimage/transform/_warps.py b/skimage/transform/_warps.py
--- a/skimage/transform/_warps.py
+++ b/skimage/transform/_warps.py
@@ -28,7 +28,7 @@ def _preprocess_resize_output_shape(image, output_shape):
     ----------
     image: ndarray
         Image to be resized.
-    output_shape: tuple or ndarray
+    output_shape: iterable
         Size of the generated output image `(rows, cols[, ...][, dim])`. If
         `dim` is not provided, the number of channels is preserved.
 
@@ -52,6 +52,7 @@ def _preprocess_resize_output_shape(image, output_shape):
     equal to output_shape_length.
 
     """
+    output_shape = tuple(output_shape)
     output_ndim = len(output_shape)
     input_shape = image.shape
     if output_ndim > image.ndim:
@@ -81,7 +82,7 @@ def resize(image, output_shape, order=None, mode='reflect', cval=0, clip=True,
     ----------
     image : ndarray
         Input image.
-    output_shape : tuple or ndarray
+    output_shape : iterable
         Size of the generated output image `(rows, cols[, ...][, dim])`. If
         `dim` is not provided, the number of channels is preserved. In case the
         number of input channels does not equal the number of output channels a
@@ -1212,7 +1213,7 @@ def resize_local_mean(image, output_shape, grid_mode=True,
     image : ndarray
         Input image. If this is a multichannel image, the axis corresponding
         to channels should be specified using `channel_axis`
-    output_shape : tuple or ndarray
+    output_shape : iterable
         Size of the generated output image. When `channel_axis` is not None,
         the `channel_axis` should either be omitted from `output_shape` or the
         ``output_shape[channel_axis]`` must match


Test patch:
diff --git a/skimage/transform/tests/test_warps.py b/skimage/transform/tests/test_warps.py
--- a/skimage/transform/tests/test_warps.py
+++ b/skimage/transform/tests/test_warps.py
@@ -380,7 +380,7 @@ def test_resize_dtype():
 @pytest.mark.parametrize('dtype', [np.float64, np.uint8])
 def test_resize_clip(order, preserve_range, anti_aliasing, dtype):
     # test if clip as expected
-    if dtype == np.uint8 and (preserve_range or order==0):
+    if dtype == np.uint8 and (preserve_range or order == 0):
         expected_max = 255
     else:
         expected_max = 1.0
@@ -911,3 +911,11 @@ def test_resize_local_mean_dtype():
                              preserve_range=False).dtype == x_f32.dtype
     assert resize_local_mean(x_f32, (10, 10),
                              preserve_range=True).dtype == x_f32.dtype
+
+
+@pytest.mark.parametrize("_type", [tuple, np.asarray, list])
+def test_output_shape_arg_type(_type):
+    img = np.random.rand(3, 3)
+    output_shape = _type([5, 5])
+
+    assert resize(img, output_shape).shape == tuple(output_shape)