过滤器同时使用两个数组中的元素

时间:2010-04-01 15:37:58

标签: matlab image-processing filter

假设我们有两个大小相同的数组 - AB

现在,我们需要一个过滤器,对于给定的掩码大小,从A中选择元素,但删除掩码的中心元素,并从B插入相应的元素。

因此3x3“伪掩码”看起来与此类似:

A A A
A B A
A A A

为平均滤波器做这样的事情非常简单。我们可以计算A中没有中心元素的元素的平均值,然后将它与适当的比例与来自B的元素组合:

h = ones(3,3);
h(2,2) =0; 
h = h/sum(h(:));
A_ave = filter2(h, A);
C = (8/9) * A_ave + (1/9) * B;

但是如何为中位数过滤器(medfilt2做更好的事情,或者对ordfilt2做更好的事情)

2 个答案:

答案 0 :(得分:4)

解决这个问题的方法是找到一种方法来组合A和B中的信息,以便过滤本身变得容易。

我想到的第一件事是沿着第三维连接A和B,并使用过滤器掩码传递,该过滤器掩码将从'A-slice'获取8个元素,从'B-slice'获取中心元素。不幸的是,这不是Matlab支持的。

虽然nlfilter仅适用于2D图像,但它允许您指定任何过滤功能。因此,您可以创建一个能够以某种方式查找A和B的正确值的函数。因此,我找到了第一个解决方案。

你创建一个新的数组C,它包含每个元素的元素索引,即第一个元素是1,第二个元素是2,然后,你运行nlfilter,它需要一个3x3的滑动窗口并传递窗口内的C值到过滤函数ffn。 ffn是一个匿名函数,它调用crazyFilter,并且已经初始化,以便在每次调用时传递A和B. CrazyFunction从C的滑动窗口获取值,这些值只是A和B中的索引,并从中收集A和B中的值。

第二个解决方案完全相同,只是不是移动滑动窗口,而是创建一个新数组,在每个列中,每个可能位置都有滑动窗口的内容。对于重叠窗口,列数组比原始数组大。同样,您只需要使用列数组C的值(它们是A和B的索引)来查找相关位置的A和B值。

修改 如果你有足够的内存,im2col和col2im可以加快这个过程的速度

%# define A,B
A = randn(100);
B = rand(100);

%# pad A, B - you may want to think about how you want to pad
Ap = padarray(A,[1,1]);
Bp = padarray(B,[1,1]);

#% EITHER -- the more more flexible way
%# create a pseudo image that has indices instead of values
C = zeros(size(Ap));
C(:) = 1:numel(Ap);
%# convert to 'column image', where each column represents a block
C = im2col(C,[3,3]);
%# read values from A
data = Ap(C);
%# replace centers with values from B
data(5,:) = Bp(C(5,:));

%# OR -- the more efficient way
%# reshape A directly into windows and fill in B
data = im2col(Ap,[3,3]);
data(5,:) = B(:);

% median and reshape
out = reshape(median(data,1),size(A));

旧版本(使用更少的内存,可能需要填充)

%# define A,B
A = randn(100);
B = rand(100);

%# define the filter function
ffun = @(x)crazyFilter(x,A,B);

%# create a pseudo image that has indices instead of values
C = zeros(size(A));
C(:) = 1:numel(A);

%# filter
filteredImage = nlfilter(C,[3,3],ffun);




%# filter function
function out = crazyFilter(input,A,B)
%#CRAZYFILTER takes the median of a 3x3 mask defined by input, taking 8 elements from A and 1 from B

%# read data from A
data = A(input(:));
%# replace center element with value from B
data(5) = B(input(5));

%# return the median
out = median(data);

答案 1 :(得分:2)

如果您的数据是unsigned integer type(类似于uint8类型的典型灰度图像),这是一个可行的解决方案。您可以将两个矩阵AB组合成一个较大整数类型的矩阵,其中一个矩阵的数据存储在较低位中,而另一个矩阵中的数据存储在较高位中。然后,您可以使用NLFILTER应用过滤功能,该功能可提取适当的数据位,以便收集必要的矩阵值。

以下示例应用您在上面描述的形式的中值滤波器(A的3乘3的元素数组与B的中心元素)到两个无符号8位矩阵随机值:

%# Initialize some variables:

A = randi([0 255],[3 3],'uint8');  %# One random matrix of uint8 values
B = randi([0 255],[3 3],'uint8');  %# Another random matrix of uint8 values

C = uint16(A)+bitshift(uint16(B),8);  %# Convert to uint16 and place the values
                                      %#   of A in the lowest 8 bits and the
                                      %#   values of B in the highest 8 bits

C = padarray(C,[1 1],'symmetric');  %# Pad the array edges

%# Make the median filtering function for each 3-by-3 block:

medFcn = @(x) median([bitand(x(1:4),255) ...  %# Get the first four A values
                      bitshift(x(5),-8) ...   %# Get the fifth B value
                      bitand(x(6:9),255)]);   %# Get the last four A values

%# Perform the filtering:

D = nlfilter(C,[3 3],medFcn);
D = uint8(D(2:end-1,2:end-1));  %# Remove the padding and convert to uint8

以下是上面使用的一些关键功能的其他链接:PADARRAYBITANDBITSHIFT