2014-11-03 75 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峰值发现,一个类似的任务。

相关问题