2016-04-26 10 views
2

2つのスタックカーネルで指定された2つの値の間にあるすべてのピクセルの数を知りたい2次元配列を持っています。ボーダーはカウントから除外する必要があります。例えば範囲内のナンシーカスタム移動ウィンドウカウントセル

:これを行うには

input = np.array([[1, 0, 0, 2, 1], 
    [0, 2, 1, 1, 7], 
    [2, 0, 6, 4, 1], 
    [1, 2, 3, 0, 5], 
    [6, 5, 4, 3, 2]]) 

kernel_min=np.array([[0, 1, 0], 
    [0, 1, 2], 
    [0, 0, 1]]) 

kernel_max=np.array([[2, 3, 2], 
    [2, 2, 4], 
    [2, 2, 3]]) 

min_max = np.dstack((kernel_min,kernel_max)) 

outcome= [[0, 0, 0, 0, 0], 
    [0, 7, 7, 9, 0], 
    [0, 8, 8, 8, 0], 
    [0, 8, 8, 8, 0], 
    [0, 0, 0, 0, 0]] 

私は、入力配列のすべての要素をループするスクリプトを作成しました。各要素の周りには、カーネルのサイズの領域が抽出され、カーネルの範囲内のセルが数えられます。

しかし、このすべての要素をループすることはかなり時間がかかります(私は巨大な配列を持っています)。 2つのカーネルの範囲内のピクセル数を高速化する方法はありますか?たとえば、すべての値をカウントする移動ウィンドウ関数です。

答えて

1

これは、配列ストライドトリックを使用してPythonループなしで行うことができます。簡単な方法は、レディメイド関数を使用することです。 Scikit Imageのview_as_windowsまたはScikit Learnのextract_patchesである。

from skimage.util import view_as_windows 

def with_strides(img, kernel_min, kernel_max): 
    win_w, win_h = kernel_min.shape 
    heatmap = np.zeros(img.shape, dtype='uint16') 
    target = heatmap[win_h//2:-win_h//2+1, win_w//2:-win_w//2+1] 

    windowed = view_as_windows(img, (win_h, win_w)) 
    mask = ((kernel_min <= windowed) & (windowed <= kernel_max)) 
    np.sum(mask, axis=(2,3), out=target) 

    return heatmap 

しかし、この方法ではメモリが非常に要求されますが、

もう1つの方法は、Pythonループを使用することですが、イメージの代わりにカーネルをループすることです。その考え方は、大きな配列でNumpy関数を呼び出すことによってオーバーヘッドを減らすことです。

def kernel_loops(img, kernel_min, kernel_max): 
    img_h, img_w = img.shape 
    win_h, win_w = kernel_min.shape 
    heatmap = np.zeros(img.shape, dtype='uint16') 
    target = heatmap[win_h//2:-win_h//2+1, win_w//2:-win_w//2+1] 

    for i in range(win_h): 
     for j in range(win_w): 
      # Negative index fails when slicing to the end 
      source = img[i:i+img_h-win_h+1, j:j+img_w-win_w+1] 
      target += (kernel_min[i,j] <= source) & (source <= kernel_max[i,j]) 

    return heatmap 

私はこの時点で代表的なタイミングを提供することはできませんが、スピードアップは重要です。パフォーマンスに及ぼすウィンドウサイズの影響を見ることは興味深いでしょう。

+0

これは本当にひどかった。スピードアップをテストするために、1035×1400ピクセルの8ビットイメージを使用しました。 は私のスクリプト-with計算は、約100秒を要したview_as_windows - 抜け は、それはそれは私がより大きな画像を処理していたときにこれは多くの時間を節約する約17秒 を取った第二のアプローチ-with約20秒に を取った機能します。どうもありがとう! Iは、サイズ(50から70)カーネルを増加させ、同じ画像を使用する場合 –

+0

は: - with_strides = 56秒(フルmemmory)を - 第2の方法は、より最適であるようkernel_loops = 32秒 はですね! –

関連する問題