【问题标题】:filter that uses elements from two arrays at the same time同时使用两个数组中的元素的过滤器
【发布时间】:2010-04-01 15:37:58
【问题描述】:

假设我们有两个大小相同的数组 - 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

【问题讨论】:

    标签: matlab image-processing filter


    【解决方案1】:

    解决这个问题的方法是找到一种方法来组合来自 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);
    

    【讨论】:

    • 内存使用并不重要。速度是,所以第一个版本似乎更好。我仍然不完全理解它是如何工作的;)我需要检查它是否给了我预期的输出。至于填充,我需要使用'对称'方法
    • 我已经更新了解释。希望这可以帮助。如果你仍然感到困惑,你应该看看线性索引在 Matlab 中是如何工作的。
    • 好的,在您的第二个解决方案中我仍然不明白的一件事:您为什么要费心创建C 矩阵?为什么不这样做:data = im2col(Ap, [3,3]) 然后data(5,:) = B(:)'
    • IM2COL 绝对是一个有用的功能(我没有,所以感谢乔纳斯!)
    • @Gacek:不按照您建议的方式进行操作的唯一原因是您想使用不同的过滤器模式。否则,您的建议就是要走的路。
    【解决方案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

    【讨论】:

    • +1 用于组合图像的巧妙方式,我认为这是不可能的!
    猜你喜欢
    • 2023-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-26
    • 1970-01-01
    • 2014-01-05
    • 1970-01-01
    相关资源
    最近更新 更多