假设我们有两个大小相同的数组 - A
和B
。
现在,我们需要一个过滤器,对于给定的掩码大小,从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
做更好的事情)
答案 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
类型的典型灰度图像),这是一个可行的解决方案。您可以将两个矩阵A
和B
组合成一个较大整数类型的矩阵,其中一个矩阵的数据存储在较低位中,而另一个矩阵中的数据存储在较高位中。然后,您可以使用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