Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
234 views
in Technique[技术] by (71.8m points)

python - Find boolean mask by pattern

I have array:

arr = np.array([1,2,3,2,3,4,3,2,1,2,3,1,2,3,2,2,3,4,2,1])
print (arr)
[1 2 3 2 3 4 3 2 1 2 3 1 2 3 2 2 3 4 2 1]

I would like find this pattern and return booelan mask:

pat = [1,2,3]
N = len(pat)

I use strides:

#https://stackoverflow.com/q/7100242/2901002
def rolling_window(a, window):
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
    strides = a.strides + (a.strides[-1],)
    c = np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
    return c
print (rolling_window(arr, N))
[[1 2 3]
 [2 3 2]
 [3 2 3]
 [2 3 4]
 [3 4 3]
 [4 3 2]
 [3 2 1]
 [2 1 2]
 [1 2 3]
 [2 3 1]
 [3 1 2]
 [1 2 3]
 [2 3 2]
 [3 2 2]
 [2 2 3]
 [2 3 4]
 [3 4 2]
 [4 2 1]]

I find positions of first values only:

b = np.all(rolling_window(arr, N) == pat, axis=1)
c = np.mgrid[0:len(b)][b]
print (c)
[ 0  8 11]

And positions another vals:

d = [i  for x in c for i in range(x, x+N)]
print (d)
[0, 1, 2, 8, 9, 10, 11, 12, 13]

Last return mask by in1d:

e = np.in1d(np.arange(len(arr)), d)
print (e)
[ True  True  True False False False False False  True  True  
  True  True  True  True False False False False False False]

Verify mask:

print (np.vstack((arr, e))) 
[[1 2 3 2 3 4 3 2 1 2 3 1 2 3 2 2 3 4 2 1]
 [1 1 1 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0]]
  1 2 3           1 2 3 1 2 3   

I think my solution is a bit over-complicated. Is there some better, more pythonic solution?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

We can simplify things at the end with Scipy supported binary-dilation -

from scipy.ndimage.morphology import binary_dilation

m = (rolling_window(arr, len(pat)) == pat).all(1)
m_ext = np.r_[m,np.zeros(len(arr) - len(m), dtype=bool)]
out = binary_dilation(m_ext, structure=[1]*N, origin=-(N//2))

For performance, we can bring in OpenCV with its template matching capability, as we are basically doing the same here, like so -

import cv2

tol = 1e-5
pat_arr = np.asarray(pat, dtype='uint8')
m = (cv2.matchTemplate(arr.astype('uint8'),pat_arr,cv2.TM_SQDIFF) < tol).ravel()

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...