测试周围的非零元素

时间:2010-08-04 02:04:28

标签: matlab matrix

以下是以下部分:

2)其他问题:

在得到非零邻居的平均值之后,我还想测试邻居元素是否等于,小于或大于非零的平均值。如果它大于或等于'1'或'0'。

注意:如果邻居在两个或多个中心的半径内,则取最小的中心平均值进行测试。

    0    12     9     
    4  **9**    15     
   11    19     0 

中间的'9'在12,15和19中心的半径范围内,所以取最小平均值[9.000,9.000,8.000] = 8.000

例如,当半径= 1米或距离1个元素时。

new_x =

     0         0          0          0         0
     0         0     **9.0000**    9.0000      0
     0      4.0000     9.0000    **9.0000**    0
     0    **8.3333** **8.0000**      0         0
     0      2.0000     4.0000      8.0000      0
     0      4.0000     5.0000      8.0000      0
     0         0          0          0         0

Test_x =

     0         0           0           0         0
     0         0       **9.0000**      1         0
     0         0           1       **9.0000**    0
     0    **8.3333**   **8.0000**      0         0
     0         0           0           0         0
     0         0           0           0         0
     0         0           0           0         0

=============================================== ==================================

1)假设我有一个矩阵,如下所示

X =

 0     0     0     0     0
 0     0    12     9     0
 0     4     9    15     0
 0    11    19     0     0
 0     2     4     8     0
 0     4     5     8     0
 0     0     0     0     0

并且我想找到大于10的周围非零元素的平均值。其余元素仍保持相同,即元素< 10。

所以我希望我的解决方案看起来像,

new_x =

     0         0         0         0         0
     0         0    9.0000    9.0000         0
     0    4.0000    9.0000    9.0000         0
     0    8.3333    8.0000         0         0
     0    2.0000    4.0000    8.0000         0
     0    4.0000    5.0000    8.0000         0
     0         0         0         0         0

不是:我只看那个比某个值更大的元素的邻居(在这种情况下是10)。

让我们说任何大于10的元素都是'中心',我们想要找到半径为1米的非零值的平均值。其中1米=距离中心1个元素。

注意:半径可能不总是1米,即可以是2或更多。在这种情况下,它不会只是中心的顶部,底部,左侧和右侧。

****还要注意矩阵边界。例如,当半径= 2或更大时,一些非零邻居的平均值在边界外。**

例如,

对于半径= 1 m = 1个元素, new_x = [(i + 1,j),(i-1,j),(i,j + 1)和(i,j-1)]的平均值 - 中心的顶部,底部,右侧和左侧。

对于半径= 2 m = 2个元素, new_x = [(i + 1,j),(i + 2,j),(i-1,j),(i-2,j),(i,j + 1),(i,j +)的平均值2),(i,j-1),(i,j-2),(i + 1,j + 1),(i + 1,j-1),(i-1,j-1),和第(i-1,J + 1)]。

=============================================== ===================

我之前尝试过一些事情,但我不熟悉这些功能。

所以请帮我解决问题。

提前谢谢。

4 个答案:

答案 0 :(得分:4)

修改: 请注意,这需要图像处理工具箱中的功能,即:COLFILTSTREL

r = 1;                       %# radius
t = 10;                      %# threshold value
mid = round((2*r+1)^2/2);    %# mid point
nhood = getnhood(strel('diamond', r));
nhood(mid) = false;
fcn = @(M)sum(M(nhood(:),:),1)./(sum(M(nhood(:),:)~=0)+all(M(nhood(:),:)==0)).*(M(mid,:)>=t)+M(mid,:).*(M(mid,:)<t);
new_x = colfilt(x, 2*[r r]+1, 'sliding',fcn)

对于r = 1:

new_x =
            0            0            0            0            0
            0            0            9            9            0
            0            4            9            9            0
            0       8.3333            8            0            0
            0            2            4            8            0
            0            4            5            8            0
            0            0            0            0            0

对于r = 2:

new_x =
            0            0            0            0            0
            0            0         11.2            9            0
            0            4            9       10.167            0
            0            7       7.7778            0            0
            0            2            4            8            0
            0            4            5            8            0
            0            0            0            0            0

事实上,它适用于任何radius >= 1

注意菱形形状结构元素如何代表邻域:

nhood =
     0     1     0
     1     0     1
     0     1     0

nhood =
     0     0     1     0     0
     0     1     1     1     0
     1     1     0     1     1
     0     1     1     1     0
     0     0     1     0     0

and so on..

<强>解释

我们使用COLFILT函数使用NxN的滑动邻域遍历矩阵,并将每个块作为列放在临时矩阵中。

我们使用函数fcn处理此临时矩阵(块)的每一列,结果将在完成后放置在正确的位置(COLFILT使用IM2COL和{{ 3}}下面)。

我们根据区块中心的值检查两种情况:

  1. 如果小于10,则返回该值:M(mid,:)

  2. 如果它的&gt; = 10,我们计算其邻域的非零元素的平均值 sum(M(nhood(:),:),1) ./ (sum(M(nhood(:),:)~=0) + all(M(nhood(:),:)==0))。 有必要避免除以零

  3. 注意1&amp;的结果如何使用R1.*(M(mid,:)<t) + R2.*(M(mid,:)>=t)组合上面的2以模拟if / else选项。

