3

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?

1

2 Answers 2

2

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]])
Sign up to request clarification or add additional context in comments.

Comments

1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.