2017-03-06 52 views
1

我已經找到兩個可以計算平均值,最大值,最小值,方差等的移動窗口的解決方案。現在,我想添加一個計數的唯一值功能按座標軸。按軸來說,我的意思是計算所有二維數組單通道。在Python中添加一個獨特的值過濾器以跨越移動窗口

len(numpy.unique(array))可以做到這一點,但需要很多迭代來計算所有數組。我可能使用的圖像大小爲2000 x 2000,因此迭代不是一個好的選擇。這關乎性能和記憶的有效性。

下面是大踏步移動窗口的兩個解決方案:

首先直接從埃裏克Rigtorp的在http://gozhnikov.github.io/2015/09/30/NumpyTipsAndTricks2.html取自http://www.mail-archive.com/[email protected]/msg29450.html

import numpy as np 

def rolling_window_lastaxis(a, window): 
    if window < 1: 
     raise ValueError, "`window` must be at least 1." 
    if window > a.shape[-1]: 
     raise ValueError, "`window` is too long." 
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window) 
    strides = a.strides + (a.strides[-1],) 
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides) 

def rolling_window(a, window): 
    if not hasattr(window, '__iter__'): 
     return rolling_window_lastaxis(a, window) 
    for i, win in enumerate(window): 
     if win > 1: 
      a = a.swapaxes(i, -1) 
      a = rolling_window_lastaxis(a, win) 
      a = a.swapaxes(-2, i) 
    return a 

filtsize = (3, 3) 
a = np.zeros((10,10), dtype=np.float) 
a[5:7,5] = 1 

b = rolling_window(a, filtsize) 
blurred = b.mean(axis=-1).mean(axis=-1) 

從亞歷克斯Rogozhnikov。

def compute_window_mean_and_var_strided(image, window_w, window_h): 
    w, h = image.shape 
    strided_image = np.lib.stride_tricks.as_strided(image, 
               shape=[w - window_w + 1, h - window_h + 1, window_w, window_h], 
               strides=image.strides + image.strides) 
    # important: trying to reshape image will create complete 4-dimensional compy 
    means = strided_image.mean(axis=(2,3)) 
    mean_squares = (strided_image ** 2).mean(axis=(2, 3)) 
    maximums = strided_image.max(axis=(2,3)) 

    variations = mean_squares - means ** 2 
    return means, maximums, variations 

image = np.random.random([500, 500]) 
compute_window_mean_and_var_strided(image, 20, 20) 

有沒有辦法在一個或兩個解決方案中添加/實現唯一值函數計數?

說明:基本上,我需要一個二維數組的唯一值過濾器,就像numpy.ndarray.mean。你

亞歷

+0

那麼,你正試圖在一個座標軸上的滑動窗口中計算「唯一值函數的數量」? – Divakar

+0

您的移動窗口尺寸和偏移量如何比較?顯然,偏移越小,潛在的節省就越高。實際上,在這些代碼片段中實現手段等的方式對我來說遠非最佳。 –

+0

@Divakar我試圖添加一個獨特的數值,就像Alex Rogozhnikov的means = strided_image.mean(axis =(2,3))或maximums = strided_image.max(axis =(2,3))例但更像unique = strided_image.unique(axis =(2,3))。 –

回答

2

這裏有一個方法scikit-image's view_as_windows有效的滑動窗口提取。

涉及的步驟:

  • 獲取滑動窗口。

  • 重塑成二維數組。請注意,這會產生一個副本,因此我們將失去views的效率,但保持向量化。

  • 排序沿着合併塊軸的軸線。

  • 獲取沿軸線分化和計數不同的元素,其與1添加時將是唯一值的每一個的那些滑動窗口的計數,因此最終預期的結果的數量。

的實施將是像這樣 -

from skimage.util import view_as_windows as viewW 

