Home > Software engineering >  Numpy: using np.pad() for an RGB image causing "operands could not be broadcast together with s
Numpy: using np.pad() for an RGB image causing "operands could not be broadcast together with s

Time:07-16

I have a function color_image_padding that takes an RGB image and adds one layer of zeros padding to the borders. The image has dimensions (Width, Height, 3), with 3 representing the 3 color channels.

My code is:

   import numpy as np

   def color_image_padding(image: np.ndarray) -> np.ndarray:
       return np.pad(image, pad_width=1)

I'm seeing this error:

"operands could not be broadcast together with shapes (4,4,3) (4,4,5)"

It's probably the color channels that are causing this error. Doesn't np.pad split the image into 3 matrices and add the zero padding accordingly?

Thanks in advance for your assistance!

EDIT

See comments below... It turns out that the generalized function image_padding() was throwing an error message because some greyscale images (i.e. 2D Numpy matrices) were passed in. Here's a minimal example:

bar = np.ones((1, 3))
bar.ndim
2

def image_padding(image: np.ndarray, amt: int) -> np.ndarray:
    return np.pad(image, pad_width=((amt, amt), (amt, amt), (0, 0)))

image_padding(bar, 2)

Full Traceback:

ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_8116/4065018867.py in <module>
----> 1 img(bar, 3)

~\AppData\Local\Temp/ipykernel_8116/1455868751.py in img(image, amt)
      1 def img(image, amt):
----> 2     return np.pad(image, pad_width=((amt, amt), (amt, amt), (0, 0)))

<__array_function__ internals> in pad(*args, **kwargs)

~\anaconda3\lib\site-packages\numpy\lib\arraypad.py in pad(array, pad_width, mode, **kwargs)
    741 
    742     # Broadcast to shape (array.ndim, 2)
--> 743     pad_width = _as_pairs(pad_width, array.ndim, as_index=True)
    744 
    745     if callable(mode):

~\anaconda3\lib\site-packages\numpy\lib\arraypad.py in _as_pairs(x, ndim, as_index)
    516     # Converting the array with `tolist` seems to improve performance
    517     # when iterating and indexing the result (see usage in `pad`)
--> 518     return np.broadcast_to(x, (ndim, 2)).tolist()
    519 
    520 

<__array_function__ internals> in broadcast_to(*args, **kwargs)

~\anaconda3\lib\site-packages\numpy\lib\stride_tricks.py in broadcast_to(array, shape, subok)
    409            [1, 2, 3]])
    410     """
--> 411     return _broadcast_to(array, shape, subok=subok, readonly=True)
    412 
    413 

~\anaconda3\lib\site-packages\numpy\lib\stride_tricks.py in _broadcast_to(array, shape, subok, readonly)
    346                          'negative')
    347     extras = []
--> 348     it = np.nditer(
    349         (array,), flags=['multi_index', 'refs_ok', 'zerosize_ok']   extras,
    350         op_flags=['readonly'], itershape=shape, order='C')

ValueError: operands could not be broadcast together with remapped shapes [original->remapped]: (3,2)  and requested shape (2,2)

Testing whether the image is greyscale or color resolves the issue:

def image_padding(image: np.ndarray, amt: int) -> np.ndarray:
    if image.ndim == 2:
        return np.pad(image, pad_width=(amt, amt))
    elif img.ndim == 3:
        return np.pad(image, pad_width=((amt, amt), (amt, amt), (0, 0)))

CodePudding user response:

So this reproduces your error - using the three term pad_width on a 2d array:

ok with 3d:

In [194]: x = np.ones((5,5,3),int)
In [196]: amt_padding=1;np.pad(x, pad_width=((amt_padding, amt_padding), (amt_padding, amt_padding), (0, 0))).shape
Out[196]: (7, 7, 3)

but if the array is 2d:

In [197]: amt_padding=1;np.pad(x[:,:,0], pad_width=((amt_padding, amt_padding), (amt_padding, amt_padding), (0, 0)))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Input In [197], in <cell line: 1>()
----> 1 amt_padding=1;np.pad(x[:,:,0], pad_width=((amt_padding, amt_padding), (amt_padding, amt_padding), (0, 0)))

File <__array_function__ internals>:5, in pad(*args, **kwargs)

File ~\anaconda3\lib\site-packages\numpy\lib\arraypad.py:743, in pad(array, pad_width, mode, **kwargs)
    740     raise TypeError('`pad_width` must be of integral type.')
    742 # Broadcast to shape (array.ndim, 2)
--> 743 pad_width = _as_pairs(pad_width, array.ndim, as_index=True)
    745 if callable(mode):
    746     # Old behavior: Use user-supplied function with np.apply_along_axis
    747     function = mode

File ~\anaconda3\lib\site-packages\numpy\lib\arraypad.py:518, in _as_pairs(x, ndim, as_index)
    514     raise ValueError("index can't contain negative values")
    516 # Converting the array with `tolist` seems to improve performance
    517 # when iterating and indexing the result (see usage in `pad`)
--> 518 return np.broadcast_to(x, (ndim, 2)).tolist()

File <__array_function__ internals>:5, in broadcast_to(*args, **kwargs)

File ~\anaconda3\lib\site-packages\numpy\lib\stride_tricks.py:411, in broadcast_to(array, shape, subok)
    366 @array_function_dispatch(_broadcast_to_dispatcher, module='numpy')
    367 def broadcast_to(array, shape, subok=False):
    368     """Broadcast an array to a new shape.
    369 
    370     Parameters
   (...)
    409            [1, 2, 3]])
    410     """
--> 411     return _broadcast_to(array, shape, subok=subok, readonly=True)

File ~\anaconda3\lib\site-packages\numpy\lib\stride_tricks.py:348, in _broadcast_to(array, shape, subok, readonly)
    345     raise ValueError('all elements of broadcast shape must be non-'
    346                      'negative')
    347 extras = []
--> 348 it = np.nditer(
    349     (array,), flags=['multi_index', 'refs_ok', 'zerosize_ok']   extras,
    350     op_flags=['readonly'], itershape=shape, order='C')
    351 with it:
    352     # never really has writebackifcopy semantics
    353     broadcast = it.itviews[0]

ValueError: operands could not be broadcast together with remapped shapes [original->remapped]: (3,2)  and requested shape (2,2)

It's passing the task to np.nditer (via broadcast_to), which is raising the error. That would account for why I've never seen it before. I've explored nditer some, but it's not something I regularly use or recommend to others.

The _as_pairs expands widths like

In [206]: np.lib.arraypad._as_pairs(1,3, as_index=True)
Out[206]: ((1, 1), (1, 1), (1, 1))

In [207]: np.lib.arraypad._as_pairs(((1,),(2,),(3,)),3, as_index=True)
Out[207]: [[1, 1], [2, 2], [3, 3]]
  • Related