improving code efficiency: standard deviation on sliding windows

前端 未结 4 1515
渐次进展
渐次进展 2020-12-03 03:29

I am trying to improve function which calculate for each pixel of an image the standard deviation of the pixels located in the neighborhood of the pixel. My function uses tw

4条回答
  •  南笙
    南笙 (楼主)
    2020-12-03 03:44

    The most often used method to do this kind of things in image processing is using summed area tables, an idea introduced in this paper in 1984. The idea is that, when you compute a quantity by adding over a window, and move the window e.g. one pixel to the right, you don't need to add all the items in the new window, you only need to subtract the leftmost column from the total, and add the new rightmost column. So if you create an accumulated sum array over both dimensions from your array, you can get the sum over a window with a couple of sums and a subtraction. If you keep summed area tables for your array and its square, it's very easy to get the variance from those two. Here's an implementation:

    def windowed_sum(a, win):
        table = np.cumsum(np.cumsum(a, axis=0), axis=1)
        win_sum = np.empty(tuple(np.subtract(a.shape, win-1)))
        win_sum[0,0] = table[win-1, win-1]
        win_sum[0, 1:] = table[win-1, win:] - table[win-1, :-win]
        win_sum[1:, 0] = table[win:, win-1] - table[:-win, win-1]
        win_sum[1:, 1:] = (table[win:, win:] + table[:-win, :-win] -
                           table[win:, :-win] - table[:-win, win:])
        return win_sum
    
    def windowed_var(a, win):
        win_a = windowed_sum(a, win)
        win_a2 = windowed_sum(a*a, win)
        return (win_a2 - win_a * win_a / win/ win) / win / win
    

    To see that this works:

    >>> a = np.arange(25).reshape(5,5)
    >>> windowed_var(a, 3)
    array([[ 17.33333333,  17.33333333,  17.33333333],
           [ 17.33333333,  17.33333333,  17.33333333],
           [ 17.33333333,  17.33333333,  17.33333333]])
    >>> np.var(a[:3, :3])
    17.333333333333332
    >>> np.var(a[-3:, -3:])
    17.333333333333332
    

    This should run a couple of notches faster than convolution based methods.

提交回复
热议问题