0

I a very new in Python. Please, apologize if the question is too simple. I have a function which return the standard deviation from the surrounding pixels of a principal pixel, something like*:

def sliding_window(arr, window_size):
    """ Construct a sliding window view of the array"""
    arr = np.asarray(arr)
    window_size = int(window_size)
    if arr.ndim != 2:
        raise ValueError("need 2-D input")
    if not (window_size > 0):
        raise ValueError("need a positive window size")
    shape = (arr.shape[0] - window_size + 1,
             arr.shape[1] - window_size + 1,
             window_size, window_size)
    if shape[0] <= 0:
        shape = (1, shape[1], arr.shape[0], shape[3])
    if shape[1] <= 0:
        shape = (shape[0], 1, shape[2], arr.shape[1])
    strides = (arr.shape[1]*arr.itemsize, arr.itemsize,
               arr.shape[1]*arr.itemsize, arr.itemsize)
    return as_strided(arr, shape=shape, strides=strides)

def std(arr, i, j, d):
    """Return d-th neighbors of cell (i, j)"""
    w = sliding_window(arr, 2*d+1)

    ix = np.clip(i - d, 0, w.shape[0]-1)
    jx = np.clip(j - d, 0, w.shape[1]-1)

    i0 = max(0, i - d - ix)
    j0 = max(0, j - d - jx)
    i1 = w.shape[2] - max(0, d - i + ix)
    j1 = w.shape[3] - max(0, d - j + jx)

    return nu.std(w[ix, jx][i0:i1,j0:j1].ravel())

Now I want to apply this function to each element of the array and get as result an array with the same structure:

For example:

array = [[2,3,4,4], 
         [3,4,3,5], 
         [4,5,6,6], 
         [3,6,7,7]]


formula =  [[std(array, 0,0,2), std(array, 1,0,2),std(array, 2,0,2),std(array, 3,0,2)],
          [std(array, 0,1,2), std(array, 1,1,2),std(array, 2,1,2),std(array, 3,1,2)],
          [std(array, 0,2,2), std(array, 1,2,2),std(array, 2,2,2),std(array, 3,2,2)],
          [std(array, 0,3,2), std(array, 1,3,2),std(array, 2,3,2),std(array, 3,3,2)]] 



    result = [[0.70710678118654757, 0.9574271077563381, 1.1989578808281798, 1.0671873729054748], 
[0.68718427093627676, 1.1331154474650633, 1.4624940645653537, 1.4229164972072998], 
[0.8660254037844386, 1.1873172373979173, 1.5, 1.4409680388158819],
 [0.68718427093627676, 1.0657403385139377, 1.35400640077266, 1.2570787221094177]]

I was trying to make a loop. Something like:

For k, v in array[i][j]:
   sd(array, i,j, n)

But until now loops are very frustrating....I hope you can help me.

Community
  • 1
  • 1
RRuiz
  • 2,159
  • 21
  • 32

2 Answers2

1

You can do it with

array = [[2,3,4,4],
        [3,4,3,5],
        [4,5,6,6],
        [3,6,7,7]]

print [[[std(array,x,i,2) for x in xrange(len(array[i]))] for i in xrange(len(array))]]

# Result

[[[0.70710678118654757, 0.9574271077563381, 1.1989578808281798, 1.0671873729054748], [0.68718427093627676, 1.1331154474650633, 1.4624940645653537, 1.4229164972072998], [0.8660254037844386, 1.1873172373979173, 1.5, 1.4409680388158819], [0.68718427093627676, 1.0657403385139377, 1.35400640077266, 1.2570787221094177]]]
seartun
  • 191
  • 8
  • Hi seaturn. Thank you. I think it is what I need. It looks that it works in Pyton 2. I tried your code in Python 3 changing the `xrange` to `range` but I have still an error called `TypeError: 'builtin_function_or_method' object is not subscriptable` – RRuiz Jan 14 '17 at 20:17
  • ohh..the `print`!! – RRuiz Jan 14 '17 at 20:18
1

It looks like you can use the scipy function 'ndimage.generic_filter'.

We give it a footprint (your window_size), and map a function (np.nanstd) onto a 1d array of each item which matches in that footprint.

Because we have to worry about borders, we can give use np.nanstd, and pad the array with nans (cval = np.nan).

import numpy as np
import scipy.ndimage as ndimage

results = np.empty(shape = (4,4), dtype = 'float') #to avoid type conversion
footprint = np.ones((2,2)) #change for your window size
#footprint[0,0] = 0 #not sure if this is intended

array = [[2,3,4,4], 
         [3,4,3,5], 
         [4,5,6,6], 
         [3,6,7,7]]

ndimage.generic_filter(array, np.nanstd, footprint=footprint, mode = 'constant', cval= np.nan, output = results, origin = -1)

results
array([[ 0.70710678,  0.5       ,  0.70710678,  0.5       ],
       [ 0.70710678,  1.11803399,  1.22474487,  0.5       ],
       [ 1.11803399,  0.70710678,  0.5       ,  0.5       ],
       [ 1.5       ,  0.5       ,  0.        ,  0.        ]])

The results are different from yours - not sure if I have something wrong in the understanding, or the footprint/origin/function.

jeremycg
  • 24,657
  • 5
  • 63
  • 74
  • Hi jeremycg. I think the `ndimage.generic_filter` give us a different output. My question is more about to apply a function to every element of a multidimentional array and obtain an array with the same structure... – RRuiz Jan 14 '17 at 20:12