简体   繁体   中英

Find numpy array coordinates of neighboring maximum

I used the accepted answer in this question to obtain local maxima in a numpy array of 2 or more dimensions so I could assign labels to them. Now I would like to also assign these labels to neighboring cells in the array, depending on gradient – ie a cell gets the same label as the neighboring cell with the highest value. This way I can iteratively assign labels to my entire array.

Assume I have an array A like

>>> A = np.array([[ 1. ,  2. ,  2.2,  3.5],
                  [ 2.1,  2.4,  3. ,  3.3],
                  [ 1. ,  3. ,  3.2,  3. ],
                  [ 2. ,  4.1,  4. ,  2. ]])

Applying the maximum_filter I get

>>> scipy.ndimage.filters.maximum_filter(A, size=3)
array([[ 2.4,  3. ,  3.5,  3.5],
       [ 3. ,  3.2,  3.5,  3.5],
       [ 4.1,  4.1,  4.1,  4. ],
       [ 4.1,  4.1,  4.1,  4. ]])

Now, for every cell in this array I would like to have the coordinates of the maximum found by the filter, ie

array([[[1,1],[1,2],[0,3],[0,3]],
       [[2,1],[2,2],[0,3],[0,3]],
       [[3,1],[3,1],[3,1],[3,2]],
       [[3,1],[3,1],[3,1],[3,2]]])

I would then use these coordinates to assign my labels iteratively.

I can do it for two dimensions using loops, ignoring borders

highest_neighbor_coordinates = np.array([[(argmax2D(A[i-1:i+2, j-1:j+2])+np.array([i-1, j-1])) for j in range(1, A.shape[1]-1)] for i in range(1, A.shape[0]-1)])

but after seeing the many filter functions in scipy.ndimage I was hoping there would be a more elegant and extensible (to >=3 dimensions) solution.

We can use pad with reflected elements to simulate the max-filter operation and get sliding windows on it with scikit-image 's view_as_windows , compute the flattened argmax indices, offset those with ranged values to translate onto global scale -

from skimage.util import view_as_windows as viewW

def window_argmax_global2D(A, size):
    hsize = (size-1)//2 # expects size as odd number
    m,n = A.shape
    A1 = np.pad(A, (hsize,hsize), mode='reflect')
    idx = viewW(A1, (size,size)).reshape(-1,size**2).argmax(-1).reshape(m,n)

    r,c = np.unravel_index(idx, (size,size))
    rows = np.abs(r + np.arange(-hsize,m-hsize)[:,None])
    cols = np.abs(c + np.arange(-hsize,n-hsize))
    return rows, cols    

Sample run -

In [201]: A
Out[201]: 
array([[1. , 2. , 2.2, 3.5],
       [2.1, 2.4, 3. , 3.3],
       [1. , 3. , 3.2, 3. ],
       [2. , 4.1, 4. , 2. ]])

In [202]: rows, cols = window_argmax_global2D(A, size=3)

In [203]: rows
Out[203]: 
array([[1, 1, 0, 0],
       [2, 2, 0, 0],
       [3, 3, 3, 3],
       [3, 3, 3, 3]])

In [204]: cols
Out[204]: 
array([[1, 2, 3, 3],
       [1, 2, 3, 3],
       [1, 1, 1, 2],
       [1, 1, 1, 2]])

Extending to n-dim

We would use np.ogrid for this extension part :

def window_argmax_global(A, size):
    hsize = (size-1)//2 # expects size as odd number
    shp = A.shape
    N = A.ndim
    A1 = np.pad(A, (hsize,hsize), mode='reflect')
    idx = viewW(A1, ([size]*N)).reshape(-1,size**N).argmax(-1).reshape(shp)

    offsets = np.ogrid[tuple(map(slice, shp))]
    out = np.unravel_index(idx, ([size]*N))
    return [np.abs(i+j-hsize) for i,j in zip(out,offsets)]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM