1

I'm very new to Python, and need do to a bit of tricky 2D array manipulation with it. I'm not sure of the best way to go about it.

Basically, I start with an array of values between 0 and 1.

I need to have a moving 2x2 window to apply to the 2D array, (edit: where the array is a 2D image; ie say 200x200 pixels or so) and within each 2x2 window, assign values 1-4, inversely, according to the array value weights (ie, the minimum cell in the 2x2 becomes 4, then the next minimum becomes 3, etc.)

I can see how to extract my 2x2 windows by a nested loop; is that the best way?

More tricky is how to go about the ordering assignment.

I thought to use numpy.where (subarray.min) iteratively on my window subarrays, but I can't see how to GET at the returned location where returns! I'm not sure that there isn't a better way to go about this.

Advice? Pointers to how to do complicated, messy, array manipulations with NumPy?

4

2 回答 2

0

So you're starting with an array like this:

In [1]: import numpy as np

In [2]: a = np.arange(20).reshape((10,-1))

In [3]: a
Out[3]: 
array([[ 0,  1],
       [ 2,  3],
       [ 4,  5],
       [ 6,  7],
       [ 8,  9],
       [10, 11],
       [12, 13],
       [14, 15],
       [16, 17],
       [18, 19]])

What you are looking for is reshape and argsort, I think.

Using the reshape member function you can change the shape without changing the sequence:

In [4]: a.reshape((-1,4))
Out[4]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15],
       [16, 17, 18, 19]])

Reshape takes a tuple. I like to think of that as (number of rows, number or columns). In this case, (-1,4) means: use 4 columns (so each row has four numbers in it), and calculate the amount of rows from the amount of data.

Using argsort you can get the array that you want.

In [2]: import numpy as np

In [3]: d = np.random.random((10, 2)).reshape((-1,4))

In [4]: d
Out[4]: 
array([[ 0.65945195,  0.1907593 ,  0.1630845 ,  0.76949532],
       [ 0.90823488,  0.71518689,  0.38422877,  0.77824007],
       [ 0.31453967,  0.76592537,  0.5871099 ,  0.09306465],
       [ 0.38251335,  0.97461878,  0.97562622,  0.87532202],
       [ 0.12358359,  0.20323007,  0.397975  ,  0.615806  ]])


In [7]: e = np.array([4-np.argsort(r) for r in d])

In [8]: e
Out[8]: 
array([[2, 3, 4, 1],
       [2, 3, 1, 4],
       [1, 4, 2, 3],
       [4, 1, 3, 2],
       [4, 3, 2, 1]])

As you can see, each row now has the required indices. Let's go over what line 7 does from the inside out:

  • for r in d: iterate over all rows in d.
  • 4 - np.argsort(r): argsort would create indices in the rang 0-3. So we substract it from 4 to get to a inverse 4-1 range. In numpy arrays, operations are done to each element, so 4 - np.array([2, 1, 0, 3]) acts like np.array([4,4,4,4]) - np.array([2, 1, 0, 3]).
  • []: the previous lines wrapped between square brackets make it a list comprehension, which is like a very fast and compact for-loop returning a list.
  • np.array: The list of arrays is combined into one big array.

Then using another reshape, you bring the data back into its original shape

In [9]: e.reshape((-1,2))
Out[9]: 
array([[2, 3],
       [4, 1],
       [2, 3],
       [1, 4],
       [1, 4],
       [2, 3],
       [4, 1],
       [3, 2],
       [4, 3],
       [2, 1]])

Edit:

Based on your comment, you can do the following. Say you have a 2D matrix:

In [1]: import numpy as np

In [2]: a = np.arange(100).reshape((-1,10))

In [3]: a
Out[3]: 
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
       [20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
       [30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
       [40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
       [50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
       [60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
       [70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
       [80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
       [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])

You can select a 2x2 submatrix like this:

In [4]: a[3:5, 0:2]
Out[4]: 
array([[30, 31],
       [40, 41]])

The patteren here is a[row:row+2, column:column+2]. Using the reshape and argsort techniques shown above you can create the new values.

In [5]: p = a[3:5, 0:2]

In [6]: e = 4-np.argsort(p.reshape((1,4))).reshape((2,2))

In [7]: e
Out[7]: 
array([[4, 3],
       [2, 1]])

You can then place this result in the original array or in a copy:

In [12]: a[3:5, 0:2] = e

In [13]: a
Out[13]: 
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
       [20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
       [ 4,  3, 32, 33, 34, 35, 36, 37, 38, 39],
       [ 2,  1, 42, 43, 44, 45, 46, 47, 48, 49],
       [50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
       [60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
       [70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
       [80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
       [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])

Note that both the width and height of the image need to be even for a 2x2 submatrix to work as intended...

于 2013-05-24T21:26:15.600 回答
0

Perhaps this will help [refer to here]

Invocation:

x = np.arange(36).reshape((6, 6))
print(x)
b = sliding_window(x, (2, 3), None, False) 
print(b)
于 2017-12-06T11:11:46.597 回答