def sliding_uniq_count(a, BSZ): 
    out_shp = np.asarray(a.shape) - BSZ + 1 
    a_slid4D = viewW(a,BSZ)  
    a_slid2D = np.sort(a_slid4D.reshape(-1,np.prod(BSZ)),axis=1)  
    return ((a_slid2D[:,1:] != a_slid2D[:,:-1]).sum(1)+1).reshape(out_shp) 

採樣運行 -

In [233]: a = np.random.randint(0,10,(6,7)) 

In [234]: a 
Out[234]: 
array([[6, 0, 5, 7, 0, 8, 5], 
     [3, 0, 7, 1, 5, 4, 8], 
     [5, 0, 5, 1, 7, 2, 3], 
     [5, 1, 3, 3, 7, 4, 9], 
     [9, 0, 7, 4, 9, 1, 1], 
     [7, 0, 4, 1, 6, 3, 4]]) 

In [235]: sliding_uniq_count(a, [3,3]) 
Out[235]: 
array([[5, 4, 4, 7, 7], 
     [5, 5, 4, 6, 7], 
     [6, 6, 6, 6, 6], 
     [7, 5, 6, 6, 6]]) 

混合方法

爲了使其具有非常大的陣列工作,以適應一切都變成記憶,我們可能不得不保持一個循環沿着輸入數據中的每一行d迭代,像這樣 -

def sliding_uniq_count_oneloop(a, BSZ): 
    S = np.prod(BSZ) 
    out_shp = np.asarray(a.shape) - BSZ + 1 
    a_slid4D = viewW(a,BSZ)  
    out = np.empty(out_shp,dtype=int) 
    for i in range(a_slid4D.shape[0]): 
     a_slid2D_i = np.sort(a_slid4D[i].reshape(-1,S),-1) 
     out[i] = (a_slid2D_i[:,1:] != a_slid2D_i[:,:-1]).sum(-1)+1 
    return out 

混合方法 - 版本II

混合動力車一個的另一個版本,具有np.lib.stride_tricks.as_strided顯式使用 -

def sliding_uniq_count_oneloop(a, BSZ): 
    S = np.prod(BSZ) 
    out_shp = np.asarray(a.shape) - BSZ + 1 
    strd = np.lib.stride_tricks.as_strided 
    m,n = a.strides 
    N = out_shp[1] 
    out = np.empty(out_shp,dtype=int) 
    for i in range(out_shp[0]): 
     a_slid3D = strd(a[i], shape=((N,) + tuple(BSZ)), strides=(n,m,n)) 
     a_slid2D_i = np.sort(a_slid3D.reshape(-1,S),-1) 
     out[i] = (a_slid2D_i[:,1:] != a_slid2D_i[:,:-1]).sum(-1)+1 
    return out 
+0

在小陣列上工作良好,但當我傳遞真實數據時遇到MemoryError。分辨率爲30米的光柵1300x3300,覆蓋範圍爲〜40km x 100km。 :-( –

+0

@AlexandreCharland查看新增加的混合版本 – Divakar

+0

工作良好可以刪除MemoryError,但是如果您嘗試: >>> x,y = 800,2000 >>> image = np.random.randint(0 ,6,(X,Y)) >>>結果= sliding_uniq_count_oneloop(圖像,[20,20]) 我們得到「ValueError異常:陣列太大;'arr.size * arr.dtype.itemsize'大於。最大可能的大小」 –

0

np.mean在給定的方向工作

由於未做任何副本。看看as_strided陣列的形狀,它看起來比原始陣列大得多。但是因爲每個「窗口」都是一個視圖,所以它不佔用任何額外的空間。像mean這樣的縮減運算符可以很好地處理這種視圖。

但請注意,你的第二個示例警告關於reshape。這會創建一個副本;它會複製所有這些窗口中的值。

unique開始與

ar = np.asanyarray(ar).flatten() 

所以馬上蝙蝠是被製作reshapened副本。這是一個副本,和1d。然後它排序元素,尋找重複等。

有找到unique行的方法,但它們需要將行轉換爲大型結構化數組元素。實際上將一個二維數組轉換爲一個可以使用的1d。

相關問題