代码之家  ›  专栏  ›  技术社区  ›  Gacek

同时使用两个数组中的元素的筛选器

  •  4
  • Gacek  · 技术社区  · 16 年前

    假设我们有两个相同大小的数组- 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 回复  |  直到 16 年前
        1
  •  4
  •   Jonas    16 年前

    解决这个问题的方法是找到一种方法来组合来自a和b的信息,从而使过滤本身变得容易。

    我首先想到的是沿着三维连接A和B,并通过一个过滤器屏蔽,它将从“A-Slice”中获取8个元素,从“B-Slice”中获取中心元素。不幸的是,这不受Matlab的支持。

    虽然nlfilter只适用于二维图像,但它允许您指定任何用于过滤的函数。因此,你可以创建一个函数,这个函数可以通过某种方式查找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);
    
        2
  •  2
  •   gnovice    16 年前

    如果您的数据是 unsigned integer type (就像典型的灰度图像类型 uint8 )你可以把两个矩阵组合起来 A B 将一个矩阵的数据存储在低位,另一个矩阵的数据存储在高位。你可以用 NLFILTER 应用一个过滤函数来提取适当的数据位以收集必要的矩阵值。

    下面的示例应用上述形式的中值滤波器(3乘3的元素数组 中心元素来自 )随机值的两个无符号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
    

    以下是上述一些关键功能的附加链接: PADARRAY , BITAND , BITSHIFT .