所以我对创建自定义非线性滤波器感兴趣。我的掩码是一个3乘3的矩阵,我想要做的是取我的中心点并查看与其直接相邻的值(不包括对角线元素)。我想通过每个相邻值减去中间元素,然后找到这些值中的最小值。基本上我正在查看高程数据,我想找到中间点的最小delta-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矩阵中的每个元素重复该过程。我该怎么做呢?谢谢!
答案 0 :(得分:5)
@chappjc的回答是完全可以接受的。但是,如果您想采用colfilt
启发式方法,则可以使用im2col
转换像素邻域,以便将3 x 3个重叠的邻域放入列中。这里发生的是像素邻域以列主格式构建,因此每个像素邻域的列被堆叠成单个列。您将获取所有这些堆叠的列并将它们放入2D矩阵中。在我们的例子中,行数将是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
周围创建了1像素的零边框,并将其存储在Zpad
中。然后,我使用im2col
将填充结果的每个3 x 3像素邻域转换为每个9个元素的列。然后,我通过对im2col
输出的第二,第四,第六和第八行进行采样来提取每个像素邻域的基本方向。一旦我提取了这些基本方向,我就提取第五行,这是每个像素邻域的中心,并使用相应的像素邻域进行减法。然后,我使用min
对所有列进行最小化操作,并对所有行进行操作(将操作维度指定为1
)。
我使用bsxfun
来促进每个邻域中的中心像素与其各自的基本方向相减。此输出将是单个向量,因此我需要将reshape
向量重新转换为矩阵。这个行向量的元素以列主格式排列,这就是为什么我需要将数组重新整形为适当的矩阵。
这就是我的例子:
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)
的示例会在out(3,3)
处产生-49,这正是您所期望的。你将不得不照顾out
边界发生的事情。我对此矩阵进行了零填充,因此沿着边界有条目,您将获取邻域的中心并减去零。你还没有正确地定义你想要沿着边界做什么,所以我假设如果你走出Z
之外沿着边界的基本方向在这种情况下为零。
答案 1 :(得分: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关于使用ordfilt2
和imdilate
进行高峰查找,这是一项类似的任务。