Skip to content Skip to sidebar Skip to footer

Get Coordinates Of Squares In Numpy Matrix

Given the following numpy matrix import numpy as np np_matrix = np.array([[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] ,[0,0,0,0,0,

Solution 1:

Your output format is frankly pretty bizarre and requires reversing the order of indices a lot, (and makes the output fairly useless for indexing the original array) but this works:

def find_boxes(np_matrix):
    np_mat = np_matrix[::-1, :]  # reversed in expected output
    def find_extent(arr, val):
        xn = arr.size
        x0 = np.flatnonzero(arr == 1)
        xi = np.searchsorted(x0, val, side = 'right')
        if xi == x0.size:
            x1 = x0[xi-1]
            x2 = xn - 1
        elif xi == 0:
            x1 = 0
            x2 = x0[xi]
        else:
            x1 = x0[xi-1]
            x2 = x0[xi]
        return np.array([x1, x2])

    green = np.where(np_mat == 2)
    green = tuple(g[np.argsort(green[-1])] for g in green)
    coords = np.empty((green[0].size, 2, 4))

    for i, (x, y) in enumerate(zip(*green)):
        coords[i, 0] =   np.tile(find_extent(np_mat[x, :], y),       2)
        coords[i, 1] = np.repeat(find_extent(np_mat[:, y], x)[::-1], 2)  # reversed again
    return np.stack(green)[::-1].T, coords.swapaxes(1,2).astype(int)
    # reversed again and transposed

Testing:

find_boxes(np_matrix)
Out: 
(array([[ 0,  0],
        [ 7, 12],
        [16, 27],
        [29, 21],
        [34,  7]], dtype=int32), 
 array([[[ 0,  6],
         [ 2,  6],
         [ 0,  0],
         [ 2,  0]],

        [[ 3, 14],
         [ 9, 14],
         [ 3,  7],
         [ 9,  7]],

        [[12, 31],
         [23, 31],
         [12, 24],
         [23, 24]],

        [[25, 22],
         [32, 22],
         [25, 15],
         [32, 15]],

        [[33, 13],
         [35, 13],
         [33,  0],
         [35,  0]]]))

Solution 2:

Another method, which makes the four directions symetric :

rm = m[::-1].T                            # (j,-i) to (x,y)
green = np.where(rm==2)                   # the costly operation
centers = np.vstack(green).T

rm[green] = 0
res = []

for x,y in centers:
    for s in (-1,1):                      # rear/frontfor t in range(2) :               # vertical/horizontal             
            v = *_,save = rm[x,y::s]            
            v[-1] = 1                     # sentinel
            res.append(y + s*v.argmax())  # find the first 1
            v[-1] = save 
            x,y,rm = y,x,rm.T             # turn rm[green] = 2  

coordinates = np.array(res).reshape(-1,4) 
corners = coordinates.take([[1,2],[3,2],[1,0],[3,0]],axis=1)    

This avoids to deal with the included/excluded behavior of Python slices, and manages borders with a sentinel system.

print(centers);print(corners)

[[ 0  0]
 [ 7 12]
 [16 27]
 [29 21]
 [34  7]]-----------[[[ 0  6]
  [ 2  6]
  [ 0  0]
  [ 2  0]][[ 3 14]
  [ 9 14]
  [ 3  7]
  [ 9  7]][[12 31]
  [23 31]
  [12 24]
  [23 24]][[25 22]
  [32 22]
  [25 15]
  [32 15]][[33 13]
  [35 13]
  [33  0]
  [35  0]]]

Post a Comment for "Get Coordinates Of Squares In Numpy Matrix"