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
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]
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')
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).
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
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
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]
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')
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).
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