How to set numpy matrix boundries to zeros?

Question:

I have numpy 10×10 matrix

image=np.ones((10,10))

I want to set its boundaries to zero.

h,w=image.shape
image[:,0:2] = 0
image[:,w-2:w] = 0
image[0:2,:] = 0
image[h-2:h,:] = 0

Is there more efficient way to do this?

Thanks

Asked By: Anas Bari

||

Answers:

Make the zeros first then assign the ones to the middle of the zeros.

>>> import numpy as np
>>> a = np.zeros((10,10))
>>> b = np.ones((6,6))
>>> a[2:-2,2:-2] = b

Or if the ones already exist.

>>> a = np.ones((10,10))

Make the zeros and do a similar assignment,

>>> b = np.zeros_like(a)
>>> b[2:-2,2:-2] = a[2:-2,2:-2]

You can use slices also if you are going to use it many times.

>>> s = slice(2,-2)
>>> b[s,s] = a[s,s]
Answered By: wwii

Here I’m assuming that you want a 10x10 matrix, where the central 6x6 block are ones while the rest are zeros. You can use np.pad for this (but you don’t need to create a larger matrix beforehand):

image = np.ones((6, 6))
padded = np.pad(image, (2, 2), mode='constant')
Answered By: Nihar Karve

I think you are using the right approach. In order to make this point apparent, I’m going to compare your solution to the other solutions proposed so far (please, notice that I have taken the liberty to refactor your code):

import numpy as np

def pad_anas(img, width=2):
    img[:width, :] = 0
    img[-width:, :] = 0
    img[:, :width] = 0
    img[:, -width:] = 0
    return img

def pad_wwii(img, width=2):
    b = np.zeros_like(img)
    b[width:-width, width:-width] = img[width:-width, width:-width]
    return b

def pad_diehard(img, width=2):
    cropped = img[width:-width, width:-width]
    padded = np.pad(cropped, (width, width), mode='constant')
    return padded

First, we check that the codes work as expected:

In [66]: x = np.random.randint(low=0, high=10, size=(10, 10))

In [67]: x
Out[67]: 
array([[4, 7, 7, 5, 7, 2, 7, 8, 0, 0],
       [6, 0, 3, 8, 7, 6, 3, 7, 9, 6],
       [0, 6, 9, 2, 6, 6, 3, 3, 1, 3],
       [7, 1, 5, 1, 4, 1, 5, 0, 3, 0],
       [9, 5, 1, 6, 5, 6, 5, 2, 6, 3],
       [8, 7, 7, 5, 9, 0, 2, 6, 4, 2],
       [3, 7, 0, 2, 5, 0, 5, 0, 6, 5],
       [3, 9, 9, 7, 6, 4, 8, 6, 9, 2],
       [6, 0, 5, 2, 9, 5, 9, 1, 2, 8],
       [6, 1, 5, 6, 9, 7, 2, 3, 7, 4]])

In [68]: pad_anas(x.copy())
Out[68]: 
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 9, 2, 6, 6, 3, 3, 0, 0],
       [0, 0, 5, 1, 4, 1, 5, 0, 0, 0],
       [0, 0, 1, 6, 5, 6, 5, 2, 0, 0],
       [0, 0, 7, 5, 9, 0, 2, 6, 0, 0],
       [0, 0, 0, 2, 5, 0, 5, 0, 0, 0],
       [0, 0, 9, 7, 6, 4, 8, 6, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

In [69]: np.all(pad_anas(x.copy()) == pad_wwii(x))
Out[69]: True

In [70]: np.all(pad_anas(x.copy()) == pad_diehard(x))
Out[70]: True

It is worth pointing out that your approach changes img in place (that’s why I passed a copy of x in the calls to pad_anas()). Let us now measure execution time:

In [71]: %timeit pad_wwii(x)
4.91 µs ± 477 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [72]: %timeit pad_diehard(x)
27.3 µs ± 2.86 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [73]: %timeit pad_anas(x)
2.53 µs ± 186 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

The results above make it evident that your approach is the best performer (similar results are obtained when using larger arrays or different widths).

Answered By: Tonechas

Though I have the feeling there should be an outperforming one-liner for this "inverse slicing" or "inplace padding", I couldn’t figure it out.

What I have to add is that (at least for large margins m) the following modification seems to slightly reduce the runtime:

img[:m, :] = 0
img[-m:, :] = 0
img[m:-m, :m] = 0
img[m:-m, -m:] = 0
Answered By: matheburg
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.