2014-11-03 61 views
3

所以我有興趣創建一個自定義的非線性濾波器。我的面具是一個3乘3的矩陣,我想要做的就是取我的中心點,並查看直接與它相鄰的值(不包括對角線元素)。我想通過每個相鄰值減去中間元素,然後找到這些值中的最小值。基本上我正在看高程數據,我想找到最小的Δ-Z到中點。如何創建自定義非線性濾波器?

例子:

Z = [64 21 31 59 38 30 92 26 81 47 43 60 53 23 18 71];

因此,可以說,我只是在看Z(3,3) = 43現在。我會拿43和減去92,60,18和47;分別產生-49,-17,25和-4。然後我希望它只輸出-49。這個過程將對Z矩陣中的每個元素重複。我會如何去做這件事?謝謝!

回答

5

@ chappjc的答案完全可以接受。但是,如果您想採用colfilt啓發式方法,則可以使用im2col轉換像素鄰域,以便將3 x 3個重疊的鄰域放入列中。這裏會發生的是,像素鄰域是以列主格式構建的,因此每個像素鄰域的列都堆疊成一個列。你會把所有這些堆積的柱子放到一個二維矩陣中。在我們的例子中,行數將是9,而我們將有多少個有效像素鄰域的列。這是您使用im2col時的結果。像素鄰域如何獲得又是列主要格式。從圖像的左上角開始,沿着行向下聚集3 x 3像素的鄰域。一旦我們到達矩陣的底部,然後我們移動到下一列,然後再次向下行。 im2col工作方式的這種行爲對於此算法的工作至關重要。

一旦你這樣做,分別提取第二,第四,第六和第八行,以獲得一個鄰居的西,北,南和東元素(基數方向)。你會減去第五行,這將是與他們各自的基本方向的鄰域的中心,然後取最小值。但是,在執行此操作之前,需要使用1像素邊框來填充陣列,以便可以在Z中處理邊框像素。這個像素邊界被假定爲零。

換句話說,嘗試做這樣的事情:

Zpad = padarray(Z, [1 1]); 
A = im2col(Zpad, [3 3]); 
cardinal_directions = A(2:2:8,:); 
out = reshape(min(bsxfun(@minus, A(5,:), cardinal_directions), [], 1), size(Z)); 

看起來像一口!我們慢慢瀏覽一下。我使用了padarray,並在原始矩陣Z周圍創建了零像素邊框,並將其存儲在Zpad中。然後,我使用im2col將填充結果的每個3 x 3像素鄰域轉換爲每個9個元素的列。然後我通過採樣im2col輸出的第二,第四,第六和第八行來提取每個像素鄰域的基本方向。一旦我提取這些基本方向,我提取第五行,這是每個像素鄰域的中心,並與他們相應的像素鄰域進行減法。然後我使用min對所有列進行最小化,並對所有行進行操作(指定操作的維數爲1)。

我使用bsxfun來方便減去每個鄰域中的中心像素及其各自的基本方向。這個輸出將是一個單獨的向量,所以我需要將這個向量重新排列成一個矩陣。這個行向量的元素按列主格式排列,所以我需要將這個數組重新排列成適當的矩陣。

這是我與你的榜樣:

out = 

    26 -43 -61 28 
    -43 -62 49 -66 
    28 -34 -49 -11 
    -28 -30 -53 11 

如果你想仔細檢查,這是對的,看看Z(2,2)。我們看到中心元素是30,而主要元素是21,38,47和92.以30和每個元素相減給我們9,-8,-17和-62。所有這些中的最小值是-62,這是在out(2,2)處看到的。同樣,你的例子Z(3,3)產生-49在out(3,3),這是你的預期。你必須照顧沿out邊界發生的事情。我對這個矩陣進行了零填充,因此沿着邊界的條目將以鄰域的中心爲中心,並以零減去。你沒有正確定義你想沿邊界做什麼,所以我假設在這種情況下,如果你走出Z以外,沿邊界的基本方向是零。

+1

其實我的'nlfilter'答案完全是廢話,但我修復了'ordfilt2'答案,以便它實際上只考慮OP詢問的4個鄰居。 :) – chappjc 2014-11-03 21:19:46

+0

@chappjc - 哈哈我在想這件事! ordfilt2'的答案比我的方法更可讀。我+爲你順利! – rayryeng 2014-11-03 21:20:30

+1

如果我從'ordfilt2'中刪除'symmetric'選項,我會得到你的答案。謝謝你保持我的誠實! ;) – chappjc 2014-11-03 21:26:41

3

對於最小/最大過濾,ordfilt2可能是最有效的(也許是imdilate/imerode,但這是另一回事)。

首先,創建一個面具,表示四個近鄰考慮:

>> mask = false(3); mask([2 4 6 8]) = true 
mask = 

    0  1  0 
    1  0  1 
    0  1  0 

篩選與面膜:

>> Zmax = ordfilt2(Z,4,mask); % last value (4th non-zero) is max 
>> out = Z - Zmax 
out = 

    26 -43 -61 28 
    -43 -62 49 -66 
    28 -34 -49 -11 
    -28 -30 -53 11 

總之,管理負數,記得要使用能數據類型。

順便說一句,見this answer關於使用ordfilt2imdilate峯值發現,一個類似的任務。