Find boolean mask by pattern

前端 未结 2 1932
一生所求
一生所求 2020-12-11 07:37

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

相关标签:
2条回答
  • 2020-12-11 07:53

    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()
    
    0 讨论(0)
  • 2020-12-11 07:58

    Not sure how safe this is, but another method would be to read back to an as_strided view of the boolean output. As long as you only have one pat at a time it shouldn't be a problem I think, and it may work with more but I can't gurantee it because reading back to as_strided can be a bit unpredictable:

    def vview(a):  #based on @jaime's answer: https://stackoverflow.com/a/16973510/4427777
        return np.ascontiguousarray(a).view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))
    
    def roll_mask(arr, pat):
        pat = np.atleast_2d(pat)
        out = np.zeros_like(arr).astype(bool)
        vout = rolling_window(out, pat.shape[-1])
        vout[np.in1d(vview(rolling_window(arr, pat.shape[-1])), vview(pat))] = True
        return out
    
    np.where(roll_mask(arr, pat))
    (array([ 0,  1,  2,  8,  9, 10, 11, 12, 13], dtype=int32),)
    
    pat = np.array([[1, 2, 3], [3, 2, 3]])
    print([i for i in arr[roll_mask(arr, pat)]])
    [1, 2, 3, 2, 3, 1, 2, 3, 1, 2, 3]
    

    It seems to work, but I wouldn't give this answer to a beginner!

    0 讨论(0)
提交回复
热议问题