0

I want to get the average value of numpy elements in a 2d array around a selected point with a selected neighborhood size and shape.

I made an example to help explain what I'm trying to do. It doesn't work with most inputs yet because of shape issues. Before I go on, is there an elegant or built in way of doing this?

import numpy as np
from skimage.morphology import disk

def get_sub_array_about_point(array, point, size):
    i1 = point[0]-(size-1)
    i2 = point[0]+size
    j1 = point[1]-(size-1)
    j2 = point[1]+size
    return array[i1:i2, j1:j2]

def get_neighborhood_mean(array, point, size, shape):

    sub_array = get_sub_array_about_point(test_array, point, size)
    """
    array([[10.1,  1.2,  1.3],
           [ 2.1, 20.2,  2.3],
           [ 3.1,  3.2,  3.3]])
    """

    masked_sub_array = np.ma.masked_where(mask==False, sub_array)
    masked_sub_array
    """
    masked_array(
      data=[[--, 1.2, --],
            [2.1, 20.2, 2.3],
            [--, 3.2, --]],
      mask=[[ True, False,  True],
            [False, False, False],
            [ True, False,  True]],
      fill_value=1e+20)
    """

    return masked_sub_array.mean()
    """
    5.8
    """

test_array = np.array([[0. , 0.1 , 0.2 , 0.3 ],
                       [1. , 10.1 , 1.2, 1.3 ],
                       [2. , 2.1, 20.2, 2.3 ],
                       [3. , 3.1 , 3.2, 3.3 ]])

mask = disk(1)
"""
array([[0, 1, 0],
       [1, 1, 1],
       [0, 1, 0]], dtype=uint8)
"""
get_neighborhood_mean(test_array, point=(2,2), size=2, shape=mask)
1

1 Answer 1

1

An elegant way of doing this is with a 2D convolution. If you normalize the elements in mask (by dividing by the sum of the elements), the convolution will give you a 2D array that's the average of the neighborhood.

from scipy.signal import convolve2d

test_array = np.array([[0. , 0.1 , 0.2 , 0.3 ],
                       [1. , 10.1 , 1.2, 1.3 ],
                       [2. , 2.1, 20.2, 2.3 ],
                       [3. , 3.1 , 3.2, 3.3 ]])

mask = np.array([[0, 1, 0],
               [1, 1, 1],
               [0, 1, 0]])

# Normalize mask
mask = mask / float(np.sum(mask))

convolve2d(test_array, mask, mode='valid')
# array([[2.9, 6.6],
#        [7.5, 5.8]])

By using mode='valid', the average values are only given for elements that don't require padding, where the mask can fit without having to extend beyond the edge of the array. So in the above case, the output array is for the center 4 elements of test_array only.

If you want to get the averages of the neighborhoods for all elements, including at the edges, zero-padding can be used by setting mode='same'.

convolve2d(test_array, mask, mode='same')
# array([[0.22, 2.08, 0.36, 0.36],
#        [2.62, 2.9 , 6.6 , 1.02],
#        [1.62, 7.5 , 5.8 , 5.42],
#        [1.62, 2.28, 5.96, 1.76]])
Sign up to request clarification or add additional context in comments.

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.