获取矩阵元素的邻居

时间:2014-01-30 16:58:31

标签: matlab

我有一个矩阵,对于每个元素,我想得到它周围元素的索引。所有这些结果必须以下列方式存储到矩阵中。矩阵的每一行对应于矩阵元素,并且该矩阵的每列包含邻居索引。例如,对于4x4矩阵,我们将得到一个16x8结果数组。一些矩阵元素没有8个邻居。

有一个例子,我认为它有效,我有什么方法可以避免循环?:

ElementNeighbors = [];
for n = 1:numel(Matrix)
    NeighborsMask = [ n-1 n+1 n+size(matrix,1) n-size(Matrix,1) n-size(Matrix,1)-1 n-size(Matrix,1)+1 ...
        n+size(Matrix,1)-1 n+size(Matrix,1)+1 ];

    ElementNeighbors = [ElementNeighbors ; NeighborsMask ];
end
ElementNeighbors (ElementNeighbors ==0|ElementNeighbors <0) = NaN;

1 个答案:

答案 0 :(得分:6)

给定矩阵M(n,m)的线性索引,你可以说服自己,元素M(i,j) = M(i-1, j-1) = M(i-1 + n * (j-2))的左上角邻居

在“线性索引”空间中,表示此元素的偏移量为

-n-1

为所有其他地点执行此操作,我们找到了

-n-1 | -1 | n-1
-n   |  x | n    => [-n-1, -n, -n+1, -1, +1, +n-1, +n, +n+1]
-n+1 | +1 | n+1     

因此,您可以使用上述值创建向量偏移量(将n替换为第一个维度)。例如,如果M是(5x4),那么

offset = [-6 -5 -4 -1 1 4 5 6];

然后创建所有索引:

indices = bsxfun(@plus, (1:m*n), offset(:));

bsxfun是“对这些元素执行此功能的一个很酷的简写;其中一个元素具有单个维度而另一个元素没有,相应地扩展”。您可以使用repmat执行相同操作,但这会创建不必要的中间矩阵(有时可能非常大)。

该命令将为所有8个邻居创建一个(8 x m*n)索引矩阵,包括那些可能不是真正邻居的索引...你需要修复的东西。

几种可能的方法:

  • 在开始之前填充矩阵
  • 不关心包装,只是摆脱掉落边缘的元素
  • 为所有“偏离边缘”的人创建一个掩码。

我更喜欢后者。 “离开边缘”意味着:

  • 排在第一行
  • 在左栏中左转
  • 排在最后一行
  • 在右栏中右转

在这四种情况中,有3种指数是“无效的”。它们在上述矩阵中的位置可以确定如下:

mask = zeros(size(M));
mask(:,1) = 1;
left = find(mask == 1);
mask(:,end) = 2;
right = find(mask == 2);
mask(1,:) = 3;
top = find(mask == 3);
mask(end,:) = 4;
bottom = find(mask == 4);

edgeMask = ones(8,m*n);
edgeMask(1:3, top) = 0;
edgeMask([1 4 6], left) = 0;
edgeMask([3 5 8], right) = 0;
edgeMask(6:8, bottom) = 0;

现在你拥有了所需的一切 - 所有指数和“无效”指数。没有循环。

如果你有野心,你可以把它变成一个单元阵列,但它会比使用完整的数组+掩码慢。例如,如果要查找值的所有邻居的平均值,可以执行

meanNeighbor = reshape(sum(M(indices).*edgeMask, 1)./sum(edgeMask, 1), size(M));

编辑重新阅读你的问题我看到你想要一个M * N,8维。我的代码是转置的。我相信你可以弄清楚如何适应它......

ATTRIBUTION @Tin对上述帖子提出了很多精彩的修改,但在审核过程中被拒绝了。我不能完全撤消这种不公正 - 但我想在此表示感谢。

扩展到不同地区和多个维度

如果你有一个N维图像矩阵M,你可以找到如下的邻居:

temp = zeros(size(M));
temp(1:3,1:3,1:3) = 1;
temp(2,2,2) = 2;
offsets = find(temp==1) - find(temp==2);

如果你想要一个大小一定半径的区域,你可以做

sz = size(M);
[xx yy zz] = meshgrid(1:sz(1), 1:sz(2), 1:sz(3));
center = round(sz/2);
rr = sqrt((xx - center(1)).^2 + (yy - center(2)).^2 + (zz - center(3)).^2);
offsets = find(rr < radius) - find(rr < 0.001);

你可以弄清楚如何处理前面为2D情况显示的边缘问题。

未经测试 - 请注意您是否发现上述任何问题。