EDIT I kept my original answer below. As Paul points out in the comments, the original answer didn’t really answer the OP question, and it would be easier to achieve using the ndimage filter. The next much more cumbersome function should do the right thing. It takes two arrays a and c and returns the minimum window size a and the values in c at the positions of the window minima in a :
def neighbor_min(a, c): ac = np.concatenate((a[None], c[None])) rows, cols = ac.shape[1:] ret = np.empty_like(ac)
Return is an array (2, rows, cols) that can be unpacked into two arrays:
>>> a = np.random.randint(100, size=(5,5)) >>> c = np.random.randint(100, size=(5,5)) >>> a array([[42, 54, 18, 88, 26], [80, 65, 83, 31, 4], [51, 52, 18, 88, 52], [ 1, 70, 5, 0, 89], [47, 34, 27, 67, 68]]) >>> c array([[94, 94, 29, 6, 76], [81, 47, 67, 21, 26], [44, 92, 20, 32, 90], [81, 25, 32, 68, 25], [49, 43, 71, 79, 77]]) >>> neighbor_min(a, c) array([[[42, 18, 18, 4, 4], [42, 18, 18, 4, 4], [ 1, 1, 0, 0, 0], [ 1, 1, 0, 0, 0], [ 1, 1, 0, 0, 0]], [[94, 29, 29, 26, 26], [94, 29, 29, 26, 26], [81, 81, 68, 68, 68], [81, 81, 68, 68, 68], [81, 81, 68, 68, 68]]])
The OP case could be resolved as:
def bd_from_ac(a, c): b,d = neighbor_min(a, c) return a*b, d
And while there is a serious performance hit, it's pretty fast:
In [3]: a = np.random.rand(1000, 1000) In [4]: c = np.random.rand(1000, 1000) In [5]: %timeit bd_from_ac(a, c) 1 loops, best of 3: 570 ms per loop
In fact, you are not using the coordinates of the minimum neighboring element for anything else, except that you extract it, so you can skip this part and create the min_neighbor function. If you do not want to resort to using cython for a fast loop, you will have to go with viewing the transitions, for example, in the Paul link. This usually converts your array (m, n) into a representation (m-2, n-2, 3, 3) the same data, and then you apply np.min to the last two axes.
Unfortunately, you have to apply it on one axis at a time, so you have to create a copy of the data (m-2, n-2, 3) . Fortunately, you can calculate at least two steps, first finish and minimize along one axis, and then along the other and get the same result. Thus, in most cases, you will have an intermediate storage the size of your input. If necessary, you can reuse the output array as an intermediate storage and avoid memory allocation, but this remains as an exercise ...
This function performs the following function. This is quite long because it has to deal not only with the central area, but also with special cases of four edges and four corners. In addition, this is a fairly compact implementation:
def neighbor_min(a): rows, cols = a.shape ret = np.empty_like(a)
Now you can do things like:
>>> a = np.random.randint(10, size=(5, 5)) >>> a array([[0, 3, 1, 8, 9], [7, 2, 7, 5, 7], [4, 2, 6, 1, 9], [2, 8, 1, 2, 3], [7, 7, 6, 8, 0]]) >>> neighbor_min(a) array([[0, 0, 1, 1, 5], [0, 0, 1, 1, 1], [2, 1, 1, 1, 1], [2, 1, 1, 0, 0], [2, 1, 1, 0, 0]])
And your original question can be resolved as:
def bd_from_ac(a, c): return a*neighbor_min(a), neighbor_min(c)
As a benchmark for performance:
In [2]: m, n = 1000, 1000 In [3]: a = np.random.rand(m, n) In [4]: c = np.random.rand(m, n) In [5]: %timeit bd_from_ac(a, c) 1 loops, best of 3: 123 ms per loop