答案 1 :(得分:3)

以下是我认为您在问题中描述的算法。对于每个像素:

  • 如果像素值小于10,则不执行任何操作。
  • 如果像素值大于或等于10,则将像素值替换为非零的4连接最近邻居的平均值。

如果这是正确的(因为它似乎来自您给出的样本矩阵),那么您可以使用NLFILTER中的函数Image Processing Toolbox(如果您有权访问它)来执行此操作操作:

fcn = @(x) [x(5) sum(x(2:2:8))/max(sum(x(2:2:8) > 0),1)]*[x(5) < 10; x(5) >= 10];
new_x = nlfilter(X,[3 3],fcn);


编辑:如果您无法访问Image Processing Toolbox,也可以使用内置的CONV2功能执行此操作,如下所示:

kernel = [0 1 0; ...                      %# Convolution kernel
          1 0 1; ...
          0 1 0];
sumX = conv2(X,kernel,'same');            %# Compute the sum of neighbors
                                          %#   for each pixel
nX = conv2(double(X > 0),kernel,'same');  %# Compute the number of non-zero
                                          %#   neighbors for each pixel
index = (X >= 10);                        %# Find logical index of pixels >= 10
new_x = X;                                %# Initialize new_x
new_x(index) = sumX(index)./max(nX(index),1);  %# Replace the pixels in index
                                               %#   with the average of their
                                               %#   non-zero neighbors

以上处理你的radius = 1的情况。要解决radius = 2的情况,你只需要将卷积内核更改为以下代码并重新运行上面的代码:

kernel = [0 0 1 0 0; ...
          0 1 1 1 0; ...
          1 1 0 1 1; ...
          0 1 1 1 0; ...
          0 0 1 0 0];

答案 2 :(得分:1)

你可以这样做:(在Octave中测试,应该在matlab中工作)

octave-3.2.3:17> toohigh = (x>=10)
toohigh =

   0   0   0   0   0
   0   0   1   0   0
   0   0   0   1   0
   0   1   1   0   0
   0   0   0   0   0
   0   0   0   0   0
   0   0   0   0   0

octave-3.2.3:18> nbr_avg = filter2(ones(3,3)/9,x)
nbr_avg =

   0.00000   1.33333   2.33333   2.33333   1.00000
   0.44444   2.77778   5.44444   5.00000   2.66667
   1.66667   6.11111   8.77778   7.11111   2.66667
   1.88889   5.44444   8.00000   6.11111   2.55556
   1.88889   5.00000   6.77778   4.88889   1.77778
   0.66667   1.66667   3.44444   2.77778   1.77778
   0.44444   1.00000   1.88889   1.44444   0.88889

octave-3.2.3:19> y=x; y(toohigh) = nbr_avg(toohigh)

y =

   0.00000   0.00000   0.00000   0.00000   0.00000
   0.00000   0.00000   5.44444   9.00000   0.00000
   0.00000   4.00000   9.00000   7.11111   0.00000
   0.00000   5.44444   8.00000   0.00000   0.00000
   0.00000   2.00000   4.00000   8.00000   0.00000
   0.00000   4.00000   5.00000   8.00000   0.00000
   0.00000   0.00000   0.00000   0.00000   0.00000

filter2函数允许你过滤邻居(不知道你想要什么函数......),如果你使用布尔索引矩阵(在这种情况下是toohigh)来选择那些成员如果原始矩阵太高,你可以用你想要的那些替换它们。

更具体地说,filter2允许您使用任意矩阵进行卷积。所有1的矩阵都做空间低通滤波器。


注意:我的数学与你的数学不符。我不太确定为什么你只想平均非零邻居(当有零时给非零邻居提供更高的权重),但是如果你想这样做,你可以filter2(ones(3,3),x) ./ M M = filter2(ones(3,3),(x ~= 0))是非零邻居的数量。

答案 3 :(得分:1)

编辑:这是一个不需要图像处理工具箱的解决方案。但是,它会使用conv2nan.m,它是免费NaN toolbox的一部分。

这种方法依赖于两种不同的过滤/卷积操作:一种获取每个元素的surrounders的总和,另一种获得非零的surrounders的数量。然后,您已准备好将它们组合起来,以获得非零线索的平均值。像这样:

% set up starting point matrix with some zeros
X = magic(4);
X(X < 5) = 0;

X(X == 0) = NaN; % convert zeros to NaNs to work with conv2nan
countmat = double(X > 0);

cmat = [0 1 0;
        1 0 1;
        0 1 0]; % consider surrounding elements only

[m1,c] = conv2nan(X,cmat); % sum of surrounding elements
[m2,c] = conv2nan(countmat,cmat); % number of surrounding elements > 0

x_new = m1./m2; % compute average we want

x_new = x_new(2:end-1,2:end-1); % trim edges created by conv2
x_new(~countmat) = 0; % restore zero elements
x_new(X < 10) = X(X < 10) % restore < 10 elements

它做了一些额外的工作,因为卷积是针对所有元素完成的,而不仅仅是那些&gt; = 10.但它比手动循环方法更通用。