@ 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
以外,沿邊界的基本方向是零。
其實我的'nlfilter'答案完全是廢話,但我修復了'ordfilt2'答案,以便它實際上只考慮OP詢問的4個鄰居。 :) – chappjc 2014-11-03 21:19:46
@chappjc - 哈哈我在想這件事! ordfilt2'的答案比我的方法更可讀。我+爲你順利! – rayryeng 2014-11-03 21:20:30
如果我從'ordfilt2'中刪除'symmetric'選項,我會得到你的答案。謝謝你保持我的誠實! ;) – chappjc 2014-11-03 21:26:41