2017-07-31 47 views
0

我發現了一個使用scipy製作循環過濾器的代碼片段,我想了解它是如何工作的。我知道skimage中有一個更好的,但我對這一場比賽感興趣。在Python中編碼循環過濾器

from scipy.ndimage.filters import generic_filter as gf 

# Define physical shape of filter mask 
def circular_filter(image_data, radius): 
    kernel = np.zeros((2*radius+1, 2*radius+1)) 
    y, x = np.ogrid[-radius:radius+1, -radius:radius+1] 
    mask = x**2 + y**2 <= radius**2 
    kernel[mask] = 1     
    filtered_image = gf(image_data, np.median, footprint = kernel) 
    return filtered_image 

但我不確定我完全理解發生了什麼事。特別是,究竟什麼行

 y, x = np.ogrid[-radius:radius+1, -radius:radius+1] 
    mask = x**2 + y**2 <= radius**2 
    kernel[mask] = 1 

呢?

我發佈了這個答案作爲我之前的一個問題的答案,但沒有回覆,所以我把它作爲一個新問題發佈。

回答

1

尋找詳細:

kernel = np.zeros((2*radius+1, 2*radius+1)) 
y, x = np.ogrid[-radius:radius+1, -radius:radius+1] 
mask = x**2 + y**2 <= radius**2 
kernel[mask] = 1     

第一行:

kernel = np.zeros((2*radius+1, 2*radius+1)) 

創建零的2-d陣列,其中的中心點和「半徑」點在任一側。對於半徑= 2,你會得到:

# __r__ +1 __r__ 
[ 0, 0, 0, 0, 0, ] #\ 
[ 0, 0, 0, 0, 0, ] #_} r 
[ 0, 0, 0, 0, 0, ] # +1 
[ 0, 0, 0, 0, 0, ] #\ 
[ 0, 0, 0, 0, 0, ] #_} r 

接下來,你從numpy.ogrid創建的開放網格 2個陣列。網格網格在numpy中是一個「技巧」,它涉及存儲一個「並行」數組或矩陣,該數組或矩陣將特定單元格的x或y座標保存在該單元格的位置。

例如,y -mesh電網可能是這樣的:

[ 0, 0, 0, 0, 0, ] 
[ 1, 1, 1, 1, 1, ] 
[ 2, 2, 2, 2, 2, ] 
[ 3, 3, 3, 3, 3, ] 
[ 4, 4, 4, 4, 4, ] 

而一個x -mesh電網可能是這樣的:

[ 0, 1, 2, 3, 4, ] 
[ 0, 1, 2, 3, 4, ] 
[ 0, 1, 2, 3, 4, ] 
[ 0, 1, 2, 3, 4, ] 
[ 0, 1, 2, 3, 4, ] 

如果你看看他們,你」我會意識到Y_grid[x][y] == yX_grid[x][y] == x這是經常使用,它有多個numpy函數來支持它。 ;-)

開放式網格與封閉式網格相似,只不過它只有「一維」。也就是說,不是一對(例如)5x5陣列,而是一個1x5陣列和一個5x1陣列。這就是ogrid所做的 - 它返回兩個打開的網格。這些值是從-radius到半徑+ 1,根據蟒規則(意味着半徑+ 1被省略了):

y, x = np.ogrid[-radius:radius+1, -radius:radius+1] 

所以y是numpy的陣列從例如存儲,-2..2 (含),x是-2..2的數組。下一步是構建一個布爾型掩碼 - 即一個佈滿值的數組。如你所知,當你在一個numpy數組上操作時,你會得到另一個numpy數組。因此,在以恆定的表達涉及兩個陣列產生另一個數組:

mask = x**2 + y**2 <= radius**2 

掩模的值將是2色的位圖,其中一個顏色是「真」,而另一顏色是「假。 「位圖將描述實心圓或磁盤。 (由於<=關係。請記住,x和y包含-2..2,而不是0..4。)

最後,從類型布爾轉換通過使用掩蔽陣列作爲kernel陣列(的零)上的覆蓋爲int時,零設置到那些每當掩碼爲「真」:

kernel[mask] = 1 

在這一點上,內核看起來像:

# __r__ +1 __r__ 
[ 0, 0, 1, 0, 0, ] #\ 
[ 0, 1, 1, 1, 0, ] #_} r 
[ 1, 1, 1, 1, 1, ] # +1 
[ 0, 1, 1, 1, 0, ] #\ 
[ 0, 0, 1, 0, 0, ] #_} r 
0

我對SciPy並不熟悉,但我會嘗試解釋一下基本概念。

這整個功能的目的是通過應用一個過濾器來改變原始圖像。該過濾器可以做很多事情,從改變圖像的對比度,或添加特殊效果等

讓我們通過不同的線路:

 kernel = np.zeros((2*radius+1, 2*radius+1)) 

在這一行,的副本正在創建圖像數據,但所有數據均爲零(因此正在使用零功能)。這樣就可以將面罩稍後應用到它上面。

 y, x = np.ogrid[-radius:radius+1, -radius:radius+1] 

這是創建所謂的「meshgrid」或多維網格。這是創建圓形「面具」。就像圖中的x軸和y軸具有均勻間隔的縮放比例一樣,這裏在網格中也是相同的。 在這種情況下,x和y變量存儲均勻間隔的值,用作軸的縮放比例。

 mask = x**2 + y**2 <= radius**2 

這裏,創建了一個「掩碼」。掩碼將用作要保護的圖像中的區域以免過濾器,以便不更改任何原始數據。請注意,在畢達哥拉斯式不等式中(這很重要,它不僅僅是一個圓而是一個圓盤)在這裏使用x和y變量,就像它們在數學意義上的方式一樣。這將創建一個具有給定半徑的磁盤,現在將其視爲掩碼。掩碼變量現在包含原始數據值不應更改的所有座標(x,y)。

 kernel[mask] = 1 

這是掩碼現在應用於之前創建的圖像副本的位置。現在,圖像有一個完美的副本(即相同的尺寸),但是具有「保護」原始數據不被改變的盤狀「掩膜」。這就是爲什麼磁盤覆蓋的所有點都設置爲1.另請注意,kernelmask的尺寸是如何匹配的。兩者都是多維的。圖像副本中的其餘值仍然設置爲零,如在第一行中所做的那樣。

 filtered_image = gf(image_data, np.median, footprint = kernel) 

這是所有東西拼合在一起的最後部分。原始數據存儲在image_data中,並且存在kernel,它是在其上應用了掩碼的圖像副本,指示不應更改數據的位置。它們都作爲參數傳遞到實際濾波函數gf(代表通用濾波器),並且輸出是新的濾波圖像。

這是圖像過濾的核心概念,如果您想了解更多信息,我建議您先學習基本的信號處理概念。信號處理課程涵蓋了這些概念如何工作的數學,但通常在真正抽象的數學中解釋,因爲這個概念可以應用於許多不同的例子。在您的代碼

+0

你說,掩碼標識圖像中不會被改變的區域。但是,這不是過濾器改變圖像的重點嗎?或者你是說這是圖像的副本,而不是原始圖像本身,它是由濾鏡更改的? – Jim421616

+0

遮罩確實識別圖像中不會被改變的區域。就像你臉上的面具來保護它,面具「保護」原始數據不被改變。這會使圖像的其他部分暴露於過濾。圖像的蒙版部分將通過座標爲1的'內核'meshgrid指示。曝光部分的座標爲0. –

+0

噢,我向後隱藏了0和1!我的錯。謝謝 :) – Jim421616