I want to be able to border an array (really, an image file) with a set of random values. The numpy.pad() function does not have any mode to do this. Is there a shorthand way to achieve this or would I have to create a function from scratch?
I think you need to create a padding function yourself to pass to np.pad.
This one pads with random integers.
def random_pad(vec, pad_width, *_, **__):
vec[:pad_width[0]] = np.random.randint(20, 30, size=pad_width[0])
vec[vec.size-pad_width[1]:] = np.random.randint(30,40, size=pad_width[1])
You can use this with np.pad like this:
In [13]: img = np.arange(12).reshape(3, 4)
In [14]: img
Out[14]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
In [15]: np.pad(img, ((2,3), (1,4)), mode=random_pad)
Out[15]:
array([[26, 21, 22, 24, 21, 37, 37, 37, 39],
[26, 25, 23, 29, 20, 39, 38, 30, 31],
[26, 0, 1, 2, 3, 37, 31, 32, 36],
[29, 4, 5, 6, 7, 30, 32, 33, 37],
[24, 8, 9, 10, 11, 33, 34, 33, 37],
[26, 36, 36, 36, 30, 32, 36, 38, 31],
[29, 33, 34, 38, 35, 31, 33, 37, 33],
[23, 37, 33, 33, 34, 32, 37, 33, 35]])
It may not be the most space-efficient, but one way to do this is to create a new array and place your existing array in the center of that.
>>> import numpy as np
>>> np.random.seed(444)
>>> arr = np.zeros((4, 5)) # your image array
>>> newsize = tuple(i + 2 for i in arr.shape)
>>> new = np.random.randint(low=0, high=50, size=newsize)
>>> new[1:-1, 1:-1] = arr
>>> new
array([[ 3, 48, 23, 8, 3, 39, 12],
[47, 0, 0, 0, 0, 0, 15],
[34, 0, 0, 0, 0, 0, 0],
[ 6, 0, 0, 0, 0, 0, 6],
[39, 0, 0, 0, 0, 0, 13],
[ 2, 15, 9, 34, 9, 24, 25]])
This is assuming your image is grayscale (2d) rather than a 3-dimensional MxNx4 RGBA array. In that case, you'd want new[1:-1, 1:-1, 1:-1].
You can also do this by passing a callable to np.pad(), but there is a caveat (see below):
from functools import partial
def _pad_random(vector, pad_width, iaxis, kwargs, low, high):
a, b = np.random.randint(low, high, size=2)
vector[:pad_width[0]] = a
vector[-pad_width[1]:] = b
return vector
pad_random = partial(_pad_random, low=0, high=50)
Usage:
>>> np.pad(arr, 1, pad_random)
array([[23., 19., 6., 47., 17., 7., 26.],
[26., 0., 0., 0., 0., 0., 37.],
[39., 0., 0., 0., 0., 0., 39.],
[39., 0., 0., 0., 0., 0., 42.],
[28., 0., 0., 0., 0., 0., 47.],
[11., 32., 37., 2., 38., 30., 44.]])
Caveat: it looks like, when you pass a function to the mode parameter of np.pad(), this function is called multiple times. Here's an example straight from the docs with a few print calls sprinkled in:
>>> def pad_with(vector, pad_width, iaxis, kwargs):
... pad_value = kwargs.get('padder', 10)
... print(vector[:pad_width[0]])
... print(vector[-pad_width[1]:])
... vector[:pad_width[0]] = pad_value
... vector[-pad_width[1]:] = pad_value
... return vector
...
>>> arr = np.arange(6).reshape(3, 2)
>>> np.pad(arr, 1, pad_with)
[0]
[0]
[0]
[0]
[0]
[0]
[0]
[0]
[10]
[10]
[0]
[0]
[0]
[0]
[0]
[0]
[10]
[10]
array([[10, 10, 10, 10],
[10, 0, 1, 10],
[10, 2, 3, 10],
[10, 4, 5, 10],
[10, 10, 10, 10]])
So, as long as the images aren't too big, it may be much more time efficient to use the first approach above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With